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 | |
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 | |
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" ) |
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: sock, family: family, protocol: protocol); |
90 | } |
91 | |
92 | /* __cgroup_bpf_run_lsm_socket */ |
93 | SEC("lsm_cgroup/socket_post_create" ) |
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: sock, family: family, protocol: protocol); |
99 | } |
100 | |
101 | static __always_inline int real_bind(struct socket *sock, |
102 | struct sockaddr *address, |
103 | int addrlen) |
104 | { |
105 | struct sockaddr_ll sa = {}; |
106 | |
107 | if (sock->sk->__sk_common.skc_family != AF_PACKET) |
108 | return 1; |
109 | |
110 | if (sock->sk->sk_kern_sock) |
111 | return 1; |
112 | |
113 | bpf_probe_read_kernel(&sa, sizeof(sa), address); |
114 | if (sa.sll_protocol) |
115 | return 0; /* EPERM */ |
116 | |
117 | /* Can access cgroup local storage. */ |
118 | if (!test_local_storage()) |
119 | return 0; /* EPERM */ |
120 | |
121 | return 1; |
122 | } |
123 | |
124 | /* __cgroup_bpf_run_lsm_socket */ |
125 | SEC("lsm_cgroup/socket_bind" ) |
126 | int BPF_PROG(socket_bind, struct socket *sock, struct sockaddr *address, |
127 | int addrlen) |
128 | { |
129 | called_socket_bind++; |
130 | return real_bind(sock: sock, address: address, addrlen: addrlen); |
131 | } |
132 | |
133 | /* __cgroup_bpf_run_lsm_socket */ |
134 | SEC("lsm_cgroup/socket_bind" ) |
135 | int BPF_PROG(socket_bind2, struct socket *sock, struct sockaddr *address, |
136 | int addrlen) |
137 | { |
138 | called_socket_bind2++; |
139 | return real_bind(sock: sock, address: address, addrlen: addrlen); |
140 | } |
141 | |
142 | /* __cgroup_bpf_run_lsm_current (via bpf_lsm_current_hooks) */ |
143 | SEC("lsm_cgroup/sk_alloc_security" ) |
144 | int BPF_PROG(socket_alloc, struct sock *sk, int family, gfp_t priority) |
145 | { |
146 | called_socket_alloc++; |
147 | /* if already have non-bpf lsms installed, EPERM will cause memory leak of non-bpf lsms */ |
148 | if (CONFIG_SECURITY_SELINUX || CONFIG_SECURITY_SMACK || CONFIG_SECURITY_APPARMOR) |
149 | return 1; |
150 | |
151 | if (family == AF_UNIX) |
152 | return 0; /* EPERM */ |
153 | |
154 | /* Can access cgroup local storage. */ |
155 | if (!test_local_storage()) |
156 | return 0; /* EPERM */ |
157 | |
158 | return 1; |
159 | } |
160 | |
161 | /* __cgroup_bpf_run_lsm_sock */ |
162 | SEC("lsm_cgroup/inet_csk_clone" ) |
163 | int BPF_PROG(socket_clone, struct sock *newsk, const struct request_sock *req) |
164 | { |
165 | int prio = 234; |
166 | |
167 | if (!newsk) |
168 | return 1; |
169 | |
170 | /* Accepted request sockets get a different priority. */ |
171 | if (bpf_setsockopt(newsk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio))) |
172 | return 1; |
173 | |
174 | /* Make sure bpf_getsockopt is allowed and works. */ |
175 | prio = 0; |
176 | if (bpf_getsockopt(newsk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio))) |
177 | return 1; |
178 | if (prio != 234) |
179 | return 1; |
180 | |
181 | /* Can access cgroup local storage. */ |
182 | if (!test_local_storage()) |
183 | return 1; |
184 | |
185 | called_socket_clone++; |
186 | |
187 | return 1; |
188 | } |
189 | |