| 1 | |
| 2 |
|
| 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 struct task_kfunc_success *open_load_task_kfunc_skel(void)
|
| 13 | {
|
| 14 | struct task_kfunc_success *skel;
|
| 15 | int err;
|
| 16 |
|
| 17 | skel = task_kfunc_success__open();
|
| 18 | if (!ASSERT_OK_PTR(skel, "skel_open"))
|
| 19 | return NULL;
|
| 20 |
|
| 21 | skel->bss->pid = getpid();
|
| 22 |
|
| 23 | err = task_kfunc_success__load(skel);
|
| 24 | if (!ASSERT_OK(err, "skel_load"))
|
| 25 | goto cleanup;
|
| 26 |
|
| 27 | return skel;
|
| 28 |
|
| 29 | cleanup:
|
| 30 | task_kfunc_success__destroy(skel);
|
| 31 | return NULL;
|
| 32 | }
|
| 33 |
|
| 34 | static void run_success_test(const char *prog_name)
|
| 35 | {
|
| 36 | struct task_kfunc_success *skel;
|
| 37 | int status;
|
| 38 | pid_t child_pid;
|
| 39 | struct bpf_program *prog;
|
| 40 | struct bpf_link *link = NULL;
|
| 41 |
|
| 42 | skel = open_load_task_kfunc_skel();
|
| 43 | if (!ASSERT_OK_PTR(skel, "open_load_skel"))
|
| 44 | return;
|
| 45 |
|
| 46 | if (!ASSERT_OK(skel->bss->err, "pre_spawn_err"))
|
| 47 | goto cleanup;
|
| 48 |
|
| 49 | prog = bpf_object__find_program_by_name(skel->obj, prog_name);
|
| 50 | if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
|
| 51 | goto cleanup;
|
| 52 |
|
| 53 | link = bpf_program__attach(prog);
|
| 54 | if (!ASSERT_OK_PTR(link, "attached_link"))
|
| 55 | goto cleanup;
|
| 56 |
|
| 57 | child_pid = fork();
|
| 58 | if (!ASSERT_GT(child_pid, -1, "child_pid"))
|
| 59 | goto cleanup;
|
| 60 | if (child_pid == 0)
|
| 61 | _exit(0);
|
| 62 | waitpid(child_pid, &status, 0);
|
| 63 |
|
| 64 | ASSERT_OK(skel->bss->err, "post_wait_err");
|
| 65 |
|
| 66 | cleanup:
|
| 67 | bpf_link__destroy(link);
|
| 68 | task_kfunc_success__destroy(skel);
|
| 69 | }
|
| 70 |
|
| 71 | static void run_syscall_success_test(const char *prog_name)
|
| 72 | {
|
| 73 | LIBBPF_OPTS(bpf_test_run_opts, opts);
|
| 74 | struct task_kfunc_success *skel;
|
| 75 | struct bpf_program *prog;
|
| 76 | int err;
|
| 77 |
|
| 78 | skel = open_load_task_kfunc_skel();
|
| 79 | if (!ASSERT_OK_PTR(skel, "open_load_skel"))
|
| 80 | return;
|
| 81 |
|
| 82 | if (!ASSERT_OK(skel->bss->err, "pre_run_err"))
|
| 83 | goto cleanup;
|
| 84 |
|
| 85 | prog = bpf_object__find_program_by_name(skel->obj, prog_name);
|
| 86 | if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
|
| 87 | goto cleanup;
|
| 88 |
|
| 89 | err = bpf_prog_test_run_opts(bpf_program__fd(prog), &opts);
|
| 90 | if (!ASSERT_OK(err, "bpf_prog_test_run_opts"))
|
| 91 | goto cleanup;
|
| 92 | if (!ASSERT_EQ(opts.retval, 0, "retval"))
|
| 93 | goto cleanup;
|
| 94 |
|
| 95 | ASSERT_OK(skel->bss->err, "post_run_err");
|
| 96 |
|
| 97 | cleanup:
|
| 98 | task_kfunc_success__destroy(skel);
|
| 99 | }
|
| 100 |
|
| 101 | static int run_vpid_test(void *prog_name)
|
| 102 | {
|
| 103 | struct task_kfunc_success *skel;
|
| 104 | struct bpf_program *prog;
|
| 105 | int prog_fd, err = 0;
|
| 106 |
|
| 107 | if (getpid() != 1)
|
| 108 | return 1;
|
| 109 |
|
| 110 | skel = open_load_task_kfunc_skel();
|
| 111 | if (!skel)
|
| 112 | return 2;
|
| 113 |
|
| 114 | if (skel->bss->err) {
|
| 115 | err = 3;
|
| 116 | goto cleanup;
|
| 117 | }
|
| 118 |
|
| 119 | prog = bpf_object__find_program_by_name(skel->obj, prog_name);
|
| 120 | if (!prog) {
|
| 121 | err = 4;
|
| 122 | goto cleanup;
|
| 123 | }
|
| 124 |
|
| 125 | prog_fd = bpf_program__fd(prog);
|
| 126 | if (prog_fd < 0) {
|
| 127 | err = 5;
|
| 128 | goto cleanup;
|
| 129 | }
|
| 130 |
|
| 131 | if (bpf_prog_test_run_opts(prog_fd, NULL)) {
|
| 132 | err = 6;
|
| 133 | goto cleanup;
|
| 134 | }
|
| 135 |
|
| 136 | if (skel->bss->err)
|
| 137 | err = 7 + skel->bss->err;
|
| 138 | cleanup:
|
| 139 | task_kfunc_success__destroy(skel);
|
| 140 | return err;
|
| 141 | }
|
| 142 |
|
| 143 | static void run_vpid_success_test(const char *prog_name)
|
| 144 | {
|
| 145 | const int stack_size = 1024 * 1024;
|
| 146 | int child_pid, wstatus;
|
| 147 | char *stack;
|
| 148 |
|
| 149 | stack = (char *)malloc(stack_size);
|
| 150 | if (!ASSERT_OK_PTR(stack, "clone_stack"))
|
| 151 | return;
|
| 152 |
|
| 153 | child_pid = clone(run_vpid_test, stack + stack_size,
|
| 154 | CLONE_NEWPID | SIGCHLD, (void *)prog_name);
|
| 155 | if (!ASSERT_GT(child_pid, -1, "child_pid"))
|
| 156 | goto cleanup;
|
| 157 |
|
| 158 | if (!ASSERT_GT(waitpid(child_pid, &wstatus, 0), -1, "waitpid"))
|
| 159 | goto cleanup;
|
| 160 |
|
| 161 | if (WEXITSTATUS(wstatus) > 7)
|
| 162 | ASSERT_OK(WEXITSTATUS(wstatus) - 7, "vpid_test_failure");
|
| 163 | else
|
| 164 | ASSERT_OK(WEXITSTATUS(wstatus), "run_vpid_test_err");
|
| 165 | cleanup:
|
| 166 | free(stack);
|
| 167 | }
|
| 168 |
|
| 169 | static const char * const success_tests[] = {
|
| 170 | "test_task_acquire_release_argument",
|
| 171 | "test_task_acquire_release_current",
|
| 172 | "test_task_acquire_leave_in_map",
|
| 173 | "test_task_map_acquire_release",
|
| 174 | "test_task_current_acquire_release",
|
| 175 | "test_task_from_pid_arg",
|
| 176 | "test_task_from_pid_current",
|
| 177 | "test_task_from_pid_invalid",
|
| 178 | "task_kfunc_acquire_trusted_walked",
|
| 179 | "task_kfunc_acquire_after_spin_unlock_non_sleepable",
|
| 180 | "task_kfunc_acquire_after_spin_unlock_explicit_rcu",
|
| 181 | "task_kfunc_acquire_after_spin_unlock_preempt_disabled",
|
| 182 | "task_kfunc_acquire_after_spin_unlock_irq_disabled",
|
| 183 | "task_kfunc_acquire_after_rcu_unlock_preempt_disabled",
|
| 184 | "task_kfunc_acquire_after_rcu_unlock_irq_disabled",
|
| 185 | "task_kfunc_acquire_after_preempt_enable_explicit_rcu",
|
| 186 | "task_kfunc_acquire_after_irq_restore_explicit_rcu",
|
| 187 | "test_task_kfunc_flavor_relo",
|
| 188 | "test_task_kfunc_flavor_relo_not_found",
|
| 189 | };
|
| 190 |
|
| 191 | static const char * const syscall_success_tests[] = {
|
| 192 | "test_task_xchg_release",
|
| 193 | };
|
| 194 |
|
| 195 | static const char * const vpid_success_tests[] = {
|
| 196 | "test_task_from_vpid_current",
|
| 197 | "test_task_from_vpid_invalid",
|
| 198 | };
|
| 199 |
|
| 200 | void test_task_kfunc(void)
|
| 201 | {
|
| 202 | int i;
|
| 203 |
|
| 204 | for (i = 0; i < ARRAY_SIZE(success_tests); i++) {
|
| 205 | if (!test__start_subtest(success_tests[i]))
|
| 206 | continue;
|
| 207 |
|
| 208 | run_success_test(success_tests[i]);
|
| 209 | }
|
| 210 |
|
| 211 | for (i = 0; i < ARRAY_SIZE(syscall_success_tests); i++) {
|
| 212 | if (!test__start_subtest(syscall_success_tests[i]))
|
| 213 | continue;
|
| 214 |
|
| 215 | run_syscall_success_test(syscall_success_tests[i]);
|
| 216 | }
|
| 217 |
|
| 218 | for (i = 0; i < ARRAY_SIZE(vpid_success_tests); i++) {
|
| 219 | if (!test__start_subtest(vpid_success_tests[i]))
|
| 220 | continue;
|
| 221 |
|
| 222 | run_vpid_success_test(vpid_success_tests[i]);
|
| 223 | }
|
| 224 |
|
| 225 | RUN_TESTS(task_kfunc_failure);
|
| 226 | }
|