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
skb_sk_no_null_check(void)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)
sk_family_non_fullsock_field_1(void)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
sk_sk_type_fullsock_field_1(void)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
sk_no_skb_sk_check_1(void)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
no_null_check_on_ret_1(void)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)
sk_sk_type_fullsock_field_2(void)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)
sk_family_non_fullsock_field_2(void)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)
sk_sk_state_narrow_load(void)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)
port_word_load_backward_compatibility(void)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)
sk_dst_port_half_load(void)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
dst_port_half_load_invalid_1(void)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)
sk_dst_port_byte_load(void)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
dst_port_byte_load_invalid(void)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
dst_port_half_load_invalid_2(void)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)
dst_ip6_load_2nd_byte(void)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)
sk_sk_type_narrow_load(void)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)
sk_sk_protocol_narrow_load(void)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
skb_sk_beyond_last_field_1(void)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
sk_no_skb_sk_check_2(void)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
no_null_check_on_ret_2(void)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)
skb_sk_tp_snd_cwnd_1(void)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)
skb_sk_tp_bytes_acked(void)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
skb_sk_beyond_last_field_2(void)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)
skb_sk_tp_snd_cwnd_2(void)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")
bpf_sk_release_skb_sk(void)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")
bpf_sk_fullsock_skb_sk(void)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")
bpf_tcp_sock_skb_sk(void)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)
sk_null_0_value_null(void)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")
sk_1_1_value_1(void)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)
stack_value_1_stack_value(void)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")
map_lookup_elem_smap_key(void)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)
xskmap_key_xs_queue_id(void)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")
map_lookup_elem_sockmap_key(void)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")
map_lookup_elem_sockhash_key(void)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
field_bpf_sk_release_sk_1(void)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
field_bpf_sk_release_sk_2(void)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
ctx_reuseport_array_key_flags(void)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
reuseport_ctx_sockmap_key_flags(void)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
reuseport_ctx_sockhash_key_flags(void)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")
of_bpf_skc_to_helpers(void)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