brintos

brintos / linux-shallow public Read only

0
0
Text · 18.0 KiB · 9333f73 Raw
679 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Tests for attaching, detaching, and replacing flow_dissector BPF program.4 */5 6#define _GNU_SOURCE7#include <errno.h>8#include <fcntl.h>9#include <sched.h>10#include <stdbool.h>11#include <sys/stat.h>12#include <unistd.h>13 14#include <linux/bpf.h>15#include <bpf/bpf.h>16 17#include "test_progs.h"18 19static int init_net = -1;20 21static __u32 query_attached_prog_id(int netns)22{23	__u32 prog_ids[1] = {};24	__u32 prog_cnt = ARRAY_SIZE(prog_ids);25	int err;26 27	err = bpf_prog_query(netns, BPF_FLOW_DISSECTOR, 0, NULL,28			     prog_ids, &prog_cnt);29	if (CHECK_FAIL(err)) {30		perror("bpf_prog_query");31		return 0;32	}33 34	return prog_cnt == 1 ? prog_ids[0] : 0;35}36 37static bool prog_is_attached(int netns)38{39	return query_attached_prog_id(netns) > 0;40}41 42static int load_prog(enum bpf_prog_type type)43{44	struct bpf_insn prog[] = {45		BPF_MOV64_IMM(BPF_REG_0, BPF_OK),46		BPF_EXIT_INSN(),47	};48	int fd;49 50	fd = bpf_test_load_program(type, prog, ARRAY_SIZE(prog), "GPL", 0, NULL, 0);51	if (CHECK_FAIL(fd < 0))52		perror("bpf_test_load_program");53 54	return fd;55}56 57static __u32 query_prog_id(int prog)58{59	struct bpf_prog_info info = {};60	__u32 info_len = sizeof(info);61	int err;62 63	err = bpf_prog_get_info_by_fd(prog, &info, &info_len);64	if (CHECK_FAIL(err || info_len != sizeof(info))) {65		perror("bpf_prog_get_info_by_fd");66		return 0;67	}68 69	return info.id;70}71 72static int unshare_net(int old_net)73{74	int err, new_net;75 76	err = unshare(CLONE_NEWNET);77	if (CHECK_FAIL(err)) {78		perror("unshare(CLONE_NEWNET)");79		return -1;80	}81	new_net = open("/proc/self/ns/net", O_RDONLY);82	if (CHECK_FAIL(new_net < 0)) {83		perror("open(/proc/self/ns/net)");84		setns(old_net, CLONE_NEWNET);85		return -1;86	}87	return new_net;88}89 90static void test_prog_attach_prog_attach(int netns, int prog1, int prog2)91{92	int err;93 94	err = bpf_prog_attach(prog1, 0, BPF_FLOW_DISSECTOR, 0);95	if (CHECK_FAIL(err)) {96		perror("bpf_prog_attach(prog1)");97		return;98	}99	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));100 101	/* Expect success when attaching a different program */102	err = bpf_prog_attach(prog2, 0, BPF_FLOW_DISSECTOR, 0);103	if (CHECK_FAIL(err)) {104		perror("bpf_prog_attach(prog2) #1");105		goto out_detach;106	}107	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog2));108 109	/* Expect failure when attaching the same program twice */110	err = bpf_prog_attach(prog2, 0, BPF_FLOW_DISSECTOR, 0);111	if (CHECK_FAIL(!err || errno != EINVAL))112		perror("bpf_prog_attach(prog2) #2");113	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog2));114 115out_detach:116	err = bpf_prog_detach2(prog2, 0, BPF_FLOW_DISSECTOR);117	if (CHECK_FAIL(err))118		perror("bpf_prog_detach");119	CHECK_FAIL(prog_is_attached(netns));120}121 122static void test_link_create_link_create(int netns, int prog1, int prog2)123{124	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts);125	int link1, link2;126 127	link1 = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &opts);128	if (CHECK_FAIL(link < 0)) {129		perror("bpf_link_create(prog1)");130		return;131	}132	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));133 134	/* Expect failure creating link when another link exists */135	errno = 0;136	link2 = bpf_link_create(prog2, netns, BPF_FLOW_DISSECTOR, &opts);137	if (CHECK_FAIL(link2 >= 0 || errno != E2BIG))138		perror("bpf_prog_attach(prog2) expected E2BIG");139	if (link2 >= 0)140		close(link2);141	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));142 143	close(link1);144	CHECK_FAIL(prog_is_attached(netns));145}146 147static void test_prog_attach_link_create(int netns, int prog1, int prog2)148{149	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts);150	int err, link;151 152	err = bpf_prog_attach(prog1, 0, BPF_FLOW_DISSECTOR, 0);153	if (CHECK_FAIL(err)) {154		perror("bpf_prog_attach(prog1)");155		return;156	}157	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));158 159	/* Expect failure creating link when prog attached */160	errno = 0;161	link = bpf_link_create(prog2, netns, BPF_FLOW_DISSECTOR, &opts);162	if (CHECK_FAIL(link >= 0 || errno != EEXIST))163		perror("bpf_link_create(prog2) expected EEXIST");164	if (link >= 0)165		close(link);166	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));167 168	err = bpf_prog_detach2(prog1, 0, BPF_FLOW_DISSECTOR);169	if (CHECK_FAIL(err))170		perror("bpf_prog_detach");171	CHECK_FAIL(prog_is_attached(netns));172}173 174static void test_link_create_prog_attach(int netns, int prog1, int prog2)175{176	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts);177	int err, link;178 179	link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &opts);180	if (CHECK_FAIL(link < 0)) {181		perror("bpf_link_create(prog1)");182		return;183	}184	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));185 186	/* Expect failure attaching prog when link exists */187	errno = 0;188	err = bpf_prog_attach(prog2, 0, BPF_FLOW_DISSECTOR, 0);189	if (CHECK_FAIL(!err || errno != EEXIST))190		perror("bpf_prog_attach(prog2) expected EEXIST");191	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));192 193	close(link);194	CHECK_FAIL(prog_is_attached(netns));195}196 197static void test_link_create_prog_detach(int netns, int prog1, int prog2)198{199	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts);200	int err, link;201 202	link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &opts);203	if (CHECK_FAIL(link < 0)) {204		perror("bpf_link_create(prog1)");205		return;206	}207	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));208 209	/* Expect failure detaching prog when link exists */210	errno = 0;211	err = bpf_prog_detach2(prog1, 0, BPF_FLOW_DISSECTOR);212	if (CHECK_FAIL(!err || errno != EINVAL))213		perror("bpf_prog_detach expected EINVAL");214	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));215 216	close(link);217	CHECK_FAIL(prog_is_attached(netns));218}219 220static void test_prog_attach_detach_query(int netns, int prog1, int prog2)221{222	int err;223 224	err = bpf_prog_attach(prog1, 0, BPF_FLOW_DISSECTOR, 0);225	if (CHECK_FAIL(err)) {226		perror("bpf_prog_attach(prog1)");227		return;228	}229	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));230 231	err = bpf_prog_detach2(prog1, 0, BPF_FLOW_DISSECTOR);232	if (CHECK_FAIL(err)) {233		perror("bpf_prog_detach");234		return;235	}236 237	/* Expect no prog attached after successful detach */238	CHECK_FAIL(prog_is_attached(netns));239}240 241static void test_link_create_close_query(int netns, int prog1, int prog2)242{243	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts);244	int link;245 246	link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &opts);247	if (CHECK_FAIL(link < 0)) {248		perror("bpf_link_create(prog1)");249		return;250	}251	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));252 253	close(link);254	/* Expect no prog attached after closing last link FD */255	CHECK_FAIL(prog_is_attached(netns));256}257 258static void test_link_update_no_old_prog(int netns, int prog1, int prog2)259{260	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, create_opts);261	DECLARE_LIBBPF_OPTS(bpf_link_update_opts, update_opts);262	int err, link;263 264	link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &create_opts);265	if (CHECK_FAIL(link < 0)) {266		perror("bpf_link_create(prog1)");267		return;268	}269	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));270 271	/* Expect success replacing the prog when old prog not specified */272	update_opts.flags = 0;273	update_opts.old_prog_fd = 0;274	err = bpf_link_update(link, prog2, &update_opts);275	if (CHECK_FAIL(err))276		perror("bpf_link_update");277	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog2));278 279	close(link);280	CHECK_FAIL(prog_is_attached(netns));281}282 283static void test_link_update_replace_old_prog(int netns, int prog1, int prog2)284{285	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, create_opts);286	DECLARE_LIBBPF_OPTS(bpf_link_update_opts, update_opts);287	int err, link;288 289	link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &create_opts);290	if (CHECK_FAIL(link < 0)) {291		perror("bpf_link_create(prog1)");292		return;293	}294	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));295 296	/* Expect success F_REPLACE and old prog specified to succeed */297	update_opts.flags = BPF_F_REPLACE;298	update_opts.old_prog_fd = prog1;299	err = bpf_link_update(link, prog2, &update_opts);300	if (CHECK_FAIL(err))301		perror("bpf_link_update");302	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog2));303 304	close(link);305	CHECK_FAIL(prog_is_attached(netns));306}307 308static void test_link_update_same_prog(int netns, int prog1, int prog2)309{310	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, create_opts);311	DECLARE_LIBBPF_OPTS(bpf_link_update_opts, update_opts);312	int err, link;313 314	link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &create_opts);315	if (CHECK_FAIL(link < 0)) {316		perror("bpf_link_create(prog1)");317		return;318	}319	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));320 321	/* Expect success updating the prog with the same one */322	update_opts.flags = 0;323	update_opts.old_prog_fd = 0;324	err = bpf_link_update(link, prog1, &update_opts);325	if (CHECK_FAIL(err))326		perror("bpf_link_update");327	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));328 329	close(link);330	CHECK_FAIL(prog_is_attached(netns));331}332 333static void test_link_update_invalid_opts(int netns, int prog1, int prog2)334{335	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, create_opts);336	DECLARE_LIBBPF_OPTS(bpf_link_update_opts, update_opts);337	int err, link;338 339	link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &create_opts);340	if (CHECK_FAIL(link < 0)) {341		perror("bpf_link_create(prog1)");342		return;343	}344	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));345 346	/* Expect update to fail w/ old prog FD but w/o F_REPLACE*/347	errno = 0;348	update_opts.flags = 0;349	update_opts.old_prog_fd = prog1;350	err = bpf_link_update(link, prog2, &update_opts);351	if (CHECK_FAIL(!err || errno != EINVAL)) {352		perror("bpf_link_update expected EINVAL");353		goto out_close;354	}355	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));356 357	/* Expect update to fail on old prog FD mismatch */358	errno = 0;359	update_opts.flags = BPF_F_REPLACE;360	update_opts.old_prog_fd = prog2;361	err = bpf_link_update(link, prog2, &update_opts);362	if (CHECK_FAIL(!err || errno != EPERM)) {363		perror("bpf_link_update expected EPERM");364		goto out_close;365	}366	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));367 368	/* Expect update to fail for invalid old prog FD */369	errno = 0;370	update_opts.flags = BPF_F_REPLACE;371	update_opts.old_prog_fd = -1;372	err = bpf_link_update(link, prog2, &update_opts);373	if (CHECK_FAIL(!err || errno != EBADF)) {374		perror("bpf_link_update expected EBADF");375		goto out_close;376	}377	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));378 379	/* Expect update to fail with invalid flags */380	errno = 0;381	update_opts.flags = BPF_F_ALLOW_MULTI;382	update_opts.old_prog_fd = 0;383	err = bpf_link_update(link, prog2, &update_opts);384	if (CHECK_FAIL(!err || errno != EINVAL))385		perror("bpf_link_update expected EINVAL");386	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));387 388out_close:389	close(link);390	CHECK_FAIL(prog_is_attached(netns));391}392 393static void test_link_update_invalid_prog(int netns, int prog1, int prog2)394{395	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, create_opts);396	DECLARE_LIBBPF_OPTS(bpf_link_update_opts, update_opts);397	int err, link, prog3;398 399	link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &create_opts);400	if (CHECK_FAIL(link < 0)) {401		perror("bpf_link_create(prog1)");402		return;403	}404	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));405 406	/* Expect failure when new prog FD is not valid */407	errno = 0;408	update_opts.flags = 0;409	update_opts.old_prog_fd = 0;410	err = bpf_link_update(link, -1, &update_opts);411	if (CHECK_FAIL(!err || errno != EBADF)) {412		perror("bpf_link_update expected EINVAL");413		goto out_close_link;414	}415	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));416 417	prog3 = load_prog(BPF_PROG_TYPE_SOCKET_FILTER);418	if (prog3 < 0)419		goto out_close_link;420 421	/* Expect failure when new prog FD type doesn't match */422	errno = 0;423	update_opts.flags = 0;424	update_opts.old_prog_fd = 0;425	err = bpf_link_update(link, prog3, &update_opts);426	if (CHECK_FAIL(!err || errno != EINVAL))427		perror("bpf_link_update expected EINVAL");428	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));429 430	close(prog3);431out_close_link:432	close(link);433	CHECK_FAIL(prog_is_attached(netns));434}435 436static void test_link_update_netns_gone(int netns, int prog1, int prog2)437{438	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, create_opts);439	DECLARE_LIBBPF_OPTS(bpf_link_update_opts, update_opts);440	int err, link, old_net;441 442	old_net = netns;443	netns = unshare_net(old_net);444	if (netns < 0)445		return;446 447	link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &create_opts);448	if (CHECK_FAIL(link < 0)) {449		perror("bpf_link_create(prog1)");450		return;451	}452	CHECK_FAIL(query_attached_prog_id(netns) != query_prog_id(prog1));453 454	close(netns);455	err = setns(old_net, CLONE_NEWNET);456	if (CHECK_FAIL(err)) {457		perror("setns(CLONE_NEWNET)");458		close(link);459		return;460	}461 462	/* Expect failure when netns destroyed */463	errno = 0;464	update_opts.flags = 0;465	update_opts.old_prog_fd = 0;466	err = bpf_link_update(link, prog2, &update_opts);467	if (CHECK_FAIL(!err || errno != ENOLINK))468		perror("bpf_link_update");469 470	close(link);471}472 473static void test_link_get_info(int netns, int prog1, int prog2)474{475	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, create_opts);476	DECLARE_LIBBPF_OPTS(bpf_link_update_opts, update_opts);477	struct bpf_link_info info = {};478	struct stat netns_stat = {};479	__u32 info_len, link_id;480	int err, link, old_net;481 482	old_net = netns;483	netns = unshare_net(old_net);484	if (netns < 0)485		return;486 487	err = fstat(netns, &netns_stat);488	if (CHECK_FAIL(err)) {489		perror("stat(netns)");490		goto out_resetns;491	}492 493	link = bpf_link_create(prog1, netns, BPF_FLOW_DISSECTOR, &create_opts);494	if (CHECK_FAIL(link < 0)) {495		perror("bpf_link_create(prog1)");496		goto out_resetns;497	}498 499	info_len = sizeof(info);500	err = bpf_link_get_info_by_fd(link, &info, &info_len);501	if (CHECK_FAIL(err)) {502		perror("bpf_obj_get_info");503		goto out_unlink;504	}505	CHECK_FAIL(info_len != sizeof(info));506 507	/* Expect link info to be sane and match prog and netns details */508	CHECK_FAIL(info.type != BPF_LINK_TYPE_NETNS);509	CHECK_FAIL(info.id == 0);510	CHECK_FAIL(info.prog_id != query_prog_id(prog1));511	CHECK_FAIL(info.netns.netns_ino != netns_stat.st_ino);512	CHECK_FAIL(info.netns.attach_type != BPF_FLOW_DISSECTOR);513 514	update_opts.flags = 0;515	update_opts.old_prog_fd = 0;516	err = bpf_link_update(link, prog2, &update_opts);517	if (CHECK_FAIL(err)) {518		perror("bpf_link_update(prog2)");519		goto out_unlink;520	}521 522	link_id = info.id;523	info_len = sizeof(info);524	err = bpf_link_get_info_by_fd(link, &info, &info_len);525	if (CHECK_FAIL(err)) {526		perror("bpf_obj_get_info");527		goto out_unlink;528	}529	CHECK_FAIL(info_len != sizeof(info));530 531	/* Expect no info change after update except in prog id */532	CHECK_FAIL(info.type != BPF_LINK_TYPE_NETNS);533	CHECK_FAIL(info.id != link_id);534	CHECK_FAIL(info.prog_id != query_prog_id(prog2));535	CHECK_FAIL(info.netns.netns_ino != netns_stat.st_ino);536	CHECK_FAIL(info.netns.attach_type != BPF_FLOW_DISSECTOR);537 538	/* Leave netns link is attached to and close last FD to it */539	err = setns(old_net, CLONE_NEWNET);540	if (CHECK_FAIL(err)) {541		perror("setns(NEWNET)");542		goto out_unlink;543	}544	close(netns);545	old_net = -1;546	netns = -1;547 548	info_len = sizeof(info);549	err = bpf_link_get_info_by_fd(link, &info, &info_len);550	if (CHECK_FAIL(err)) {551		perror("bpf_obj_get_info");552		goto out_unlink;553	}554	CHECK_FAIL(info_len != sizeof(info));555 556	/* Expect netns_ino to change to 0 */557	CHECK_FAIL(info.type != BPF_LINK_TYPE_NETNS);558	CHECK_FAIL(info.id != link_id);559	CHECK_FAIL(info.prog_id != query_prog_id(prog2));560	CHECK_FAIL(info.netns.netns_ino != 0);561	CHECK_FAIL(info.netns.attach_type != BPF_FLOW_DISSECTOR);562 563out_unlink:564	close(link);565out_resetns:566	if (old_net != -1)567		setns(old_net, CLONE_NEWNET);568	if (netns != -1)569		close(netns);570}571 572static void run_tests(int netns)573{574	struct test {575		const char *test_name;576		void (*test_func)(int netns, int prog1, int prog2);577	} tests[] = {578		{ "prog attach, prog attach",579		  test_prog_attach_prog_attach },580		{ "link create, link create",581		  test_link_create_link_create },582		{ "prog attach, link create",583		  test_prog_attach_link_create },584		{ "link create, prog attach",585		  test_link_create_prog_attach },586		{ "link create, prog detach",587		  test_link_create_prog_detach },588		{ "prog attach, detach, query",589		  test_prog_attach_detach_query },590		{ "link create, close, query",591		  test_link_create_close_query },592		{ "link update no old prog",593		  test_link_update_no_old_prog },594		{ "link update with replace old prog",595		  test_link_update_replace_old_prog },596		{ "link update with same prog",597		  test_link_update_same_prog },598		{ "link update invalid opts",599		  test_link_update_invalid_opts },600		{ "link update invalid prog",601		  test_link_update_invalid_prog },602		{ "link update netns gone",603		  test_link_update_netns_gone },604		{ "link get info",605		  test_link_get_info },606	};607	int i, progs[2] = { -1, -1 };608	char test_name[80];609 610	for (i = 0; i < ARRAY_SIZE(progs); i++) {611		progs[i] = load_prog(BPF_PROG_TYPE_FLOW_DISSECTOR);612		if (progs[i] < 0)613			goto out_close;614	}615 616	for (i = 0; i < ARRAY_SIZE(tests); i++) {617		snprintf(test_name, sizeof(test_name),618			 "flow dissector %s%s",619			 tests[i].test_name,620			 netns == init_net ? " (init_net)" : "");621		if (test__start_subtest(test_name))622			tests[i].test_func(netns, progs[0], progs[1]);623	}624out_close:625	for (i = 0; i < ARRAY_SIZE(progs); i++) {626		if (progs[i] >= 0)627			CHECK_FAIL(close(progs[i]));628	}629}630 631void serial_test_flow_dissector_reattach(void)632{633	int err, new_net, saved_net;634 635	saved_net = open("/proc/self/ns/net", O_RDONLY);636	if (CHECK_FAIL(saved_net < 0)) {637		perror("open(/proc/self/ns/net");638		return;639	}640 641	init_net = open("/proc/1/ns/net", O_RDONLY);642	if (CHECK_FAIL(init_net < 0)) {643		perror("open(/proc/1/ns/net)");644		goto out_close;645	}646 647	err = setns(init_net, CLONE_NEWNET);648	if (CHECK_FAIL(err)) {649		perror("setns(/proc/1/ns/net)");650		goto out_close;651	}652 653	if (prog_is_attached(init_net)) {654		test__skip();655		printf("Can't test with flow dissector attached to init_net\n");656		goto out_setns;657	}658 659	/* First run tests in root network namespace */660	run_tests(init_net);661 662	/* Then repeat tests in a non-root namespace */663	new_net = unshare_net(init_net);664	if (new_net < 0)665		goto out_setns;666	run_tests(new_net);667	close(new_net);668 669out_setns:670	/* Move back to netns we started in. */671	err = setns(saved_net, CLONE_NEWNET);672	if (CHECK_FAIL(err))673		perror("setns(/proc/self/ns/net)");674 675out_close:676	close(init_net);677	close(saved_net);678}679