Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

selftests/bpf: Add tests for bpf_task_from_vpid() kfunc

This patch adds test cases for bpf_task_from_vpid() kfunc.

task_kfunc_from_vpid_no_null_check is used to test the case where
the return value is not checked for NULL pointer.

test_task_from_vpid_current is used to test obtaining the
struct task_struct of the process in the pid namespace based on vpid.

test_task_from_vpid_invalid is used to test the case of invalid vpid.

test_task_from_vpid_current and test_task_from_vpid_invalid will run
in the new namespace.

Signed-off-by: Juntong Deng <juntong.deng@outlook.com>
Link: https://lore.kernel.org/r/AM6PR03MB5848F13435CD650AC4B7BD7099442@AM6PR03MB5848.eurprd03.prod.outlook.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Juntong Deng and committed by
Alexei Starovoitov
f987a640 675c3596

+146
+80
tools/testing/selftests/bpf/prog_tests/task_kfunc.c
··· 68 68 task_kfunc_success__destroy(skel); 69 69 } 70 70 71 + static int run_vpid_test(void *prog_name) 72 + { 73 + struct task_kfunc_success *skel; 74 + struct bpf_program *prog; 75 + int prog_fd, err = 0; 76 + 77 + if (getpid() != 1) 78 + return 1; 79 + 80 + skel = open_load_task_kfunc_skel(); 81 + if (!skel) 82 + return 2; 83 + 84 + if (skel->bss->err) { 85 + err = 3; 86 + goto cleanup; 87 + } 88 + 89 + prog = bpf_object__find_program_by_name(skel->obj, prog_name); 90 + if (!prog) { 91 + err = 4; 92 + goto cleanup; 93 + } 94 + 95 + prog_fd = bpf_program__fd(prog); 96 + if (prog_fd < 0) { 97 + err = 5; 98 + goto cleanup; 99 + } 100 + 101 + if (bpf_prog_test_run_opts(prog_fd, NULL)) { 102 + err = 6; 103 + goto cleanup; 104 + } 105 + 106 + if (skel->bss->err) 107 + err = 7 + skel->bss->err; 108 + cleanup: 109 + task_kfunc_success__destroy(skel); 110 + return err; 111 + } 112 + 113 + static void run_vpid_success_test(const char *prog_name) 114 + { 115 + const int stack_size = 1024 * 1024; 116 + int child_pid, wstatus; 117 + char *stack; 118 + 119 + stack = (char *)malloc(stack_size); 120 + if (!ASSERT_OK_PTR(stack, "clone_stack")) 121 + return; 122 + 123 + child_pid = clone(run_vpid_test, stack + stack_size, 124 + CLONE_NEWPID | SIGCHLD, (void *)prog_name); 125 + if (!ASSERT_GT(child_pid, -1, "child_pid")) 126 + goto cleanup; 127 + 128 + if (!ASSERT_GT(waitpid(child_pid, &wstatus, 0), -1, "waitpid")) 129 + goto cleanup; 130 + 131 + if (WEXITSTATUS(wstatus) > 7) 132 + ASSERT_OK(WEXITSTATUS(wstatus) - 7, "vpid_test_failure"); 133 + else 134 + ASSERT_OK(WEXITSTATUS(wstatus), "run_vpid_test_err"); 135 + cleanup: 136 + free(stack); 137 + } 138 + 71 139 static const char * const success_tests[] = { 72 140 "test_task_acquire_release_argument", 73 141 "test_task_acquire_release_current", ··· 151 83 "test_task_kfunc_flavor_relo_not_found", 152 84 }; 153 85 86 + static const char * const vpid_success_tests[] = { 87 + "test_task_from_vpid_current", 88 + "test_task_from_vpid_invalid", 89 + }; 90 + 154 91 void test_task_kfunc(void) 155 92 { 156 93 int i; ··· 165 92 continue; 166 93 167 94 run_success_test(success_tests[i]); 95 + } 96 + 97 + for (i = 0; i < ARRAY_SIZE(vpid_success_tests); i++) { 98 + if (!test__start_subtest(vpid_success_tests[i])) 99 + continue; 100 + 101 + run_vpid_success_test(vpid_success_tests[i]); 168 102 } 169 103 170 104 RUN_TESTS(task_kfunc_failure);
+1
tools/testing/selftests/bpf/progs/task_kfunc_common.h
··· 23 23 struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym; 24 24 void bpf_task_release(struct task_struct *p) __ksym; 25 25 struct task_struct *bpf_task_from_pid(s32 pid) __ksym; 26 + struct task_struct *bpf_task_from_vpid(s32 vpid) __ksym; 26 27 void bpf_rcu_read_lock(void) __ksym; 27 28 void bpf_rcu_read_unlock(void) __ksym; 28 29
+14
tools/testing/selftests/bpf/progs/task_kfunc_failure.c
··· 247 247 return 0; 248 248 } 249 249 250 + SEC("tp_btf/task_newtask") 251 + __failure __msg("Possibly NULL pointer passed to trusted arg0") 252 + int BPF_PROG(task_kfunc_from_vpid_no_null_check, struct task_struct *task, u64 clone_flags) 253 + { 254 + struct task_struct *acquired; 255 + 256 + acquired = bpf_task_from_vpid(task->pid); 257 + 258 + /* Releasing bpf_task_from_vpid() lookup without a NULL check. */ 259 + bpf_task_release(acquired); 260 + 261 + return 0; 262 + } 263 + 250 264 SEC("lsm/task_free") 251 265 __failure __msg("R1 must be a rcu pointer") 252 266 int BPF_PROG(task_kfunc_from_lsm_task_free, struct task_struct *task)
+51
tools/testing/selftests/bpf/progs/task_kfunc_success.c
··· 366 366 367 367 return 0; 368 368 } 369 + 370 + SEC("syscall") 371 + int test_task_from_vpid_current(const void *ctx) 372 + { 373 + struct task_struct *current, *v_task; 374 + 375 + v_task = bpf_task_from_vpid(1); 376 + if (!v_task) { 377 + err = 1; 378 + return 0; 379 + } 380 + 381 + current = bpf_get_current_task_btf(); 382 + 383 + /* The current process should be the init process (pid 1) in the new pid namespace. */ 384 + if (current != v_task) 385 + err = 2; 386 + 387 + bpf_task_release(v_task); 388 + return 0; 389 + } 390 + 391 + SEC("syscall") 392 + int test_task_from_vpid_invalid(const void *ctx) 393 + { 394 + struct task_struct *v_task; 395 + 396 + v_task = bpf_task_from_vpid(-1); 397 + if (v_task) { 398 + err = 1; 399 + goto err; 400 + } 401 + 402 + /* There should be only one process (current process) in the new pid namespace. */ 403 + v_task = bpf_task_from_vpid(2); 404 + if (v_task) { 405 + err = 2; 406 + goto err; 407 + } 408 + 409 + v_task = bpf_task_from_vpid(9999); 410 + if (v_task) { 411 + err = 3; 412 + goto err; 413 + } 414 + 415 + return 0; 416 + err: 417 + bpf_task_release(v_task); 418 + return 0; 419 + }