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