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")
lock_id_kptr_preserve(void * ctx)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")
lock_id_global_zero(void * ctx)48 int lock_id_global_zero(void *ctx)
49 {
50 bpf_this_cpu_ptr(&lockA);
51 return 0;
52 }
53
54 SEC("?tc")
lock_id_mapval_preserve(void * ctx)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")
lock_id_innermapval_preserve(void * ctx)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")
lock_id_mismatch_mapval_mapval(void * ctx)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")
lock_id_mismatch_innermapval_innermapval1(void * ctx)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")
lock_id_mismatch_innermapval_innermapval2(void * ctx)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
global_subprog(struct __sk_buff * ctx)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
static_subprog_call_global(struct __sk_buff * ctx)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")
lock_global_subprog_call1(struct __sk_buff * ctx)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")
lock_global_subprog_call2(struct __sk_buff * ctx)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
global_subprog_int(int i)250 global_subprog_int(int i)
251 {
252 if (i)
253 bpf_printk("%p", &i);
254 return i;
255 }
256
257 int __noinline
global_sleepable_helper_subprog(int i)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
global_sleepable_kfunc_subprog(int i)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
global_subprog_calling_sleepable_global(int i)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")
lock_global_sleepable_helper_subprog(struct __sk_buff * ctx)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")
lock_global_sleepable_kfunc_subprog(struct __sk_buff * ctx)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")
lock_global_sleepable_subprog_indirect(struct __sk_buff * ctx)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
lock_different_value(struct bpf_map * map,int * key,struct foo * value,struct callback_ctx * ctx)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
nest_lock_different_value(struct bpf_map * map,int * key,struct foo * value,void * data)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")
callback_value_lock_identity(void * ctx)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
nest_lock_different_inner_value(struct bpf_map * map,int * key,struct foo * value,void * data)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")
callback_inner_map_value_lock_identity(void * ctx)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