1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ 3 4 #define _GNU_SOURCE 5 #include <sys/wait.h> 6 #include <test_progs.h> 7 #include <unistd.h> 8 9 #include "task_kfunc_failure.skel.h" 10 #include "task_kfunc_success.skel.h" 11 12 static size_t log_buf_sz = 1 << 20; /* 1 MB */ 13 static char obj_log_buf[1048576]; 14 15 static struct task_kfunc_success *open_load_task_kfunc_skel(void) 16 { 17 struct task_kfunc_success *skel; 18 int err; 19 20 skel = task_kfunc_success__open(); 21 if (!ASSERT_OK_PTR(skel, "skel_open")) 22 return NULL; 23 24 skel->bss->pid = getpid(); 25 26 err = task_kfunc_success__load(skel); 27 if (!ASSERT_OK(err, "skel_load")) 28 goto cleanup; 29 30 return skel; 31 32 cleanup: 33 task_kfunc_success__destroy(skel); 34 return NULL; 35 } 36 37 static void run_success_test(const char *prog_name) 38 { 39 struct task_kfunc_success *skel; 40 int status; 41 pid_t child_pid; 42 struct bpf_program *prog; 43 struct bpf_link *link = NULL; 44 45 skel = open_load_task_kfunc_skel(); 46 if (!ASSERT_OK_PTR(skel, "open_load_skel")) 47 return; 48 49 if (!ASSERT_OK(skel->bss->err, "pre_spawn_err")) 50 goto cleanup; 51 52 prog = bpf_object__find_program_by_name(skel->obj, prog_name); 53 if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) 54 goto cleanup; 55 56 link = bpf_program__attach(prog); 57 if (!ASSERT_OK_PTR(link, "attached_link")) 58 goto cleanup; 59 60 child_pid = fork(); 61 if (!ASSERT_GT(child_pid, -1, "child_pid")) 62 goto cleanup; 63 if (child_pid == 0) 64 _exit(0); 65 waitpid(child_pid, &status, 0); 66 67 ASSERT_OK(skel->bss->err, "post_wait_err"); 68 69 cleanup: 70 bpf_link__destroy(link); 71 task_kfunc_success__destroy(skel); 72 } 73 74 static const char * const success_tests[] = { 75 "test_task_acquire_release_argument", 76 "test_task_acquire_release_current", 77 "test_task_acquire_leave_in_map", 78 "test_task_xchg_release", 79 "test_task_get_release", 80 "test_task_current_acquire_release", 81 "test_task_from_pid_arg", 82 "test_task_from_pid_current", 83 "test_task_from_pid_invalid", 84 }; 85 86 static struct { 87 const char *prog_name; 88 const char *expected_err_msg; 89 } failure_tests[] = { 90 {"task_kfunc_acquire_untrusted", "R1 must be referenced or trusted"}, 91 {"task_kfunc_acquire_fp", "arg#0 pointer type STRUCT task_struct must point"}, 92 {"task_kfunc_acquire_unsafe_kretprobe", "reg type unsupported for arg#0 function"}, 93 {"task_kfunc_acquire_trusted_walked", "R1 must be referenced or trusted"}, 94 {"task_kfunc_acquire_null", "arg#0 pointer type STRUCT task_struct must point"}, 95 {"task_kfunc_acquire_unreleased", "Unreleased reference"}, 96 {"task_kfunc_get_non_kptr_param", "arg#0 expected pointer to map value"}, 97 {"task_kfunc_get_non_kptr_acquired", "arg#0 expected pointer to map value"}, 98 {"task_kfunc_get_null", "arg#0 expected pointer to map value"}, 99 {"task_kfunc_xchg_unreleased", "Unreleased reference"}, 100 {"task_kfunc_get_unreleased", "Unreleased reference"}, 101 {"task_kfunc_release_untrusted", "arg#0 is untrusted_ptr_or_null_ expected ptr_ or socket"}, 102 {"task_kfunc_release_fp", "arg#0 pointer type STRUCT task_struct must point"}, 103 {"task_kfunc_release_null", "arg#0 is ptr_or_null_ expected ptr_ or socket"}, 104 {"task_kfunc_release_unacquired", "release kernel function bpf_task_release expects"}, 105 {"task_kfunc_from_pid_no_null_check", "arg#0 is ptr_or_null_ expected ptr_ or socket"}, 106 {"task_kfunc_from_lsm_task_free", "reg type unsupported for arg#0 function"}, 107 }; 108 109 static void verify_fail(const char *prog_name, const char *expected_err_msg) 110 { 111 LIBBPF_OPTS(bpf_object_open_opts, opts); 112 struct task_kfunc_failure *skel; 113 int err, i; 114 115 opts.kernel_log_buf = obj_log_buf; 116 opts.kernel_log_size = log_buf_sz; 117 opts.kernel_log_level = 1; 118 119 skel = task_kfunc_failure__open_opts(&opts); 120 if (!ASSERT_OK_PTR(skel, "task_kfunc_failure__open_opts")) 121 goto cleanup; 122 123 for (i = 0; i < ARRAY_SIZE(failure_tests); i++) { 124 struct bpf_program *prog; 125 const char *curr_name = failure_tests[i].prog_name; 126 127 prog = bpf_object__find_program_by_name(skel->obj, curr_name); 128 if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) 129 goto cleanup; 130 131 bpf_program__set_autoload(prog, !strcmp(curr_name, prog_name)); 132 } 133 134 err = task_kfunc_failure__load(skel); 135 if (!ASSERT_ERR(err, "unexpected load success")) 136 goto cleanup; 137 138 if (!ASSERT_OK_PTR(strstr(obj_log_buf, expected_err_msg), "expected_err_msg")) { 139 fprintf(stderr, "Expected err_msg: %s\n", expected_err_msg); 140 fprintf(stderr, "Verifier output: %s\n", obj_log_buf); 141 } 142 143 cleanup: 144 task_kfunc_failure__destroy(skel); 145 } 146 147 void test_task_kfunc(void) 148 { 149 int i; 150 151 for (i = 0; i < ARRAY_SIZE(success_tests); i++) { 152 if (!test__start_subtest(success_tests[i])) 153 continue; 154 155 run_success_test(success_tests[i]); 156 } 157 158 for (i = 0; i < ARRAY_SIZE(failure_tests); i++) { 159 if (!test__start_subtest(failure_tests[i].prog_name)) 160 continue; 161 162 verify_fail(failure_tests[i].prog_name, failure_tests[i].expected_err_msg); 163 } 164 } 165