xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/bpf/verifier/var_off.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun {
2*4882a593Smuzhiyun 	"variable-offset ctx access",
3*4882a593Smuzhiyun 	.insns = {
4*4882a593Smuzhiyun 	/* Get an unknown value */
5*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
6*4882a593Smuzhiyun 	/* Make it small and 4-byte aligned */
7*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
8*4882a593Smuzhiyun 	/* add it to skb.  We now have either &skb->len or
9*4882a593Smuzhiyun 	 * &skb->pkt_type, but we don't know which
10*4882a593Smuzhiyun 	 */
11*4882a593Smuzhiyun 	BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_2),
12*4882a593Smuzhiyun 	/* dereference it */
13*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_1, 0),
14*4882a593Smuzhiyun 	BPF_EXIT_INSN(),
15*4882a593Smuzhiyun 	},
16*4882a593Smuzhiyun 	.errstr = "variable ctx access var_off=(0x0; 0x4)",
17*4882a593Smuzhiyun 	.result = REJECT,
18*4882a593Smuzhiyun 	.prog_type = BPF_PROG_TYPE_LWT_IN,
19*4882a593Smuzhiyun },
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun 	"variable-offset stack read, priv vs unpriv",
22*4882a593Smuzhiyun 	.insns = {
23*4882a593Smuzhiyun 	/* Fill the top 8 bytes of the stack */
24*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
25*4882a593Smuzhiyun 	/* Get an unknown value */
26*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
27*4882a593Smuzhiyun 	/* Make it small and 4-byte aligned */
28*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
29*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8),
30*4882a593Smuzhiyun 	/* add it to fp.  We now have either fp-4 or fp-8, but
31*4882a593Smuzhiyun 	 * we don't know which
32*4882a593Smuzhiyun 	 */
33*4882a593Smuzhiyun 	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
34*4882a593Smuzhiyun 	/* dereference it for a stack read */
35*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0),
36*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_0, 0),
37*4882a593Smuzhiyun 	BPF_EXIT_INSN(),
38*4882a593Smuzhiyun 	},
39*4882a593Smuzhiyun 	.result = ACCEPT,
40*4882a593Smuzhiyun 	.result_unpriv = REJECT,
41*4882a593Smuzhiyun 	.errstr_unpriv = "R2 variable stack access prohibited for !root",
42*4882a593Smuzhiyun 	.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
43*4882a593Smuzhiyun },
44*4882a593Smuzhiyun {
45*4882a593Smuzhiyun 	"variable-offset stack read, uninitialized",
46*4882a593Smuzhiyun 	.insns = {
47*4882a593Smuzhiyun 	/* Get an unknown value */
48*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
49*4882a593Smuzhiyun 	/* Make it small and 4-byte aligned */
50*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
51*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8),
52*4882a593Smuzhiyun 	/* add it to fp.  We now have either fp-4 or fp-8, but
53*4882a593Smuzhiyun 	 * we don't know which
54*4882a593Smuzhiyun 	 */
55*4882a593Smuzhiyun 	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
56*4882a593Smuzhiyun 	/* dereference it for a stack read */
57*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 0),
58*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_0, 0),
59*4882a593Smuzhiyun 	BPF_EXIT_INSN(),
60*4882a593Smuzhiyun 	},
61*4882a593Smuzhiyun 	.result = REJECT,
62*4882a593Smuzhiyun 	.errstr = "invalid variable-offset read from stack R2",
63*4882a593Smuzhiyun 	.prog_type = BPF_PROG_TYPE_LWT_IN,
64*4882a593Smuzhiyun },
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	"variable-offset stack write, priv vs unpriv",
67*4882a593Smuzhiyun 	.insns = {
68*4882a593Smuzhiyun 	/* Get an unknown value */
69*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
70*4882a593Smuzhiyun 	/* Make it small and 8-byte aligned */
71*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 8),
72*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
73*4882a593Smuzhiyun 	/* Add it to fp.  We now have either fp-8 or fp-16, but
74*4882a593Smuzhiyun 	 * we don't know which
75*4882a593Smuzhiyun 	 */
76*4882a593Smuzhiyun 	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
77*4882a593Smuzhiyun 	/* Dereference it for a stack write */
78*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
79*4882a593Smuzhiyun 	/* Now read from the address we just wrote. This shows
80*4882a593Smuzhiyun 	 * that, after a variable-offset write, a priviledged
81*4882a593Smuzhiyun 	 * program can read the slots that were in the range of
82*4882a593Smuzhiyun 	 * that write (even if the verifier doesn't actually know
83*4882a593Smuzhiyun 	 * if the slot being read was really written to or not.
84*4882a593Smuzhiyun 	 */
85*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_2, 0),
86*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_0, 0),
87*4882a593Smuzhiyun 	BPF_EXIT_INSN(),
88*4882a593Smuzhiyun 	},
89*4882a593Smuzhiyun 	/* Variable stack access is rejected for unprivileged.
90*4882a593Smuzhiyun 	 */
91*4882a593Smuzhiyun 	.errstr_unpriv = "R2 variable stack access prohibited for !root",
92*4882a593Smuzhiyun 	.result_unpriv = REJECT,
93*4882a593Smuzhiyun 	.result = ACCEPT,
94*4882a593Smuzhiyun },
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	"variable-offset stack write clobbers spilled regs",
97*4882a593Smuzhiyun 	.insns = {
98*4882a593Smuzhiyun 	/* Dummy instruction; needed because we need to patch the next one
99*4882a593Smuzhiyun 	 * and we can't patch the first instruction.
100*4882a593Smuzhiyun 	 */
101*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_6, 0),
102*4882a593Smuzhiyun 	/* Make R0 a map ptr */
103*4882a593Smuzhiyun 	BPF_LD_MAP_FD(BPF_REG_0, 0),
104*4882a593Smuzhiyun 	/* Get an unknown value */
105*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
106*4882a593Smuzhiyun 	/* Make it small and 8-byte aligned */
107*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 8),
108*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
109*4882a593Smuzhiyun 	/* Add it to fp. We now have either fp-8 or fp-16, but
110*4882a593Smuzhiyun 	 * we don't know which.
111*4882a593Smuzhiyun 	 */
112*4882a593Smuzhiyun 	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
113*4882a593Smuzhiyun 	/* Spill R0(map ptr) into stack */
114*4882a593Smuzhiyun 	BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8),
115*4882a593Smuzhiyun 	/* Dereference the unknown value for a stack write */
116*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),
117*4882a593Smuzhiyun 	/* Fill the register back into R2 */
118*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_10, -8),
119*4882a593Smuzhiyun 	/* Try to dereference R2 for a memory load */
120*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_2, 8),
121*4882a593Smuzhiyun 	BPF_EXIT_INSN(),
122*4882a593Smuzhiyun 	},
123*4882a593Smuzhiyun 	.fixup_map_hash_8b = { 1 },
124*4882a593Smuzhiyun 	/* The unpriviledged case is not too interesting; variable
125*4882a593Smuzhiyun 	 * stack access is rejected.
126*4882a593Smuzhiyun 	 */
127*4882a593Smuzhiyun 	.errstr_unpriv = "R2 variable stack access prohibited for !root",
128*4882a593Smuzhiyun 	.result_unpriv = REJECT,
129*4882a593Smuzhiyun 	/* In the priviledged case, dereferencing a spilled-and-then-filled
130*4882a593Smuzhiyun 	 * register is rejected because the previous variable offset stack
131*4882a593Smuzhiyun 	 * write might have overwritten the spilled pointer (i.e. we lose track
132*4882a593Smuzhiyun 	 * of the spilled register when we analyze the write).
133*4882a593Smuzhiyun 	 */
134*4882a593Smuzhiyun 	.errstr = "R2 invalid mem access 'inv'",
135*4882a593Smuzhiyun 	.result = REJECT,
136*4882a593Smuzhiyun },
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	"indirect variable-offset stack access, unbounded",
139*4882a593Smuzhiyun 	.insns = {
140*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_2, 6),
141*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_3, 28),
142*4882a593Smuzhiyun 	/* Fill the top 16 bytes of the stack. */
143*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
144*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
145*4882a593Smuzhiyun 	/* Get an unknown value. */
146*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_DW, BPF_REG_4, BPF_REG_1, offsetof(struct bpf_sock_ops,
147*4882a593Smuzhiyun 							   bytes_received)),
148*4882a593Smuzhiyun 	/* Check the lower bound but don't check the upper one. */
149*4882a593Smuzhiyun 	BPF_JMP_IMM(BPF_JSLT, BPF_REG_4, 0, 4),
150*4882a593Smuzhiyun 	/* Point the lower bound to initialized stack. Offset is now in range
151*4882a593Smuzhiyun 	 * from fp-16 to fp+0x7fffffffffffffef, i.e. max value is unbounded.
152*4882a593Smuzhiyun 	 */
153*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_SUB, BPF_REG_4, 16),
154*4882a593Smuzhiyun 	BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_10),
155*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_5, 8),
156*4882a593Smuzhiyun 	/* Dereference it indirectly. */
157*4882a593Smuzhiyun 	BPF_EMIT_CALL(BPF_FUNC_getsockopt),
158*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_0, 0),
159*4882a593Smuzhiyun 	BPF_EXIT_INSN(),
160*4882a593Smuzhiyun 	},
161*4882a593Smuzhiyun 	.errstr = "invalid unbounded variable-offset indirect access to stack R4",
162*4882a593Smuzhiyun 	.result = REJECT,
163*4882a593Smuzhiyun 	.prog_type = BPF_PROG_TYPE_SOCK_OPS,
164*4882a593Smuzhiyun },
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun 	"indirect variable-offset stack access, max out of bound",
167*4882a593Smuzhiyun 	.insns = {
168*4882a593Smuzhiyun 	/* Fill the top 8 bytes of the stack */
169*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
170*4882a593Smuzhiyun 	/* Get an unknown value */
171*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
172*4882a593Smuzhiyun 	/* Make it small and 4-byte aligned */
173*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
174*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 8),
175*4882a593Smuzhiyun 	/* add it to fp.  We now have either fp-4 or fp-8, but
176*4882a593Smuzhiyun 	 * we don't know which
177*4882a593Smuzhiyun 	 */
178*4882a593Smuzhiyun 	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
179*4882a593Smuzhiyun 	/* dereference it indirectly */
180*4882a593Smuzhiyun 	BPF_LD_MAP_FD(BPF_REG_1, 0),
181*4882a593Smuzhiyun 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
182*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_0, 0),
183*4882a593Smuzhiyun 	BPF_EXIT_INSN(),
184*4882a593Smuzhiyun 	},
185*4882a593Smuzhiyun 	.fixup_map_hash_8b = { 5 },
186*4882a593Smuzhiyun 	.errstr = "invalid variable-offset indirect access to stack R2",
187*4882a593Smuzhiyun 	.result = REJECT,
188*4882a593Smuzhiyun 	.prog_type = BPF_PROG_TYPE_LWT_IN,
189*4882a593Smuzhiyun },
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	"indirect variable-offset stack access, min out of bound",
192*4882a593Smuzhiyun 	.insns = {
193*4882a593Smuzhiyun 	/* Fill the top 8 bytes of the stack */
194*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
195*4882a593Smuzhiyun 	/* Get an unknown value */
196*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
197*4882a593Smuzhiyun 	/* Make it small and 4-byte aligned */
198*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
199*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 516),
200*4882a593Smuzhiyun 	/* add it to fp.  We now have either fp-516 or fp-512, but
201*4882a593Smuzhiyun 	 * we don't know which
202*4882a593Smuzhiyun 	 */
203*4882a593Smuzhiyun 	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
204*4882a593Smuzhiyun 	/* dereference it indirectly */
205*4882a593Smuzhiyun 	BPF_LD_MAP_FD(BPF_REG_1, 0),
206*4882a593Smuzhiyun 	BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem),
207*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_0, 0),
208*4882a593Smuzhiyun 	BPF_EXIT_INSN(),
209*4882a593Smuzhiyun 	},
210*4882a593Smuzhiyun 	.fixup_map_hash_8b = { 5 },
211*4882a593Smuzhiyun 	.errstr = "invalid variable-offset indirect access to stack R2",
212*4882a593Smuzhiyun 	.result = REJECT,
213*4882a593Smuzhiyun 	.prog_type = BPF_PROG_TYPE_LWT_IN,
214*4882a593Smuzhiyun },
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	"indirect variable-offset stack access, max_off+size > max_initialized",
217*4882a593Smuzhiyun 	.insns = {
218*4882a593Smuzhiyun 	/* Fill only the second from top 8 bytes of the stack. */
219*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
220*4882a593Smuzhiyun 	/* Get an unknown value. */
221*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
222*4882a593Smuzhiyun 	/* Make it small and 4-byte aligned. */
223*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
224*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
225*4882a593Smuzhiyun 	/* Add it to fp.  We now have either fp-12 or fp-16, but we don't know
226*4882a593Smuzhiyun 	 * which. fp-12 size 8 is partially uninitialized stack.
227*4882a593Smuzhiyun 	 */
228*4882a593Smuzhiyun 	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
229*4882a593Smuzhiyun 	/* Dereference it indirectly. */
230*4882a593Smuzhiyun 	BPF_LD_MAP_FD(BPF_REG_1, 0),
231*4882a593Smuzhiyun 	BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
232*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_0, 0),
233*4882a593Smuzhiyun 	BPF_EXIT_INSN(),
234*4882a593Smuzhiyun 	},
235*4882a593Smuzhiyun 	.fixup_map_hash_8b = { 5 },
236*4882a593Smuzhiyun 	.errstr = "invalid indirect read from stack R2 var_off",
237*4882a593Smuzhiyun 	.result = REJECT,
238*4882a593Smuzhiyun 	.prog_type = BPF_PROG_TYPE_LWT_IN,
239*4882a593Smuzhiyun },
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	"indirect variable-offset stack access, min_off < min_initialized",
242*4882a593Smuzhiyun 	.insns = {
243*4882a593Smuzhiyun 	/* Fill only the top 8 bytes of the stack. */
244*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
245*4882a593Smuzhiyun 	/* Get an unknown value */
246*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
247*4882a593Smuzhiyun 	/* Make it small and 4-byte aligned. */
248*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
249*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
250*4882a593Smuzhiyun 	/* Add it to fp.  We now have either fp-12 or fp-16, but we don't know
251*4882a593Smuzhiyun 	 * which. fp-16 size 8 is partially uninitialized stack.
252*4882a593Smuzhiyun 	 */
253*4882a593Smuzhiyun 	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
254*4882a593Smuzhiyun 	/* Dereference it indirectly. */
255*4882a593Smuzhiyun 	BPF_LD_MAP_FD(BPF_REG_1, 0),
256*4882a593Smuzhiyun 	BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
257*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_0, 0),
258*4882a593Smuzhiyun 	BPF_EXIT_INSN(),
259*4882a593Smuzhiyun 	},
260*4882a593Smuzhiyun 	.fixup_map_hash_8b = { 5 },
261*4882a593Smuzhiyun 	.errstr = "invalid indirect read from stack R2 var_off",
262*4882a593Smuzhiyun 	.result = REJECT,
263*4882a593Smuzhiyun 	.prog_type = BPF_PROG_TYPE_LWT_IN,
264*4882a593Smuzhiyun },
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun 	"indirect variable-offset stack access, priv vs unpriv",
267*4882a593Smuzhiyun 	.insns = {
268*4882a593Smuzhiyun 	/* Fill the top 16 bytes of the stack. */
269*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
270*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
271*4882a593Smuzhiyun 	/* Get an unknown value. */
272*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
273*4882a593Smuzhiyun 	/* Make it small and 4-byte aligned. */
274*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
275*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
276*4882a593Smuzhiyun 	/* Add it to fp.  We now have either fp-12 or fp-16, we don't know
277*4882a593Smuzhiyun 	 * which, but either way it points to initialized stack.
278*4882a593Smuzhiyun 	 */
279*4882a593Smuzhiyun 	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
280*4882a593Smuzhiyun 	/* Dereference it indirectly. */
281*4882a593Smuzhiyun 	BPF_LD_MAP_FD(BPF_REG_1, 0),
282*4882a593Smuzhiyun 	BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
283*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_0, 0),
284*4882a593Smuzhiyun 	BPF_EXIT_INSN(),
285*4882a593Smuzhiyun 	},
286*4882a593Smuzhiyun 	.fixup_map_hash_8b = { 6 },
287*4882a593Smuzhiyun 	.errstr_unpriv = "R2 variable stack access prohibited for !root",
288*4882a593Smuzhiyun 	.result_unpriv = REJECT,
289*4882a593Smuzhiyun 	.result = ACCEPT,
290*4882a593Smuzhiyun 	.prog_type = BPF_PROG_TYPE_CGROUP_SKB,
291*4882a593Smuzhiyun },
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun 	"indirect variable-offset stack access, uninitialized",
294*4882a593Smuzhiyun 	.insns = {
295*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_2, 6),
296*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_3, 28),
297*4882a593Smuzhiyun 	/* Fill the top 16 bytes of the stack. */
298*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_W, BPF_REG_10, -16, 0),
299*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
300*4882a593Smuzhiyun 	/* Get an unknown value. */
301*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_4, BPF_REG_1, 0),
302*4882a593Smuzhiyun 	/* Make it small and 4-byte aligned. */
303*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_AND, BPF_REG_4, 4),
304*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_SUB, BPF_REG_4, 16),
305*4882a593Smuzhiyun 	/* Add it to fp.  We now have either fp-12 or fp-16, we don't know
306*4882a593Smuzhiyun 	 * which, but either way it points to initialized stack.
307*4882a593Smuzhiyun 	 */
308*4882a593Smuzhiyun 	BPF_ALU64_REG(BPF_ADD, BPF_REG_4, BPF_REG_10),
309*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_5, 8),
310*4882a593Smuzhiyun 	/* Dereference it indirectly. */
311*4882a593Smuzhiyun 	BPF_EMIT_CALL(BPF_FUNC_getsockopt),
312*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_0, 0),
313*4882a593Smuzhiyun 	BPF_EXIT_INSN(),
314*4882a593Smuzhiyun 	},
315*4882a593Smuzhiyun 	.errstr = "invalid indirect read from stack R4 var_off",
316*4882a593Smuzhiyun 	.result = REJECT,
317*4882a593Smuzhiyun 	.prog_type = BPF_PROG_TYPE_SOCK_OPS,
318*4882a593Smuzhiyun },
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun 	"indirect variable-offset stack access, ok",
321*4882a593Smuzhiyun 	.insns = {
322*4882a593Smuzhiyun 	/* Fill the top 16 bytes of the stack. */
323*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -16, 0),
324*4882a593Smuzhiyun 	BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0),
325*4882a593Smuzhiyun 	/* Get an unknown value. */
326*4882a593Smuzhiyun 	BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 0),
327*4882a593Smuzhiyun 	/* Make it small and 4-byte aligned. */
328*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_AND, BPF_REG_2, 4),
329*4882a593Smuzhiyun 	BPF_ALU64_IMM(BPF_SUB, BPF_REG_2, 16),
330*4882a593Smuzhiyun 	/* Add it to fp.  We now have either fp-12 or fp-16, we don't know
331*4882a593Smuzhiyun 	 * which, but either way it points to initialized stack.
332*4882a593Smuzhiyun 	 */
333*4882a593Smuzhiyun 	BPF_ALU64_REG(BPF_ADD, BPF_REG_2, BPF_REG_10),
334*4882a593Smuzhiyun 	/* Dereference it indirectly. */
335*4882a593Smuzhiyun 	BPF_LD_MAP_FD(BPF_REG_1, 0),
336*4882a593Smuzhiyun 	BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
337*4882a593Smuzhiyun 	BPF_MOV64_IMM(BPF_REG_0, 0),
338*4882a593Smuzhiyun 	BPF_EXIT_INSN(),
339*4882a593Smuzhiyun 	},
340*4882a593Smuzhiyun 	.fixup_map_hash_8b = { 6 },
341*4882a593Smuzhiyun 	.result = ACCEPT,
342*4882a593Smuzhiyun 	.prog_type = BPF_PROG_TYPE_LWT_IN,
343*4882a593Smuzhiyun },
344