1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */ 3 4 #include <vmlinux.h> 5 #include <bpf/bpf_helpers.h> 6 #include <bpf/bpf_tracing.h> 7 #include "bpf_misc.h" 8 #include "bpf_experimental.h" 9 10 char _license[] SEC("license") = "GPL"; 11 12 /* Timer tests */ 13 14 struct timer_elem { 15 struct bpf_timer t; 16 }; 17 18 struct { 19 __uint(type, BPF_MAP_TYPE_ARRAY); 20 __uint(max_entries, 1); 21 __type(key, int); 22 __type(value, struct timer_elem); 23 } timer_map SEC(".maps"); 24 25 static int timer_cb(void *map, int *key, struct bpf_timer *timer) 26 { 27 u32 data; 28 /* Timer callbacks are never sleepable, even from non-sleepable programs */ 29 bpf_copy_from_user(&data, sizeof(data), NULL); 30 return 0; 31 } 32 33 SEC("fentry/bpf_fentry_test1") 34 __failure __msg("sleepable helper bpf_copy_from_user#{{[0-9]+}} in non-sleepable prog") 35 int timer_non_sleepable_prog(void *ctx) 36 { 37 struct timer_elem *val; 38 int key = 0; 39 40 val = bpf_map_lookup_elem(&timer_map, &key); 41 if (!val) 42 return 0; 43 44 bpf_timer_init(&val->t, &timer_map, 0); 45 bpf_timer_set_callback(&val->t, timer_cb); 46 return 0; 47 } 48 49 SEC("lsm.s/file_open") 50 __failure __msg("sleepable helper bpf_copy_from_user#{{[0-9]+}} in non-sleepable prog") 51 int timer_sleepable_prog(void *ctx) 52 { 53 struct timer_elem *val; 54 int key = 0; 55 56 val = bpf_map_lookup_elem(&timer_map, &key); 57 if (!val) 58 return 0; 59 60 bpf_timer_init(&val->t, &timer_map, 0); 61 bpf_timer_set_callback(&val->t, timer_cb); 62 return 0; 63 } 64 65 static int timer_sys_bpf_cb(void *map, int *key, struct bpf_timer *timer) 66 { 67 __u64 attr = 0; 68 69 bpf_sys_bpf(BPF_MAP_FREEZE, &attr, sizeof(attr)); 70 return 0; 71 } 72 73 SEC("syscall") 74 __failure __msg("sleepable helper bpf_sys_bpf#{{[0-9]+}} in non-sleepable prog") 75 int timer_sys_bpf_prog(void *ctx) 76 { 77 struct timer_elem *val; 78 int key = 0; 79 80 val = bpf_map_lookup_elem(&timer_map, &key); 81 if (!val) 82 return 0; 83 84 bpf_timer_init(&val->t, &timer_map, 0); 85 bpf_timer_set_callback(&val->t, timer_sys_bpf_cb); 86 return 0; 87 } 88 89 static int timer_sys_close_cb(void *map, int *key, struct bpf_timer *timer) 90 { 91 bpf_sys_close(0); 92 return 0; 93 } 94 95 SEC("syscall") 96 __failure __msg("sleepable helper bpf_sys_close#{{[0-9]+}} in non-sleepable prog") 97 int timer_sys_close_prog(void *ctx) 98 { 99 struct timer_elem *val; 100 int key = 0; 101 102 val = bpf_map_lookup_elem(&timer_map, &key); 103 if (!val) 104 return 0; 105 106 bpf_timer_init(&val->t, &timer_map, 0); 107 bpf_timer_set_callback(&val->t, timer_sys_close_cb); 108 return 0; 109 } 110 111 static int timer_btf_find_cb(void *map, int *key, struct bpf_timer *timer) 112 { 113 char name[] = "task_struct"; 114 115 bpf_btf_find_by_name_kind(name, sizeof(name), BTF_KIND_STRUCT, 0); 116 return 0; 117 } 118 119 SEC("syscall") 120 __failure __msg("sleepable helper bpf_btf_find_by_name_kind#{{[0-9]+}} in non-sleepable prog") 121 int timer_btf_find_prog(void *ctx) 122 { 123 struct timer_elem *val; 124 int key = 0; 125 126 val = bpf_map_lookup_elem(&timer_map, &key); 127 if (!val) 128 return 0; 129 130 bpf_timer_init(&val->t, &timer_map, 0); 131 bpf_timer_set_callback(&val->t, timer_btf_find_cb); 132 return 0; 133 } 134 135 SEC("syscall") 136 __success 137 int syscall_sys_bpf_prog(void *ctx) 138 { 139 __u64 attr = 0; 140 141 bpf_sys_bpf(BPF_MAP_FREEZE, &attr, sizeof(attr)); 142 return 0; 143 } 144 145 SEC("syscall") 146 __success 147 int syscall_sys_close_prog(void *ctx) 148 { 149 bpf_sys_close(0); 150 return 0; 151 } 152 153 SEC("syscall") 154 __success 155 int syscall_btf_find_prog(void *ctx) 156 { 157 char name[] = "task_struct"; 158 159 bpf_btf_find_by_name_kind(name, sizeof(name), BTF_KIND_STRUCT, 0); 160 return 0; 161 } 162 163 /* Workqueue tests */ 164 165 struct wq_elem { 166 struct bpf_wq w; 167 }; 168 169 struct { 170 __uint(type, BPF_MAP_TYPE_ARRAY); 171 __uint(max_entries, 1); 172 __type(key, int); 173 __type(value, struct wq_elem); 174 } wq_map SEC(".maps"); 175 176 static int wq_cb(void *map, int *key, void *value) 177 { 178 u32 data; 179 /* Workqueue callbacks are always sleepable, even from non-sleepable programs */ 180 bpf_copy_from_user(&data, sizeof(data), NULL); 181 return 0; 182 } 183 184 SEC("fentry/bpf_fentry_test1") 185 __success 186 int wq_non_sleepable_prog(void *ctx) 187 { 188 struct wq_elem *val; 189 int key = 0; 190 191 val = bpf_map_lookup_elem(&wq_map, &key); 192 if (!val) 193 return 0; 194 195 if (bpf_wq_init(&val->w, &wq_map, 0) != 0) 196 return 0; 197 if (bpf_wq_set_callback(&val->w, wq_cb, 0) != 0) 198 return 0; 199 return 0; 200 } 201 202 SEC("lsm.s/file_open") 203 __success 204 int wq_sleepable_prog(void *ctx) 205 { 206 struct wq_elem *val; 207 int key = 0; 208 209 val = bpf_map_lookup_elem(&wq_map, &key); 210 if (!val) 211 return 0; 212 213 if (bpf_wq_init(&val->w, &wq_map, 0) != 0) 214 return 0; 215 if (bpf_wq_set_callback(&val->w, wq_cb, 0) != 0) 216 return 0; 217 return 0; 218 } 219 220 /* Task work tests */ 221 222 struct task_work_elem { 223 struct bpf_task_work tw; 224 }; 225 226 struct { 227 __uint(type, BPF_MAP_TYPE_ARRAY); 228 __uint(max_entries, 1); 229 __type(key, int); 230 __type(value, struct task_work_elem); 231 } task_work_map SEC(".maps"); 232 233 static int task_work_cb(struct bpf_map *map, void *key, void *value) 234 { 235 u32 data; 236 /* Task work callbacks are always sleepable, even from non-sleepable programs */ 237 bpf_copy_from_user(&data, sizeof(data), NULL); 238 return 0; 239 } 240 241 SEC("fentry/bpf_fentry_test1") 242 __success 243 int task_work_non_sleepable_prog(void *ctx) 244 { 245 struct task_work_elem *val; 246 struct task_struct *task; 247 int key = 0; 248 249 val = bpf_map_lookup_elem(&task_work_map, &key); 250 if (!val) 251 return 0; 252 253 task = bpf_get_current_task_btf(); 254 if (!task) 255 return 0; 256 257 bpf_task_work_schedule_resume(task, &val->tw, &task_work_map, task_work_cb); 258 return 0; 259 } 260 261 SEC("lsm.s/file_open") 262 __success 263 int task_work_sleepable_prog(void *ctx) 264 { 265 struct task_work_elem *val; 266 struct task_struct *task; 267 int key = 0; 268 269 val = bpf_map_lookup_elem(&task_work_map, &key); 270 if (!val) 271 return 0; 272 273 task = bpf_get_current_task_btf(); 274 if (!task) 275 return 0; 276 277 bpf_task_work_schedule_resume(task, &val->tw, &task_work_map, task_work_cb); 278 return 0; 279 } 280