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