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
8char _license[] SEC("license") = "GPL";
9
10extern bool CONFIG_SECURITY_SELINUX __kconfig __weak;
11extern bool CONFIG_SECURITY_SMACK __kconfig __weak;
12extern 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
26struct {
27 __uint(type, BPF_MAP_TYPE_CGROUP_STORAGE);
28 __type(key, __u64);
29 __type(value, __u64);
30} cgroup_storage SEC(".maps");
31
32int called_socket_post_create;
33int called_socket_post_create2;
34int called_socket_bind;
35int called_socket_bind2;
36int called_socket_alloc;
37int called_socket_clone;
38
39static __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
51static __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 */
84SEC("lsm_cgroup/socket_post_create")
85int 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 */
93SEC("lsm_cgroup/socket_post_create")
94int 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
101static __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 */
125SEC("lsm_cgroup/socket_bind")
126int 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 */
134SEC("lsm_cgroup/socket_bind")
135int 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) */
143SEC("lsm_cgroup/sk_alloc_security")
144int 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 */
162SEC("lsm_cgroup/inet_csk_clone")
163int 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

source code of linux/tools/testing/selftests/bpf/progs/lsm_cgroup.c