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