1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include "vmlinux.h"
4 #include "bpf_tracing_net.h"
5 #include <bpf/bpf_helpers.h>
6 #include <bpf/bpf_tracing.h>
7 
8 char _license[] SEC("license") = "GPL";
9 
10 #ifndef AF_PACKET
11 #define AF_PACKET 17
12 #endif
13 
14 #ifndef AF_UNIX
15 #define AF_UNIX 1
16 #endif
17 
18 #ifndef EPERM
19 #define EPERM 1
20 #endif
21 
22 struct {
23 	__uint(type, BPF_MAP_TYPE_CGROUP_STORAGE);
24 	__type(key, __u64);
25 	__type(value, __u64);
26 } cgroup_storage SEC(".maps");
27 
28 int called_socket_post_create;
29 int called_socket_post_create2;
30 int called_socket_bind;
31 int called_socket_bind2;
32 int called_socket_alloc;
33 int called_socket_clone;
34 
35 static __always_inline int test_local_storage(void)
36 {
37 	__u64 *val;
38 
39 	val = bpf_get_local_storage(&cgroup_storage, 0);
40 	if (!val)
41 		return 0;
42 	*val += 1;
43 
44 	return 1;
45 }
46 
47 static __always_inline int real_create(struct socket *sock, int family,
48 				       int protocol)
49 {
50 	struct sock *sk;
51 	int prio = 123;
52 
53 	/* Reject non-tx-only AF_PACKET. */
54 	if (family == AF_PACKET && protocol != 0)
55 		return 0; /* EPERM */
56 
57 	sk = sock->sk;
58 	if (!sk)
59 		return 1;
60 
61 	/* The rest of the sockets get default policy. */
62 	if (bpf_setsockopt(sk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)))
63 		return 0; /* EPERM */
64 
65 	/* Make sure bpf_getsockopt is allowed and works. */
66 	prio = 0;
67 	if (bpf_getsockopt(sk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)))
68 		return 0; /* EPERM */
69 	if (prio != 123)
70 		return 0; /* EPERM */
71 
72 	/* Can access cgroup local storage. */
73 	if (!test_local_storage())
74 		return 0; /* EPERM */
75 
76 	return 1;
77 }
78 
79 /* __cgroup_bpf_run_lsm_socket */
80 SEC("lsm_cgroup/socket_post_create")
81 int BPF_PROG(socket_post_create, struct socket *sock, int family,
82 	     int type, int protocol, int kern)
83 {
84 	called_socket_post_create++;
85 	return real_create(sock, family, protocol);
86 }
87 
88 /* __cgroup_bpf_run_lsm_socket */
89 SEC("lsm_cgroup/socket_post_create")
90 int BPF_PROG(socket_post_create2, struct socket *sock, int family,
91 	     int type, int protocol, int kern)
92 {
93 	called_socket_post_create2++;
94 	return real_create(sock, family, protocol);
95 }
96 
97 static __always_inline int real_bind(struct socket *sock,
98 				     struct sockaddr *address,
99 				     int addrlen)
100 {
101 	struct sockaddr_ll sa = {};
102 
103 	if (sock->sk->__sk_common.skc_family != AF_PACKET)
104 		return 1;
105 
106 	if (sock->sk->sk_kern_sock)
107 		return 1;
108 
109 	bpf_probe_read_kernel(&sa, sizeof(sa), address);
110 	if (sa.sll_protocol)
111 		return 0; /* EPERM */
112 
113 	/* Can access cgroup local storage. */
114 	if (!test_local_storage())
115 		return 0; /* EPERM */
116 
117 	return 1;
118 }
119 
120 /* __cgroup_bpf_run_lsm_socket */
121 SEC("lsm_cgroup/socket_bind")
122 int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address,
123 	     int addrlen)
124 {
125 	called_socket_bind++;
126 	return real_bind(sock, address, addrlen);
127 }
128 
129 /* __cgroup_bpf_run_lsm_socket */
130 SEC("lsm_cgroup/socket_bind")
131 int BPF_PROG(socket_bind2, struct socket *sock, struct sockaddr *address,
132 	     int addrlen)
133 {
134 	called_socket_bind2++;
135 	return real_bind(sock, address, addrlen);
136 }
137 
138 /* __cgroup_bpf_run_lsm_current (via bpf_lsm_current_hooks) */
139 SEC("lsm_cgroup/sk_alloc_security")
140 int BPF_PROG(socket_alloc, struct sock *sk, int family, gfp_t priority)
141 {
142 	called_socket_alloc++;
143 	if (family == AF_UNIX)
144 		return 0; /* EPERM */
145 
146 	/* Can access cgroup local storage. */
147 	if (!test_local_storage())
148 		return 0; /* EPERM */
149 
150 	return 1;
151 }
152 
153 /* __cgroup_bpf_run_lsm_sock */
154 SEC("lsm_cgroup/inet_csk_clone")
155 int BPF_PROG(socket_clone, struct sock *newsk, const struct request_sock *req)
156 {
157 	int prio = 234;
158 
159 	if (!newsk)
160 		return 1;
161 
162 	/* Accepted request sockets get a different priority. */
163 	if (bpf_setsockopt(newsk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)))
164 		return 1;
165 
166 	/* Make sure bpf_getsockopt is allowed and works. */
167 	prio = 0;
168 	if (bpf_getsockopt(newsk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)))
169 		return 1;
170 	if (prio != 234)
171 		return 1;
172 
173 	/* Can access cgroup local storage. */
174 	if (!test_local_storage())
175 		return 1;
176 
177 	called_socket_clone++;
178 
179 	return 1;
180 }
181