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 }; 82 83 static struct { 84 const char *prog_name; 85 const char *expected_err_msg; 86 } failure_tests[] = { 87 {"task_kfunc_acquire_untrusted", "R1 must be referenced or trusted"}, 88 {"task_kfunc_acquire_fp", "arg#0 pointer type STRUCT task_struct must point"}, 89 {"task_kfunc_acquire_unsafe_kretprobe", "reg type unsupported for arg#0 function"}, 90 {"task_kfunc_acquire_trusted_walked", "R1 must be referenced or trusted"}, 91 {"task_kfunc_acquire_null", "arg#0 pointer type STRUCT task_struct must point"}, 92 {"task_kfunc_acquire_unreleased", "Unreleased reference"}, 93 {"task_kfunc_get_non_kptr_param", "arg#0 expected pointer to map value"}, 94 {"task_kfunc_get_non_kptr_acquired", "arg#0 expected pointer to map value"}, 95 {"task_kfunc_get_null", "arg#0 expected pointer to map value"}, 96 {"task_kfunc_xchg_unreleased", "Unreleased reference"}, 97 {"task_kfunc_get_unreleased", "Unreleased reference"}, 98 {"task_kfunc_release_untrusted", "arg#0 is untrusted_ptr_or_null_ expected ptr_ or socket"}, 99 {"task_kfunc_release_fp", "arg#0 pointer type STRUCT task_struct must point"}, 100 {"task_kfunc_release_null", "arg#0 is ptr_or_null_ expected ptr_ or socket"}, 101 {"task_kfunc_release_unacquired", "release kernel function bpf_task_release expects"}, 102 }; 103 104 static void verify_fail(const char *prog_name, const char *expected_err_msg) 105 { 106 LIBBPF_OPTS(bpf_object_open_opts, opts); 107 struct task_kfunc_failure *skel; 108 int err, i; 109 110 opts.kernel_log_buf = obj_log_buf; 111 opts.kernel_log_size = log_buf_sz; 112 opts.kernel_log_level = 1; 113 114 skel = task_kfunc_failure__open_opts(&opts); 115 if (!ASSERT_OK_PTR(skel, "task_kfunc_failure__open_opts")) 116 goto cleanup; 117 118 for (i = 0; i < ARRAY_SIZE(failure_tests); i++) { 119 struct bpf_program *prog; 120 const char *curr_name = failure_tests[i].prog_name; 121 122 prog = bpf_object__find_program_by_name(skel->obj, curr_name); 123 if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) 124 goto cleanup; 125 126 bpf_program__set_autoload(prog, !strcmp(curr_name, prog_name)); 127 } 128 129 err = task_kfunc_failure__load(skel); 130 if (!ASSERT_ERR(err, "unexpected load success")) 131 goto cleanup; 132 133 if (!ASSERT_OK_PTR(strstr(obj_log_buf, expected_err_msg), "expected_err_msg")) { 134 fprintf(stderr, "Expected err_msg: %s\n", expected_err_msg); 135 fprintf(stderr, "Verifier output: %s\n", obj_log_buf); 136 } 137 138 cleanup: 139 task_kfunc_failure__destroy(skel); 140 } 141 142 void test_task_kfunc(void) 143 { 144 int i; 145 146 for (i = 0; i < ARRAY_SIZE(success_tests); i++) { 147 if (!test__start_subtest(success_tests[i])) 148 continue; 149 150 run_success_test(success_tests[i]); 151 } 152 153 for (i = 0; i < ARRAY_SIZE(failure_tests); i++) { 154 if (!test__start_subtest(failure_tests[i].prog_name)) 155 continue; 156 157 verify_fail(failure_tests[i].prog_name, failure_tests[i].expected_err_msg); 158 } 159 } 160