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