1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Converted from tools/testing/selftests/bpf/verifier/sock.c */ |
3 | |
4 | #include <linux/bpf.h> |
5 | #include <bpf/bpf_helpers.h> |
6 | #include "bpf_misc.h" |
7 | |
8 | #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) |
9 | #define offsetofend(TYPE, MEMBER) \ |
10 | (offsetof(TYPE, MEMBER) + sizeof_field(TYPE, MEMBER)) |
11 | |
12 | struct { |
13 | __uint(type, BPF_MAP_TYPE_REUSEPORT_SOCKARRAY); |
14 | __uint(max_entries, 1); |
15 | __type(key, __u32); |
16 | __type(value, __u64); |
17 | } map_reuseport_array SEC(".maps" ); |
18 | |
19 | struct { |
20 | __uint(type, BPF_MAP_TYPE_SOCKHASH); |
21 | __uint(max_entries, 1); |
22 | __type(key, int); |
23 | __type(value, int); |
24 | } map_sockhash SEC(".maps" ); |
25 | |
26 | struct { |
27 | __uint(type, BPF_MAP_TYPE_SOCKMAP); |
28 | __uint(max_entries, 1); |
29 | __type(key, int); |
30 | __type(value, int); |
31 | } map_sockmap SEC(".maps" ); |
32 | |
33 | struct { |
34 | __uint(type, BPF_MAP_TYPE_XSKMAP); |
35 | __uint(max_entries, 1); |
36 | __type(key, int); |
37 | __type(value, int); |
38 | } map_xskmap SEC(".maps" ); |
39 | |
40 | struct val { |
41 | int cnt; |
42 | struct bpf_spin_lock l; |
43 | }; |
44 | |
45 | struct { |
46 | __uint(type, BPF_MAP_TYPE_SK_STORAGE); |
47 | __uint(max_entries, 0); |
48 | __type(key, int); |
49 | __type(value, struct val); |
50 | __uint(map_flags, BPF_F_NO_PREALLOC); |
51 | } sk_storage_map SEC(".maps" ); |
52 | |
53 | SEC("cgroup/skb" ) |
54 | __description("skb->sk: no NULL check" ) |
55 | __failure __msg("invalid mem access 'sock_common_or_null'" ) |
56 | __failure_unpriv |
57 | __naked void skb_sk_no_null_check(void) |
58 | { |
59 | asm volatile (" \ |
60 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
61 | r0 = *(u32*)(r1 + 0); \ |
62 | r0 = 0; \ |
63 | exit; \ |
64 | " : |
65 | : __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)) |
66 | : __clobber_all); |
67 | } |
68 | |
69 | SEC("cgroup/skb" ) |
70 | __description("skb->sk: sk->family [non fullsock field]" ) |
71 | __success __success_unpriv __retval(0) |
72 | __naked void sk_family_non_fullsock_field_1(void) |
73 | { |
74 | asm volatile (" \ |
75 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
76 | if r1 != 0 goto l0_%=; \ |
77 | r0 = 0; \ |
78 | exit; \ |
79 | l0_%=: r0 = *(u32*)(r1 + %[bpf_sock_family]); \ |
80 | r0 = 0; \ |
81 | exit; \ |
82 | " : |
83 | : __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
84 | __imm_const(bpf_sock_family, offsetof(struct bpf_sock, family)) |
85 | : __clobber_all); |
86 | } |
87 | |
88 | SEC("cgroup/skb" ) |
89 | __description("skb->sk: sk->type [fullsock field]" ) |
90 | __failure __msg("invalid sock_common access" ) |
91 | __failure_unpriv |
92 | __naked void sk_sk_type_fullsock_field_1(void) |
93 | { |
94 | asm volatile (" \ |
95 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
96 | if r1 != 0 goto l0_%=; \ |
97 | r0 = 0; \ |
98 | exit; \ |
99 | l0_%=: r0 = *(u32*)(r1 + %[bpf_sock_type]); \ |
100 | r0 = 0; \ |
101 | exit; \ |
102 | " : |
103 | : __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
104 | __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type)) |
105 | : __clobber_all); |
106 | } |
107 | |
108 | SEC("cgroup/skb" ) |
109 | __description("bpf_sk_fullsock(skb->sk): no !skb->sk check" ) |
110 | __failure __msg("type=sock_common_or_null expected=sock_common" ) |
111 | __failure_unpriv |
112 | __naked void sk_no_skb_sk_check_1(void) |
113 | { |
114 | asm volatile (" \ |
115 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
116 | call %[bpf_sk_fullsock]; \ |
117 | r0 = 0; \ |
118 | exit; \ |
119 | " : |
120 | : __imm(bpf_sk_fullsock), |
121 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)) |
122 | : __clobber_all); |
123 | } |
124 | |
125 | SEC("cgroup/skb" ) |
126 | __description("sk_fullsock(skb->sk): no NULL check on ret" ) |
127 | __failure __msg("invalid mem access 'sock_or_null'" ) |
128 | __failure_unpriv |
129 | __naked void no_null_check_on_ret_1(void) |
130 | { |
131 | asm volatile (" \ |
132 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
133 | if r1 != 0 goto l0_%=; \ |
134 | r0 = 0; \ |
135 | exit; \ |
136 | l0_%=: call %[bpf_sk_fullsock]; \ |
137 | r0 = *(u32*)(r0 + %[bpf_sock_type]); \ |
138 | r0 = 0; \ |
139 | exit; \ |
140 | " : |
141 | : __imm(bpf_sk_fullsock), |
142 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
143 | __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type)) |
144 | : __clobber_all); |
145 | } |
146 | |
147 | SEC("cgroup/skb" ) |
148 | __description("sk_fullsock(skb->sk): sk->type [fullsock field]" ) |
149 | __success __success_unpriv __retval(0) |
150 | __naked void sk_sk_type_fullsock_field_2(void) |
151 | { |
152 | asm volatile (" \ |
153 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
154 | if r1 != 0 goto l0_%=; \ |
155 | r0 = 0; \ |
156 | exit; \ |
157 | l0_%=: call %[bpf_sk_fullsock]; \ |
158 | if r0 != 0 goto l1_%=; \ |
159 | r0 = 0; \ |
160 | exit; \ |
161 | l1_%=: r0 = *(u32*)(r0 + %[bpf_sock_type]); \ |
162 | r0 = 0; \ |
163 | exit; \ |
164 | " : |
165 | : __imm(bpf_sk_fullsock), |
166 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
167 | __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type)) |
168 | : __clobber_all); |
169 | } |
170 | |
171 | SEC("cgroup/skb" ) |
172 | __description("sk_fullsock(skb->sk): sk->family [non fullsock field]" ) |
173 | __success __success_unpriv __retval(0) |
174 | __naked void sk_family_non_fullsock_field_2(void) |
175 | { |
176 | asm volatile (" \ |
177 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
178 | if r1 != 0 goto l0_%=; \ |
179 | r0 = 0; \ |
180 | exit; \ |
181 | l0_%=: call %[bpf_sk_fullsock]; \ |
182 | if r0 != 0 goto l1_%=; \ |
183 | exit; \ |
184 | l1_%=: r0 = *(u32*)(r0 + %[bpf_sock_family]); \ |
185 | r0 = 0; \ |
186 | exit; \ |
187 | " : |
188 | : __imm(bpf_sk_fullsock), |
189 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
190 | __imm_const(bpf_sock_family, offsetof(struct bpf_sock, family)) |
191 | : __clobber_all); |
192 | } |
193 | |
194 | SEC("cgroup/skb" ) |
195 | __description("sk_fullsock(skb->sk): sk->state [narrow load]" ) |
196 | __success __success_unpriv __retval(0) |
197 | __naked void sk_sk_state_narrow_load(void) |
198 | { |
199 | asm volatile (" \ |
200 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
201 | if r1 != 0 goto l0_%=; \ |
202 | r0 = 0; \ |
203 | exit; \ |
204 | l0_%=: call %[bpf_sk_fullsock]; \ |
205 | if r0 != 0 goto l1_%=; \ |
206 | r0 = 0; \ |
207 | exit; \ |
208 | l1_%=: r0 = *(u8*)(r0 + %[bpf_sock_state]); \ |
209 | r0 = 0; \ |
210 | exit; \ |
211 | " : |
212 | : __imm(bpf_sk_fullsock), |
213 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
214 | __imm_const(bpf_sock_state, offsetof(struct bpf_sock, state)) |
215 | : __clobber_all); |
216 | } |
217 | |
218 | SEC("cgroup/skb" ) |
219 | __description("sk_fullsock(skb->sk): sk->dst_port [word load] (backward compatibility)" ) |
220 | __success __success_unpriv __retval(0) |
221 | __naked void port_word_load_backward_compatibility(void) |
222 | { |
223 | asm volatile (" \ |
224 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
225 | if r1 != 0 goto l0_%=; \ |
226 | r0 = 0; \ |
227 | exit; \ |
228 | l0_%=: call %[bpf_sk_fullsock]; \ |
229 | if r0 != 0 goto l1_%=; \ |
230 | r0 = 0; \ |
231 | exit; \ |
232 | l1_%=: r0 = *(u32*)(r0 + %[bpf_sock_dst_port]); \ |
233 | r0 = 0; \ |
234 | exit; \ |
235 | " : |
236 | : __imm(bpf_sk_fullsock), |
237 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
238 | __imm_const(bpf_sock_dst_port, offsetof(struct bpf_sock, dst_port)) |
239 | : __clobber_all); |
240 | } |
241 | |
242 | SEC("cgroup/skb" ) |
243 | __description("sk_fullsock(skb->sk): sk->dst_port [half load]" ) |
244 | __success __success_unpriv __retval(0) |
245 | __naked void sk_dst_port_half_load(void) |
246 | { |
247 | asm volatile (" \ |
248 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
249 | if r1 != 0 goto l0_%=; \ |
250 | r0 = 0; \ |
251 | exit; \ |
252 | l0_%=: call %[bpf_sk_fullsock]; \ |
253 | if r0 != 0 goto l1_%=; \ |
254 | r0 = 0; \ |
255 | exit; \ |
256 | l1_%=: r0 = *(u16*)(r0 + %[bpf_sock_dst_port]); \ |
257 | r0 = 0; \ |
258 | exit; \ |
259 | " : |
260 | : __imm(bpf_sk_fullsock), |
261 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
262 | __imm_const(bpf_sock_dst_port, offsetof(struct bpf_sock, dst_port)) |
263 | : __clobber_all); |
264 | } |
265 | |
266 | SEC("cgroup/skb" ) |
267 | __description("sk_fullsock(skb->sk): sk->dst_port [half load] (invalid)" ) |
268 | __failure __msg("invalid sock access" ) |
269 | __failure_unpriv |
270 | __naked void dst_port_half_load_invalid_1(void) |
271 | { |
272 | asm volatile (" \ |
273 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
274 | if r1 != 0 goto l0_%=; \ |
275 | r0 = 0; \ |
276 | exit; \ |
277 | l0_%=: call %[bpf_sk_fullsock]; \ |
278 | if r0 != 0 goto l1_%=; \ |
279 | r0 = 0; \ |
280 | exit; \ |
281 | l1_%=: r0 = *(u16*)(r0 + %[__imm_0]); \ |
282 | r0 = 0; \ |
283 | exit; \ |
284 | " : |
285 | : __imm(bpf_sk_fullsock), |
286 | __imm_const(__imm_0, offsetof(struct bpf_sock, dst_port) + 2), |
287 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)) |
288 | : __clobber_all); |
289 | } |
290 | |
291 | SEC("cgroup/skb" ) |
292 | __description("sk_fullsock(skb->sk): sk->dst_port [byte load]" ) |
293 | __success __success_unpriv __retval(0) |
294 | __naked void sk_dst_port_byte_load(void) |
295 | { |
296 | asm volatile (" \ |
297 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
298 | if r1 != 0 goto l0_%=; \ |
299 | r0 = 0; \ |
300 | exit; \ |
301 | l0_%=: call %[bpf_sk_fullsock]; \ |
302 | if r0 != 0 goto l1_%=; \ |
303 | r0 = 0; \ |
304 | exit; \ |
305 | l1_%=: r2 = *(u8*)(r0 + %[bpf_sock_dst_port]); \ |
306 | r2 = *(u8*)(r0 + %[__imm_0]); \ |
307 | r0 = 0; \ |
308 | exit; \ |
309 | " : |
310 | : __imm(bpf_sk_fullsock), |
311 | __imm_const(__imm_0, offsetof(struct bpf_sock, dst_port) + 1), |
312 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
313 | __imm_const(bpf_sock_dst_port, offsetof(struct bpf_sock, dst_port)) |
314 | : __clobber_all); |
315 | } |
316 | |
317 | SEC("cgroup/skb" ) |
318 | __description("sk_fullsock(skb->sk): sk->dst_port [byte load] (invalid)" ) |
319 | __failure __msg("invalid sock access" ) |
320 | __failure_unpriv |
321 | __naked void dst_port_byte_load_invalid(void) |
322 | { |
323 | asm volatile (" \ |
324 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
325 | if r1 != 0 goto l0_%=; \ |
326 | r0 = 0; \ |
327 | exit; \ |
328 | l0_%=: call %[bpf_sk_fullsock]; \ |
329 | if r0 != 0 goto l1_%=; \ |
330 | r0 = 0; \ |
331 | exit; \ |
332 | l1_%=: r0 = *(u8*)(r0 + %[__imm_0]); \ |
333 | r0 = 0; \ |
334 | exit; \ |
335 | " : |
336 | : __imm(bpf_sk_fullsock), |
337 | __imm_const(__imm_0, offsetof(struct bpf_sock, dst_port) + 2), |
338 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)) |
339 | : __clobber_all); |
340 | } |
341 | |
342 | SEC("cgroup/skb" ) |
343 | __description("sk_fullsock(skb->sk): past sk->dst_port [half load] (invalid)" ) |
344 | __failure __msg("invalid sock access" ) |
345 | __failure_unpriv |
346 | __naked void dst_port_half_load_invalid_2(void) |
347 | { |
348 | asm volatile (" \ |
349 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
350 | if r1 != 0 goto l0_%=; \ |
351 | r0 = 0; \ |
352 | exit; \ |
353 | l0_%=: call %[bpf_sk_fullsock]; \ |
354 | if r0 != 0 goto l1_%=; \ |
355 | r0 = 0; \ |
356 | exit; \ |
357 | l1_%=: r0 = *(u16*)(r0 + %[bpf_sock_dst_port__end]); \ |
358 | r0 = 0; \ |
359 | exit; \ |
360 | " : |
361 | : __imm(bpf_sk_fullsock), |
362 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
363 | __imm_const(bpf_sock_dst_port__end, offsetofend(struct bpf_sock, dst_port)) |
364 | : __clobber_all); |
365 | } |
366 | |
367 | SEC("cgroup/skb" ) |
368 | __description("sk_fullsock(skb->sk): sk->dst_ip6 [load 2nd byte]" ) |
369 | __success __success_unpriv __retval(0) |
370 | __naked void dst_ip6_load_2nd_byte(void) |
371 | { |
372 | asm volatile (" \ |
373 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
374 | if r1 != 0 goto l0_%=; \ |
375 | r0 = 0; \ |
376 | exit; \ |
377 | l0_%=: call %[bpf_sk_fullsock]; \ |
378 | if r0 != 0 goto l1_%=; \ |
379 | r0 = 0; \ |
380 | exit; \ |
381 | l1_%=: r0 = *(u8*)(r0 + %[__imm_0]); \ |
382 | r0 = 0; \ |
383 | exit; \ |
384 | " : |
385 | : __imm(bpf_sk_fullsock), |
386 | __imm_const(__imm_0, offsetof(struct bpf_sock, dst_ip6[0]) + 1), |
387 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)) |
388 | : __clobber_all); |
389 | } |
390 | |
391 | SEC("cgroup/skb" ) |
392 | __description("sk_fullsock(skb->sk): sk->type [narrow load]" ) |
393 | __success __success_unpriv __retval(0) |
394 | __naked void sk_sk_type_narrow_load(void) |
395 | { |
396 | asm volatile (" \ |
397 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
398 | if r1 != 0 goto l0_%=; \ |
399 | r0 = 0; \ |
400 | exit; \ |
401 | l0_%=: call %[bpf_sk_fullsock]; \ |
402 | if r0 != 0 goto l1_%=; \ |
403 | r0 = 0; \ |
404 | exit; \ |
405 | l1_%=: r0 = *(u8*)(r0 + %[bpf_sock_type]); \ |
406 | r0 = 0; \ |
407 | exit; \ |
408 | " : |
409 | : __imm(bpf_sk_fullsock), |
410 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
411 | __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type)) |
412 | : __clobber_all); |
413 | } |
414 | |
415 | SEC("cgroup/skb" ) |
416 | __description("sk_fullsock(skb->sk): sk->protocol [narrow load]" ) |
417 | __success __success_unpriv __retval(0) |
418 | __naked void sk_sk_protocol_narrow_load(void) |
419 | { |
420 | asm volatile (" \ |
421 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
422 | if r1 != 0 goto l0_%=; \ |
423 | r0 = 0; \ |
424 | exit; \ |
425 | l0_%=: call %[bpf_sk_fullsock]; \ |
426 | if r0 != 0 goto l1_%=; \ |
427 | r0 = 0; \ |
428 | exit; \ |
429 | l1_%=: r0 = *(u8*)(r0 + %[bpf_sock_protocol]); \ |
430 | r0 = 0; \ |
431 | exit; \ |
432 | " : |
433 | : __imm(bpf_sk_fullsock), |
434 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
435 | __imm_const(bpf_sock_protocol, offsetof(struct bpf_sock, protocol)) |
436 | : __clobber_all); |
437 | } |
438 | |
439 | SEC("cgroup/skb" ) |
440 | __description("sk_fullsock(skb->sk): beyond last field" ) |
441 | __failure __msg("invalid sock access" ) |
442 | __failure_unpriv |
443 | __naked void skb_sk_beyond_last_field_1(void) |
444 | { |
445 | asm volatile (" \ |
446 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
447 | if r1 != 0 goto l0_%=; \ |
448 | r0 = 0; \ |
449 | exit; \ |
450 | l0_%=: call %[bpf_sk_fullsock]; \ |
451 | if r0 != 0 goto l1_%=; \ |
452 | r0 = 0; \ |
453 | exit; \ |
454 | l1_%=: r0 = *(u32*)(r0 + %[bpf_sock_rx_queue_mapping__end]);\ |
455 | r0 = 0; \ |
456 | exit; \ |
457 | " : |
458 | : __imm(bpf_sk_fullsock), |
459 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
460 | __imm_const(bpf_sock_rx_queue_mapping__end, offsetofend(struct bpf_sock, rx_queue_mapping)) |
461 | : __clobber_all); |
462 | } |
463 | |
464 | SEC("cgroup/skb" ) |
465 | __description("bpf_tcp_sock(skb->sk): no !skb->sk check" ) |
466 | __failure __msg("type=sock_common_or_null expected=sock_common" ) |
467 | __failure_unpriv |
468 | __naked void sk_no_skb_sk_check_2(void) |
469 | { |
470 | asm volatile (" \ |
471 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
472 | call %[bpf_tcp_sock]; \ |
473 | r0 = 0; \ |
474 | exit; \ |
475 | " : |
476 | : __imm(bpf_tcp_sock), |
477 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)) |
478 | : __clobber_all); |
479 | } |
480 | |
481 | SEC("cgroup/skb" ) |
482 | __description("bpf_tcp_sock(skb->sk): no NULL check on ret" ) |
483 | __failure __msg("invalid mem access 'tcp_sock_or_null'" ) |
484 | __failure_unpriv |
485 | __naked void no_null_check_on_ret_2(void) |
486 | { |
487 | asm volatile (" \ |
488 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
489 | if r1 != 0 goto l0_%=; \ |
490 | r0 = 0; \ |
491 | exit; \ |
492 | l0_%=: call %[bpf_tcp_sock]; \ |
493 | r0 = *(u32*)(r0 + %[bpf_tcp_sock_snd_cwnd]); \ |
494 | r0 = 0; \ |
495 | exit; \ |
496 | " : |
497 | : __imm(bpf_tcp_sock), |
498 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
499 | __imm_const(bpf_tcp_sock_snd_cwnd, offsetof(struct bpf_tcp_sock, snd_cwnd)) |
500 | : __clobber_all); |
501 | } |
502 | |
503 | SEC("cgroup/skb" ) |
504 | __description("bpf_tcp_sock(skb->sk): tp->snd_cwnd" ) |
505 | __success __success_unpriv __retval(0) |
506 | __naked void skb_sk_tp_snd_cwnd_1(void) |
507 | { |
508 | asm volatile (" \ |
509 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
510 | if r1 != 0 goto l0_%=; \ |
511 | r0 = 0; \ |
512 | exit; \ |
513 | l0_%=: call %[bpf_tcp_sock]; \ |
514 | if r0 != 0 goto l1_%=; \ |
515 | exit; \ |
516 | l1_%=: r0 = *(u32*)(r0 + %[bpf_tcp_sock_snd_cwnd]); \ |
517 | r0 = 0; \ |
518 | exit; \ |
519 | " : |
520 | : __imm(bpf_tcp_sock), |
521 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
522 | __imm_const(bpf_tcp_sock_snd_cwnd, offsetof(struct bpf_tcp_sock, snd_cwnd)) |
523 | : __clobber_all); |
524 | } |
525 | |
526 | SEC("cgroup/skb" ) |
527 | __description("bpf_tcp_sock(skb->sk): tp->bytes_acked" ) |
528 | __success __success_unpriv __retval(0) |
529 | __naked void skb_sk_tp_bytes_acked(void) |
530 | { |
531 | asm volatile (" \ |
532 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
533 | if r1 != 0 goto l0_%=; \ |
534 | r0 = 0; \ |
535 | exit; \ |
536 | l0_%=: call %[bpf_tcp_sock]; \ |
537 | if r0 != 0 goto l1_%=; \ |
538 | exit; \ |
539 | l1_%=: r0 = *(u64*)(r0 + %[bpf_tcp_sock_bytes_acked]); \ |
540 | r0 = 0; \ |
541 | exit; \ |
542 | " : |
543 | : __imm(bpf_tcp_sock), |
544 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
545 | __imm_const(bpf_tcp_sock_bytes_acked, offsetof(struct bpf_tcp_sock, bytes_acked)) |
546 | : __clobber_all); |
547 | } |
548 | |
549 | SEC("cgroup/skb" ) |
550 | __description("bpf_tcp_sock(skb->sk): beyond last field" ) |
551 | __failure __msg("invalid tcp_sock access" ) |
552 | __failure_unpriv |
553 | __naked void skb_sk_beyond_last_field_2(void) |
554 | { |
555 | asm volatile (" \ |
556 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
557 | if r1 != 0 goto l0_%=; \ |
558 | r0 = 0; \ |
559 | exit; \ |
560 | l0_%=: call %[bpf_tcp_sock]; \ |
561 | if r0 != 0 goto l1_%=; \ |
562 | exit; \ |
563 | l1_%=: r0 = *(u64*)(r0 + %[bpf_tcp_sock_bytes_acked__end]);\ |
564 | r0 = 0; \ |
565 | exit; \ |
566 | " : |
567 | : __imm(bpf_tcp_sock), |
568 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
569 | __imm_const(bpf_tcp_sock_bytes_acked__end, offsetofend(struct bpf_tcp_sock, bytes_acked)) |
570 | : __clobber_all); |
571 | } |
572 | |
573 | SEC("cgroup/skb" ) |
574 | __description("bpf_tcp_sock(bpf_sk_fullsock(skb->sk)): tp->snd_cwnd" ) |
575 | __success __success_unpriv __retval(0) |
576 | __naked void skb_sk_tp_snd_cwnd_2(void) |
577 | { |
578 | asm volatile (" \ |
579 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
580 | if r1 != 0 goto l0_%=; \ |
581 | r0 = 0; \ |
582 | exit; \ |
583 | l0_%=: call %[bpf_sk_fullsock]; \ |
584 | if r0 != 0 goto l1_%=; \ |
585 | exit; \ |
586 | l1_%=: r1 = r0; \ |
587 | call %[bpf_tcp_sock]; \ |
588 | if r0 != 0 goto l2_%=; \ |
589 | exit; \ |
590 | l2_%=: r0 = *(u32*)(r0 + %[bpf_tcp_sock_snd_cwnd]); \ |
591 | r0 = 0; \ |
592 | exit; \ |
593 | " : |
594 | : __imm(bpf_sk_fullsock), |
595 | __imm(bpf_tcp_sock), |
596 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)), |
597 | __imm_const(bpf_tcp_sock_snd_cwnd, offsetof(struct bpf_tcp_sock, snd_cwnd)) |
598 | : __clobber_all); |
599 | } |
600 | |
601 | SEC("tc" ) |
602 | __description("bpf_sk_release(skb->sk)" ) |
603 | __failure __msg("R1 must be referenced when passed to release function" ) |
604 | __naked void bpf_sk_release_skb_sk(void) |
605 | { |
606 | asm volatile (" \ |
607 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
608 | if r1 == 0 goto l0_%=; \ |
609 | call %[bpf_sk_release]; \ |
610 | l0_%=: r0 = 0; \ |
611 | exit; \ |
612 | " : |
613 | : __imm(bpf_sk_release), |
614 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)) |
615 | : __clobber_all); |
616 | } |
617 | |
618 | SEC("tc" ) |
619 | __description("bpf_sk_release(bpf_sk_fullsock(skb->sk))" ) |
620 | __failure __msg("R1 must be referenced when passed to release function" ) |
621 | __naked void bpf_sk_fullsock_skb_sk(void) |
622 | { |
623 | asm volatile (" \ |
624 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
625 | if r1 != 0 goto l0_%=; \ |
626 | r0 = 0; \ |
627 | exit; \ |
628 | l0_%=: call %[bpf_sk_fullsock]; \ |
629 | if r0 != 0 goto l1_%=; \ |
630 | exit; \ |
631 | l1_%=: r1 = r0; \ |
632 | call %[bpf_sk_release]; \ |
633 | r0 = 1; \ |
634 | exit; \ |
635 | " : |
636 | : __imm(bpf_sk_fullsock), |
637 | __imm(bpf_sk_release), |
638 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)) |
639 | : __clobber_all); |
640 | } |
641 | |
642 | SEC("tc" ) |
643 | __description("bpf_sk_release(bpf_tcp_sock(skb->sk))" ) |
644 | __failure __msg("R1 must be referenced when passed to release function" ) |
645 | __naked void bpf_tcp_sock_skb_sk(void) |
646 | { |
647 | asm volatile (" \ |
648 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
649 | if r1 != 0 goto l0_%=; \ |
650 | r0 = 0; \ |
651 | exit; \ |
652 | l0_%=: call %[bpf_tcp_sock]; \ |
653 | if r0 != 0 goto l1_%=; \ |
654 | exit; \ |
655 | l1_%=: r1 = r0; \ |
656 | call %[bpf_sk_release]; \ |
657 | r0 = 1; \ |
658 | exit; \ |
659 | " : |
660 | : __imm(bpf_sk_release), |
661 | __imm(bpf_tcp_sock), |
662 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)) |
663 | : __clobber_all); |
664 | } |
665 | |
666 | SEC("tc" ) |
667 | __description("sk_storage_get(map, skb->sk, NULL, 0): value == NULL" ) |
668 | __success __retval(0) |
669 | __naked void sk_null_0_value_null(void) |
670 | { |
671 | asm volatile (" \ |
672 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
673 | if r1 != 0 goto l0_%=; \ |
674 | r0 = 0; \ |
675 | exit; \ |
676 | l0_%=: call %[bpf_sk_fullsock]; \ |
677 | if r0 != 0 goto l1_%=; \ |
678 | r0 = 0; \ |
679 | exit; \ |
680 | l1_%=: r4 = 0; \ |
681 | r3 = 0; \ |
682 | r2 = r0; \ |
683 | r1 = %[sk_storage_map] ll; \ |
684 | call %[bpf_sk_storage_get]; \ |
685 | r0 = 0; \ |
686 | exit; \ |
687 | " : |
688 | : __imm(bpf_sk_fullsock), |
689 | __imm(bpf_sk_storage_get), |
690 | __imm_addr(sk_storage_map), |
691 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)) |
692 | : __clobber_all); |
693 | } |
694 | |
695 | SEC("tc" ) |
696 | __description("sk_storage_get(map, skb->sk, 1, 1): value == 1" ) |
697 | __failure __msg("R3 type=scalar expected=fp" ) |
698 | __naked void sk_1_1_value_1(void) |
699 | { |
700 | asm volatile (" \ |
701 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
702 | if r1 != 0 goto l0_%=; \ |
703 | r0 = 0; \ |
704 | exit; \ |
705 | l0_%=: call %[bpf_sk_fullsock]; \ |
706 | if r0 != 0 goto l1_%=; \ |
707 | r0 = 0; \ |
708 | exit; \ |
709 | l1_%=: r4 = 1; \ |
710 | r3 = 1; \ |
711 | r2 = r0; \ |
712 | r1 = %[sk_storage_map] ll; \ |
713 | call %[bpf_sk_storage_get]; \ |
714 | r0 = 0; \ |
715 | exit; \ |
716 | " : |
717 | : __imm(bpf_sk_fullsock), |
718 | __imm(bpf_sk_storage_get), |
719 | __imm_addr(sk_storage_map), |
720 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)) |
721 | : __clobber_all); |
722 | } |
723 | |
724 | SEC("tc" ) |
725 | __description("sk_storage_get(map, skb->sk, &stack_value, 1): stack_value" ) |
726 | __success __retval(0) |
727 | __naked void stack_value_1_stack_value(void) |
728 | { |
729 | asm volatile (" \ |
730 | r2 = 0; \ |
731 | *(u64*)(r10 - 8) = r2; \ |
732 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
733 | if r1 != 0 goto l0_%=; \ |
734 | r0 = 0; \ |
735 | exit; \ |
736 | l0_%=: call %[bpf_sk_fullsock]; \ |
737 | if r0 != 0 goto l1_%=; \ |
738 | r0 = 0; \ |
739 | exit; \ |
740 | l1_%=: r4 = 1; \ |
741 | r3 = r10; \ |
742 | r3 += -8; \ |
743 | r2 = r0; \ |
744 | r1 = %[sk_storage_map] ll; \ |
745 | call %[bpf_sk_storage_get]; \ |
746 | r0 = 0; \ |
747 | exit; \ |
748 | " : |
749 | : __imm(bpf_sk_fullsock), |
750 | __imm(bpf_sk_storage_get), |
751 | __imm_addr(sk_storage_map), |
752 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)) |
753 | : __clobber_all); |
754 | } |
755 | |
756 | SEC("tc" ) |
757 | __description("bpf_map_lookup_elem(smap, &key)" ) |
758 | __failure __msg("cannot pass map_type 24 into func bpf_map_lookup_elem" ) |
759 | __naked void map_lookup_elem_smap_key(void) |
760 | { |
761 | asm volatile (" \ |
762 | r1 = 0; \ |
763 | *(u32*)(r10 - 4) = r1; \ |
764 | r2 = r10; \ |
765 | r2 += -4; \ |
766 | r1 = %[sk_storage_map] ll; \ |
767 | call %[bpf_map_lookup_elem]; \ |
768 | r0 = 0; \ |
769 | exit; \ |
770 | " : |
771 | : __imm(bpf_map_lookup_elem), |
772 | __imm_addr(sk_storage_map) |
773 | : __clobber_all); |
774 | } |
775 | |
776 | SEC("xdp" ) |
777 | __description("bpf_map_lookup_elem(xskmap, &key); xs->queue_id" ) |
778 | __success __retval(0) |
779 | __naked void xskmap_key_xs_queue_id(void) |
780 | { |
781 | asm volatile (" \ |
782 | r1 = 0; \ |
783 | *(u32*)(r10 - 8) = r1; \ |
784 | r2 = r10; \ |
785 | r2 += -8; \ |
786 | r1 = %[map_xskmap] ll; \ |
787 | call %[bpf_map_lookup_elem]; \ |
788 | if r0 != 0 goto l0_%=; \ |
789 | exit; \ |
790 | l0_%=: r0 = *(u32*)(r0 + %[bpf_xdp_sock_queue_id]); \ |
791 | r0 = 0; \ |
792 | exit; \ |
793 | " : |
794 | : __imm(bpf_map_lookup_elem), |
795 | __imm_addr(map_xskmap), |
796 | __imm_const(bpf_xdp_sock_queue_id, offsetof(struct bpf_xdp_sock, queue_id)) |
797 | : __clobber_all); |
798 | } |
799 | |
800 | SEC("sk_skb" ) |
801 | __description("bpf_map_lookup_elem(sockmap, &key)" ) |
802 | __failure __msg("Unreleased reference id=2 alloc_insn=6" ) |
803 | __naked void map_lookup_elem_sockmap_key(void) |
804 | { |
805 | asm volatile (" \ |
806 | r1 = 0; \ |
807 | *(u32*)(r10 - 4) = r1; \ |
808 | r2 = r10; \ |
809 | r2 += -4; \ |
810 | r1 = %[map_sockmap] ll; \ |
811 | call %[bpf_map_lookup_elem]; \ |
812 | r0 = 0; \ |
813 | exit; \ |
814 | " : |
815 | : __imm(bpf_map_lookup_elem), |
816 | __imm_addr(map_sockmap) |
817 | : __clobber_all); |
818 | } |
819 | |
820 | SEC("sk_skb" ) |
821 | __description("bpf_map_lookup_elem(sockhash, &key)" ) |
822 | __failure __msg("Unreleased reference id=2 alloc_insn=6" ) |
823 | __naked void map_lookup_elem_sockhash_key(void) |
824 | { |
825 | asm volatile (" \ |
826 | r1 = 0; \ |
827 | *(u32*)(r10 - 4) = r1; \ |
828 | r2 = r10; \ |
829 | r2 += -4; \ |
830 | r1 = %[map_sockhash] ll; \ |
831 | call %[bpf_map_lookup_elem]; \ |
832 | r0 = 0; \ |
833 | exit; \ |
834 | " : |
835 | : __imm(bpf_map_lookup_elem), |
836 | __imm_addr(map_sockhash) |
837 | : __clobber_all); |
838 | } |
839 | |
840 | SEC("sk_skb" ) |
841 | __description("bpf_map_lookup_elem(sockmap, &key); sk->type [fullsock field]; bpf_sk_release(sk)" ) |
842 | __success |
843 | __naked void field_bpf_sk_release_sk_1(void) |
844 | { |
845 | asm volatile (" \ |
846 | r1 = 0; \ |
847 | *(u32*)(r10 - 4) = r1; \ |
848 | r2 = r10; \ |
849 | r2 += -4; \ |
850 | r1 = %[map_sockmap] ll; \ |
851 | call %[bpf_map_lookup_elem]; \ |
852 | if r0 != 0 goto l0_%=; \ |
853 | exit; \ |
854 | l0_%=: r1 = r0; \ |
855 | r0 = *(u32*)(r0 + %[bpf_sock_type]); \ |
856 | call %[bpf_sk_release]; \ |
857 | exit; \ |
858 | " : |
859 | : __imm(bpf_map_lookup_elem), |
860 | __imm(bpf_sk_release), |
861 | __imm_addr(map_sockmap), |
862 | __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type)) |
863 | : __clobber_all); |
864 | } |
865 | |
866 | SEC("sk_skb" ) |
867 | __description("bpf_map_lookup_elem(sockhash, &key); sk->type [fullsock field]; bpf_sk_release(sk)" ) |
868 | __success |
869 | __naked void field_bpf_sk_release_sk_2(void) |
870 | { |
871 | asm volatile (" \ |
872 | r1 = 0; \ |
873 | *(u32*)(r10 - 4) = r1; \ |
874 | r2 = r10; \ |
875 | r2 += -4; \ |
876 | r1 = %[map_sockhash] ll; \ |
877 | call %[bpf_map_lookup_elem]; \ |
878 | if r0 != 0 goto l0_%=; \ |
879 | exit; \ |
880 | l0_%=: r1 = r0; \ |
881 | r0 = *(u32*)(r0 + %[bpf_sock_type]); \ |
882 | call %[bpf_sk_release]; \ |
883 | exit; \ |
884 | " : |
885 | : __imm(bpf_map_lookup_elem), |
886 | __imm(bpf_sk_release), |
887 | __imm_addr(map_sockhash), |
888 | __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type)) |
889 | : __clobber_all); |
890 | } |
891 | |
892 | SEC("sk_reuseport" ) |
893 | __description("bpf_sk_select_reuseport(ctx, reuseport_array, &key, flags)" ) |
894 | __success |
895 | __naked void ctx_reuseport_array_key_flags(void) |
896 | { |
897 | asm volatile (" \ |
898 | r4 = 0; \ |
899 | r2 = 0; \ |
900 | *(u32*)(r10 - 4) = r2; \ |
901 | r3 = r10; \ |
902 | r3 += -4; \ |
903 | r2 = %[map_reuseport_array] ll; \ |
904 | call %[bpf_sk_select_reuseport]; \ |
905 | exit; \ |
906 | " : |
907 | : __imm(bpf_sk_select_reuseport), |
908 | __imm_addr(map_reuseport_array) |
909 | : __clobber_all); |
910 | } |
911 | |
912 | SEC("sk_reuseport" ) |
913 | __description("bpf_sk_select_reuseport(ctx, sockmap, &key, flags)" ) |
914 | __success |
915 | __naked void reuseport_ctx_sockmap_key_flags(void) |
916 | { |
917 | asm volatile (" \ |
918 | r4 = 0; \ |
919 | r2 = 0; \ |
920 | *(u32*)(r10 - 4) = r2; \ |
921 | r3 = r10; \ |
922 | r3 += -4; \ |
923 | r2 = %[map_sockmap] ll; \ |
924 | call %[bpf_sk_select_reuseport]; \ |
925 | exit; \ |
926 | " : |
927 | : __imm(bpf_sk_select_reuseport), |
928 | __imm_addr(map_sockmap) |
929 | : __clobber_all); |
930 | } |
931 | |
932 | SEC("sk_reuseport" ) |
933 | __description("bpf_sk_select_reuseport(ctx, sockhash, &key, flags)" ) |
934 | __success |
935 | __naked void reuseport_ctx_sockhash_key_flags(void) |
936 | { |
937 | asm volatile (" \ |
938 | r4 = 0; \ |
939 | r2 = 0; \ |
940 | *(u32*)(r10 - 4) = r2; \ |
941 | r3 = r10; \ |
942 | r3 += -4; \ |
943 | r2 = %[map_sockmap] ll; \ |
944 | call %[bpf_sk_select_reuseport]; \ |
945 | exit; \ |
946 | " : |
947 | : __imm(bpf_sk_select_reuseport), |
948 | __imm_addr(map_sockmap) |
949 | : __clobber_all); |
950 | } |
951 | |
952 | SEC("tc" ) |
953 | __description("mark null check on return value of bpf_skc_to helpers" ) |
954 | __failure __msg("invalid mem access" ) |
955 | __naked void of_bpf_skc_to_helpers(void) |
956 | { |
957 | asm volatile (" \ |
958 | r1 = *(u64*)(r1 + %[__sk_buff_sk]); \ |
959 | if r1 != 0 goto l0_%=; \ |
960 | r0 = 0; \ |
961 | exit; \ |
962 | l0_%=: r6 = r1; \ |
963 | call %[bpf_skc_to_tcp_sock]; \ |
964 | r7 = r0; \ |
965 | r1 = r6; \ |
966 | call %[bpf_skc_to_tcp_request_sock]; \ |
967 | r8 = r0; \ |
968 | if r8 != 0 goto l1_%=; \ |
969 | r0 = 0; \ |
970 | exit; \ |
971 | l1_%=: r0 = *(u8*)(r7 + 0); \ |
972 | exit; \ |
973 | " : |
974 | : __imm(bpf_skc_to_tcp_request_sock), |
975 | __imm(bpf_skc_to_tcp_sock), |
976 | __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)) |
977 | : __clobber_all); |
978 | } |
979 | |
980 | char _license[] SEC("license" ) = "GPL" ; |
981 | |