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");
18 
19 struct {
20 	__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
21 	__uint(max_entries, 1);
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 	},
29 };
30 
31 SEC(".data.A") struct bpf_spin_lock lockA;
32 SEC(".data.B") struct bpf_spin_lock lockB;
33 
34 SEC("?tc")
35 int lock_id_kptr_preserve(void *ctx)
36 {
37 	struct foo *f;
38 
39 	f = bpf_obj_new(typeof(*f));
40 	if (!f)
41 		return 0;
42 	bpf_this_cpu_ptr(f);
43 	return 0;
44 }
45 
46 SEC("?tc")
47 int lock_id_global_zero(void *ctx)
48 {
49 	bpf_this_cpu_ptr(&lockA);
50 	return 0;
51 }
52 
53 SEC("?tc")
54 int lock_id_mapval_preserve(void *ctx)
55 {
56 	struct foo *f;
57 	int key = 0;
58 
59 	f = bpf_map_lookup_elem(&array_map, &key);
60 	if (!f)
61 		return 0;
62 	bpf_this_cpu_ptr(f);
63 	return 0;
64 }
65 
66 SEC("?tc")
67 int lock_id_innermapval_preserve(void *ctx)
68 {
69 	struct foo *f;
70 	int key = 0;
71 	void *map;
72 
73 	map = bpf_map_lookup_elem(&map_of_maps, &key);
74 	if (!map)
75 		return 0;
76 	f = bpf_map_lookup_elem(map, &key);
77 	if (!f)
78 		return 0;
79 	bpf_this_cpu_ptr(f);
80 	return 0;
81 }
82 
83 #define CHECK(test, A, B)                                      \
84 	SEC("?tc")                                             \
85 	int lock_id_mismatch_##test(void *ctx)                 \
86 	{                                                      \
87 		struct foo *f1, *f2, *v, *iv;                  \
88 		int key = 0;                                   \
89 		void *map;                                     \
90                                                                \
91 		map = bpf_map_lookup_elem(&map_of_maps, &key); \
92 		if (!map)                                      \
93 			return 0;                              \
94 		iv = bpf_map_lookup_elem(map, &key);           \
95 		if (!iv)                                       \
96 			return 0;                              \
97 		v = bpf_map_lookup_elem(&array_map, &key);     \
98 		if (!v)                                        \
99 			return 0;                              \
100 		f1 = bpf_obj_new(typeof(*f1));                 \
101 		if (!f1)                                       \
102 			return 0;                              \
103 		f2 = bpf_obj_new(typeof(*f2));                 \
104 		if (!f2) {                                     \
105 			bpf_obj_drop(f1);                      \
106 			return 0;                              \
107 		}                                              \
108 		bpf_spin_lock(A);                              \
109 		bpf_spin_unlock(B);                            \
110 		return 0;                                      \
111 	}
112 
113 CHECK(kptr_kptr, &f1->lock, &f2->lock);
114 CHECK(kptr_global, &f1->lock, &lockA);
115 CHECK(kptr_mapval, &f1->lock, &v->lock);
116 CHECK(kptr_innermapval, &f1->lock, &iv->lock);
117 
118 CHECK(global_global, &lockA, &lockB);
119 CHECK(global_kptr, &lockA, &f1->lock);
120 CHECK(global_mapval, &lockA, &v->lock);
121 CHECK(global_innermapval, &lockA, &iv->lock);
122 
123 SEC("?tc")
124 int lock_id_mismatch_mapval_mapval(void *ctx)
125 {
126 	struct foo *f1, *f2;
127 	int key = 0;
128 
129 	f1 = bpf_map_lookup_elem(&array_map, &key);
130 	if (!f1)
131 		return 0;
132 	f2 = bpf_map_lookup_elem(&array_map, &key);
133 	if (!f2)
134 		return 0;
135 
136 	bpf_spin_lock(&f1->lock);
137 	f1->data = 42;
138 	bpf_spin_unlock(&f2->lock);
139 
140 	return 0;
141 }
142 
143 CHECK(mapval_kptr, &v->lock, &f1->lock);
144 CHECK(mapval_global, &v->lock, &lockB);
145 CHECK(mapval_innermapval, &v->lock, &iv->lock);
146 
147 SEC("?tc")
148 int lock_id_mismatch_innermapval_innermapval1(void *ctx)
149 {
150 	struct foo *f1, *f2;
151 	int key = 0;
152 	void *map;
153 
154 	map = bpf_map_lookup_elem(&map_of_maps, &key);
155 	if (!map)
156 		return 0;
157 	f1 = bpf_map_lookup_elem(map, &key);
158 	if (!f1)
159 		return 0;
160 	f2 = bpf_map_lookup_elem(map, &key);
161 	if (!f2)
162 		return 0;
163 
164 	bpf_spin_lock(&f1->lock);
165 	f1->data = 42;
166 	bpf_spin_unlock(&f2->lock);
167 
168 	return 0;
169 }
170 
171 SEC("?tc")
172 int lock_id_mismatch_innermapval_innermapval2(void *ctx)
173 {
174 	struct foo *f1, *f2;
175 	int key = 0;
176 	void *map;
177 
178 	map = bpf_map_lookup_elem(&map_of_maps, &key);
179 	if (!map)
180 		return 0;
181 	f1 = bpf_map_lookup_elem(map, &key);
182 	if (!f1)
183 		return 0;
184 	map = bpf_map_lookup_elem(&map_of_maps, &key);
185 	if (!map)
186 		return 0;
187 	f2 = bpf_map_lookup_elem(map, &key);
188 	if (!f2)
189 		return 0;
190 
191 	bpf_spin_lock(&f1->lock);
192 	f1->data = 42;
193 	bpf_spin_unlock(&f2->lock);
194 
195 	return 0;
196 }
197 
198 CHECK(innermapval_kptr, &iv->lock, &f1->lock);
199 CHECK(innermapval_global, &iv->lock, &lockA);
200 CHECK(innermapval_mapval, &iv->lock, &v->lock);
201 
202 #undef CHECK
203 
204 __noinline
205 int global_subprog(struct __sk_buff *ctx)
206 {
207 	volatile int ret = 0;
208 
209 	if (ctx->protocol)
210 		ret += ctx->protocol;
211 	return ret + ctx->mark;
212 }
213 
214 __noinline
215 static int static_subprog_call_global(struct __sk_buff *ctx)
216 {
217 	volatile int ret = 0;
218 
219 	if (ctx->protocol)
220 		return ret;
221 	return ret + ctx->len + global_subprog(ctx);
222 }
223 
224 SEC("?tc")
225 int lock_global_subprog_call1(struct __sk_buff *ctx)
226 {
227 	int ret = 0;
228 
229 	bpf_spin_lock(&lockA);
230 	if (ctx->mark == 42)
231 		ret = global_subprog(ctx);
232 	bpf_spin_unlock(&lockA);
233 	return ret;
234 }
235 
236 SEC("?tc")
237 int lock_global_subprog_call2(struct __sk_buff *ctx)
238 {
239 	int ret = 0;
240 
241 	bpf_spin_lock(&lockA);
242 	if (ctx->mark == 42)
243 		ret = static_subprog_call_global(ctx);
244 	bpf_spin_unlock(&lockA);
245 	return ret;
246 }
247 
248 char _license[] SEC("license") = "GPL";
249