xref: /linux/tools/testing/selftests/bpf/progs/test_spin_lock_fail.c (revision 7e170da2edec9fb0717543571cc14b0aabee2b46)
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