xref: /linux/tools/testing/selftests/bpf/progs/verifier_flow_keys.c (revision b2128290c29902315e632ea59e0504d6bc9e9b42)
1*3ce6b424SNuoqi Gui // SPDX-License-Identifier: GPL-2.0
2*3ce6b424SNuoqi Gui /* Bounds checks for PTR_TO_FLOW_KEYS pointer arithmetic. */
3*3ce6b424SNuoqi Gui 
4*3ce6b424SNuoqi Gui #include "vmlinux.h"
5*3ce6b424SNuoqi Gui #include <bpf/bpf_helpers.h>
6*3ce6b424SNuoqi Gui #include "bpf_misc.h"
7*3ce6b424SNuoqi Gui 
8*3ce6b424SNuoqi Gui /* sizeof(struct bpf_flow_keys) is well under 4096, so +0x1000 is OOB. */
9*3ce6b424SNuoqi Gui 
10*3ce6b424SNuoqi Gui SEC("flow_dissector")
11*3ce6b424SNuoqi Gui __description("flow_keys: in-bounds constant pointer arithmetic accepted")
12*3ce6b424SNuoqi Gui __success
13*3ce6b424SNuoqi Gui __naked void flow_keys_const_inbounds(void)
14*3ce6b424SNuoqi Gui {
15*3ce6b424SNuoqi Gui 	asm volatile ("					\
16*3ce6b424SNuoqi Gui 	r1 = *(u64 *)(r1 + %[flow_keys]);		\
17*3ce6b424SNuoqi Gui 	r1 += 8;					\
18*3ce6b424SNuoqi Gui 	r0 = *(u64 *)(r1 + 0);				\
19*3ce6b424SNuoqi Gui 	r0 = 0;						\
20*3ce6b424SNuoqi Gui 	exit;						\
21*3ce6b424SNuoqi Gui "	:
22*3ce6b424SNuoqi Gui 	: __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys))
23*3ce6b424SNuoqi Gui 	: __clobber_all);
24*3ce6b424SNuoqi Gui }
25*3ce6b424SNuoqi Gui 
26*3ce6b424SNuoqi Gui SEC("flow_dissector")
27*3ce6b424SNuoqi Gui __description("flow_keys: OOB via constant pointer arithmetic rejected")
28*3ce6b424SNuoqi Gui __failure __msg("invalid access to flow keys off=4096 size=8")
29*3ce6b424SNuoqi Gui __naked void flow_keys_const_oob_read(void)
30*3ce6b424SNuoqi Gui {
31*3ce6b424SNuoqi Gui 	asm volatile ("					\
32*3ce6b424SNuoqi Gui 	r1 = *(u64 *)(r1 + %[flow_keys]);		\
33*3ce6b424SNuoqi Gui 	r1 += 4096;					\
34*3ce6b424SNuoqi Gui 	r0 = *(u64 *)(r1 + 0);				\
35*3ce6b424SNuoqi Gui 	r0 = 0;						\
36*3ce6b424SNuoqi Gui 	exit;						\
37*3ce6b424SNuoqi Gui "	:
38*3ce6b424SNuoqi Gui 	: __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys))
39*3ce6b424SNuoqi Gui 	: __clobber_all);
40*3ce6b424SNuoqi Gui }
41*3ce6b424SNuoqi Gui 
42*3ce6b424SNuoqi Gui SEC("flow_dissector")
43*3ce6b424SNuoqi Gui __description("flow_keys: OOB write via constant pointer arithmetic rejected")
44*3ce6b424SNuoqi Gui __failure __msg("invalid access to flow keys off=4096 size=8")
45*3ce6b424SNuoqi Gui __naked void flow_keys_const_oob_write(void)
46*3ce6b424SNuoqi Gui {
47*3ce6b424SNuoqi Gui 	asm volatile ("					\
48*3ce6b424SNuoqi Gui 	r1 = *(u64 *)(r1 + %[flow_keys]);		\
49*3ce6b424SNuoqi Gui 	r1 += 4096;					\
50*3ce6b424SNuoqi Gui 	r2 = 0;						\
51*3ce6b424SNuoqi Gui 	*(u64 *)(r1 + 0) = r2;				\
52*3ce6b424SNuoqi Gui 	r0 = 0;						\
53*3ce6b424SNuoqi Gui 	exit;						\
54*3ce6b424SNuoqi Gui "	:
55*3ce6b424SNuoqi Gui 	: __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys))
56*3ce6b424SNuoqi Gui 	: __clobber_all);
57*3ce6b424SNuoqi Gui }
58*3ce6b424SNuoqi Gui 
59*3ce6b424SNuoqi Gui /* Equivalent OOB expressed directly in insn->off; this form was always
60*3ce6b424SNuoqi Gui  * rejected and is kept to show both forms now share one diagnostic.
61*3ce6b424SNuoqi Gui  */
62*3ce6b424SNuoqi Gui SEC("flow_dissector")
63*3ce6b424SNuoqi Gui __description("flow_keys: OOB via insn->off rejected")
64*3ce6b424SNuoqi Gui __failure __msg("invalid access to flow keys off=4096 size=8")
65*3ce6b424SNuoqi Gui __naked void flow_keys_insn_off_oob(void)
66*3ce6b424SNuoqi Gui {
67*3ce6b424SNuoqi Gui 	asm volatile ("					\
68*3ce6b424SNuoqi Gui 	r1 = *(u64 *)(r1 + %[flow_keys]);		\
69*3ce6b424SNuoqi Gui 	r0 = *(u64 *)(r1 + 4096);			\
70*3ce6b424SNuoqi Gui 	r0 = 0;						\
71*3ce6b424SNuoqi Gui 	exit;						\
72*3ce6b424SNuoqi Gui "	:
73*3ce6b424SNuoqi Gui 	: __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys))
74*3ce6b424SNuoqi Gui 	: __clobber_all);
75*3ce6b424SNuoqi Gui }
76*3ce6b424SNuoqi Gui 
77*3ce6b424SNuoqi Gui SEC("flow_dissector")
78*3ce6b424SNuoqi Gui __description("flow_keys: variable pointer arithmetic rejected")
79*3ce6b424SNuoqi Gui __failure __msg("R1 pointer arithmetic on flow_keys prohibited")
80*3ce6b424SNuoqi Gui __naked void flow_keys_var_read(void)
81*3ce6b424SNuoqi Gui {
82*3ce6b424SNuoqi Gui 	asm volatile ("					\
83*3ce6b424SNuoqi Gui 	r6 = r1;					\
84*3ce6b424SNuoqi Gui 	call %[bpf_get_prandom_u32];			\
85*3ce6b424SNuoqi Gui 	r0 &= 0xFFFF;					\
86*3ce6b424SNuoqi Gui 	r1 = *(u64 *)(r6 + %[flow_keys]);		\
87*3ce6b424SNuoqi Gui 	r1 += r0;					\
88*3ce6b424SNuoqi Gui 	r0 = *(u64 *)(r1 + 0);				\
89*3ce6b424SNuoqi Gui 	r0 = 0;						\
90*3ce6b424SNuoqi Gui 	exit;						\
91*3ce6b424SNuoqi Gui "	:
92*3ce6b424SNuoqi Gui 	: __imm_const(flow_keys, offsetof(struct __sk_buff, flow_keys)),
93*3ce6b424SNuoqi Gui 	  __imm(bpf_get_prandom_u32)
94*3ce6b424SNuoqi Gui 	: __clobber_all);
95*3ce6b424SNuoqi Gui }
96*3ce6b424SNuoqi Gui 
97*3ce6b424SNuoqi Gui char _license[] SEC("license") = "GPL";
98