Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
  1// SPDX-License-Identifier: GPL-2.0
  2/* Converted from tools/testing/selftests/bpf/verifier/search_pruning.c */
  3
  4#include <linux/bpf.h>
  5#include <../../../include/linux/filter.h>
  6#include <bpf/bpf_helpers.h>
  7#include "bpf_misc.h"
  8
  9#define MAX_ENTRIES 11
 10
 11struct test_val {
 12	unsigned int index;
 13	int foo[MAX_ENTRIES];
 14};
 15
 16struct {
 17	__uint(type, BPF_MAP_TYPE_HASH);
 18	__uint(max_entries, 1);
 19	__type(key, long long);
 20	__type(value, struct test_val);
 21} map_hash_48b SEC(".maps");
 22
 23struct {
 24	__uint(type, BPF_MAP_TYPE_HASH);
 25	__uint(max_entries, 1);
 26	__type(key, long long);
 27	__type(value, long long);
 28} map_hash_8b SEC(".maps");
 29
 30SEC("socket")
 31__description("pointer/scalar confusion in state equality check (way 1)")
 32__success __failure_unpriv __msg_unpriv("R0 leaks addr as return value")
 33__retval(POINTER_VALUE)
 34__naked void state_equality_check_way_1(void)
 35{
 36	asm volatile ("					\
 37	r1 = 0;						\
 38	*(u64*)(r10 - 8) = r1;				\
 39	r2 = r10;					\
 40	r2 += -8;					\
 41	r1 = %[map_hash_8b] ll;				\
 42	call %[bpf_map_lookup_elem];			\
 43	if r0 == 0 goto l0_%=;				\
 44	r0 = *(u64*)(r0 + 0);				\
 45	goto l1_%=;					\
 46l0_%=:	r0 = r10;					\
 47l1_%=:	goto l2_%=;					\
 48l2_%=:	exit;						\
 49"	:
 50	: __imm(bpf_map_lookup_elem),
 51	  __imm_addr(map_hash_8b)
 52	: __clobber_all);
 53}
 54
 55SEC("socket")
 56__description("pointer/scalar confusion in state equality check (way 2)")
 57__success __failure_unpriv __msg_unpriv("R0 leaks addr as return value")
 58__retval(POINTER_VALUE)
 59__naked void state_equality_check_way_2(void)
 60{
 61	asm volatile ("					\
 62	r1 = 0;						\
 63	*(u64*)(r10 - 8) = r1;				\
 64	r2 = r10;					\
 65	r2 += -8;					\
 66	r1 = %[map_hash_8b] ll;				\
 67	call %[bpf_map_lookup_elem];			\
 68	if r0 != 0 goto l0_%=;				\
 69	r0 = r10;					\
 70	goto l1_%=;					\
 71l0_%=:	r0 = *(u64*)(r0 + 0);				\
 72l1_%=:	exit;						\
 73"	:
 74	: __imm(bpf_map_lookup_elem),
 75	  __imm_addr(map_hash_8b)
 76	: __clobber_all);
 77}
 78
 79SEC("lwt_in")
 80__description("liveness pruning and write screening")
 81__failure __msg("R0 !read_ok")
 82__naked void liveness_pruning_and_write_screening(void)
 83{
 84	asm volatile ("					\
 85	/* Get an unknown value */			\
 86	r2 = *(u32*)(r1 + 0);				\
 87	/* branch conditions teach us nothing about R2 */\
 88	if r2 >= 0 goto l0_%=;				\
 89	r0 = 0;						\
 90l0_%=:	if r2 >= 0 goto l1_%=;				\
 91	r0 = 0;						\
 92l1_%=:	exit;						\
 93"	::: __clobber_all);
 94}
 95
 96SEC("socket")
 97__description("varlen_map_value_access pruning")
 98__failure __msg("R0 unbounded memory access")
 99__failure_unpriv __msg_unpriv("R0 leaks addr")
100__flag(BPF_F_ANY_ALIGNMENT)
101__naked void varlen_map_value_access_pruning(void)
102{
103	asm volatile ("					\
104	r1 = 0;						\
105	*(u64*)(r10 - 8) = r1;				\
106	r2 = r10;					\
107	r2 += -8;					\
108	r1 = %[map_hash_48b] ll;			\
109	call %[bpf_map_lookup_elem];			\
110	if r0 == 0 goto l0_%=;				\
111	r1 = *(u64*)(r0 + 0);				\
112	w2 = %[max_entries];				\
113	if r2 s> r1 goto l1_%=;				\
114	w1 = 0;						\
115l1_%=:	w1 <<= 2;					\
116	r0 += r1;					\
117	goto l2_%=;					\
118l2_%=:	r1 = %[test_val_foo];				\
119	*(u64*)(r0 + 0) = r1;				\
120l0_%=:	exit;						\
121"	:
122	: __imm(bpf_map_lookup_elem),
123	  __imm_addr(map_hash_48b),
124	  __imm_const(max_entries, MAX_ENTRIES),
125	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
126	: __clobber_all);
127}
128
129SEC("tracepoint")
130__description("search pruning: all branches should be verified (nop operation)")
131__failure __msg("R6 invalid mem access 'scalar'")
132__naked void should_be_verified_nop_operation(void)
133{
134	asm volatile ("					\
135	r2 = r10;					\
136	r2 += -8;					\
137	r1 = 0;						\
138	*(u64*)(r2 + 0) = r1;				\
139	r1 = %[map_hash_8b] ll;				\
140	call %[bpf_map_lookup_elem];			\
141	if r0 == 0 goto l0_%=;				\
142	r3 = *(u64*)(r0 + 0);				\
143	if r3 == 0xbeef goto l1_%=;			\
144	r4 = 0;						\
145	goto l2_%=;					\
146l1_%=:	r4 = 1;						\
147l2_%=:	*(u64*)(r10 - 16) = r4;				\
148	call %[bpf_ktime_get_ns];			\
149	r5 = *(u64*)(r10 - 16);				\
150	if r5 == 0 goto l0_%=;				\
151	r6 = 0;						\
152	r1 = 0xdead;					\
153	*(u64*)(r6 + 0) = r1;				\
154l0_%=:	exit;						\
155"	:
156	: __imm(bpf_ktime_get_ns),
157	  __imm(bpf_map_lookup_elem),
158	  __imm_addr(map_hash_8b)
159	: __clobber_all);
160}
161
162SEC("socket")
163__description("search pruning: all branches should be verified (invalid stack access)")
164/* in privileged mode reads from uninitialized stack locations are permitted */
165__success __failure_unpriv
166__msg_unpriv("invalid read from stack off -16+0 size 8")
167__retval(0)
168__naked void be_verified_invalid_stack_access(void)
169{
170	asm volatile ("					\
171	r2 = r10;					\
172	r2 += -8;					\
173	r1 = 0;						\
174	*(u64*)(r2 + 0) = r1;				\
175	r1 = %[map_hash_8b] ll;				\
176	call %[bpf_map_lookup_elem];			\
177	if r0 == 0 goto l0_%=;				\
178	r3 = *(u64*)(r0 + 0);				\
179	r4 = 0;						\
180	if r3 == 0xbeef goto l1_%=;			\
181	*(u64*)(r10 - 16) = r4;				\
182	goto l2_%=;					\
183l1_%=:	*(u64*)(r10 - 24) = r4;				\
184l2_%=:	call %[bpf_ktime_get_ns];			\
185	r5 = *(u64*)(r10 - 16);				\
186l0_%=:	exit;						\
187"	:
188	: __imm(bpf_ktime_get_ns),
189	  __imm(bpf_map_lookup_elem),
190	  __imm_addr(map_hash_8b)
191	: __clobber_all);
192}
193
194SEC("tracepoint")
195__description("precision tracking for u32 spill/fill")
196__failure __msg("R0 min value is outside of the allowed memory range")
197__naked void tracking_for_u32_spill_fill(void)
198{
199	asm volatile ("					\
200	r7 = r1;					\
201	call %[bpf_get_prandom_u32];			\
202	w6 = 32;					\
203	if r0 == 0 goto l0_%=;				\
204	w6 = 4;						\
205l0_%=:	/* Additional insns to introduce a pruning point. */\
206	call %[bpf_get_prandom_u32];			\
207	r3 = 0;						\
208	r3 = 0;						\
209	if r0 == 0 goto l1_%=;				\
210	r3 = 0;						\
211l1_%=:	/* u32 spill/fill */				\
212	*(u32*)(r10 - 8) = r6;				\
213	r8 = *(u32*)(r10 - 8);				\
214	/* out-of-bound map value access for r6=32 */	\
215	r1 = 0;						\
216	*(u64*)(r10 - 16) = r1;				\
217	r2 = r10;					\
218	r2 += -16;					\
219	r1 = %[map_hash_8b] ll;				\
220	call %[bpf_map_lookup_elem];			\
221	if r0 == 0 goto l2_%=;				\
222	r0 += r8;					\
223	r1 = *(u32*)(r0 + 0);				\
224l2_%=:	r0 = 0;						\
225	exit;						\
226"	:
227	: __imm(bpf_get_prandom_u32),
228	  __imm(bpf_map_lookup_elem),
229	  __imm_addr(map_hash_8b)
230	: __clobber_all);
231}
232
233SEC("tracepoint")
234__description("precision tracking for u32 spills, u64 fill")
235__failure __msg("div by zero")
236__naked void for_u32_spills_u64_fill(void)
237{
238	asm volatile ("					\
239	call %[bpf_get_prandom_u32];			\
240	r6 = r0;					\
241	w7 = 0xffffffff;				\
242	/* Additional insns to introduce a pruning point. */\
243	r3 = 1;						\
244	r3 = 1;						\
245	r3 = 1;						\
246	r3 = 1;						\
247	call %[bpf_get_prandom_u32];			\
248	if r0 == 0 goto l0_%=;				\
249	r3 = 1;						\
250l0_%=:	w3 /= 0;					\
251	/* u32 spills, u64 fill */			\
252	*(u32*)(r10 - 4) = r6;				\
253	*(u32*)(r10 - 8) = r7;				\
254	r8 = *(u64*)(r10 - 8);				\
255	/* if r8 != X goto pc+1  r8 known in fallthrough branch */\
256	if r8 != 0xffffffff goto l1_%=;			\
257	r3 = 1;						\
258l1_%=:	/* if r8 == X goto pc+1  condition always true on first\
259	 * traversal, so starts backtracking to mark r8 as requiring\
260	 * precision. r7 marked as needing precision. r6 not marked\
261	 * since it's not tracked.			\
262	 */						\
263	if r8 == 0xffffffff goto l2_%=;			\
264	/* fails if r8 correctly marked unknown after fill. */\
265	w3 /= 0;					\
266l2_%=:	r0 = 0;						\
267	exit;						\
268"	:
269	: __imm(bpf_get_prandom_u32)
270	: __clobber_all);
271}
272
273SEC("socket")
274__description("allocated_stack")
275__success __msg("processed 15 insns")
276__success_unpriv __msg_unpriv("") __log_level(1) __retval(0)
277__naked void allocated_stack(void)
278{
279	asm volatile ("					\
280	r6 = r1;					\
281	call %[bpf_get_prandom_u32];			\
282	r7 = r0;					\
283	if r0 == 0 goto l0_%=;				\
284	r0 = 0;						\
285	*(u64*)(r10 - 8) = r6;				\
286	r6 = *(u64*)(r10 - 8);				\
287	*(u8*)(r10 - 9) = r7;				\
288	r7 = *(u8*)(r10 - 9);				\
289l0_%=:	if r0 != 0 goto l1_%=;				\
290l1_%=:	if r0 != 0 goto l2_%=;				\
291l2_%=:	if r0 != 0 goto l3_%=;				\
292l3_%=:	if r0 != 0 goto l4_%=;				\
293l4_%=:	exit;						\
294"	:
295	: __imm(bpf_get_prandom_u32)
296	: __clobber_all);
297}
298
299/* The test performs a conditional 64-bit write to a stack location
300 * fp[-8], this is followed by an unconditional 8-bit write to fp[-8],
301 * then data is read from fp[-8]. This sequence is unsafe.
302 *
303 * The test would be mistakenly marked as safe w/o dst register parent
304 * preservation in verifier.c:copy_register_state() function.
305 *
306 * Note the usage of BPF_F_TEST_STATE_FREQ to force creation of the
307 * checkpoint state after conditional 64-bit assignment.
308 */
309
310SEC("socket")
311__description("write tracking and register parent chain bug")
312/* in privileged mode reads from uninitialized stack locations are permitted */
313__success __failure_unpriv
314__msg_unpriv("invalid read from stack off -8+1 size 8")
315__retval(0) __flag(BPF_F_TEST_STATE_FREQ)
316__naked void and_register_parent_chain_bug(void)
317{
318	asm volatile ("					\
319	/* r6 = ktime_get_ns() */			\
320	call %[bpf_ktime_get_ns];			\
321	r6 = r0;					\
322	/* r0 = ktime_get_ns() */			\
323	call %[bpf_ktime_get_ns];			\
324	/* if r0 > r6 goto +1 */			\
325	if r0 > r6 goto l0_%=;				\
326	/* *(u64 *)(r10 - 8) = 0xdeadbeef */		\
327	r0 = 0xdeadbeef;				\
328	*(u64*)(r10 - 8) = r0;				\
329l0_%=:	r1 = 42;					\
330	*(u8*)(r10 - 8) = r1;				\
331	r2 = *(u64*)(r10 - 8);				\
332	/* exit(0) */					\
333	r0 = 0;						\
334	exit;						\
335"	:
336	: __imm(bpf_ktime_get_ns)
337	: __clobber_all);
338}
339
340/* Without checkpoint forcibly inserted at the back-edge a loop this
341 * test would take a very long time to verify.
342 */
343SEC("kprobe")
344__failure __log_level(4)
345__msg("BPF program is too large.")
346__naked void short_loop1(void)
347{
348	asm volatile (
349	"   r7 = *(u16 *)(r1 +0);"
350	"1: r7 += 0x1ab064b9;"
351	"   .8byte %[jset];" /* same as 'if r7 & 0x702000 goto 1b;' */
352	"   r7 &= 0x1ee60e;"
353	"   r7 += r1;"
354	"   if r7 s> 0x37d2 goto +0;"
355	"   r0 = 0;"
356	"   exit;"
357	:
358	: __imm_insn(jset, BPF_JMP_IMM(BPF_JSET, BPF_REG_7, 0x702000, -2))
359	: __clobber_all);
360}
361
362char _license[] SEC("license") = "GPL";