Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.4.
  1// SPDX-License-Identifier: GPL-2.0
  2#include <linux/bpf.h>
  3#include <test_progs.h>
  4#include "cgroup_helpers.h"
  5
  6static char bpf_log_buf[4096];
  7static bool verbose;
  8
  9enum sock_create_test_error {
 10	OK = 0,
 11	DENY_CREATE,
 12};
 13
 14static struct sock_create_test {
 15	const char			*descr;
 16	const struct bpf_insn		insns[64];
 17	enum bpf_attach_type		attach_type;
 18	enum bpf_attach_type		expected_attach_type;
 19
 20	int				domain;
 21	int				type;
 22	int				protocol;
 23
 24	int				optname;
 25	int				optval;
 26	enum sock_create_test_error	error;
 27} tests[] = {
 28	{
 29		.descr = "AF_INET set priority",
 30		.insns = {
 31			/* r3 = 123 (priority) */
 32			BPF_MOV64_IMM(BPF_REG_3, 123),
 33			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
 34				    offsetof(struct bpf_sock, priority)),
 35
 36			/* return 1 */
 37			BPF_MOV64_IMM(BPF_REG_0, 1),
 38			BPF_EXIT_INSN(),
 39		},
 40		.expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
 41		.attach_type = BPF_CGROUP_INET_SOCK_CREATE,
 42
 43		.domain = AF_INET,
 44		.type = SOCK_DGRAM,
 45
 46		.optname = SO_PRIORITY,
 47		.optval = 123,
 48	},
 49	{
 50		.descr = "AF_INET6 set priority",
 51		.insns = {
 52			/* r3 = 123 (priority) */
 53			BPF_MOV64_IMM(BPF_REG_3, 123),
 54			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
 55				    offsetof(struct bpf_sock, priority)),
 56
 57			/* return 1 */
 58			BPF_MOV64_IMM(BPF_REG_0, 1),
 59			BPF_EXIT_INSN(),
 60		},
 61		.expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
 62		.attach_type = BPF_CGROUP_INET_SOCK_CREATE,
 63
 64		.domain = AF_INET6,
 65		.type = SOCK_DGRAM,
 66
 67		.optname = SO_PRIORITY,
 68		.optval = 123,
 69	},
 70	{
 71		.descr = "AF_INET set mark",
 72		.insns = {
 73			BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
 74
 75			/* get uid of process */
 76			BPF_EMIT_CALL(BPF_FUNC_get_current_uid_gid),
 77			BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xffffffff),
 78
 79			/* if uid is 0, use given mark(666), else use uid as the mark */
 80			BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
 81			BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
 82			BPF_MOV64_IMM(BPF_REG_3, 666),
 83
 84			BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
 85			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
 86				    offsetof(struct bpf_sock, mark)),
 87
 88			/* return 1 */
 89			BPF_MOV64_IMM(BPF_REG_0, 1),
 90			BPF_EXIT_INSN(),
 91		},
 92		.expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
 93		.attach_type = BPF_CGROUP_INET_SOCK_CREATE,
 94
 95		.domain = AF_INET,
 96		.type = SOCK_DGRAM,
 97
 98		.optname = SO_MARK,
 99		.optval = 666,
100	},
101	{
102		.descr = "AF_INET6 set mark",
103		.insns = {
104			BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
105
106			/* get uid of process */
107			BPF_EMIT_CALL(BPF_FUNC_get_current_uid_gid),
108			BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xffffffff),
109
110			/* if uid is 0, use given mark(666), else use uid as the mark */
111			BPF_MOV64_REG(BPF_REG_3, BPF_REG_0),
112			BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1),
113			BPF_MOV64_IMM(BPF_REG_3, 666),
114
115			BPF_MOV64_REG(BPF_REG_1, BPF_REG_6),
116			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
117				    offsetof(struct bpf_sock, mark)),
118
119			/* return 1 */
120			BPF_MOV64_IMM(BPF_REG_0, 1),
121			BPF_EXIT_INSN(),
122		},
123		.expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
124		.attach_type = BPF_CGROUP_INET_SOCK_CREATE,
125
126		.domain = AF_INET6,
127		.type = SOCK_DGRAM,
128
129		.optname = SO_MARK,
130		.optval = 666,
131	},
132	{
133		.descr = "AF_INET bound to iface",
134		.insns = {
135			/* r3 = 1 (lo interface) */
136			BPF_MOV64_IMM(BPF_REG_3, 1),
137			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
138				    offsetof(struct bpf_sock, bound_dev_if)),
139
140			/* return 1 */
141			BPF_MOV64_IMM(BPF_REG_0, 1),
142			BPF_EXIT_INSN(),
143		},
144		.expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
145		.attach_type = BPF_CGROUP_INET_SOCK_CREATE,
146
147		.domain = AF_INET,
148		.type = SOCK_DGRAM,
149
150		.optname = SO_BINDTOIFINDEX,
151		.optval = 1,
152	},
153	{
154		.descr = "AF_INET6 bound to iface",
155		.insns = {
156			/* r3 = 1 (lo interface) */
157			BPF_MOV64_IMM(BPF_REG_3, 1),
158			BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3,
159				    offsetof(struct bpf_sock, bound_dev_if)),
160
161			/* return 1 */
162			BPF_MOV64_IMM(BPF_REG_0, 1),
163			BPF_EXIT_INSN(),
164		},
165		.expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
166		.attach_type = BPF_CGROUP_INET_SOCK_CREATE,
167
168		.domain = AF_INET6,
169		.type = SOCK_DGRAM,
170
171		.optname = SO_BINDTOIFINDEX,
172		.optval = 1,
173	},
174	{
175		.descr = "block AF_INET, SOCK_DGRAM, IPPROTO_ICMP socket",
176		.insns = {
177			BPF_MOV64_IMM(BPF_REG_0, 1),	/* r0 = verdict */
178
179			/* sock->family == AF_INET */
180			BPF_LDX_MEM(BPF_H, BPF_REG_2, BPF_REG_1,
181				    offsetof(struct bpf_sock, family)),
182			BPF_JMP_IMM(BPF_JNE, BPF_REG_2, AF_INET, 5),
183
184			/* sock->type == SOCK_DGRAM */
185			BPF_LDX_MEM(BPF_H, BPF_REG_2, BPF_REG_1,
186				    offsetof(struct bpf_sock, type)),
187			BPF_JMP_IMM(BPF_JNE, BPF_REG_2, SOCK_DGRAM, 3),
188
189			/* sock->protocol == IPPROTO_ICMP */
190			BPF_LDX_MEM(BPF_H, BPF_REG_2, BPF_REG_1,
191				    offsetof(struct bpf_sock, protocol)),
192			BPF_JMP_IMM(BPF_JNE, BPF_REG_2, IPPROTO_ICMP, 1),
193
194			/* return 0 (block) */
195			BPF_MOV64_IMM(BPF_REG_0, 0),
196			BPF_EXIT_INSN(),
197		},
198		.expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
199		.attach_type = BPF_CGROUP_INET_SOCK_CREATE,
200
201		.domain = AF_INET,
202		.type = SOCK_DGRAM,
203		.protocol = IPPROTO_ICMP,
204
205		.error = DENY_CREATE,
206	},
207	{
208		.descr = "block AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6 socket",
209		.insns = {
210			BPF_MOV64_IMM(BPF_REG_0, 1),	/* r0 = verdict */
211
212			/* sock->family == AF_INET6 */
213			BPF_LDX_MEM(BPF_H, BPF_REG_2, BPF_REG_1,
214				    offsetof(struct bpf_sock, family)),
215			BPF_JMP_IMM(BPF_JNE, BPF_REG_2, AF_INET6, 5),
216
217			/* sock->type == SOCK_DGRAM */
218			BPF_LDX_MEM(BPF_H, BPF_REG_2, BPF_REG_1,
219				    offsetof(struct bpf_sock, type)),
220			BPF_JMP_IMM(BPF_JNE, BPF_REG_2, SOCK_DGRAM, 3),
221
222			/* sock->protocol == IPPROTO_ICMPV6 */
223			BPF_LDX_MEM(BPF_H, BPF_REG_2, BPF_REG_1,
224				    offsetof(struct bpf_sock, protocol)),
225			BPF_JMP_IMM(BPF_JNE, BPF_REG_2, IPPROTO_ICMPV6, 1),
226
227			/* return 0 (block) */
228			BPF_MOV64_IMM(BPF_REG_0, 0),
229			BPF_EXIT_INSN(),
230		},
231		.expected_attach_type = BPF_CGROUP_INET_SOCK_CREATE,
232		.attach_type = BPF_CGROUP_INET_SOCK_CREATE,
233
234		.domain = AF_INET,
235		.type = SOCK_DGRAM,
236		.protocol = IPPROTO_ICMPV6,
237
238		.error = DENY_CREATE,
239	},
240	{
241		.descr = "load w/o expected_attach_type (compat mode)",
242		.insns = {
243			/* return 1 */
244			BPF_MOV64_IMM(BPF_REG_0, 1),
245			BPF_EXIT_INSN(),
246		},
247		.expected_attach_type = 0,
248		.attach_type = BPF_CGROUP_INET_SOCK_CREATE,
249
250		.domain = AF_INET,
251		.type = SOCK_STREAM,
252	},
253};
254
255static int load_prog(const struct bpf_insn *insns,
256		     enum bpf_attach_type expected_attach_type)
257{
258	LIBBPF_OPTS(bpf_prog_load_opts, opts,
259		    .expected_attach_type = expected_attach_type,
260		    .log_level = 2,
261		    .log_buf = bpf_log_buf,
262		    .log_size = sizeof(bpf_log_buf),
263	);
264	int fd, insns_cnt = 0;
265
266	for (;
267	     insns[insns_cnt].code != (BPF_JMP | BPF_EXIT);
268	     insns_cnt++) {
269	}
270	insns_cnt++;
271
272	fd = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", insns,
273			   insns_cnt, &opts);
274	if (verbose && fd < 0)
275		fprintf(stderr, "%s\n", bpf_log_buf);
276
277	return fd;
278}
279
280static int run_test(int cgroup_fd, struct sock_create_test *test)
281{
282	int sock_fd, err, prog_fd, optval, ret = -1;
283	socklen_t optlen = sizeof(optval);
284
285	prog_fd = load_prog(test->insns, test->expected_attach_type);
286	if (prog_fd < 0) {
287		log_err("Failed to load BPF program");
288		return -1;
289	}
290
291	err = bpf_prog_attach(prog_fd, cgroup_fd, test->attach_type, 0);
292	if (err < 0) {
293		log_err("Failed to attach BPF program");
294		goto close_prog_fd;
295	}
296
297	sock_fd = socket(test->domain, test->type, test->protocol);
298	if (sock_fd < 0) {
299		if (test->error == DENY_CREATE)
300			ret = 0;
301		else
302			log_err("Failed to create socket");
303
304		goto detach_prog;
305	}
306
307	if (test->optname) {
308		err = getsockopt(sock_fd, SOL_SOCKET, test->optname, &optval, &optlen);
309		if (err) {
310			log_err("Failed to call getsockopt");
311			goto cleanup;
312		}
313
314		if (optval != test->optval) {
315			errno = 0;
316			log_err("getsockopt returned unexpected optval");
317			goto cleanup;
318		}
319	}
320
321	ret = test->error != OK;
322
323cleanup:
324	close(sock_fd);
325detach_prog:
326	bpf_prog_detach2(prog_fd, cgroup_fd, test->attach_type);
327close_prog_fd:
328	close(prog_fd);
329	return ret;
330}
331
332void test_sock_create(void)
333{
334	int cgroup_fd, i;
335
336	cgroup_fd = test__join_cgroup("/sock_create");
337	if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup"))
338		return;
339
340	for (i = 0; i < ARRAY_SIZE(tests); i++) {
341		if (!test__start_subtest(tests[i].descr))
342			continue;
343
344		ASSERT_OK(run_test(cgroup_fd, &tests[i]), tests[i].descr);
345	}
346
347	close(cgroup_fd);
348}