xref: /linux/tools/testing/selftests/bpf/progs/lsm_cgroup.c (revision cec8423776176eb73429443ecb859789af9602e5)
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 extern bool CONFIG_SECURITY_SELINUX __kconfig __weak;
11 extern bool CONFIG_SECURITY_SMACK __kconfig __weak;
12 extern bool CONFIG_SECURITY_APPARMOR __kconfig __weak;
13 
14 #ifndef AF_PACKET
15 #define AF_PACKET 17
16 #endif
17 
18 #ifndef AF_UNIX
19 #define AF_UNIX 1
20 #endif
21 
22 #ifndef EPERM
23 #define EPERM 1
24 #endif
25 
26 struct {
27 	__uint(type, BPF_MAP_TYPE_CGROUP_STORAGE);
28 	__type(key, __u64);
29 	__type(value, __u64);
30 } cgroup_storage SEC(".maps");
31 
32 int called_socket_post_create;
33 int called_socket_post_create2;
34 int called_socket_bind;
35 int called_socket_bind2;
36 int called_socket_alloc;
37 int called_socket_clone;
38 int skipcap_retval = -4095;
39 int socket_retval = -4095;
40 
41 static __always_inline int test_local_storage(void)
42 {
43 	__u64 *val;
44 
45 	val = bpf_get_local_storage(&cgroup_storage, 0);
46 	if (!val)
47 		return 0;
48 	*val += 1;
49 
50 	return 1;
51 }
52 
53 static __always_inline int real_create(struct socket *sock, int family,
54 				       int protocol)
55 {
56 	struct sock *sk;
57 	int prio = 123;
58 
59 	/* Reject non-tx-only AF_PACKET. */
60 	if (family == AF_PACKET && protocol != 0)
61 		return 0; /* EPERM */
62 
63 	sk = sock->sk;
64 	if (!sk)
65 		return 1;
66 
67 	/* The rest of the sockets get default policy. */
68 	if (bpf_setsockopt(sk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)))
69 		return 0; /* EPERM */
70 
71 	/* Make sure bpf_getsockopt is allowed and works. */
72 	prio = 0;
73 	if (bpf_getsockopt(sk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)))
74 		return 0; /* EPERM */
75 	if (prio != 123)
76 		return 0; /* EPERM */
77 
78 	/* Can access cgroup local storage. */
79 	if (!test_local_storage())
80 		return 0; /* EPERM */
81 
82 	return 1;
83 }
84 
85 /* __cgroup_bpf_run_lsm_socket */
86 SEC("lsm_cgroup/socket_post_create")
87 int BPF_PROG(socket_post_create, struct socket *sock, int family,
88 	     int type, int protocol, int kern)
89 {
90 	called_socket_post_create++;
91 	return real_create(sock, family, protocol);
92 }
93 
94 /* __cgroup_bpf_run_lsm_socket */
95 SEC("lsm_cgroup/socket_post_create")
96 int BPF_PROG(socket_post_create2, struct socket *sock, int family,
97 	     int type, int protocol, int kern)
98 {
99 	called_socket_post_create2++;
100 	return real_create(sock, family, protocol);
101 }
102 
103 static __always_inline int real_bind(struct socket *sock,
104 				     struct sockaddr *address,
105 				     int addrlen)
106 {
107 	struct sockaddr_ll sa = {};
108 	struct sock *sk = sock->sk;
109 
110 	if (!sk)
111 		return 1;
112 
113 	if (sk->__sk_common.skc_family != AF_PACKET)
114 		return 1;
115 
116 	if (sk->sk_kern_sock)
117 		return 1;
118 
119 	bpf_probe_read_kernel(&sa, sizeof(sa), address);
120 	if (sa.sll_protocol)
121 		return 0; /* EPERM */
122 
123 	/* Can access cgroup local storage. */
124 	if (!test_local_storage())
125 		return 0; /* EPERM */
126 
127 	return 1;
128 }
129 
130 /* __cgroup_bpf_run_lsm_socket */
131 SEC("lsm_cgroup/socket_bind")
132 int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address,
133 	     int addrlen)
134 {
135 	called_socket_bind++;
136 	return real_bind(sock, address, addrlen);
137 }
138 
139 /* __cgroup_bpf_run_lsm_socket */
140 SEC("lsm_cgroup/socket_bind")
141 int BPF_PROG(socket_bind2, struct socket *sock, struct sockaddr *address,
142 	     int addrlen)
143 {
144 	called_socket_bind2++;
145 	return real_bind(sock, address, addrlen);
146 }
147 
148 /* __cgroup_bpf_run_lsm_current (via bpf_lsm_current_hooks) */
149 SEC("lsm_cgroup/sk_alloc_security")
150 int BPF_PROG(socket_alloc, struct sock *sk, int family, gfp_t priority)
151 {
152 	called_socket_alloc++;
153 	/* if already have non-bpf lsms installed, EPERM will cause memory leak of non-bpf lsms */
154 	if (CONFIG_SECURITY_SELINUX || CONFIG_SECURITY_SMACK || CONFIG_SECURITY_APPARMOR)
155 		return 1;
156 
157 	if (family == AF_UNIX)
158 		return 0; /* EPERM */
159 
160 	/* Can access cgroup local storage. */
161 	if (!test_local_storage())
162 		return 0; /* EPERM */
163 
164 	return 1;
165 }
166 
167 /* __cgroup_bpf_run_lsm_sock */
168 SEC("lsm_cgroup/inet_csk_clone")
169 int BPF_PROG(socket_clone, struct sock *newsk, const struct request_sock *req)
170 {
171 	int prio = 234;
172 
173 	if (!newsk)
174 		return 1;
175 
176 	/* Accepted request sockets get a different priority. */
177 	if (bpf_setsockopt(newsk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)))
178 		return 1;
179 
180 	/* Make sure bpf_getsockopt is allowed and works. */
181 	prio = 0;
182 	if (bpf_getsockopt(newsk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)))
183 		return 1;
184 	if (prio != 234)
185 		return 1;
186 
187 	/* Can access cgroup local storage. */
188 	if (!test_local_storage())
189 		return 1;
190 
191 	called_socket_clone++;
192 
193 	return 1;
194 }
195 
196 SEC("lsm_cgroup/inode_xattr_skipcap")
197 int BPF_PROG(skipcap_first, const char *name)
198 {
199 	return 0;
200 }
201 
202 SEC("lsm_cgroup/inode_xattr_skipcap")
203 int BPF_PROG(skipcap_second, const char *name)
204 {
205 	skipcap_retval = bpf_get_retval();
206 	bpf_set_retval(0);
207 	return 1;
208 }
209 
210 SEC("lsm_cgroup/socket_create")
211 int BPF_PROG(socket_first, int family, int type, int protocol, int kern)
212 {
213 	return 0;
214 }
215 
216 SEC("lsm_cgroup/socket_create")
217 int BPF_PROG(socket_second, int family, int type, int protocol, int kern)
218 {
219 	socket_retval = bpf_get_retval();
220 	bpf_set_retval(0);
221 	return 1;
222 }
223