xref: /linux/tools/testing/selftests/bpf/progs/verifier_sock.c (revision fbc988f236a60cf50a89da78fc6b7213daa9999c)
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
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)
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)
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)
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
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
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
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)
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)
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)
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)
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)
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
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)
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
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
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)
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)
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)
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
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
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
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)
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)
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
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)
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")
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")
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")
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)
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")
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)
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")
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)
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")
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")
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
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
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
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
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
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")
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")
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")
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")
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")
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
1082 long skb_pull_data2(struct __sk_buff *sk, __u32 len)
1083 {
1084 	return bpf_skb_pull_data(sk, len);
1085 }
1086 
1087 __noinline
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")
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
1110 long xdp_pull_data2(struct xdp_md *x, __u32 len)
1111 {
1112 	return bpf_xdp_pull_data(x, len);
1113 }
1114 
1115 __noinline
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")
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")
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
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
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")
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")
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
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