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

selftests/bpf: Test bpf_kptr_xchg stashing into local kptr

Test stashing both referenced kptr and local kptr into local kptrs. Then,
test unstashing them.

Acked-by: Martin KaFai Lau <martin.lau@kernel.org>
Acked-by: Hou Tao <houtao1@huawei.com>
Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
Signed-off-by: Amery Hung <amery.hung@bytedance.com>
Link: https://lore.kernel.org/r/20240813212424.2871455-6-amery.hung@bytedance.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Dave Marchevsky and committed by
Alexei Starovoitov
91c96842 b0966c72

+53 -3
+28 -2
tools/testing/selftests/bpf/progs/local_kptr_stash.c
··· 8 8 #include "../bpf_experimental.h" 9 9 #include "../bpf_testmod/bpf_testmod_kfunc.h" 10 10 11 + struct plain_local; 12 + 11 13 struct node_data { 12 14 long key; 13 15 long data; 16 + struct plain_local __kptr * stashed_in_local_kptr; 14 17 struct bpf_rb_node node; 15 18 }; 16 19 ··· 88 85 89 86 static int create_and_stash(int idx, int val) 90 87 { 88 + struct plain_local *inner_local_kptr; 91 89 struct map_value *mapval; 92 90 struct node_data *res; 93 91 ··· 96 92 if (!mapval) 97 93 return 1; 98 94 95 + inner_local_kptr = bpf_obj_new(typeof(*inner_local_kptr)); 96 + if (!inner_local_kptr) 97 + return 2; 98 + 99 99 res = bpf_obj_new(typeof(*res)); 100 - if (!res) 101 - return 1; 100 + if (!res) { 101 + bpf_obj_drop(inner_local_kptr); 102 + return 3; 103 + } 102 104 res->key = val; 105 + 106 + inner_local_kptr = bpf_kptr_xchg(&res->stashed_in_local_kptr, inner_local_kptr); 107 + if (inner_local_kptr) { 108 + /* Should never happen, we just obj_new'd res */ 109 + bpf_obj_drop(inner_local_kptr); 110 + bpf_obj_drop(res); 111 + return 4; 112 + } 103 113 104 114 res = bpf_kptr_xchg(&mapval->node, res); 105 115 if (res) ··· 187 169 SEC("tc") 188 170 long unstash_rb_node(void *ctx) 189 171 { 172 + struct plain_local *inner_local_kptr = NULL; 190 173 struct map_value *mapval; 191 174 struct node_data *res; 192 175 long retval; ··· 199 180 200 181 res = bpf_kptr_xchg(&mapval->node, NULL); 201 182 if (res) { 183 + inner_local_kptr = bpf_kptr_xchg(&res->stashed_in_local_kptr, inner_local_kptr); 184 + if (!inner_local_kptr) { 185 + bpf_obj_drop(res); 186 + return 1; 187 + } 188 + bpf_obj_drop(inner_local_kptr); 189 + 202 190 retval = res->key; 203 191 bpf_obj_drop(res); 204 192 return retval;
+25 -1
tools/testing/selftests/bpf/progs/task_kfunc_success.c
··· 5 5 #include <bpf/bpf_tracing.h> 6 6 #include <bpf/bpf_helpers.h> 7 7 8 + #include "../bpf_experimental.h" 8 9 #include "task_kfunc_common.h" 9 10 10 11 char _license[] SEC("license") = "GPL"; ··· 144 143 int BPF_PROG(test_task_xchg_release, struct task_struct *task, u64 clone_flags) 145 144 { 146 145 struct task_struct *kptr; 147 - struct __tasks_kfunc_map_value *v; 146 + struct __tasks_kfunc_map_value *v, *local; 148 147 long status; 149 148 150 149 if (!is_test_kfunc_task()) ··· 168 167 return 0; 169 168 } 170 169 170 + local = bpf_obj_new(typeof(*local)); 171 + if (!local) { 172 + err = 4; 173 + bpf_task_release(kptr); 174 + return 0; 175 + } 176 + 177 + kptr = bpf_kptr_xchg(&local->task, kptr); 178 + if (kptr) { 179 + err = 5; 180 + bpf_obj_drop(local); 181 + bpf_task_release(kptr); 182 + return 0; 183 + } 184 + 185 + kptr = bpf_kptr_xchg(&local->task, NULL); 186 + if (!kptr) { 187 + err = 6; 188 + bpf_obj_drop(local); 189 + return 0; 190 + } 191 + 192 + bpf_obj_drop(local); 171 193 bpf_task_release(kptr); 172 194 173 195 return 0;