1 // SPDX-License-Identifier: GPL-2.0 2 #include <vmlinux.h> 3 #include <bpf/bpf_tracing.h> 4 #include <bpf/bpf_helpers.h> 5 #include "bpf_experimental.h" 6 7 struct foo { 8 struct bpf_spin_lock lock; 9 int data; 10 }; 11 12 struct array_map { 13 __uint(type, BPF_MAP_TYPE_ARRAY); 14 __type(key, int); 15 __type(value, struct foo); 16 __uint(max_entries, 1); 17 } array_map SEC(".maps"), array_map_b SEC(".maps"); 18 19 struct { 20 __uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS); 21 __uint(max_entries, 2); 22 __type(key, int); 23 __type(value, int); 24 __array(values, struct array_map); 25 } map_of_maps SEC(".maps") = { 26 .values = { 27 [0] = &array_map, 28 [1] = &array_map_b, 29 }, 30 }; 31 32 static struct bpf_spin_lock lockA SEC(".data.A"); 33 static struct bpf_spin_lock lockB SEC(".data.B"); 34 35 SEC("?tc") 36 int lock_id_kptr_preserve(void *ctx) 37 { 38 struct foo *f; 39 40 f = bpf_obj_new(typeof(*f)); 41 if (!f) 42 return 0; 43 bpf_this_cpu_ptr(f); 44 return 0; 45 } 46 47 SEC("?tc") 48 int lock_id_global_zero(void *ctx) 49 { 50 bpf_this_cpu_ptr(&lockA); 51 return 0; 52 } 53 54 SEC("?tc") 55 int lock_id_mapval_preserve(void *ctx) 56 { 57 struct foo *f; 58 int key = 0; 59 60 f = bpf_map_lookup_elem(&array_map, &key); 61 if (!f) 62 return 0; 63 bpf_this_cpu_ptr(f); 64 return 0; 65 } 66 67 SEC("?tc") 68 int lock_id_innermapval_preserve(void *ctx) 69 { 70 struct foo *f; 71 int key = 0; 72 void *map; 73 74 map = bpf_map_lookup_elem(&map_of_maps, &key); 75 if (!map) 76 return 0; 77 f = bpf_map_lookup_elem(map, &key); 78 if (!f) 79 return 0; 80 bpf_this_cpu_ptr(f); 81 return 0; 82 } 83 84 #define CHECK(test, A, B) \ 85 SEC("?tc") \ 86 int lock_id_mismatch_##test(void *ctx) \ 87 { \ 88 struct foo *f1, *f2, *v, *iv; \ 89 int key = 0; \ 90 void *map; \ 91 \ 92 map = bpf_map_lookup_elem(&map_of_maps, &key); \ 93 if (!map) \ 94 return 0; \ 95 iv = bpf_map_lookup_elem(map, &key); \ 96 if (!iv) \ 97 return 0; \ 98 v = bpf_map_lookup_elem(&array_map, &key); \ 99 if (!v) \ 100 return 0; \ 101 f1 = bpf_obj_new(typeof(*f1)); \ 102 if (!f1) \ 103 return 0; \ 104 f2 = bpf_obj_new(typeof(*f2)); \ 105 if (!f2) { \ 106 bpf_obj_drop(f1); \ 107 return 0; \ 108 } \ 109 bpf_spin_lock(A); \ 110 bpf_spin_unlock(B); \ 111 return 0; \ 112 } 113 114 CHECK(kptr_kptr, &f1->lock, &f2->lock); 115 CHECK(kptr_global, &f1->lock, &lockA); 116 CHECK(kptr_mapval, &f1->lock, &v->lock); 117 CHECK(kptr_innermapval, &f1->lock, &iv->lock); 118 119 CHECK(global_global, &lockA, &lockB); 120 CHECK(global_kptr, &lockA, &f1->lock); 121 CHECK(global_mapval, &lockA, &v->lock); 122 CHECK(global_innermapval, &lockA, &iv->lock); 123 124 SEC("?tc") 125 int lock_id_mismatch_mapval_mapval(void *ctx) 126 { 127 struct foo *f1, *f2; 128 int key = 0; 129 130 f1 = bpf_map_lookup_elem(&array_map, &key); 131 if (!f1) 132 return 0; 133 f2 = bpf_map_lookup_elem(&array_map, &key); 134 if (!f2) 135 return 0; 136 137 bpf_spin_lock(&f1->lock); 138 f1->data = 42; 139 bpf_spin_unlock(&f2->lock); 140 141 return 0; 142 } 143 144 CHECK(mapval_kptr, &v->lock, &f1->lock); 145 CHECK(mapval_global, &v->lock, &lockB); 146 CHECK(mapval_innermapval, &v->lock, &iv->lock); 147 148 SEC("?tc") 149 int lock_id_mismatch_innermapval_innermapval1(void *ctx) 150 { 151 struct foo *f1, *f2; 152 int key = 0; 153 void *map; 154 155 map = bpf_map_lookup_elem(&map_of_maps, &key); 156 if (!map) 157 return 0; 158 f1 = bpf_map_lookup_elem(map, &key); 159 if (!f1) 160 return 0; 161 f2 = bpf_map_lookup_elem(map, &key); 162 if (!f2) 163 return 0; 164 165 bpf_spin_lock(&f1->lock); 166 f1->data = 42; 167 bpf_spin_unlock(&f2->lock); 168 169 return 0; 170 } 171 172 SEC("?tc") 173 int lock_id_mismatch_innermapval_innermapval2(void *ctx) 174 { 175 struct foo *f1, *f2; 176 int key = 0; 177 void *map; 178 179 map = bpf_map_lookup_elem(&map_of_maps, &key); 180 if (!map) 181 return 0; 182 f1 = bpf_map_lookup_elem(map, &key); 183 if (!f1) 184 return 0; 185 map = bpf_map_lookup_elem(&map_of_maps, &key); 186 if (!map) 187 return 0; 188 f2 = bpf_map_lookup_elem(map, &key); 189 if (!f2) 190 return 0; 191 192 bpf_spin_lock(&f1->lock); 193 f1->data = 42; 194 bpf_spin_unlock(&f2->lock); 195 196 return 0; 197 } 198 199 CHECK(innermapval_kptr, &iv->lock, &f1->lock); 200 CHECK(innermapval_global, &iv->lock, &lockA); 201 CHECK(innermapval_mapval, &iv->lock, &v->lock); 202 203 #undef CHECK 204 205 __noinline 206 int global_subprog(struct __sk_buff *ctx) 207 { 208 volatile int ret = 0; 209 210 if (ctx->protocol) 211 ret += ctx->protocol; 212 return ret + ctx->mark; 213 } 214 215 __noinline 216 static int static_subprog_call_global(struct __sk_buff *ctx) 217 { 218 volatile int ret = 0; 219 220 if (ctx->protocol) 221 return ret; 222 return ret + ctx->len + global_subprog(ctx); 223 } 224 225 SEC("?tc") 226 int lock_global_subprog_call1(struct __sk_buff *ctx) 227 { 228 int ret = 0; 229 230 bpf_spin_lock(&lockA); 231 if (ctx->mark == 42) 232 ret = global_subprog(ctx); 233 bpf_spin_unlock(&lockA); 234 return ret; 235 } 236 237 SEC("?tc") 238 int lock_global_subprog_call2(struct __sk_buff *ctx) 239 { 240 int ret = 0; 241 242 bpf_spin_lock(&lockA); 243 if (ctx->mark == 42) 244 ret = static_subprog_call_global(ctx); 245 bpf_spin_unlock(&lockA); 246 return ret; 247 } 248 249 int __noinline 250 global_subprog_int(int i) 251 { 252 if (i) 253 bpf_printk("%p", &i); 254 return i; 255 } 256 257 int __noinline 258 global_sleepable_helper_subprog(int i) 259 { 260 if (i) 261 bpf_copy_from_user(&i, sizeof(i), NULL); 262 return i; 263 } 264 265 int __noinline 266 global_sleepable_kfunc_subprog(int i) 267 { 268 if (i) 269 bpf_copy_from_user_str(&i, sizeof(i), NULL, 0); 270 global_subprog_int(i); 271 return i; 272 } 273 274 int __noinline 275 global_subprog_calling_sleepable_global(int i) 276 { 277 if (!i) 278 global_sleepable_kfunc_subprog(i); 279 return i; 280 } 281 282 SEC("?syscall") 283 int lock_global_sleepable_helper_subprog(struct __sk_buff *ctx) 284 { 285 int ret = 0; 286 287 bpf_spin_lock(&lockA); 288 if (ctx->mark == 42) 289 ret = global_sleepable_helper_subprog(ctx->mark); 290 bpf_spin_unlock(&lockA); 291 return ret; 292 } 293 294 SEC("?syscall") 295 int lock_global_sleepable_kfunc_subprog(struct __sk_buff *ctx) 296 { 297 int ret = 0; 298 299 bpf_spin_lock(&lockA); 300 if (ctx->mark == 42) 301 ret = global_sleepable_kfunc_subprog(ctx->mark); 302 bpf_spin_unlock(&lockA); 303 return ret; 304 } 305 306 SEC("?syscall") 307 int lock_global_sleepable_subprog_indirect(struct __sk_buff *ctx) 308 { 309 int ret = 0; 310 311 bpf_spin_lock(&lockA); 312 if (ctx->mark == 42) 313 ret = global_subprog_calling_sleepable_global(ctx->mark); 314 bpf_spin_unlock(&lockA); 315 return ret; 316 } 317 318 struct { 319 __uint(type, BPF_MAP_TYPE_ARRAY); 320 __uint(max_entries, 2); 321 __type(key, int); 322 __type(value, struct foo); 323 } callback_array_map SEC(".maps"); 324 325 struct callback_ctx { 326 struct foo *value; 327 }; 328 329 static long lock_different_value(struct bpf_map *map, int *key, 330 struct foo *value, struct callback_ctx *ctx) 331 { 332 bpf_spin_lock(&value->lock); 333 bpf_spin_unlock(&ctx->value->lock); 334 return 0; 335 } 336 337 static long nest_lock_different_value(struct bpf_map *map, int *key, 338 struct foo *value, void *data) 339 { 340 struct callback_ctx ctx = { .value = value }; 341 342 bpf_for_each_map_elem(&callback_array_map, lock_different_value, &ctx, 0); 343 return 0; 344 } 345 346 SEC("?tc") 347 int callback_value_lock_identity(void *ctx) 348 { 349 bpf_for_each_map_elem(&callback_array_map, nest_lock_different_value, NULL, 0); 350 return 0; 351 } 352 353 static long nest_lock_different_inner_value(struct bpf_map *map, int *key, 354 struct foo *value, void *data) 355 { 356 struct callback_ctx ctx = { .value = value }; 357 int inner_key = 1; 358 void *inner_map; 359 360 inner_map = bpf_map_lookup_elem(&map_of_maps, &inner_key); 361 if (!inner_map) 362 return 0; 363 bpf_for_each_map_elem(inner_map, lock_different_value, &ctx, 0); 364 return 0; 365 } 366 367 SEC("?tc") 368 int callback_inner_map_value_lock_identity(void *ctx) 369 { 370 int inner_key = 0; 371 void *inner_map; 372 373 inner_map = bpf_map_lookup_elem(&map_of_maps, &inner_key); 374 if (!inner_map) 375 return 0; 376 bpf_for_each_map_elem(inner_map, nest_lock_different_inner_value, NULL, 0); 377 return 0; 378 } 379 380 char _license[] SEC("license") = "GPL"; 381