brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · f79c8e5 Raw
325 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2021 Facebook */3#include <test_progs.h>4#include <network_helpers.h>5#include "kfunc_call_fail.skel.h"6#include "kfunc_call_test.skel.h"7#include "kfunc_call_test.lskel.h"8#include "kfunc_call_test_subprog.skel.h"9#include "kfunc_call_test_subprog.lskel.h"10#include "kfunc_call_destructive.skel.h"11 12#include "cap_helpers.h"13 14static size_t log_buf_sz = 1048576; /* 1 MB */15static char obj_log_buf[1048576];16 17enum kfunc_test_type {18	tc_test = 0,19	syscall_test,20	syscall_null_ctx_test,21};22 23struct kfunc_test_params {24	const char *prog_name;25	unsigned long lskel_prog_desc_offset;26	int retval;27	enum kfunc_test_type test_type;28	const char *expected_err_msg;29};30 31#define __BPF_TEST_SUCCESS(name, __retval, type) \32	{ \33	  .prog_name = #name, \34	  .lskel_prog_desc_offset = offsetof(struct kfunc_call_test_lskel, progs.name), \35	  .retval = __retval, \36	  .test_type = type, \37	  .expected_err_msg = NULL, \38	}39 40#define __BPF_TEST_FAIL(name, __retval, type, error_msg) \41	{ \42	  .prog_name = #name, \43	  .lskel_prog_desc_offset = 0 /* unused when test is failing */, \44	  .retval = __retval, \45	  .test_type = type, \46	  .expected_err_msg = error_msg, \47	}48 49#define TC_TEST(name, retval) __BPF_TEST_SUCCESS(name, retval, tc_test)50#define SYSCALL_TEST(name, retval) __BPF_TEST_SUCCESS(name, retval, syscall_test)51#define SYSCALL_NULL_CTX_TEST(name, retval) __BPF_TEST_SUCCESS(name, retval, syscall_null_ctx_test)52 53#define TC_FAIL(name, retval, error_msg) __BPF_TEST_FAIL(name, retval, tc_test, error_msg)54#define SYSCALL_NULL_CTX_FAIL(name, retval, error_msg) \55	__BPF_TEST_FAIL(name, retval, syscall_null_ctx_test, error_msg)56 57static struct kfunc_test_params kfunc_tests[] = {58	/* failure cases:59	 * if retval is 0 -> the program will fail to load and the error message is an error60	 * if retval is not 0 -> the program can be loaded but running it will gives the61	 *                       provided return value. The error message is thus the one62	 *                       from a successful load63	 */64	SYSCALL_NULL_CTX_FAIL(kfunc_syscall_test_fail, -EINVAL, "processed 4 insns"),65	SYSCALL_NULL_CTX_FAIL(kfunc_syscall_test_null_fail, -EINVAL, "processed 4 insns"),66	TC_FAIL(kfunc_call_test_get_mem_fail_rdonly, 0, "R0 cannot write into rdonly_mem"),67	TC_FAIL(kfunc_call_test_get_mem_fail_use_after_free, 0, "invalid mem access 'scalar'"),68	TC_FAIL(kfunc_call_test_get_mem_fail_oob, 0, "min value is outside of the allowed memory range"),69	TC_FAIL(kfunc_call_test_get_mem_fail_not_const, 0, "is not a const"),70	TC_FAIL(kfunc_call_test_mem_acquire_fail, 0, "acquire kernel function does not return PTR_TO_BTF_ID"),71	TC_FAIL(kfunc_call_test_pointer_arg_type_mismatch, 0, "arg#0 expected pointer to ctx, but got scalar"),72 73	/* success cases */74	TC_TEST(kfunc_call_test1, 12),75	TC_TEST(kfunc_call_test2, 3),76	TC_TEST(kfunc_call_test4, -1234),77	TC_TEST(kfunc_call_test_ref_btf_id, 0),78	TC_TEST(kfunc_call_test_get_mem, 42),79	SYSCALL_TEST(kfunc_syscall_test, 0),80	SYSCALL_NULL_CTX_TEST(kfunc_syscall_test_null, 0),81	TC_TEST(kfunc_call_test_static_unused_arg, 0),82	TC_TEST(kfunc_call_ctx, 0),83};84 85struct syscall_test_args {86	__u8 data[16];87	size_t size;88};89 90static void verify_success(struct kfunc_test_params *param)91{92	struct kfunc_call_test_lskel *lskel = NULL;93	LIBBPF_OPTS(bpf_test_run_opts, topts);94	struct bpf_prog_desc *lskel_prog;95	struct kfunc_call_test *skel;96	struct bpf_program *prog;97	int prog_fd, err;98	struct syscall_test_args args = {99		.size = 10,100	};101 102	switch (param->test_type) {103	case syscall_test:104		topts.ctx_in = &args;105		topts.ctx_size_in = sizeof(args);106		/* fallthrough */107	case syscall_null_ctx_test:108		break;109	case tc_test:110		topts.data_in = &pkt_v4;111		topts.data_size_in = sizeof(pkt_v4);112		topts.repeat = 1;113		break;114	}115 116	/* first test with normal libbpf */117	skel = kfunc_call_test__open_and_load();118	if (!ASSERT_OK_PTR(skel, "skel"))119		return;120 121	prog = bpf_object__find_program_by_name(skel->obj, param->prog_name);122	if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))123		goto cleanup;124 125	prog_fd = bpf_program__fd(prog);126	err = bpf_prog_test_run_opts(prog_fd, &topts);127	if (!ASSERT_OK(err, param->prog_name))128		goto cleanup;129 130	if (!ASSERT_EQ(topts.retval, param->retval, "retval"))131		goto cleanup;132 133	/* second test with light skeletons */134	lskel = kfunc_call_test_lskel__open_and_load();135	if (!ASSERT_OK_PTR(lskel, "lskel"))136		goto cleanup;137 138	lskel_prog = (struct bpf_prog_desc *)((char *)lskel + param->lskel_prog_desc_offset);139 140	prog_fd = lskel_prog->prog_fd;141	err = bpf_prog_test_run_opts(prog_fd, &topts);142	if (!ASSERT_OK(err, param->prog_name))143		goto cleanup;144 145	ASSERT_EQ(topts.retval, param->retval, "retval");146 147cleanup:148	kfunc_call_test__destroy(skel);149	if (lskel)150		kfunc_call_test_lskel__destroy(lskel);151}152 153static void verify_fail(struct kfunc_test_params *param)154{155	LIBBPF_OPTS(bpf_object_open_opts, opts);156	LIBBPF_OPTS(bpf_test_run_opts, topts);157	struct bpf_program *prog;158	struct kfunc_call_fail *skel;159	int prog_fd, err;160	struct syscall_test_args args = {161		.size = 10,162	};163 164	opts.kernel_log_buf = obj_log_buf;165	opts.kernel_log_size = log_buf_sz;166	opts.kernel_log_level = 1;167 168	switch (param->test_type) {169	case syscall_test:170		topts.ctx_in = &args;171		topts.ctx_size_in = sizeof(args);172		/* fallthrough */173	case syscall_null_ctx_test:174		break;175	case tc_test:176		topts.data_in = &pkt_v4;177		topts.data_size_in = sizeof(pkt_v4);178		topts.repeat = 1;179		break;180	}181 182	skel = kfunc_call_fail__open_opts(&opts);183	if (!ASSERT_OK_PTR(skel, "kfunc_call_fail__open_opts"))184		goto cleanup;185 186	prog = bpf_object__find_program_by_name(skel->obj, param->prog_name);187	if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))188		goto cleanup;189 190	bpf_program__set_autoload(prog, true);191 192	err = kfunc_call_fail__load(skel);193	if (!param->retval) {194		/* the verifier is supposed to complain and refuses to load */195		if (!ASSERT_ERR(err, "unexpected load success"))196			goto out_err;197 198	} else {199		/* the program is loaded but must dynamically fail */200		if (!ASSERT_OK(err, "unexpected load error"))201			goto out_err;202 203		prog_fd = bpf_program__fd(prog);204		err = bpf_prog_test_run_opts(prog_fd, &topts);205		if (!ASSERT_EQ(err, param->retval, param->prog_name))206			goto out_err;207	}208 209out_err:210	if (!ASSERT_OK_PTR(strstr(obj_log_buf, param->expected_err_msg), "expected_err_msg")) {211		fprintf(stderr, "Expected err_msg: %s\n", param->expected_err_msg);212		fprintf(stderr, "Verifier output: %s\n", obj_log_buf);213	}214 215cleanup:216	kfunc_call_fail__destroy(skel);217}218 219static void test_main(void)220{221	int i;222 223	for (i = 0; i < ARRAY_SIZE(kfunc_tests); i++) {224		if (!test__start_subtest(kfunc_tests[i].prog_name))225			continue;226 227		if (!kfunc_tests[i].expected_err_msg)228			verify_success(&kfunc_tests[i]);229		else230			verify_fail(&kfunc_tests[i]);231	}232}233 234static void test_subprog(void)235{236	struct kfunc_call_test_subprog *skel;237	int prog_fd, err;238	LIBBPF_OPTS(bpf_test_run_opts, topts,239		.data_in = &pkt_v4,240		.data_size_in = sizeof(pkt_v4),241		.repeat = 1,242	);243 244	skel = kfunc_call_test_subprog__open_and_load();245	if (!ASSERT_OK_PTR(skel, "skel"))246		return;247 248	prog_fd = bpf_program__fd(skel->progs.kfunc_call_test1);249	err = bpf_prog_test_run_opts(prog_fd, &topts);250	ASSERT_OK(err, "bpf_prog_test_run(test1)");251	ASSERT_EQ(topts.retval, 10, "test1-retval");252	ASSERT_NEQ(skel->data->active_res, -1, "active_res");253	ASSERT_EQ(skel->data->sk_state_res, BPF_TCP_CLOSE, "sk_state_res");254 255	kfunc_call_test_subprog__destroy(skel);256}257 258static void test_subprog_lskel(void)259{260	struct kfunc_call_test_subprog_lskel *skel;261	int prog_fd, err;262	LIBBPF_OPTS(bpf_test_run_opts, topts,263		.data_in = &pkt_v4,264		.data_size_in = sizeof(pkt_v4),265		.repeat = 1,266	);267 268	skel = kfunc_call_test_subprog_lskel__open_and_load();269	if (!ASSERT_OK_PTR(skel, "skel"))270		return;271 272	prog_fd = skel->progs.kfunc_call_test1.prog_fd;273	err = bpf_prog_test_run_opts(prog_fd, &topts);274	ASSERT_OK(err, "bpf_prog_test_run(test1)");275	ASSERT_EQ(topts.retval, 10, "test1-retval");276	ASSERT_NEQ(skel->data->active_res, -1, "active_res");277	ASSERT_EQ(skel->data->sk_state_res, BPF_TCP_CLOSE, "sk_state_res");278 279	kfunc_call_test_subprog_lskel__destroy(skel);280}281 282static int test_destructive_open_and_load(void)283{284	struct kfunc_call_destructive *skel;285	int err;286 287	skel = kfunc_call_destructive__open();288	if (!ASSERT_OK_PTR(skel, "prog_open"))289		return -1;290 291	err = kfunc_call_destructive__load(skel);292 293	kfunc_call_destructive__destroy(skel);294 295	return err;296}297 298static void test_destructive(void)299{300	__u64 save_caps = 0;301 302	ASSERT_OK(test_destructive_open_and_load(), "successful_load");303 304	if (!ASSERT_OK(cap_disable_effective(1ULL << CAP_SYS_BOOT, &save_caps), "drop_caps"))305		return;306 307	ASSERT_EQ(test_destructive_open_and_load(), -13, "no_caps_failure");308 309	cap_enable_effective(save_caps, NULL);310}311 312void test_kfunc_call(void)313{314	test_main();315 316	if (test__start_subtest("subprog"))317		test_subprog();318 319	if (test__start_subtest("subprog_lskel"))320		test_subprog_lskel();321 322	if (test__start_subtest("destructive"))323		test_destructive();324}325