brintos

brintos / linux-shallow public Read only

0
0
Text · 16.2 KiB · f29fc78 Raw
601 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2019 Facebook */3#include <test_progs.h>4#include <network_helpers.h>5#include <bpf/btf.h>6#include "bind4_prog.skel.h"7#include "freplace_progmap.skel.h"8#include "xdp_dummy.skel.h"9 10typedef int (*test_cb)(struct bpf_object *obj);11 12static int check_data_map(struct bpf_object *obj, int prog_cnt, bool reset)13{14	struct bpf_map *data_map = NULL, *map;15	__u64 *result = NULL;16	const int zero = 0;17	__u32 duration = 0;18	int ret = -1, i;19 20	result = malloc((prog_cnt + 32 /* spare */) * sizeof(__u64));21	if (CHECK(!result, "alloc_memory", "failed to alloc memory"))22		return -ENOMEM;23 24	bpf_object__for_each_map(map, obj)25		if (bpf_map__is_internal(map)) {26			data_map = map;27			break;28		}29	if (CHECK(!data_map, "find_data_map", "data map not found\n"))30		goto out;31 32	ret = bpf_map_lookup_elem(bpf_map__fd(data_map), &zero, result);33	if (CHECK(ret, "get_result",34		  "failed to get output data: %d\n", ret))35		goto out;36 37	for (i = 0; i < prog_cnt; i++) {38		if (CHECK(result[i] != 1, "result",39			  "fexit_bpf2bpf result[%d] failed err %llu\n",40			  i, result[i]))41			goto out;42		result[i] = 0;43	}44	if (reset) {45		ret = bpf_map_update_elem(bpf_map__fd(data_map), &zero, result, 0);46		if (CHECK(ret, "reset_result", "failed to reset result\n"))47			goto out;48	}49 50	ret = 0;51out:52	free(result);53	return ret;54}55 56static void test_fexit_bpf2bpf_common(const char *obj_file,57				      const char *target_obj_file,58				      int prog_cnt,59				      const char **prog_name,60				      bool run_prog,61				      test_cb cb)62{63	struct bpf_object *obj = NULL, *tgt_obj;64	__u32 tgt_prog_id, info_len;65	struct bpf_prog_info prog_info = {};66	struct bpf_program **prog = NULL, *p;67	struct bpf_link **link = NULL;68	int err, tgt_fd, i;69	struct btf *btf;70	LIBBPF_OPTS(bpf_test_run_opts, topts,71		.data_in = &pkt_v6,72		.data_size_in = sizeof(pkt_v6),73		.repeat = 1,74	);75 76	err = bpf_prog_test_load(target_obj_file, BPF_PROG_TYPE_UNSPEC,77			    &tgt_obj, &tgt_fd);78	if (!ASSERT_OK(err, "tgt_prog_load"))79		return;80 81	info_len = sizeof(prog_info);82	err = bpf_prog_get_info_by_fd(tgt_fd, &prog_info, &info_len);83	if (!ASSERT_OK(err, "tgt_fd_get_info"))84		goto close_prog;85 86	tgt_prog_id = prog_info.id;87	btf = bpf_object__btf(tgt_obj);88 89	link = calloc(sizeof(struct bpf_link *), prog_cnt);90	if (!ASSERT_OK_PTR(link, "link_ptr"))91		goto close_prog;92 93	prog = calloc(sizeof(struct bpf_program *), prog_cnt);94	if (!ASSERT_OK_PTR(prog, "prog_ptr"))95		goto close_prog;96 97	obj = bpf_object__open_file(obj_file, NULL);98	if (!ASSERT_OK_PTR(obj, "obj_open"))99		goto close_prog;100 101	bpf_object__for_each_program(p, obj) {102		err = bpf_program__set_attach_target(p, tgt_fd, NULL);103		ASSERT_OK(err, "set_attach_target");104	}105 106	err = bpf_object__load(obj);107	if (!ASSERT_OK(err, "obj_load"))108		goto close_prog;109 110	for (i = 0; i < prog_cnt; i++) {111		struct bpf_link_info link_info;112		struct bpf_program *pos;113		const char *pos_sec_name;114		char *tgt_name;115		__s32 btf_id;116 117		tgt_name = strstr(prog_name[i], "/");118		if (!ASSERT_OK_PTR(tgt_name, "tgt_name"))119			goto close_prog;120		btf_id = btf__find_by_name_kind(btf, tgt_name + 1, BTF_KIND_FUNC);121 122		prog[i] = NULL;123		bpf_object__for_each_program(pos, obj) {124			pos_sec_name = bpf_program__section_name(pos);125			if (pos_sec_name && !strcmp(pos_sec_name, prog_name[i])) {126				prog[i] = pos;127				break;128			}129		}130		if (!ASSERT_OK_PTR(prog[i], prog_name[i]))131			goto close_prog;132 133		link[i] = bpf_program__attach_trace(prog[i]);134		if (!ASSERT_OK_PTR(link[i], "attach_trace"))135			goto close_prog;136 137		info_len = sizeof(link_info);138		memset(&link_info, 0, sizeof(link_info));139		err = bpf_link_get_info_by_fd(bpf_link__fd(link[i]),140					      &link_info, &info_len);141		ASSERT_OK(err, "link_fd_get_info");142		ASSERT_EQ(link_info.tracing.attach_type,143			  bpf_program__expected_attach_type(prog[i]),144			  "link_attach_type");145		ASSERT_EQ(link_info.tracing.target_obj_id, tgt_prog_id, "link_tgt_obj_id");146		ASSERT_EQ(link_info.tracing.target_btf_id, btf_id, "link_tgt_btf_id");147	}148 149	if (cb) {150		err = cb(obj);151		if (err)152			goto close_prog;153	}154 155	if (!run_prog)156		goto close_prog;157 158	err = bpf_prog_test_run_opts(tgt_fd, &topts);159	ASSERT_OK(err, "prog_run");160	ASSERT_EQ(topts.retval, 0, "prog_run_ret");161 162	if (check_data_map(obj, prog_cnt, false))163		goto close_prog;164 165close_prog:166	for (i = 0; i < prog_cnt; i++)167		bpf_link__destroy(link[i]);168	bpf_object__close(obj);169	bpf_object__close(tgt_obj);170	free(link);171	free(prog);172}173 174static void test_target_no_callees(void)175{176	const char *prog_name[] = {177		"fexit/test_pkt_md_access",178	};179	test_fexit_bpf2bpf_common("./fexit_bpf2bpf_simple.bpf.o",180				  "./test_pkt_md_access.bpf.o",181				  ARRAY_SIZE(prog_name),182				  prog_name, true, NULL);183}184 185static void test_target_yes_callees(void)186{187	const char *prog_name[] = {188		"fexit/test_pkt_access",189		"fexit/test_pkt_access_subprog1",190		"fexit/test_pkt_access_subprog2",191		"fexit/test_pkt_access_subprog3",192	};193	test_fexit_bpf2bpf_common("./fexit_bpf2bpf.bpf.o",194				  "./test_pkt_access.bpf.o",195				  ARRAY_SIZE(prog_name),196				  prog_name, true, NULL);197}198 199static void test_func_replace(void)200{201	const char *prog_name[] = {202		"fexit/test_pkt_access",203		"fexit/test_pkt_access_subprog1",204		"fexit/test_pkt_access_subprog2",205		"fexit/test_pkt_access_subprog3",206		"freplace/get_skb_len",207		"freplace/get_skb_ifindex",208		"freplace/get_constant",209		"freplace/test_pkt_write_access_subprog",210	};211	test_fexit_bpf2bpf_common("./fexit_bpf2bpf.bpf.o",212				  "./test_pkt_access.bpf.o",213				  ARRAY_SIZE(prog_name),214				  prog_name, true, NULL);215}216 217static void test_func_replace_verify(void)218{219	const char *prog_name[] = {220		"freplace/do_bind",221	};222	test_fexit_bpf2bpf_common("./freplace_connect4.bpf.o",223				  "./connect4_prog.bpf.o",224				  ARRAY_SIZE(prog_name),225				  prog_name, false, NULL);226}227 228static int test_second_attach(struct bpf_object *obj)229{230	const char *prog_name = "security_new_get_constant";231	const char *tgt_name = "get_constant";232	const char *tgt_obj_file = "./test_pkt_access.bpf.o";233	struct bpf_program *prog = NULL;234	struct bpf_object *tgt_obj;235	struct bpf_link *link;236	int err = 0, tgt_fd;237	LIBBPF_OPTS(bpf_test_run_opts, topts,238		.data_in = &pkt_v6,239		.data_size_in = sizeof(pkt_v6),240		.repeat = 1,241	);242 243	prog = bpf_object__find_program_by_name(obj, prog_name);244	if (!ASSERT_OK_PTR(prog, "find_prog"))245		return -ENOENT;246 247	err = bpf_prog_test_load(tgt_obj_file, BPF_PROG_TYPE_UNSPEC,248			    &tgt_obj, &tgt_fd);249	if (!ASSERT_OK(err, "second_prog_load"))250		return err;251 252	link = bpf_program__attach_freplace(prog, tgt_fd, tgt_name);253	if (!ASSERT_OK_PTR(link, "second_link"))254		goto out;255 256	err = bpf_prog_test_run_opts(tgt_fd, &topts);257	if (!ASSERT_OK(err, "ipv6 test_run"))258		goto out;259	if (!ASSERT_OK(topts.retval, "ipv6 retval"))260		goto out;261 262	err = check_data_map(obj, 1, true);263	if (err)264		goto out;265 266out:267	bpf_link__destroy(link);268	bpf_object__close(tgt_obj);269	return err;270}271 272static void test_func_replace_multi(void)273{274	const char *prog_name[] = {275		"freplace/get_constant",276	};277	test_fexit_bpf2bpf_common("./freplace_get_constant.bpf.o",278				  "./test_pkt_access.bpf.o",279				  ARRAY_SIZE(prog_name),280				  prog_name, true, test_second_attach);281}282 283static void test_fmod_ret_freplace(void)284{285	struct bpf_object *freplace_obj = NULL, *pkt_obj, *fmod_obj = NULL;286	const char *freplace_name = "./freplace_get_constant.bpf.o";287	const char *fmod_ret_name = "./fmod_ret_freplace.bpf.o";288	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);289	const char *tgt_name = "./test_pkt_access.bpf.o";290	struct bpf_link *freplace_link = NULL;291	struct bpf_program *prog;292	__u32 duration = 0;293	int err, pkt_fd, attach_prog_fd;294 295	err = bpf_prog_test_load(tgt_name, BPF_PROG_TYPE_UNSPEC,296			    &pkt_obj, &pkt_fd);297	/* the target prog should load fine */298	if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n",299		  tgt_name, err, errno))300		return;301 302	freplace_obj = bpf_object__open_file(freplace_name, NULL);303	if (!ASSERT_OK_PTR(freplace_obj, "freplace_obj_open"))304		goto out;305 306	prog = bpf_object__next_program(freplace_obj, NULL);307	err = bpf_program__set_attach_target(prog, pkt_fd, NULL);308	ASSERT_OK(err, "freplace__set_attach_target");309 310	err = bpf_object__load(freplace_obj);311	if (CHECK(err, "freplace_obj_load", "err %d\n", err))312		goto out;313 314	freplace_link = bpf_program__attach_trace(prog);315	if (!ASSERT_OK_PTR(freplace_link, "freplace_attach_trace"))316		goto out;317 318	fmod_obj = bpf_object__open_file(fmod_ret_name, NULL);319	if (!ASSERT_OK_PTR(fmod_obj, "fmod_obj_open"))320		goto out;321 322	attach_prog_fd = bpf_program__fd(prog);323	prog = bpf_object__next_program(fmod_obj, NULL);324	err = bpf_program__set_attach_target(prog, attach_prog_fd, NULL);325	ASSERT_OK(err, "fmod_ret_set_attach_target");326 327	err = bpf_object__load(fmod_obj);328	if (CHECK(!err, "fmod_obj_load", "loading fmod_ret should fail\n"))329		goto out;330 331out:332	bpf_link__destroy(freplace_link);333	bpf_object__close(freplace_obj);334	bpf_object__close(fmod_obj);335	bpf_object__close(pkt_obj);336}337 338 339static void test_func_sockmap_update(void)340{341	const char *prog_name[] = {342		"freplace/cls_redirect",343	};344	test_fexit_bpf2bpf_common("./freplace_cls_redirect.bpf.o",345				  "./test_cls_redirect.bpf.o",346				  ARRAY_SIZE(prog_name),347				  prog_name, false, NULL);348}349 350static void test_obj_load_failure_common(const char *obj_file,351					 const char *target_obj_file,352					 const char *exp_msg)353{354	/*355	 * standalone test that asserts failure to load freplace prog356	 * because of invalid return code.357	 */358	struct bpf_object *obj = NULL, *pkt_obj;359	struct bpf_program *prog;360	char log_buf[64 * 1024];361	int err, pkt_fd;362	__u32 duration = 0;363 364	err = bpf_prog_test_load(target_obj_file, BPF_PROG_TYPE_UNSPEC,365			    &pkt_obj, &pkt_fd);366	/* the target prog should load fine */367	if (CHECK(err, "tgt_prog_load", "file %s err %d errno %d\n",368		  target_obj_file, err, errno))369		return;370 371	obj = bpf_object__open_file(obj_file, NULL);372	if (!ASSERT_OK_PTR(obj, "obj_open"))373		goto close_prog;374 375	prog = bpf_object__next_program(obj, NULL);376	err = bpf_program__set_attach_target(prog, pkt_fd, NULL);377	ASSERT_OK(err, "set_attach_target");378 379	log_buf[0] = '\0';380	if (exp_msg)381		bpf_program__set_log_buf(prog, log_buf, sizeof(log_buf));382	if (env.verbosity > VERBOSE_NONE)383		bpf_program__set_log_level(prog, 2);384 385	/* It should fail to load the program */386	err = bpf_object__load(obj);387	if (env.verbosity > VERBOSE_NONE && exp_msg) /* we overtook log */388		printf("VERIFIER LOG:\n================\n%s\n================\n", log_buf);389	if (CHECK(!err, "bpf_obj_load should fail", "err %d\n", err))390		goto close_prog;391 392	if (exp_msg)393		ASSERT_HAS_SUBSTR(log_buf, exp_msg, "fail_msg");394close_prog:395	bpf_object__close(obj);396	bpf_object__close(pkt_obj);397}398 399static void test_func_replace_return_code(void)400{401	/* test invalid return code in the replaced program */402	test_obj_load_failure_common("./freplace_connect_v4_prog.bpf.o",403				     "./connect4_prog.bpf.o", NULL);404}405 406static void test_func_map_prog_compatibility(void)407{408	/* test with spin lock map value in the replaced program */409	test_obj_load_failure_common("./freplace_attach_probe.bpf.o",410				     "./test_attach_probe.bpf.o", NULL);411}412 413static void test_func_replace_unreliable(void)414{415	/* freplace'ing unreliable main prog should fail with error416	 * "Cannot replace static functions"417	 */418	test_obj_load_failure_common("freplace_unreliable_prog.bpf.o",419				     "./verifier_btf_unreliable_prog.bpf.o",420				     "Cannot replace static functions");421}422 423static void test_func_replace_global_func(void)424{425	const char *prog_name[] = {426		"freplace/test_pkt_access",427	};428 429	test_fexit_bpf2bpf_common("./freplace_global_func.bpf.o",430				  "./test_pkt_access.bpf.o",431				  ARRAY_SIZE(prog_name),432				  prog_name, false, NULL);433}434 435static int find_prog_btf_id(const char *name, __u32 attach_prog_fd)436{437	struct bpf_prog_info info = {};438	__u32 info_len = sizeof(info);439	struct btf *btf;440	int ret;441 442	ret = bpf_prog_get_info_by_fd(attach_prog_fd, &info, &info_len);443	if (ret)444		return ret;445 446	if (!info.btf_id)447		return -EINVAL;448 449	btf = btf__load_from_kernel_by_id(info.btf_id);450	ret = libbpf_get_error(btf);451	if (ret)452		return ret;453 454	ret = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC);455	btf__free(btf);456	return ret;457}458 459static int load_fentry(int attach_prog_fd, int attach_btf_id)460{461	LIBBPF_OPTS(bpf_prog_load_opts, opts,462		    .expected_attach_type = BPF_TRACE_FENTRY,463		    .attach_prog_fd = attach_prog_fd,464		    .attach_btf_id = attach_btf_id,465	);466	struct bpf_insn insns[] = {467		BPF_MOV64_IMM(BPF_REG_0, 0),468		BPF_EXIT_INSN(),469	};470 471	return bpf_prog_load(BPF_PROG_TYPE_TRACING,472			     "bind4_fentry",473			     "GPL",474			     insns,475			     ARRAY_SIZE(insns),476			     &opts);477}478 479static void test_fentry_to_cgroup_bpf(void)480{481	struct bind4_prog *skel = NULL;482	struct bpf_prog_info info = {};483	__u32 info_len = sizeof(info);484	int cgroup_fd = -1;485	int fentry_fd = -1;486	int btf_id;487 488	cgroup_fd = test__join_cgroup("/fentry_to_cgroup_bpf");489	if (!ASSERT_GE(cgroup_fd, 0, "cgroup_fd"))490		return;491 492	skel = bind4_prog__open_and_load();493	if (!ASSERT_OK_PTR(skel, "skel"))494		goto cleanup;495 496	skel->links.bind_v4_prog = bpf_program__attach_cgroup(skel->progs.bind_v4_prog, cgroup_fd);497	if (!ASSERT_OK_PTR(skel->links.bind_v4_prog, "bpf_program__attach_cgroup"))498		goto cleanup;499 500	btf_id = find_prog_btf_id("bind_v4_prog", bpf_program__fd(skel->progs.bind_v4_prog));501	if (!ASSERT_GE(btf_id, 0, "find_prog_btf_id"))502		goto cleanup;503 504	fentry_fd = load_fentry(bpf_program__fd(skel->progs.bind_v4_prog), btf_id);505	if (!ASSERT_GE(fentry_fd, 0, "load_fentry"))506		goto cleanup;507 508	/* Make sure bpf_prog_get_info_by_fd works correctly when attaching509	 * to another BPF program.510	 */511 512	ASSERT_OK(bpf_prog_get_info_by_fd(fentry_fd, &info, &info_len),513		  "bpf_prog_get_info_by_fd");514 515	ASSERT_EQ(info.btf_id, 0, "info.btf_id");516	ASSERT_EQ(info.attach_btf_id, btf_id, "info.attach_btf_id");517	ASSERT_GT(info.attach_btf_obj_id, 0, "info.attach_btf_obj_id");518 519cleanup:520	if (cgroup_fd >= 0)521		close(cgroup_fd);522	if (fentry_fd >= 0)523		close(fentry_fd);524	bind4_prog__destroy(skel);525}526 527static void test_func_replace_progmap(void)528{529	struct bpf_cpumap_val value = { .qsize = 1 };530	struct freplace_progmap *skel = NULL;531	struct xdp_dummy *tgt_skel = NULL;532	__u32 key = 0;533	int err;534 535	skel = freplace_progmap__open();536	if (!ASSERT_OK_PTR(skel, "prog_open"))537		return;538 539	tgt_skel = xdp_dummy__open_and_load();540	if (!ASSERT_OK_PTR(tgt_skel, "tgt_prog_load"))541		goto out;542 543	err = bpf_program__set_attach_target(skel->progs.xdp_cpumap_prog,544					     bpf_program__fd(tgt_skel->progs.xdp_dummy_prog),545					     "xdp_dummy_prog");546	if (!ASSERT_OK(err, "set_attach_target"))547		goto out;548 549	err = freplace_progmap__load(skel);550	if (!ASSERT_OK(err, "obj_load"))551		goto out;552 553	/* Prior to fixing the kernel, loading the PROG_TYPE_EXT 'redirect'554	 * program above will cause the map owner type of 'cpumap' to be set to555	 * PROG_TYPE_EXT. This in turn will cause the bpf_map_update_elem()556	 * below to fail, because the program we are inserting into the map is557	 * of PROG_TYPE_XDP. After fixing the kernel, the initial ownership will558	 * be correctly resolved to the *target* of the PROG_TYPE_EXT program559	 * (i.e., PROG_TYPE_XDP) and the map update will succeed.560	 */561	value.bpf_prog.fd = bpf_program__fd(skel->progs.xdp_drop_prog);562	err = bpf_map_update_elem(bpf_map__fd(skel->maps.cpu_map),563				  &key, &value, 0);564	ASSERT_OK(err, "map_update");565 566out:567	xdp_dummy__destroy(tgt_skel);568	freplace_progmap__destroy(skel);569}570 571/* NOTE: affect other tests, must run in serial mode */572void serial_test_fexit_bpf2bpf(void)573{574	if (test__start_subtest("target_no_callees"))575		test_target_no_callees();576	if (test__start_subtest("target_yes_callees"))577		test_target_yes_callees();578	if (test__start_subtest("func_replace"))579		test_func_replace();580	if (test__start_subtest("func_replace_verify"))581		test_func_replace_verify();582	if (test__start_subtest("func_sockmap_update"))583		test_func_sockmap_update();584	if (test__start_subtest("func_replace_return_code"))585		test_func_replace_return_code();586	if (test__start_subtest("func_map_prog_compatibility"))587		test_func_map_prog_compatibility();588	if (test__start_subtest("func_replace_unreliable"))589		test_func_replace_unreliable();590	if (test__start_subtest("func_replace_multi"))591		test_func_replace_multi();592	if (test__start_subtest("fmod_ret_freplace"))593		test_fmod_ret_freplace();594	if (test__start_subtest("func_replace_global_func"))595		test_func_replace_global_func();596	if (test__start_subtest("fentry_to_cgroup_bpf"))597		test_fentry_to_cgroup_bpf();598	if (test__start_subtest("func_replace_progmap"))599		test_func_replace_progmap();600}601