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 
test_local_storage(void)39 static __always_inline int test_local_storage(void)
40 {
41 	__u64 *val;
42 
43 	val = bpf_get_local_storage(&cgroup_storage, 0);
44 	if (!val)
45 		return 0;
46 	*val += 1;
47 
48 	return 1;
49 }
50 
real_create(struct socket * sock,int family,int protocol)51 static __always_inline int real_create(struct socket *sock, int family,
52 				       int protocol)
53 {
54 	struct sock *sk;
55 	int prio = 123;
56 
57 	/* Reject non-tx-only AF_PACKET. */
58 	if (family == AF_PACKET && protocol != 0)
59 		return 0; /* EPERM */
60 
61 	sk = sock->sk;
62 	if (!sk)
63 		return 1;
64 
65 	/* The rest of the sockets get default policy. */
66 	if (bpf_setsockopt(sk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)))
67 		return 0; /* EPERM */
68 
69 	/* Make sure bpf_getsockopt is allowed and works. */
70 	prio = 0;
71 	if (bpf_getsockopt(sk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)))
72 		return 0; /* EPERM */
73 	if (prio != 123)
74 		return 0; /* EPERM */
75 
76 	/* Can access cgroup local storage. */
77 	if (!test_local_storage())
78 		return 0; /* EPERM */
79 
80 	return 1;
81 }
82 
83 /* __cgroup_bpf_run_lsm_socket */
84 SEC("lsm_cgroup/socket_post_create")
BPF_PROG(socket_post_create,struct socket * sock,int family,int type,int protocol,int kern)85 int BPF_PROG(socket_post_create, struct socket *sock, int family,
86 	     int type, int protocol, int kern)
87 {
88 	called_socket_post_create++;
89 	return real_create(sock, family, protocol);
90 }
91 
92 /* __cgroup_bpf_run_lsm_socket */
93 SEC("lsm_cgroup/socket_post_create")
BPF_PROG(socket_post_create2,struct socket * sock,int family,int type,int protocol,int kern)94 int BPF_PROG(socket_post_create2, struct socket *sock, int family,
95 	     int type, int protocol, int kern)
96 {
97 	called_socket_post_create2++;
98 	return real_create(sock, family, protocol);
99 }
100 
real_bind(struct socket * sock,struct sockaddr * address,int addrlen)101 static __always_inline int real_bind(struct socket *sock,
102 				     struct sockaddr *address,
103 				     int addrlen)
104 {
105 	struct sockaddr_ll sa = {};
106 	struct sock *sk = sock->sk;
107 
108 	if (!sk)
109 		return 1;
110 
111 	if (sk->__sk_common.skc_family != AF_PACKET)
112 		return 1;
113 
114 	if (sk->sk_kern_sock)
115 		return 1;
116 
117 	bpf_probe_read_kernel(&sa, sizeof(sa), address);
118 	if (sa.sll_protocol)
119 		return 0; /* EPERM */
120 
121 	/* Can access cgroup local storage. */
122 	if (!test_local_storage())
123 		return 0; /* EPERM */
124 
125 	return 1;
126 }
127 
128 /* __cgroup_bpf_run_lsm_socket */
129 SEC("lsm_cgroup/socket_bind")
BPF_PROG(socket_bind,struct socket * sock,struct sockaddr * address,int addrlen)130 int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address,
131 	     int addrlen)
132 {
133 	called_socket_bind++;
134 	return real_bind(sock, address, addrlen);
135 }
136 
137 /* __cgroup_bpf_run_lsm_socket */
138 SEC("lsm_cgroup/socket_bind")
BPF_PROG(socket_bind2,struct socket * sock,struct sockaddr * address,int addrlen)139 int BPF_PROG(socket_bind2, struct socket *sock, struct sockaddr *address,
140 	     int addrlen)
141 {
142 	called_socket_bind2++;
143 	return real_bind(sock, address, addrlen);
144 }
145 
146 /* __cgroup_bpf_run_lsm_current (via bpf_lsm_current_hooks) */
147 SEC("lsm_cgroup/sk_alloc_security")
BPF_PROG(socket_alloc,struct sock * sk,int family,gfp_t priority)148 int BPF_PROG(socket_alloc, struct sock *sk, int family, gfp_t priority)
149 {
150 	called_socket_alloc++;
151 	/* if already have non-bpf lsms installed, EPERM will cause memory leak of non-bpf lsms */
152 	if (CONFIG_SECURITY_SELINUX || CONFIG_SECURITY_SMACK || CONFIG_SECURITY_APPARMOR)
153 		return 1;
154 
155 	if (family == AF_UNIX)
156 		return 0; /* EPERM */
157 
158 	/* Can access cgroup local storage. */
159 	if (!test_local_storage())
160 		return 0; /* EPERM */
161 
162 	return 1;
163 }
164 
165 /* __cgroup_bpf_run_lsm_sock */
166 SEC("lsm_cgroup/inet_csk_clone")
BPF_PROG(socket_clone,struct sock * newsk,const struct request_sock * req)167 int BPF_PROG(socket_clone, struct sock *newsk, const struct request_sock *req)
168 {
169 	int prio = 234;
170 
171 	if (!newsk)
172 		return 1;
173 
174 	/* Accepted request sockets get a different priority. */
175 	if (bpf_setsockopt(newsk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)))
176 		return 1;
177 
178 	/* Make sure bpf_getsockopt is allowed and works. */
179 	prio = 0;
180 	if (bpf_getsockopt(newsk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)))
181 		return 1;
182 	if (prio != 234)
183 		return 1;
184 
185 	/* Can access cgroup local storage. */
186 	if (!test_local_storage())
187 		return 1;
188 
189 	called_socket_clone++;
190 
191 	return 1;
192 }
193