12cbc469aSKumar Kartikeya Dwivedi // SPDX-License-Identifier: GPL-2.0
22cbc469aSKumar Kartikeya Dwivedi #include <test_progs.h>
3*0ef6740eSKumar Kartikeya Dwivedi #include <network_helpers.h>
42cbc469aSKumar Kartikeya Dwivedi 
52cbc469aSKumar Kartikeya Dwivedi #include "map_kptr.skel.h"
604accf79SKumar Kartikeya Dwivedi #include "map_kptr_fail.skel.h"
72cbc469aSKumar Kartikeya Dwivedi 
804accf79SKumar Kartikeya Dwivedi static char log_buf[1024 * 1024];
904accf79SKumar Kartikeya Dwivedi 
1004accf79SKumar Kartikeya Dwivedi struct {
1104accf79SKumar Kartikeya Dwivedi 	const char *prog_name;
1204accf79SKumar Kartikeya Dwivedi 	const char *err_msg;
1304accf79SKumar Kartikeya Dwivedi } map_kptr_fail_tests[] = {
1404accf79SKumar Kartikeya Dwivedi 	{ "size_not_bpf_dw", "kptr access size must be BPF_DW" },
1504accf79SKumar Kartikeya Dwivedi 	{ "non_const_var_off", "kptr access cannot have variable offset" },
1604accf79SKumar Kartikeya Dwivedi 	{ "non_const_var_off_kptr_xchg", "R1 doesn't have constant offset. kptr has to be" },
1704accf79SKumar Kartikeya Dwivedi 	{ "misaligned_access_write", "kptr access misaligned expected=8 off=7" },
1804accf79SKumar Kartikeya Dwivedi 	{ "misaligned_access_read", "kptr access misaligned expected=8 off=1" },
1904accf79SKumar Kartikeya Dwivedi 	{ "reject_var_off_store", "variable untrusted_ptr_ access var_off=(0x0; 0x1e0)" },
2004accf79SKumar Kartikeya Dwivedi 	{ "reject_bad_type_match", "invalid kptr access, R1 type=untrusted_ptr_prog_test_ref_kfunc" },
2104accf79SKumar Kartikeya Dwivedi 	{ "marked_as_untrusted_or_null", "R1 type=untrusted_ptr_or_null_ expected=percpu_ptr_" },
2204accf79SKumar Kartikeya Dwivedi 	{ "correct_btf_id_check_size", "access beyond struct prog_test_ref_kfunc at off 32 size 4" },
2304accf79SKumar Kartikeya Dwivedi 	{ "inherit_untrusted_on_walk", "R1 type=untrusted_ptr_ expected=percpu_ptr_" },
2404accf79SKumar Kartikeya Dwivedi 	{ "reject_kptr_xchg_on_unref", "off=8 kptr isn't referenced kptr" },
2504accf79SKumar Kartikeya Dwivedi 	{ "reject_kptr_get_no_map_val", "arg#0 expected pointer to map value" },
2604accf79SKumar Kartikeya Dwivedi 	{ "reject_kptr_get_no_null_map_val", "arg#0 expected pointer to map value" },
2704accf79SKumar Kartikeya Dwivedi 	{ "reject_kptr_get_no_kptr", "arg#0 no referenced kptr at map value offset=0" },
2804accf79SKumar Kartikeya Dwivedi 	{ "reject_kptr_get_on_unref", "arg#0 no referenced kptr at map value offset=8" },
2904accf79SKumar Kartikeya Dwivedi 	{ "reject_kptr_get_bad_type_match", "kernel function bpf_kfunc_call_test_kptr_get args#0" },
3004accf79SKumar Kartikeya Dwivedi 	{ "mark_ref_as_untrusted_or_null", "R1 type=untrusted_ptr_or_null_ expected=percpu_ptr_" },
3104accf79SKumar Kartikeya Dwivedi 	{ "reject_untrusted_store_to_ref", "store to referenced kptr disallowed" },
3204accf79SKumar Kartikeya Dwivedi 	{ "reject_bad_type_xchg", "invalid kptr access, R2 type=ptr_prog_test_ref_kfunc expected=ptr_prog_test_member" },
3304accf79SKumar Kartikeya Dwivedi 	{ "reject_untrusted_xchg", "R2 type=untrusted_ptr_ expected=ptr_" },
3404accf79SKumar Kartikeya Dwivedi 	{ "reject_member_of_ref_xchg", "invalid kptr access, R2 type=ptr_prog_test_ref_kfunc" },
3504accf79SKumar Kartikeya Dwivedi 	{ "reject_indirect_helper_access", "kptr cannot be accessed indirectly by helper" },
3604accf79SKumar Kartikeya Dwivedi 	{ "reject_indirect_global_func_access", "kptr cannot be accessed indirectly by helper" },
3704accf79SKumar Kartikeya Dwivedi 	{ "kptr_xchg_ref_state", "Unreleased reference id=5 alloc_insn=" },
3804accf79SKumar Kartikeya Dwivedi 	{ "kptr_get_ref_state", "Unreleased reference id=3 alloc_insn=" },
3904accf79SKumar Kartikeya Dwivedi };
4004accf79SKumar Kartikeya Dwivedi 
4104accf79SKumar Kartikeya Dwivedi static void test_map_kptr_fail_prog(const char *prog_name, const char *err_msg)
4204accf79SKumar Kartikeya Dwivedi {
4304accf79SKumar Kartikeya Dwivedi 	LIBBPF_OPTS(bpf_object_open_opts, opts, .kernel_log_buf = log_buf,
4404accf79SKumar Kartikeya Dwivedi 						.kernel_log_size = sizeof(log_buf),
4504accf79SKumar Kartikeya Dwivedi 						.kernel_log_level = 1);
4604accf79SKumar Kartikeya Dwivedi 	struct map_kptr_fail *skel;
4704accf79SKumar Kartikeya Dwivedi 	struct bpf_program *prog;
4804accf79SKumar Kartikeya Dwivedi 	int ret;
4904accf79SKumar Kartikeya Dwivedi 
5004accf79SKumar Kartikeya Dwivedi 	skel = map_kptr_fail__open_opts(&opts);
5104accf79SKumar Kartikeya Dwivedi 	if (!ASSERT_OK_PTR(skel, "map_kptr_fail__open_opts"))
5204accf79SKumar Kartikeya Dwivedi 		return;
5304accf79SKumar Kartikeya Dwivedi 
5404accf79SKumar Kartikeya Dwivedi 	prog = bpf_object__find_program_by_name(skel->obj, prog_name);
5504accf79SKumar Kartikeya Dwivedi 	if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
5604accf79SKumar Kartikeya Dwivedi 		goto end;
5704accf79SKumar Kartikeya Dwivedi 
5804accf79SKumar Kartikeya Dwivedi 	bpf_program__set_autoload(prog, true);
5904accf79SKumar Kartikeya Dwivedi 
6004accf79SKumar Kartikeya Dwivedi 	ret = map_kptr_fail__load(skel);
6104accf79SKumar Kartikeya Dwivedi 	if (!ASSERT_ERR(ret, "map_kptr__load must fail"))
6204accf79SKumar Kartikeya Dwivedi 		goto end;
6304accf79SKumar Kartikeya Dwivedi 
6404accf79SKumar Kartikeya Dwivedi 	if (!ASSERT_OK_PTR(strstr(log_buf, err_msg), "expected error message")) {
6504accf79SKumar Kartikeya Dwivedi 		fprintf(stderr, "Expected: %s\n", err_msg);
6604accf79SKumar Kartikeya Dwivedi 		fprintf(stderr, "Verifier: %s\n", log_buf);
6704accf79SKumar Kartikeya Dwivedi 	}
6804accf79SKumar Kartikeya Dwivedi 
6904accf79SKumar Kartikeya Dwivedi end:
7004accf79SKumar Kartikeya Dwivedi 	map_kptr_fail__destroy(skel);
7104accf79SKumar Kartikeya Dwivedi }
7204accf79SKumar Kartikeya Dwivedi 
7304accf79SKumar Kartikeya Dwivedi static void test_map_kptr_fail(void)
7404accf79SKumar Kartikeya Dwivedi {
7504accf79SKumar Kartikeya Dwivedi 	int i;
7604accf79SKumar Kartikeya Dwivedi 
7704accf79SKumar Kartikeya Dwivedi 	for (i = 0; i < ARRAY_SIZE(map_kptr_fail_tests); i++) {
7804accf79SKumar Kartikeya Dwivedi 		if (!test__start_subtest(map_kptr_fail_tests[i].prog_name))
7904accf79SKumar Kartikeya Dwivedi 			continue;
8004accf79SKumar Kartikeya Dwivedi 		test_map_kptr_fail_prog(map_kptr_fail_tests[i].prog_name,
8104accf79SKumar Kartikeya Dwivedi 					map_kptr_fail_tests[i].err_msg);
8204accf79SKumar Kartikeya Dwivedi 	}
8304accf79SKumar Kartikeya Dwivedi }
8404accf79SKumar Kartikeya Dwivedi 
85*0ef6740eSKumar Kartikeya Dwivedi static void test_map_kptr_success(bool test_run)
862cbc469aSKumar Kartikeya Dwivedi {
87*0ef6740eSKumar Kartikeya Dwivedi 	LIBBPF_OPTS(bpf_test_run_opts, opts,
88*0ef6740eSKumar Kartikeya Dwivedi 		.data_in = &pkt_v4,
89*0ef6740eSKumar Kartikeya Dwivedi 		.data_size_in = sizeof(pkt_v4),
90*0ef6740eSKumar Kartikeya Dwivedi 		.repeat = 1,
91*0ef6740eSKumar Kartikeya Dwivedi 	);
922cbc469aSKumar Kartikeya Dwivedi 	struct map_kptr *skel;
932cbc469aSKumar Kartikeya Dwivedi 	int key = 0, ret;
942cbc469aSKumar Kartikeya Dwivedi 	char buf[24];
952cbc469aSKumar Kartikeya Dwivedi 
962cbc469aSKumar Kartikeya Dwivedi 	skel = map_kptr__open_and_load();
972cbc469aSKumar Kartikeya Dwivedi 	if (!ASSERT_OK_PTR(skel, "map_kptr__open_and_load"))
982cbc469aSKumar Kartikeya Dwivedi 		return;
992cbc469aSKumar Kartikeya Dwivedi 
100*0ef6740eSKumar Kartikeya Dwivedi 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref), &opts);
101*0ef6740eSKumar Kartikeya Dwivedi 	ASSERT_OK(ret, "test_map_kptr_ref refcount");
102*0ef6740eSKumar Kartikeya Dwivedi 	ASSERT_OK(opts.retval, "test_map_kptr_ref retval");
103*0ef6740eSKumar Kartikeya Dwivedi 	ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_map_kptr_ref2), &opts);
104*0ef6740eSKumar Kartikeya Dwivedi 	ASSERT_OK(ret, "test_map_kptr_ref2 refcount");
105*0ef6740eSKumar Kartikeya Dwivedi 	ASSERT_OK(opts.retval, "test_map_kptr_ref2 retval");
106*0ef6740eSKumar Kartikeya Dwivedi 
107*0ef6740eSKumar Kartikeya Dwivedi 	if (test_run)
108*0ef6740eSKumar Kartikeya Dwivedi 		return;
109*0ef6740eSKumar Kartikeya Dwivedi 
1102cbc469aSKumar Kartikeya Dwivedi 	ret = bpf_map_update_elem(bpf_map__fd(skel->maps.array_map), &key, buf, 0);
1112cbc469aSKumar Kartikeya Dwivedi 	ASSERT_OK(ret, "array_map update");
1122cbc469aSKumar Kartikeya Dwivedi 	ret = bpf_map_update_elem(bpf_map__fd(skel->maps.array_map), &key, buf, 0);
1132cbc469aSKumar Kartikeya Dwivedi 	ASSERT_OK(ret, "array_map update2");
1142cbc469aSKumar Kartikeya Dwivedi 
1152cbc469aSKumar Kartikeya Dwivedi 	ret = bpf_map_update_elem(bpf_map__fd(skel->maps.hash_map), &key, buf, 0);
1162cbc469aSKumar Kartikeya Dwivedi 	ASSERT_OK(ret, "hash_map update");
1172cbc469aSKumar Kartikeya Dwivedi 	ret = bpf_map_delete_elem(bpf_map__fd(skel->maps.hash_map), &key);
1182cbc469aSKumar Kartikeya Dwivedi 	ASSERT_OK(ret, "hash_map delete");
1192cbc469aSKumar Kartikeya Dwivedi 
1202cbc469aSKumar Kartikeya Dwivedi 	ret = bpf_map_update_elem(bpf_map__fd(skel->maps.hash_malloc_map), &key, buf, 0);
1212cbc469aSKumar Kartikeya Dwivedi 	ASSERT_OK(ret, "hash_malloc_map update");
1222cbc469aSKumar Kartikeya Dwivedi 	ret = bpf_map_delete_elem(bpf_map__fd(skel->maps.hash_malloc_map), &key);
1232cbc469aSKumar Kartikeya Dwivedi 	ASSERT_OK(ret, "hash_malloc_map delete");
1242cbc469aSKumar Kartikeya Dwivedi 
1252cbc469aSKumar Kartikeya Dwivedi 	ret = bpf_map_update_elem(bpf_map__fd(skel->maps.lru_hash_map), &key, buf, 0);
1262cbc469aSKumar Kartikeya Dwivedi 	ASSERT_OK(ret, "lru_hash_map update");
1272cbc469aSKumar Kartikeya Dwivedi 	ret = bpf_map_delete_elem(bpf_map__fd(skel->maps.lru_hash_map), &key);
1282cbc469aSKumar Kartikeya Dwivedi 	ASSERT_OK(ret, "lru_hash_map delete");
1292cbc469aSKumar Kartikeya Dwivedi 
1302cbc469aSKumar Kartikeya Dwivedi 	map_kptr__destroy(skel);
1312cbc469aSKumar Kartikeya Dwivedi }
13204accf79SKumar Kartikeya Dwivedi 
13304accf79SKumar Kartikeya Dwivedi void test_map_kptr(void)
13404accf79SKumar Kartikeya Dwivedi {
135*0ef6740eSKumar Kartikeya Dwivedi 	if (test__start_subtest("success")) {
136*0ef6740eSKumar Kartikeya Dwivedi 		test_map_kptr_success(false);
137*0ef6740eSKumar Kartikeya Dwivedi 		/* Do test_run twice, so that we see refcount going back to 1
138*0ef6740eSKumar Kartikeya Dwivedi 		 * after we leave it in map from first iteration.
139*0ef6740eSKumar Kartikeya Dwivedi 		 */
140*0ef6740eSKumar Kartikeya Dwivedi 		test_map_kptr_success(true);
141*0ef6740eSKumar Kartikeya Dwivedi 	}
14204accf79SKumar Kartikeya Dwivedi 	test_map_kptr_fail();
14304accf79SKumar Kartikeya Dwivedi }
144