1 // SPDX-License-Identifier: GPL-2.0
2 /* Converted from tools/testing/selftests/bpf/verifier/sock.c */
3
4 #include "vmlinux.h"
5 #include <bpf/bpf_helpers.h>
6 #include "bpf_misc.h"
7
8 struct {
9 __uint(type, BPF_MAP_TYPE_REUSEPORT_SOCKARRAY);
10 __uint(max_entries, 1);
11 __type(key, __u32);
12 __type(value, __u64);
13 } map_reuseport_array SEC(".maps");
14
15 struct {
16 __uint(type, BPF_MAP_TYPE_SOCKHASH);
17 __uint(max_entries, 1);
18 __type(key, int);
19 __type(value, int);
20 } map_sockhash SEC(".maps");
21
22 struct {
23 __uint(type, BPF_MAP_TYPE_SOCKMAP);
24 __uint(max_entries, 1);
25 __type(key, int);
26 __type(value, int);
27 } map_sockmap SEC(".maps");
28
29 struct {
30 __uint(type, BPF_MAP_TYPE_XSKMAP);
31 __uint(max_entries, 1);
32 __type(key, int);
33 __type(value, int);
34 } map_xskmap SEC(".maps");
35
36 struct val {
37 int cnt;
38 struct bpf_spin_lock l;
39 };
40
41 struct {
42 __uint(type, BPF_MAP_TYPE_SK_STORAGE);
43 __uint(max_entries, 0);
44 __type(key, int);
45 __type(value, struct val);
46 __uint(map_flags, BPF_F_NO_PREALLOC);
47 } sk_storage_map SEC(".maps");
48
49 struct {
50 __uint(type, BPF_MAP_TYPE_PROG_ARRAY);
51 __uint(max_entries, 1);
52 __uint(key_size, sizeof(__u32));
53 __uint(value_size, sizeof(__u32));
54 } jmp_table SEC(".maps");
55
56 SEC("cgroup/skb")
57 __description("skb->sk: no NULL check")
58 __failure __msg("invalid mem access 'sock_common_or_null'")
59 __failure_unpriv
skb_sk_no_null_check(void)60 __naked void skb_sk_no_null_check(void)
61 {
62 asm volatile (" \
63 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
64 r0 = *(u32*)(r1 + 0); \
65 r0 = 0; \
66 exit; \
67 " :
68 : __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk))
69 : __clobber_all);
70 }
71
72 SEC("cgroup/skb")
73 __description("skb->sk: sk->family [non fullsock field]")
74 __success __success_unpriv __retval(0)
sk_family_non_fullsock_field_1(void)75 __naked void sk_family_non_fullsock_field_1(void)
76 {
77 asm volatile (" \
78 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
79 if r1 != 0 goto l0_%=; \
80 r0 = 0; \
81 exit; \
82 l0_%=: r0 = *(u32*)(r1 + %[bpf_sock_family]); \
83 r0 = 0; \
84 exit; \
85 " :
86 : __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
87 __imm_const(bpf_sock_family, offsetof(struct bpf_sock, family))
88 : __clobber_all);
89 }
90
91 SEC("socket")
92 __description("skb->sk: sk->rx_queue_mapping [no sign extension]")
93 __success __success_unpriv __retval(0)
sk_rx_queue_mapping_no_sign_ext(void)94 __naked void sk_rx_queue_mapping_no_sign_ext(void)
95 {
96 asm volatile (" \
97 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
98 if r1 != 0 goto l0_%=; \
99 r0 = 0xdead; \
100 exit; \
101 l0_%=: r0 = *(u32*)(r1 + %[bpf_sock_rx_queue_mapping]); \
102 r0 >>= 32; \
103 exit; \
104 " :
105 : __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
106 __imm_const(bpf_sock_rx_queue_mapping, offsetof(struct bpf_sock, rx_queue_mapping))
107 : __clobber_all);
108 }
109
110 SEC("socket")
111 __description("skb->sk: sk->rx_queue_mapping [narrow load mask]")
112 __success __success_unpriv __retval(0)
sk_rx_queue_mapping_narrow_load_mask(void)113 __naked void sk_rx_queue_mapping_narrow_load_mask(void)
114 {
115 asm volatile (" \
116 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
117 if r1 != 0 goto l0_%=; \
118 r0 = 0xdead; \
119 exit; \
120 l0_%=: r0 = *(u16*)(r1 + %[bpf_sock_rx_queue_mapping]); \
121 r0 >>= 16; \
122 exit; \
123 " :
124 : __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
125 __imm_const(bpf_sock_rx_queue_mapping, offsetof(struct bpf_sock, rx_queue_mapping))
126 : __clobber_all);
127 }
128
129 SEC("cgroup/skb")
130 __description("skb->sk: sk->type [fullsock field]")
131 __failure __msg("invalid sock_common access")
132 __failure_unpriv
sk_sk_type_fullsock_field_1(void)133 __naked void sk_sk_type_fullsock_field_1(void)
134 {
135 asm volatile (" \
136 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
137 if r1 != 0 goto l0_%=; \
138 r0 = 0; \
139 exit; \
140 l0_%=: r0 = *(u32*)(r1 + %[bpf_sock_type]); \
141 r0 = 0; \
142 exit; \
143 " :
144 : __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
145 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type))
146 : __clobber_all);
147 }
148
149 SEC("cgroup/skb")
150 __description("bpf_sk_fullsock(skb->sk): no !skb->sk check")
151 __failure __msg("type=sock_common_or_null expected=sock_common")
152 __failure_unpriv
sk_no_skb_sk_check_1(void)153 __naked void sk_no_skb_sk_check_1(void)
154 {
155 asm volatile (" \
156 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
157 call %[bpf_sk_fullsock]; \
158 r0 = 0; \
159 exit; \
160 " :
161 : __imm(bpf_sk_fullsock),
162 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk))
163 : __clobber_all);
164 }
165
166 SEC("cgroup/skb")
167 __description("sk_fullsock(skb->sk): no NULL check on ret")
168 __failure __msg("invalid mem access 'sock_or_null'")
169 __failure_unpriv
no_null_check_on_ret_1(void)170 __naked void no_null_check_on_ret_1(void)
171 {
172 asm volatile (" \
173 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
174 if r1 != 0 goto l0_%=; \
175 r0 = 0; \
176 exit; \
177 l0_%=: call %[bpf_sk_fullsock]; \
178 r0 = *(u32*)(r0 + %[bpf_sock_type]); \
179 r0 = 0; \
180 exit; \
181 " :
182 : __imm(bpf_sk_fullsock),
183 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
184 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type))
185 : __clobber_all);
186 }
187
188 SEC("cgroup/skb")
189 __description("sk_fullsock(skb->sk): sk->type [fullsock field]")
190 __success __success_unpriv __retval(0)
sk_sk_type_fullsock_field_2(void)191 __naked void sk_sk_type_fullsock_field_2(void)
192 {
193 asm volatile (" \
194 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
195 if r1 != 0 goto l0_%=; \
196 r0 = 0; \
197 exit; \
198 l0_%=: call %[bpf_sk_fullsock]; \
199 if r0 != 0 goto l1_%=; \
200 r0 = 0; \
201 exit; \
202 l1_%=: r0 = *(u32*)(r0 + %[bpf_sock_type]); \
203 r0 = 0; \
204 exit; \
205 " :
206 : __imm(bpf_sk_fullsock),
207 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
208 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type))
209 : __clobber_all);
210 }
211
212 SEC("cgroup/skb")
213 __description("sk_fullsock(skb->sk): sk->family [non fullsock field]")
214 __success __success_unpriv __retval(0)
sk_family_non_fullsock_field_2(void)215 __naked void sk_family_non_fullsock_field_2(void)
216 {
217 asm volatile (" \
218 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
219 if r1 != 0 goto l0_%=; \
220 r0 = 0; \
221 exit; \
222 l0_%=: call %[bpf_sk_fullsock]; \
223 if r0 != 0 goto l1_%=; \
224 exit; \
225 l1_%=: r0 = *(u32*)(r0 + %[bpf_sock_family]); \
226 r0 = 0; \
227 exit; \
228 " :
229 : __imm(bpf_sk_fullsock),
230 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
231 __imm_const(bpf_sock_family, offsetof(struct bpf_sock, family))
232 : __clobber_all);
233 }
234
235 SEC("cgroup/skb")
236 __description("sk_fullsock(skb->sk): sk->state [narrow load]")
237 __success __success_unpriv __retval(0)
sk_sk_state_narrow_load(void)238 __naked void sk_sk_state_narrow_load(void)
239 {
240 asm volatile (" \
241 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
242 if r1 != 0 goto l0_%=; \
243 r0 = 0; \
244 exit; \
245 l0_%=: call %[bpf_sk_fullsock]; \
246 if r0 != 0 goto l1_%=; \
247 r0 = 0; \
248 exit; \
249 l1_%=: r0 = *(u8*)(r0 + %[bpf_sock_state]); \
250 r0 = 0; \
251 exit; \
252 " :
253 : __imm(bpf_sk_fullsock),
254 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
255 __imm_const(bpf_sock_state, offsetof(struct bpf_sock, state))
256 : __clobber_all);
257 }
258
259 SEC("cgroup/skb")
260 __description("sk_fullsock(skb->sk): sk->dst_port [word load] (backward compatibility)")
261 __success __success_unpriv __retval(0)
port_word_load_backward_compatibility(void)262 __naked void port_word_load_backward_compatibility(void)
263 {
264 asm volatile (" \
265 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
266 if r1 != 0 goto l0_%=; \
267 r0 = 0; \
268 exit; \
269 l0_%=: call %[bpf_sk_fullsock]; \
270 if r0 != 0 goto l1_%=; \
271 r0 = 0; \
272 exit; \
273 l1_%=: r0 = *(u32*)(r0 + %[bpf_sock_dst_port]); \
274 r0 = 0; \
275 exit; \
276 " :
277 : __imm(bpf_sk_fullsock),
278 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
279 __imm_const(bpf_sock_dst_port, offsetof(struct bpf_sock, dst_port))
280 : __clobber_all);
281 }
282
283 SEC("cgroup/skb")
284 __description("sk_fullsock(skb->sk): sk->dst_port [half load]")
285 __success __success_unpriv __retval(0)
sk_dst_port_half_load(void)286 __naked void sk_dst_port_half_load(void)
287 {
288 asm volatile (" \
289 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
290 if r1 != 0 goto l0_%=; \
291 r0 = 0; \
292 exit; \
293 l0_%=: call %[bpf_sk_fullsock]; \
294 if r0 != 0 goto l1_%=; \
295 r0 = 0; \
296 exit; \
297 l1_%=: r0 = *(u16*)(r0 + %[bpf_sock_dst_port]); \
298 r0 = 0; \
299 exit; \
300 " :
301 : __imm(bpf_sk_fullsock),
302 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
303 __imm_const(bpf_sock_dst_port, offsetof(struct bpf_sock, dst_port))
304 : __clobber_all);
305 }
306
307 SEC("cgroup/skb")
308 __description("sk_fullsock(skb->sk): sk->dst_port [half load] (invalid)")
309 __failure __msg("invalid sock access")
310 __failure_unpriv
dst_port_half_load_invalid_1(void)311 __naked void dst_port_half_load_invalid_1(void)
312 {
313 asm volatile (" \
314 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
315 if r1 != 0 goto l0_%=; \
316 r0 = 0; \
317 exit; \
318 l0_%=: call %[bpf_sk_fullsock]; \
319 if r0 != 0 goto l1_%=; \
320 r0 = 0; \
321 exit; \
322 l1_%=: r0 = *(u16*)(r0 + %[__imm_0]); \
323 r0 = 0; \
324 exit; \
325 " :
326 : __imm(bpf_sk_fullsock),
327 __imm_const(__imm_0, offsetof(struct bpf_sock, dst_port) + 2),
328 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk))
329 : __clobber_all);
330 }
331
332 SEC("cgroup/skb")
333 __description("sk_fullsock(skb->sk): sk->dst_port [byte load]")
334 __success __success_unpriv __retval(0)
sk_dst_port_byte_load(void)335 __naked void sk_dst_port_byte_load(void)
336 {
337 asm volatile (" \
338 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
339 if r1 != 0 goto l0_%=; \
340 r0 = 0; \
341 exit; \
342 l0_%=: call %[bpf_sk_fullsock]; \
343 if r0 != 0 goto l1_%=; \
344 r0 = 0; \
345 exit; \
346 l1_%=: r2 = *(u8*)(r0 + %[bpf_sock_dst_port]); \
347 r2 = *(u8*)(r0 + %[__imm_0]); \
348 r0 = 0; \
349 exit; \
350 " :
351 : __imm(bpf_sk_fullsock),
352 __imm_const(__imm_0, offsetof(struct bpf_sock, dst_port) + 1),
353 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
354 __imm_const(bpf_sock_dst_port, offsetof(struct bpf_sock, dst_port))
355 : __clobber_all);
356 }
357
358 SEC("cgroup/skb")
359 __description("sk_fullsock(skb->sk): sk->dst_port [byte load] (invalid)")
360 __failure __msg("invalid sock access")
361 __failure_unpriv
dst_port_byte_load_invalid(void)362 __naked void dst_port_byte_load_invalid(void)
363 {
364 asm volatile (" \
365 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
366 if r1 != 0 goto l0_%=; \
367 r0 = 0; \
368 exit; \
369 l0_%=: call %[bpf_sk_fullsock]; \
370 if r0 != 0 goto l1_%=; \
371 r0 = 0; \
372 exit; \
373 l1_%=: r0 = *(u8*)(r0 + %[__imm_0]); \
374 r0 = 0; \
375 exit; \
376 " :
377 : __imm(bpf_sk_fullsock),
378 __imm_const(__imm_0, offsetof(struct bpf_sock, dst_port) + 2),
379 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk))
380 : __clobber_all);
381 }
382
383 SEC("cgroup/skb")
384 __description("sk_fullsock(skb->sk): past sk->dst_port [half load] (invalid)")
385 __failure __msg("invalid sock access")
386 __failure_unpriv
dst_port_half_load_invalid_2(void)387 __naked void dst_port_half_load_invalid_2(void)
388 {
389 asm volatile (" \
390 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
391 if r1 != 0 goto l0_%=; \
392 r0 = 0; \
393 exit; \
394 l0_%=: call %[bpf_sk_fullsock]; \
395 if r0 != 0 goto l1_%=; \
396 r0 = 0; \
397 exit; \
398 l1_%=: r0 = *(u16*)(r0 + %[bpf_sock_dst_port__end]); \
399 r0 = 0; \
400 exit; \
401 " :
402 : __imm(bpf_sk_fullsock),
403 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
404 __imm_const(bpf_sock_dst_port__end, offsetofend(struct bpf_sock, dst_port))
405 : __clobber_all);
406 }
407
408 SEC("cgroup/skb")
409 __description("sk_fullsock(skb->sk): sk->dst_ip6 [load 2nd byte]")
410 __success __success_unpriv __retval(0)
dst_ip6_load_2nd_byte(void)411 __naked void dst_ip6_load_2nd_byte(void)
412 {
413 asm volatile (" \
414 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
415 if r1 != 0 goto l0_%=; \
416 r0 = 0; \
417 exit; \
418 l0_%=: call %[bpf_sk_fullsock]; \
419 if r0 != 0 goto l1_%=; \
420 r0 = 0; \
421 exit; \
422 l1_%=: r0 = *(u8*)(r0 + %[__imm_0]); \
423 r0 = 0; \
424 exit; \
425 " :
426 : __imm(bpf_sk_fullsock),
427 __imm_const(__imm_0, offsetof(struct bpf_sock, dst_ip6[0]) + 1),
428 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk))
429 : __clobber_all);
430 }
431
432 SEC("cgroup/skb")
433 __description("sk_fullsock(skb->sk): sk->type [narrow load]")
434 __success __success_unpriv __retval(0)
sk_sk_type_narrow_load(void)435 __naked void sk_sk_type_narrow_load(void)
436 {
437 asm volatile (" \
438 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
439 if r1 != 0 goto l0_%=; \
440 r0 = 0; \
441 exit; \
442 l0_%=: call %[bpf_sk_fullsock]; \
443 if r0 != 0 goto l1_%=; \
444 r0 = 0; \
445 exit; \
446 l1_%=: r0 = *(u8*)(r0 + %[bpf_sock_type]); \
447 r0 = 0; \
448 exit; \
449 " :
450 : __imm(bpf_sk_fullsock),
451 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
452 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type))
453 : __clobber_all);
454 }
455
456 SEC("cgroup/skb")
457 __description("sk_fullsock(skb->sk): sk->protocol [narrow load]")
458 __success __success_unpriv __retval(0)
sk_sk_protocol_narrow_load(void)459 __naked void sk_sk_protocol_narrow_load(void)
460 {
461 asm volatile (" \
462 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
463 if r1 != 0 goto l0_%=; \
464 r0 = 0; \
465 exit; \
466 l0_%=: call %[bpf_sk_fullsock]; \
467 if r0 != 0 goto l1_%=; \
468 r0 = 0; \
469 exit; \
470 l1_%=: r0 = *(u8*)(r0 + %[bpf_sock_protocol]); \
471 r0 = 0; \
472 exit; \
473 " :
474 : __imm(bpf_sk_fullsock),
475 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
476 __imm_const(bpf_sock_protocol, offsetof(struct bpf_sock, protocol))
477 : __clobber_all);
478 }
479
480 SEC("cgroup/skb")
481 __description("sk_fullsock(skb->sk): beyond last field")
482 __failure __msg("invalid sock access")
483 __failure_unpriv
skb_sk_beyond_last_field_1(void)484 __naked void skb_sk_beyond_last_field_1(void)
485 {
486 asm volatile (" \
487 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
488 if r1 != 0 goto l0_%=; \
489 r0 = 0; \
490 exit; \
491 l0_%=: call %[bpf_sk_fullsock]; \
492 if r0 != 0 goto l1_%=; \
493 r0 = 0; \
494 exit; \
495 l1_%=: r0 = *(u32*)(r0 + %[bpf_sock_rx_queue_mapping__end]);\
496 r0 = 0; \
497 exit; \
498 " :
499 : __imm(bpf_sk_fullsock),
500 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
501 __imm_const(bpf_sock_rx_queue_mapping__end, offsetofend(struct bpf_sock, rx_queue_mapping))
502 : __clobber_all);
503 }
504
505 SEC("cgroup/skb")
506 __description("bpf_tcp_sock(skb->sk): no !skb->sk check")
507 __failure __msg("type=sock_common_or_null expected=sock_common")
508 __failure_unpriv
sk_no_skb_sk_check_2(void)509 __naked void sk_no_skb_sk_check_2(void)
510 {
511 asm volatile (" \
512 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
513 call %[bpf_tcp_sock]; \
514 r0 = 0; \
515 exit; \
516 " :
517 : __imm(bpf_tcp_sock),
518 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk))
519 : __clobber_all);
520 }
521
522 SEC("cgroup/skb")
523 __description("bpf_tcp_sock(skb->sk): no NULL check on ret")
524 __failure __msg("invalid mem access 'tcp_sock_or_null'")
525 __failure_unpriv
no_null_check_on_ret_2(void)526 __naked void no_null_check_on_ret_2(void)
527 {
528 asm volatile (" \
529 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
530 if r1 != 0 goto l0_%=; \
531 r0 = 0; \
532 exit; \
533 l0_%=: call %[bpf_tcp_sock]; \
534 r0 = *(u32*)(r0 + %[bpf_tcp_sock_snd_cwnd]); \
535 r0 = 0; \
536 exit; \
537 " :
538 : __imm(bpf_tcp_sock),
539 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
540 __imm_const(bpf_tcp_sock_snd_cwnd, offsetof(struct bpf_tcp_sock, snd_cwnd))
541 : __clobber_all);
542 }
543
544 SEC("cgroup/skb")
545 __description("bpf_tcp_sock(skb->sk): tp->snd_cwnd")
546 __success __success_unpriv __retval(0)
skb_sk_tp_snd_cwnd_1(void)547 __naked void skb_sk_tp_snd_cwnd_1(void)
548 {
549 asm volatile (" \
550 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
551 if r1 != 0 goto l0_%=; \
552 r0 = 0; \
553 exit; \
554 l0_%=: call %[bpf_tcp_sock]; \
555 if r0 != 0 goto l1_%=; \
556 exit; \
557 l1_%=: r0 = *(u32*)(r0 + %[bpf_tcp_sock_snd_cwnd]); \
558 r0 = 0; \
559 exit; \
560 " :
561 : __imm(bpf_tcp_sock),
562 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
563 __imm_const(bpf_tcp_sock_snd_cwnd, offsetof(struct bpf_tcp_sock, snd_cwnd))
564 : __clobber_all);
565 }
566
567 SEC("cgroup/skb")
568 __description("bpf_tcp_sock(skb->sk): tp->bytes_acked")
569 __success __success_unpriv __retval(0)
skb_sk_tp_bytes_acked(void)570 __naked void skb_sk_tp_bytes_acked(void)
571 {
572 asm volatile (" \
573 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
574 if r1 != 0 goto l0_%=; \
575 r0 = 0; \
576 exit; \
577 l0_%=: call %[bpf_tcp_sock]; \
578 if r0 != 0 goto l1_%=; \
579 exit; \
580 l1_%=: r0 = *(u64*)(r0 + %[bpf_tcp_sock_bytes_acked]); \
581 r0 = 0; \
582 exit; \
583 " :
584 : __imm(bpf_tcp_sock),
585 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
586 __imm_const(bpf_tcp_sock_bytes_acked, offsetof(struct bpf_tcp_sock, bytes_acked))
587 : __clobber_all);
588 }
589
590 SEC("cgroup/skb")
591 __description("bpf_tcp_sock(skb->sk): beyond last field")
592 __failure __msg("invalid tcp_sock access")
593 __failure_unpriv
skb_sk_beyond_last_field_2(void)594 __naked void skb_sk_beyond_last_field_2(void)
595 {
596 asm volatile (" \
597 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
598 if r1 != 0 goto l0_%=; \
599 r0 = 0; \
600 exit; \
601 l0_%=: call %[bpf_tcp_sock]; \
602 if r0 != 0 goto l1_%=; \
603 exit; \
604 l1_%=: r0 = *(u64*)(r0 + %[bpf_tcp_sock_bytes_acked__end]);\
605 r0 = 0; \
606 exit; \
607 " :
608 : __imm(bpf_tcp_sock),
609 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
610 __imm_const(bpf_tcp_sock_bytes_acked__end, offsetofend(struct bpf_tcp_sock, bytes_acked))
611 : __clobber_all);
612 }
613
614 SEC("cgroup/skb")
615 __description("bpf_tcp_sock(bpf_sk_fullsock(skb->sk)): tp->snd_cwnd")
616 __success __success_unpriv __retval(0)
skb_sk_tp_snd_cwnd_2(void)617 __naked void skb_sk_tp_snd_cwnd_2(void)
618 {
619 asm volatile (" \
620 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
621 if r1 != 0 goto l0_%=; \
622 r0 = 0; \
623 exit; \
624 l0_%=: call %[bpf_sk_fullsock]; \
625 if r0 != 0 goto l1_%=; \
626 exit; \
627 l1_%=: r1 = r0; \
628 call %[bpf_tcp_sock]; \
629 if r0 != 0 goto l2_%=; \
630 exit; \
631 l2_%=: r0 = *(u32*)(r0 + %[bpf_tcp_sock_snd_cwnd]); \
632 r0 = 0; \
633 exit; \
634 " :
635 : __imm(bpf_sk_fullsock),
636 __imm(bpf_tcp_sock),
637 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk)),
638 __imm_const(bpf_tcp_sock_snd_cwnd, offsetof(struct bpf_tcp_sock, snd_cwnd))
639 : __clobber_all);
640 }
641
642 SEC("tc")
643 __description("bpf_sk_release(skb->sk)")
644 __failure __msg("release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
bpf_sk_release_skb_sk(void)645 __naked void bpf_sk_release_skb_sk(void)
646 {
647 asm volatile (" \
648 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
649 if r1 == 0 goto l0_%=; \
650 call %[bpf_sk_release]; \
651 l0_%=: r0 = 0; \
652 exit; \
653 " :
654 : __imm(bpf_sk_release),
655 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk))
656 : __clobber_all);
657 }
658
659 SEC("tc")
660 __description("bpf_sk_release(bpf_sk_fullsock(skb->sk))")
661 __failure __msg("release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
bpf_sk_fullsock_skb_sk(void)662 __naked void bpf_sk_fullsock_skb_sk(void)
663 {
664 asm volatile (" \
665 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
666 if r1 != 0 goto l0_%=; \
667 r0 = 0; \
668 exit; \
669 l0_%=: call %[bpf_sk_fullsock]; \
670 if r0 != 0 goto l1_%=; \
671 exit; \
672 l1_%=: r1 = r0; \
673 call %[bpf_sk_release]; \
674 r0 = 1; \
675 exit; \
676 " :
677 : __imm(bpf_sk_fullsock),
678 __imm(bpf_sk_release),
679 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk))
680 : __clobber_all);
681 }
682
683 SEC("tc")
684 __description("bpf_sk_release(bpf_tcp_sock(skb->sk))")
685 __failure __msg("release helper bpf_sk_release expects referenced PTR_TO_BTF_ID passed to R1")
bpf_tcp_sock_skb_sk(void)686 __naked void bpf_tcp_sock_skb_sk(void)
687 {
688 asm volatile (" \
689 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
690 if r1 != 0 goto l0_%=; \
691 r0 = 0; \
692 exit; \
693 l0_%=: call %[bpf_tcp_sock]; \
694 if r0 != 0 goto l1_%=; \
695 exit; \
696 l1_%=: r1 = r0; \
697 call %[bpf_sk_release]; \
698 r0 = 1; \
699 exit; \
700 " :
701 : __imm(bpf_sk_release),
702 __imm(bpf_tcp_sock),
703 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk))
704 : __clobber_all);
705 }
706
707 SEC("tc")
708 __description("sk_storage_get(map, skb->sk, NULL, 0): value == NULL")
709 __success __retval(0)
sk_null_0_value_null(void)710 __naked void sk_null_0_value_null(void)
711 {
712 asm volatile (" \
713 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
714 if r1 != 0 goto l0_%=; \
715 r0 = 0; \
716 exit; \
717 l0_%=: call %[bpf_sk_fullsock]; \
718 if r0 != 0 goto l1_%=; \
719 r0 = 0; \
720 exit; \
721 l1_%=: r4 = 0; \
722 r3 = 0; \
723 r2 = r0; \
724 r1 = %[sk_storage_map] ll; \
725 call %[bpf_sk_storage_get]; \
726 r0 = 0; \
727 exit; \
728 " :
729 : __imm(bpf_sk_fullsock),
730 __imm(bpf_sk_storage_get),
731 __imm_addr(sk_storage_map),
732 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk))
733 : __clobber_all);
734 }
735
736 SEC("tc")
737 __description("sk_storage_get(map, skb->sk, 1, 1): value == 1")
738 __failure __msg("R3 type=scalar expected=fp")
sk_1_1_value_1(void)739 __naked void sk_1_1_value_1(void)
740 {
741 asm volatile (" \
742 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
743 if r1 != 0 goto l0_%=; \
744 r0 = 0; \
745 exit; \
746 l0_%=: call %[bpf_sk_fullsock]; \
747 if r0 != 0 goto l1_%=; \
748 r0 = 0; \
749 exit; \
750 l1_%=: r4 = 1; \
751 r3 = 1; \
752 r2 = r0; \
753 r1 = %[sk_storage_map] ll; \
754 call %[bpf_sk_storage_get]; \
755 r0 = 0; \
756 exit; \
757 " :
758 : __imm(bpf_sk_fullsock),
759 __imm(bpf_sk_storage_get),
760 __imm_addr(sk_storage_map),
761 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk))
762 : __clobber_all);
763 }
764
765 SEC("tc")
766 __description("sk_storage_get(map, skb->sk, &stack_value, 1): stack_value")
767 __success __retval(0)
stack_value_1_stack_value(void)768 __naked void stack_value_1_stack_value(void)
769 {
770 asm volatile (" \
771 r2 = 0; \
772 *(u64*)(r10 - 8) = r2; \
773 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
774 if r1 != 0 goto l0_%=; \
775 r0 = 0; \
776 exit; \
777 l0_%=: call %[bpf_sk_fullsock]; \
778 if r0 != 0 goto l1_%=; \
779 r0 = 0; \
780 exit; \
781 l1_%=: r4 = 1; \
782 r3 = r10; \
783 r3 += -8; \
784 r2 = r0; \
785 r1 = %[sk_storage_map] ll; \
786 call %[bpf_sk_storage_get]; \
787 r0 = 0; \
788 exit; \
789 " :
790 : __imm(bpf_sk_fullsock),
791 __imm(bpf_sk_storage_get),
792 __imm_addr(sk_storage_map),
793 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk))
794 : __clobber_all);
795 }
796
797 SEC("tc")
798 __description("bpf_map_lookup_elem(smap, &key)")
799 __failure __msg("cannot pass map_type 24 into func bpf_map_lookup_elem")
map_lookup_elem_smap_key(void)800 __naked void map_lookup_elem_smap_key(void)
801 {
802 asm volatile (" \
803 r1 = 0; \
804 *(u32*)(r10 - 4) = r1; \
805 r2 = r10; \
806 r2 += -4; \
807 r1 = %[sk_storage_map] ll; \
808 call %[bpf_map_lookup_elem]; \
809 r0 = 0; \
810 exit; \
811 " :
812 : __imm(bpf_map_lookup_elem),
813 __imm_addr(sk_storage_map)
814 : __clobber_all);
815 }
816
817 SEC("xdp")
818 __description("bpf_map_lookup_elem(xskmap, &key); xs->queue_id")
819 __success __retval(0)
xskmap_key_xs_queue_id(void)820 __naked void xskmap_key_xs_queue_id(void)
821 {
822 asm volatile (" \
823 r1 = 0; \
824 *(u32*)(r10 - 8) = r1; \
825 r2 = r10; \
826 r2 += -8; \
827 r1 = %[map_xskmap] ll; \
828 call %[bpf_map_lookup_elem]; \
829 if r0 != 0 goto l0_%=; \
830 exit; \
831 l0_%=: r0 = *(u32*)(r0 + %[bpf_xdp_sock_queue_id]); \
832 r0 = 0; \
833 exit; \
834 " :
835 : __imm(bpf_map_lookup_elem),
836 __imm_addr(map_xskmap),
837 __imm_const(bpf_xdp_sock_queue_id, offsetof(struct bpf_xdp_sock, queue_id))
838 : __clobber_all);
839 }
840
841 SEC("sk_skb")
842 __description("bpf_map_lookup_elem(sockmap, &key)")
843 __failure __msg("Unreleased reference id=2 alloc_insn=6")
map_lookup_elem_sockmap_key(void)844 __naked void map_lookup_elem_sockmap_key(void)
845 {
846 asm volatile (" \
847 r1 = 0; \
848 *(u32*)(r10 - 4) = r1; \
849 r2 = r10; \
850 r2 += -4; \
851 r1 = %[map_sockmap] ll; \
852 call %[bpf_map_lookup_elem]; \
853 r0 = 0; \
854 exit; \
855 " :
856 : __imm(bpf_map_lookup_elem),
857 __imm_addr(map_sockmap)
858 : __clobber_all);
859 }
860
861 SEC("sk_skb")
862 __description("bpf_map_lookup_elem(sockhash, &key)")
863 __failure __msg("Unreleased reference id=2 alloc_insn=6")
map_lookup_elem_sockhash_key(void)864 __naked void map_lookup_elem_sockhash_key(void)
865 {
866 asm volatile (" \
867 r1 = 0; \
868 *(u32*)(r10 - 4) = r1; \
869 r2 = r10; \
870 r2 += -4; \
871 r1 = %[map_sockhash] ll; \
872 call %[bpf_map_lookup_elem]; \
873 r0 = 0; \
874 exit; \
875 " :
876 : __imm(bpf_map_lookup_elem),
877 __imm_addr(map_sockhash)
878 : __clobber_all);
879 }
880
881 SEC("sk_skb")
882 __description("bpf_map_lookup_elem(sockmap, &key); sk->type [fullsock field]; bpf_sk_release(sk)")
883 __success
field_bpf_sk_release_sk_1(void)884 __naked void field_bpf_sk_release_sk_1(void)
885 {
886 asm volatile (" \
887 r1 = 0; \
888 *(u32*)(r10 - 4) = r1; \
889 r2 = r10; \
890 r2 += -4; \
891 r1 = %[map_sockmap] ll; \
892 call %[bpf_map_lookup_elem]; \
893 if r0 != 0 goto l0_%=; \
894 exit; \
895 l0_%=: r1 = r0; \
896 r0 = *(u32*)(r0 + %[bpf_sock_type]); \
897 call %[bpf_sk_release]; \
898 exit; \
899 " :
900 : __imm(bpf_map_lookup_elem),
901 __imm(bpf_sk_release),
902 __imm_addr(map_sockmap),
903 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type))
904 : __clobber_all);
905 }
906
907 SEC("sk_skb")
908 __description("bpf_map_lookup_elem(sockhash, &key); sk->type [fullsock field]; bpf_sk_release(sk)")
909 __success
field_bpf_sk_release_sk_2(void)910 __naked void field_bpf_sk_release_sk_2(void)
911 {
912 asm volatile (" \
913 r1 = 0; \
914 *(u32*)(r10 - 4) = r1; \
915 r2 = r10; \
916 r2 += -4; \
917 r1 = %[map_sockhash] ll; \
918 call %[bpf_map_lookup_elem]; \
919 if r0 != 0 goto l0_%=; \
920 exit; \
921 l0_%=: r1 = r0; \
922 r0 = *(u32*)(r0 + %[bpf_sock_type]); \
923 call %[bpf_sk_release]; \
924 exit; \
925 " :
926 : __imm(bpf_map_lookup_elem),
927 __imm(bpf_sk_release),
928 __imm_addr(map_sockhash),
929 __imm_const(bpf_sock_type, offsetof(struct bpf_sock, type))
930 : __clobber_all);
931 }
932
933 SEC("sk_reuseport")
934 __description("bpf_sk_select_reuseport(ctx, reuseport_array, &key, flags)")
935 __success
ctx_reuseport_array_key_flags(void)936 __naked void ctx_reuseport_array_key_flags(void)
937 {
938 asm volatile (" \
939 r4 = 0; \
940 r2 = 0; \
941 *(u32*)(r10 - 4) = r2; \
942 r3 = r10; \
943 r3 += -4; \
944 r2 = %[map_reuseport_array] ll; \
945 call %[bpf_sk_select_reuseport]; \
946 exit; \
947 " :
948 : __imm(bpf_sk_select_reuseport),
949 __imm_addr(map_reuseport_array)
950 : __clobber_all);
951 }
952
953 SEC("sk_reuseport")
954 __description("bpf_sk_select_reuseport(ctx, sockmap, &key, flags)")
955 __success
reuseport_ctx_sockmap_key_flags(void)956 __naked void reuseport_ctx_sockmap_key_flags(void)
957 {
958 asm volatile (" \
959 r4 = 0; \
960 r2 = 0; \
961 *(u32*)(r10 - 4) = r2; \
962 r3 = r10; \
963 r3 += -4; \
964 r2 = %[map_sockmap] ll; \
965 call %[bpf_sk_select_reuseport]; \
966 exit; \
967 " :
968 : __imm(bpf_sk_select_reuseport),
969 __imm_addr(map_sockmap)
970 : __clobber_all);
971 }
972
973 SEC("sk_reuseport")
974 __description("bpf_sk_select_reuseport(ctx, sockhash, &key, flags)")
975 __success
reuseport_ctx_sockhash_key_flags(void)976 __naked void reuseport_ctx_sockhash_key_flags(void)
977 {
978 asm volatile (" \
979 r4 = 0; \
980 r2 = 0; \
981 *(u32*)(r10 - 4) = r2; \
982 r3 = r10; \
983 r3 += -4; \
984 r2 = %[map_sockmap] ll; \
985 call %[bpf_sk_select_reuseport]; \
986 exit; \
987 " :
988 : __imm(bpf_sk_select_reuseport),
989 __imm_addr(map_sockmap)
990 : __clobber_all);
991 }
992
993 SEC("tc")
994 __description("mark null check on return value of bpf_skc_to helpers")
995 __failure __msg("invalid mem access")
of_bpf_skc_to_helpers(void)996 __naked void of_bpf_skc_to_helpers(void)
997 {
998 asm volatile (" \
999 r1 = *(u64*)(r1 + %[__sk_buff_sk]); \
1000 if r1 != 0 goto l0_%=; \
1001 r0 = 0; \
1002 exit; \
1003 l0_%=: r6 = r1; \
1004 call %[bpf_skc_to_tcp_sock]; \
1005 r7 = r0; \
1006 r1 = r6; \
1007 call %[bpf_skc_to_tcp_request_sock]; \
1008 r8 = r0; \
1009 if r8 != 0 goto l1_%=; \
1010 r0 = 0; \
1011 exit; \
1012 l1_%=: r0 = *(u8*)(r7 + 0); \
1013 exit; \
1014 " :
1015 : __imm(bpf_skc_to_tcp_request_sock),
1016 __imm(bpf_skc_to_tcp_sock),
1017 __imm_const(__sk_buff_sk, offsetof(struct __sk_buff, sk))
1018 : __clobber_all);
1019 }
1020
1021 SEC("cgroup/post_bind4")
1022 __description("sk->src_ip6[0] [load 1st byte]")
1023 __failure __msg("invalid bpf_context access off=28 size=2")
post_bind4_read_src_ip6(void)1024 __naked void post_bind4_read_src_ip6(void)
1025 {
1026 asm volatile (" \
1027 r6 = r1; \
1028 r7 = *(u16*)(r6 + %[bpf_sock_src_ip6_0]); \
1029 r0 = 1; \
1030 exit; \
1031 " :
1032 : __imm_const(bpf_sock_src_ip6_0, offsetof(struct bpf_sock, src_ip6[0]))
1033 : __clobber_all);
1034 }
1035
1036 SEC("cgroup/post_bind4")
1037 __description("sk->mark [load mark]")
1038 __failure __msg("invalid bpf_context access off=16 size=2")
post_bind4_read_mark(void)1039 __naked void post_bind4_read_mark(void)
1040 {
1041 asm volatile (" \
1042 r6 = r1; \
1043 r7 = *(u16*)(r6 + %[bpf_sock_mark]); \
1044 r0 = 1; \
1045 exit; \
1046 " :
1047 : __imm_const(bpf_sock_mark, offsetof(struct bpf_sock, mark))
1048 : __clobber_all);
1049 }
1050
1051 SEC("cgroup/post_bind6")
1052 __description("sk->src_ip4 [load src_ip4]")
1053 __failure __msg("invalid bpf_context access off=24 size=2")
post_bind6_read_src_ip4(void)1054 __naked void post_bind6_read_src_ip4(void)
1055 {
1056 asm volatile (" \
1057 r6 = r1; \
1058 r7 = *(u16*)(r6 + %[bpf_sock_src_ip4]); \
1059 r0 = 1; \
1060 exit; \
1061 " :
1062 : __imm_const(bpf_sock_src_ip4, offsetof(struct bpf_sock, src_ip4))
1063 : __clobber_all);
1064 }
1065
1066 SEC("cgroup/sock_create")
1067 __description("sk->src_port [word load]")
1068 __failure __msg("invalid bpf_context access off=44 size=2")
sock_create_read_src_port(void)1069 __naked void sock_create_read_src_port(void)
1070 {
1071 asm volatile (" \
1072 r6 = r1; \
1073 r7 = *(u16*)(r6 + %[bpf_sock_src_port]); \
1074 r0 = 1; \
1075 exit; \
1076 " :
1077 : __imm_const(bpf_sock_src_port, offsetof(struct bpf_sock, src_port))
1078 : __clobber_all);
1079 }
1080
1081 __noinline
skb_pull_data2(struct __sk_buff * sk,__u32 len)1082 long skb_pull_data2(struct __sk_buff *sk, __u32 len)
1083 {
1084 return bpf_skb_pull_data(sk, len);
1085 }
1086
1087 __noinline
skb_pull_data1(struct __sk_buff * sk,__u32 len)1088 long skb_pull_data1(struct __sk_buff *sk, __u32 len)
1089 {
1090 return skb_pull_data2(sk, len);
1091 }
1092
1093 /* global function calls bpf_skb_pull_data(), which invalidates packet
1094 * pointers established before global function call.
1095 */
1096 SEC("tc")
1097 __failure __msg("invalid mem access")
invalidate_pkt_pointers_from_global_func(struct __sk_buff * sk)1098 int invalidate_pkt_pointers_from_global_func(struct __sk_buff *sk)
1099 {
1100 int *p = (void *)(long)sk->data;
1101
1102 if ((void *)(p + 1) > (void *)(long)sk->data_end)
1103 return TCX_DROP;
1104 skb_pull_data1(sk, 0);
1105 *p = 42; /* this is unsafe */
1106 return TCX_PASS;
1107 }
1108
1109 __noinline
xdp_pull_data2(struct xdp_md * x,__u32 len)1110 long xdp_pull_data2(struct xdp_md *x, __u32 len)
1111 {
1112 return bpf_xdp_pull_data(x, len);
1113 }
1114
1115 __noinline
xdp_pull_data1(struct xdp_md * x,__u32 len)1116 long xdp_pull_data1(struct xdp_md *x, __u32 len)
1117 {
1118 return xdp_pull_data2(x, len);
1119 }
1120
1121 /* global function calls bpf_xdp_pull_data(), which invalidates packet
1122 * pointers established before global function call.
1123 */
1124 SEC("xdp")
1125 __failure __msg("invalid mem access")
invalidate_xdp_pkt_pointers_from_global_func(struct xdp_md * x)1126 int invalidate_xdp_pkt_pointers_from_global_func(struct xdp_md *x)
1127 {
1128 int *p = (void *)(long)x->data;
1129
1130 if ((void *)(p + 1) > (void *)(long)x->data_end)
1131 return XDP_DROP;
1132 xdp_pull_data1(x, 0);
1133 *p = 42; /* this is unsafe */
1134 return XDP_PASS;
1135 }
1136
1137 /* XDP packet changing kfunc calls invalidate packet pointers */
1138 SEC("xdp")
1139 __failure __msg("invalid mem access")
invalidate_xdp_pkt_pointers(struct xdp_md * x)1140 int invalidate_xdp_pkt_pointers(struct xdp_md *x)
1141 {
1142 int *p = (void *)(long)x->data;
1143
1144 if ((void *)(p + 1) > (void *)(long)x->data_end)
1145 return XDP_DROP;
1146 bpf_xdp_pull_data(x, 0);
1147 *p = 42; /* this is unsafe */
1148 return XDP_PASS;
1149 }
1150
1151 __noinline
tail_call(struct __sk_buff * sk)1152 int tail_call(struct __sk_buff *sk)
1153 {
1154 bpf_tail_call_static(sk, &jmp_table, 0);
1155 return 0;
1156 }
1157
1158 static __noinline
static_tail_call(struct __sk_buff * sk)1159 int static_tail_call(struct __sk_buff *sk)
1160 {
1161 int ret = 0;
1162
1163 bpf_tail_call_static(sk, &jmp_table, 0);
1164 barrier_var(ret);
1165 return ret;
1166 }
1167
1168 /* Tail calls in sub-programs invalidate packet pointers. */
1169 SEC("tc")
1170 __failure __msg("invalid mem access")
invalidate_pkt_pointers_by_global_tail_call(struct __sk_buff * sk)1171 int invalidate_pkt_pointers_by_global_tail_call(struct __sk_buff *sk)
1172 {
1173 int *p = (void *)(long)sk->data;
1174
1175 if ((void *)(p + 1) > (void *)(long)sk->data_end)
1176 return TCX_DROP;
1177 tail_call(sk);
1178 *p = 42; /* this is unsafe */
1179 return TCX_PASS;
1180 }
1181
1182 /* Tail calls in static sub-programs invalidate packet pointers. */
1183 SEC("tc")
1184 __failure __msg("invalid mem access")
invalidate_pkt_pointers_by_static_tail_call(struct __sk_buff * sk)1185 int invalidate_pkt_pointers_by_static_tail_call(struct __sk_buff *sk)
1186 {
1187 int *p = (void *)(long)sk->data;
1188 int ret;
1189
1190 if ((void *)(p + 1) > (void *)(long)sk->data_end)
1191 return TCX_DROP;
1192 ret = static_tail_call(sk);
1193 __sink(ret);
1194 *p = 42; /* this is unsafe */
1195 return TCX_PASS;
1196 }
1197
1198 /* Direct tail calls do not invalidate packet pointers. */
1199 SEC("tc")
1200 __success
invalidate_pkt_pointers_by_tail_call(struct __sk_buff * sk)1201 int invalidate_pkt_pointers_by_tail_call(struct __sk_buff *sk)
1202 {
1203 int *p = (void *)(long)sk->data;
1204
1205 if ((void *)(p + 1) > (void *)(long)sk->data_end)
1206 return TCX_DROP;
1207 bpf_tail_call_static(sk, &jmp_table, 0);
1208 *p = 42; /* this is NOT unsafe: tail calls don't return */
1209 return TCX_PASS;
1210 }
1211
1212 char _license[] SEC("license") = "GPL";
1213