File Index
Files and directories
Sign in
FILE

verifier_unpriv.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/bpf/progs/verifier_unpriv.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Converted from tools/testing/selftests/bpf/verifier/unpriv.c */
  3
  4#include <linux/bpf.h>
  5#include <bpf/bpf_helpers.h>
  6#include "../../../include/linux/filter.h"
  7#include "bpf_misc.h"
  8
  9#define BPF_SK_LOOKUP(func) \
 10	/* struct bpf_sock_tuple tuple = {} */ \
 11	"r2 = 0;"			\
 12	"*(u32*)(r10 - 8) = r2;"	\
 13	"*(u64*)(r10 - 16) = r2;"	\
 14	"*(u64*)(r10 - 24) = r2;"	\
 15	"*(u64*)(r10 - 32) = r2;"	\
 16	"*(u64*)(r10 - 40) = r2;"	\
 17	"*(u64*)(r10 - 48) = r2;"	\
 18	/* sk = func(ctx, &tuple, sizeof tuple, 0, 0) */ \
 19	"r2 = r10;"			\
 20	"r2 += -48;"			\
 21	"r3 = %[sizeof_bpf_sock_tuple];"\
 22	"r4 = 0;"			\
 23	"r5 = 0;"			\
 24	"call %[" #func "];"
 25
 26struct {
 27	__uint(type, BPF_MAP_TYPE_HASH);
 28	__uint(max_entries, 1);
 29	__type(key, long long);
 30	__type(value, long long);
 31} map_hash_8b SEC(".maps");
 32
 33void dummy_prog_42_socket(void);
 34void dummy_prog_24_socket(void);
 35void dummy_prog_loop1_socket(void);
 36
 37struct {
 38	__uint(type, BPF_MAP_TYPE_PROG_ARRAY);
 39	__uint(max_entries, 4);
 40	__uint(key_size, sizeof(int));
 41	__array(values, void (void));
 42} map_prog1_socket SEC(".maps") = {
 43	.values = {
 44		[0] = (void *)&dummy_prog_42_socket,
 45		[1] = (void *)&dummy_prog_loop1_socket,
 46		[2] = (void *)&dummy_prog_24_socket,
 47	},
 48};
 49
 50SEC("socket")
 51__auxiliary __auxiliary_unpriv
 52__naked void dummy_prog_42_socket(void)
 53{
 54	asm volatile ("r0 = 42; exit;");
 55}
 56
 57SEC("socket")
 58__auxiliary __auxiliary_unpriv
 59__naked void dummy_prog_24_socket(void)
 60{
 61	asm volatile ("r0 = 24; exit;");
 62}
 63
 64SEC("socket")
 65__auxiliary __auxiliary_unpriv
 66__naked void dummy_prog_loop1_socket(void)
 67{
 68	asm volatile ("			\
 69	r3 = 1;				\
 70	r2 = %[map_prog1_socket] ll;	\
 71	call %[bpf_tail_call];		\
 72	r0 = 41;			\
 73	exit;				\
 74"	:
 75	: __imm(bpf_tail_call),
 76	  __imm_addr(map_prog1_socket)
 77	: __clobber_all);
 78}
 79
 80SEC("socket")
 81__description("unpriv: return pointer")
 82__success __failure_unpriv __msg_unpriv("R0 leaks addr")
 83__retval(POINTER_VALUE)
 84__naked void unpriv_return_pointer(void)
 85{
 86	asm volatile ("					\
 87	r0 = r10;					\
 88	exit;						\
 89"	::: __clobber_all);
 90}
 91
 92SEC("socket")
 93__description("unpriv: add const to pointer")
 94__success __success_unpriv __retval(0)
 95__naked void unpriv_add_const_to_pointer(void)
 96{
 97	asm volatile ("					\
 98	r1 += 8;					\
 99	r0 = 0;						\
100	exit;						\
101"	::: __clobber_all);
102}
103
104SEC("socket")
105__description("unpriv: add pointer to pointer")
106__failure __msg("R1 pointer += pointer")
107__failure_unpriv
108__naked void unpriv_add_pointer_to_pointer(void)
109{
110	asm volatile ("					\
111	r1 += r10;					\
112	r0 = 0;						\
113	exit;						\
114"	::: __clobber_all);
115}
116
117SEC("socket")
118__description("unpriv: neg pointer")
119__success __failure_unpriv __msg_unpriv("R1 pointer arithmetic")
120__retval(0)
121__naked void unpriv_neg_pointer(void)
122{
123	asm volatile ("					\
124	r1 = -r1;					\
125	r0 = 0;						\
126	exit;						\
127"	::: __clobber_all);
128}
129
130SEC("socket")
131__description("unpriv: cmp pointer with const")
132__success __failure_unpriv __msg_unpriv("R1 pointer comparison")
133__retval(0)
134__naked void unpriv_cmp_pointer_with_const(void)
135{
136	asm volatile ("					\
137	if r1 == 0 goto l0_%=;				\
138l0_%=:	r0 = 0;						\
139	exit;						\
140"	::: __clobber_all);
141}
142
143SEC("socket")
144__description("unpriv: cmp pointer with pointer")
145__success __failure_unpriv __msg_unpriv("R10 pointer comparison")
146__retval(0)
147__naked void unpriv_cmp_pointer_with_pointer(void)
148{
149	asm volatile ("					\
150	if r1 == r10 goto l0_%=;			\
151l0_%=:	r0 = 0;						\
152	exit;						\
153"	::: __clobber_all);
154}
155
156SEC("tracepoint")
157__description("unpriv: check that printk is disallowed")
158__success
159__naked void check_that_printk_is_disallowed(void)
160{
161	asm volatile ("					\
162	r1 = 0;						\
163	*(u64*)(r10 - 8) = r1;				\
164	r1 = r10;					\
165	r1 += -8;					\
166	r2 = 8;						\
167	r3 = r1;					\
168	call %[bpf_trace_printk];			\
169	r0 = 0;						\
170	exit;						\
171"	:
172	: __imm(bpf_trace_printk)
173	: __clobber_all);
174}
175
176SEC("socket")
177__description("unpriv: pass pointer to helper function")
178__success __failure_unpriv __msg_unpriv("R4 leaks addr")
179__retval(0)
180__naked void pass_pointer_to_helper_function(void)
181{
182	asm volatile ("					\
183	r1 = 0;						\
184	*(u64*)(r10 - 8) = r1;				\
185	r2 = r10;					\
186	r2 += -8;					\
187	r1 = %[map_hash_8b] ll;				\
188	r3 = r2;					\
189	r4 = r2;					\
190	call %[bpf_map_update_elem];			\
191	r0 = 0;						\
192	exit;						\
193"	:
194	: __imm(bpf_map_update_elem),
195	  __imm_addr(map_hash_8b)
196	: __clobber_all);
197}
198
199SEC("socket")
200__description("unpriv: indirectly pass pointer on stack to helper function")
201__success __failure_unpriv
202__msg_unpriv("invalid read from stack R2 off -8+0 size 8")
203__retval(0)
204__naked void on_stack_to_helper_function(void)
205{
206	asm volatile ("					\
207	*(u64*)(r10 - 8) = r10;				\
208	r2 = r10;					\
209	r2 += -8;					\
210	r1 = %[map_hash_8b] ll;				\
211	call %[bpf_map_lookup_elem];			\
212	r0 = 0;						\
213	exit;						\
214"	:
215	: __imm(bpf_map_lookup_elem),
216	  __imm_addr(map_hash_8b)
217	: __clobber_all);
218}
219
220SEC("socket")
221__description("unpriv: mangle pointer on stack 1")
222__success __failure_unpriv __msg_unpriv("attempt to corrupt spilled")
223__retval(0)
224__naked void mangle_pointer_on_stack_1(void)
225{
226	asm volatile ("					\
227	*(u64*)(r10 - 8) = r10;				\
228	r0 = 0;						\
229	*(u32*)(r10 - 8) = r0;				\
230	r0 = 0;						\
231	exit;						\
232"	::: __clobber_all);
233}
234
235SEC("socket")
236__description("unpriv: mangle pointer on stack 2")
237__success __failure_unpriv __msg_unpriv("attempt to corrupt spilled")
238__retval(0)
239__naked void mangle_pointer_on_stack_2(void)
240{
241	asm volatile ("					\
242	*(u64*)(r10 - 8) = r10;				\
243	r0 = 0;						\
244	*(u8*)(r10 - 1) = r0;				\
245	r0 = 0;						\
246	exit;						\
247"	::: __clobber_all);
248}
249
250SEC("socket")
251__description("unpriv: read pointer from stack in small chunks")
252__failure __msg("invalid size")
253__failure_unpriv
254__naked void from_stack_in_small_chunks(void)
255{
256	asm volatile ("					\
257	*(u64*)(r10 - 8) = r10;				\
258	r0 = *(u32*)(r10 - 8);				\
259	r0 = 0;						\
260	exit;						\
261"	::: __clobber_all);
262}
263
264SEC("socket")
265__description("unpriv: write pointer into ctx")
266__failure __msg("invalid bpf_context access")
267__failure_unpriv __msg_unpriv("R1 leaks addr")
268__naked void unpriv_write_pointer_into_ctx(void)
269{
270	asm volatile ("					\
271	*(u64*)(r1 + 0) = r1;				\
272	r0 = 0;						\
273	exit;						\
274"	::: __clobber_all);
275}
276
277SEC("socket")
278__description("unpriv: spill/fill of ctx")
279__success __success_unpriv __retval(0)
280__naked void unpriv_spill_fill_of_ctx(void)
281{
282	asm volatile ("					\
283	r6 = r10;					\
284	r6 += -8;					\
285	*(u64*)(r6 + 0) = r1;				\
286	r1 = *(u64*)(r6 + 0);				\
287	r0 = 0;						\
288	exit;						\
289"	::: __clobber_all);
290}
291
292SEC("tc")
293__description("unpriv: spill/fill of ctx 2")
294__success __retval(0)
295__naked void spill_fill_of_ctx_2(void)
296{
297	asm volatile ("					\
298	r6 = r10;					\
299	r6 += -8;					\
300	*(u64*)(r6 + 0) = r1;				\
301	r1 = *(u64*)(r6 + 0);				\
302	call %[bpf_get_hash_recalc];			\
303	r0 = 0;						\
304	exit;						\
305"	:
306	: __imm(bpf_get_hash_recalc)
307	: __clobber_all);
308}
309
310SEC("tc")
311__description("unpriv: spill/fill of ctx 3")
312__failure __msg("R1 type=fp expected=ctx")
313__naked void spill_fill_of_ctx_3(void)
314{
315	asm volatile ("					\
316	r6 = r10;					\
317	r6 += -8;					\
318	*(u64*)(r6 + 0) = r1;				\
319	*(u64*)(r6 + 0) = r10;				\
320	r1 = *(u64*)(r6 + 0);				\
321	call %[bpf_get_hash_recalc];			\
322	exit;						\
323"	:
324	: __imm(bpf_get_hash_recalc)
325	: __clobber_all);
326}
327
328SEC("tc")
329__description("unpriv: spill/fill of ctx 4")
330__failure __msg("R1 type=scalar expected=ctx")
331__naked void spill_fill_of_ctx_4(void)
332{
333	asm volatile ("					\
334	r6 = r10;					\
335	r6 += -8;					\
336	*(u64*)(r6 + 0) = r1;				\
337	r0 = 1;						\
338	lock *(u64 *)(r10 - 8) += r0;			\
339	r1 = *(u64*)(r6 + 0);				\
340	call %[bpf_get_hash_recalc];			\
341	exit;						\
342"	:
343	: __imm(bpf_get_hash_recalc)
344	: __clobber_all);
345}
346
347SEC("tc")
348__description("unpriv: spill/fill of different pointers stx")
349__failure __msg("same insn cannot be used with different pointers")
350__naked void fill_of_different_pointers_stx(void)
351{
352	asm volatile ("					\
353	r3 = 42;					\
354	r6 = r10;					\
355	r6 += -8;					\
356	if r1 == 0 goto l0_%=;				\
357	r2 = r10;					\
358	r2 += -16;					\
359	*(u64*)(r6 + 0) = r2;				\
360l0_%=:	if r1 != 0 goto l1_%=;				\
361	*(u64*)(r6 + 0) = r1;				\
362l1_%=:	r1 = *(u64*)(r6 + 0);				\
363	*(u32*)(r1 + %[__sk_buff_mark]) = r3;		\
364	r0 = 0;						\
365	exit;						\
366"	:
367	: __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
368	: __clobber_all);
369}
370
371/* Same as above, but use BPF_ST_MEM to save 42
372 * instead of BPF_STX_MEM.
373 */
374SEC("tc")
375__description("unpriv: spill/fill of different pointers st")
376__failure __msg("same insn cannot be used with different pointers")
377__naked void fill_of_different_pointers_st(void)
378{
379	asm volatile ("					\
380	r6 = r10;					\
381	r6 += -8;					\
382	if r1 == 0 goto l0_%=;				\
383	r2 = r10;					\
384	r2 += -16;					\
385	*(u64*)(r6 + 0) = r2;				\
386l0_%=:	if r1 != 0 goto l1_%=;				\
387	*(u64*)(r6 + 0) = r1;				\
388l1_%=:	r1 = *(u64*)(r6 + 0);				\
389	.8byte %[st_mem];				\
390	r0 = 0;						\
391	exit;						\
392"	:
393	: __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)),
394	  __imm_insn(st_mem,
395		     BPF_ST_MEM(BPF_W, BPF_REG_1, offsetof(struct __sk_buff, mark), 42))
396	: __clobber_all);
397}
398
399SEC("tc")
400__description("unpriv: spill/fill of different pointers stx - ctx and sock")
401__failure __msg("type=ctx expected=sock")
402__naked void pointers_stx_ctx_and_sock(void)
403{
404	asm volatile ("					\
405	r8 = r1;					\
406	/* struct bpf_sock *sock = bpf_sock_lookup(...); */\
407"	BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
408"	r2 = r0;					\
409	/* u64 foo; */					\
410	/* void *target = &foo; */			\
411	r6 = r10;					\
412	r6 += -8;					\
413	r1 = r8;					\
414	/* if (skb == NULL) *target = sock; */		\
415	if r1 == 0 goto l0_%=;				\
416	*(u64*)(r6 + 0) = r2;				\
417l0_%=:	/* else *target = skb; */			\
418	if r1 != 0 goto l1_%=;				\
419	*(u64*)(r6 + 0) = r1;				\
420l1_%=:	/* struct __sk_buff *skb = *target; */		\
421	r1 = *(u64*)(r6 + 0);				\
422	/* skb->mark = 42; */				\
423	r3 = 42;					\
424	*(u32*)(r1 + %[__sk_buff_mark]) = r3;		\
425	/* if (sk) bpf_sk_release(sk) */		\
426	if r1 == 0 goto l2_%=;				\
427	call %[bpf_sk_release];				\
428l2_%=:	r0 = 0;						\
429	exit;						\
430"	:
431	: __imm(bpf_sk_lookup_tcp),
432	  __imm(bpf_sk_release),
433	  __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)),
434	  __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
435	: __clobber_all);
436}
437
438SEC("tc")
439__description("unpriv: spill/fill of different pointers stx - leak sock")
440__failure
441//.errstr = "same insn cannot be used with different pointers",
442__msg("Unreleased reference")
443__naked void different_pointers_stx_leak_sock(void)
444{
445	asm volatile ("					\
446	r8 = r1;					\
447	/* struct bpf_sock *sock = bpf_sock_lookup(...); */\
448"	BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
449"	r2 = r0;					\
450	/* u64 foo; */					\
451	/* void *target = &foo; */			\
452	r6 = r10;					\
453	r6 += -8;					\
454	r1 = r8;					\
455	/* if (skb == NULL) *target = sock; */		\
456	if r1 == 0 goto l0_%=;				\
457	*(u64*)(r6 + 0) = r2;				\
458l0_%=:	/* else *target = skb; */			\
459	if r1 != 0 goto l1_%=;				\
460	*(u64*)(r6 + 0) = r1;				\
461l1_%=:	/* struct __sk_buff *skb = *target; */		\
462	r1 = *(u64*)(r6 + 0);				\
463	/* skb->mark = 42; */				\
464	r3 = 42;					\
465	*(u32*)(r1 + %[__sk_buff_mark]) = r3;		\
466	exit;						\
467"	:
468	: __imm(bpf_sk_lookup_tcp),
469	  __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark)),
470	  __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
471	: __clobber_all);
472}
473
474SEC("tc")
475__description("unpriv: spill/fill of different pointers stx - sock and ctx (read)")
476__failure __msg("same insn cannot be used with different pointers")
477__naked void stx_sock_and_ctx_read(void)
478{
479	asm volatile ("					\
480	r8 = r1;					\
481	/* struct bpf_sock *sock = bpf_sock_lookup(...); */\
482"	BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
483"	r2 = r0;					\
484	/* u64 foo; */					\
485	/* void *target = &foo; */			\
486	r6 = r10;					\
487	r6 += -8;					\
488	r1 = r8;					\
489	/* if (skb) *target = skb */			\
490	if r1 == 0 goto l0_%=;				\
491	*(u64*)(r6 + 0) = r1;				\
492l0_%=:	/* else *target = sock */			\
493	if r1 != 0 goto l1_%=;				\
494	*(u64*)(r6 + 0) = r2;				\
495l1_%=:	/* struct bpf_sock *sk = *target; */		\
496	r1 = *(u64*)(r6 + 0);				\
497	/* if (sk) u32 foo = sk->mark; bpf_sk_release(sk); */\
498	if r1 == 0 goto l2_%=;				\
499	r3 = *(u32*)(r1 + %[bpf_sock_mark]);		\
500	call %[bpf_sk_release];				\
501l2_%=:	r0 = 0;						\
502	exit;						\
503"	:
504	: __imm(bpf_sk_lookup_tcp),
505	  __imm(bpf_sk_release),
506	  __imm_const(bpf_sock_mark, offsetof(struct bpf_sock, mark)),
507	  __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
508	: __clobber_all);
509}
510
511SEC("tc")
512__description("unpriv: spill/fill of different pointers stx - sock and ctx (write)")
513__failure
514//.errstr = "same insn cannot be used with different pointers",
515__msg("cannot write into sock")
516__naked void stx_sock_and_ctx_write(void)
517{
518	asm volatile ("					\
519	r8 = r1;					\
520	/* struct bpf_sock *sock = bpf_sock_lookup(...); */\
521"	BPF_SK_LOOKUP(bpf_sk_lookup_tcp)
522"	r2 = r0;					\
523	/* u64 foo; */					\
524	/* void *target = &foo; */			\
525	r6 = r10;					\
526	r6 += -8;					\
527	r1 = r8;					\
528	/* if (skb) *target = skb */			\
529	if r1 == 0 goto l0_%=;				\
530	*(u64*)(r6 + 0) = r1;				\
531l0_%=:	/* else *target = sock */			\
532	if r1 != 0 goto l1_%=;				\
533	*(u64*)(r6 + 0) = r2;				\
534l1_%=:	/* struct bpf_sock *sk = *target; */		\
535	r1 = *(u64*)(r6 + 0);				\
536	/* if (sk) sk->mark = 42; bpf_sk_release(sk); */\
537	if r1 == 0 goto l2_%=;				\
538	r3 = 42;					\
539	*(u32*)(r1 + %[bpf_sock_mark]) = r3;		\
540	call %[bpf_sk_release];				\
541l2_%=:	r0 = 0;						\
542	exit;						\
543"	:
544	: __imm(bpf_sk_lookup_tcp),
545	  __imm(bpf_sk_release),
546	  __imm_const(bpf_sock_mark, offsetof(struct bpf_sock, mark)),
547	  __imm_const(sizeof_bpf_sock_tuple, sizeof(struct bpf_sock_tuple))
548	: __clobber_all);
549}
550
551SEC("socket")
552__description("unpriv: write pointer into map elem value")
553__success __failure_unpriv __msg_unpriv("R0 leaks addr")
554__retval(0)
555__naked void pointer_into_map_elem_value(void)
556{
557	asm volatile ("					\
558	r1 = 0;						\
559	*(u64*)(r10 - 8) = r1;				\
560	r2 = r10;					\
561	r2 += -8;					\
562	r1 = %[map_hash_8b] ll;				\
563	call %[bpf_map_lookup_elem];			\
564	if r0 == 0 goto l0_%=;				\
565	*(u64*)(r0 + 0) = r0;				\
566l0_%=:	exit;						\
567"	:
568	: __imm(bpf_map_lookup_elem),
569	  __imm_addr(map_hash_8b)
570	: __clobber_all);
571}
572
573SEC("socket")
574__description("alu32: mov u32 const")
575__success __success_unpriv
576__retval(0)
577#ifdef SPEC_V1
578__xlated_unpriv("if r0 == 0x0 goto pc+2")
579__xlated_unpriv("nospec") /* inserted to prevent `R7 invalid mem access 'scalar'` */
580__xlated_unpriv("goto pc-1") /* sanitized dead code */
581__xlated_unpriv("exit")
582#endif
583__naked void alu32_mov_u32_const(void)
584{
585	asm volatile ("					\
586	w7 = 0;						\
587	w7 &= 1;					\
588	w0 = w7;					\
589	if r0 == 0 goto l0_%=;				\
590	r0 = *(u64*)(r7 + 0);				\
591l0_%=:	exit;						\
592"	::: __clobber_all);
593}
594
595SEC("socket")
596__description("unpriv: partial copy of pointer")
597__success __failure_unpriv __msg_unpriv("R10 partial copy")
598__retval(0)
599__naked void unpriv_partial_copy_of_pointer(void)
600{
601	asm volatile ("					\
602	w1 = w10;					\
603	r0 = 0;						\
604	exit;						\
605"	::: __clobber_all);
606}
607
608SEC("socket")
609__description("unpriv: pass pointer to tail_call")
610__success __failure_unpriv __msg_unpriv("R3 leaks addr into helper")
611__retval(0)
612__naked void pass_pointer_to_tail_call(void)
613{
614	asm volatile ("					\
615	r3 = r1;					\
616	r2 = %[map_prog1_socket] ll;			\
617	call %[bpf_tail_call];				\
618	r0 = 0;						\
619	exit;						\
620"	:
621	: __imm(bpf_tail_call),
622	  __imm_addr(map_prog1_socket)
623	: __clobber_all);
624}
625
626SEC("socket")
627__description("unpriv: cmp map pointer with zero")
628__success __success_unpriv
629__retval(0)
630__naked void cmp_map_pointer_with_zero(void)
631{
632	asm volatile ("					\
633	r1 = %[map_hash_8b] ll;				\
634	if r1 == 0 goto l0_%=;				\
635l0_%=:	r0 = 0;						\
636	exit;						\
637"	:
638	: __imm_addr(map_hash_8b)
639	: __clobber_all);
640}
641
642SEC("socket")
643__description("unpriv: cmp map pointer with const")
644__success __failure_unpriv __msg_unpriv("R1 pointer comparison prohibited")
645__retval(0)
646__naked void cmp_map_pointer_with_const(void)
647{
648	asm volatile ("					\
649	r1 = %[map_hash_8b] ll;				\
650	if r1 == 0x0000beef goto l0_%=;			\
651l0_%=:	r0 = 0;						\
652	exit;						\
653"	:
654	: __imm_addr(map_hash_8b)
655	: __clobber_all);
656}
657
658SEC("socket")
659__description("unpriv: write into frame pointer")
660__failure __msg("frame pointer is read only")
661__failure_unpriv
662__naked void unpriv_write_into_frame_pointer(void)
663{
664	asm volatile ("					\
665	r10 = r1;					\
666	r0 = 0;						\
667	exit;						\
668"	::: __clobber_all);
669}
670
671SEC("socket")
672__description("unpriv: spill/fill frame pointer")
673__failure __msg("frame pointer is read only")
674__failure_unpriv
675__naked void unpriv_spill_fill_frame_pointer(void)
676{
677	asm volatile ("					\
678	r6 = r10;					\
679	r6 += -8;					\
680	*(u64*)(r6 + 0) = r10;				\
681	r10 = *(u64*)(r6 + 0);				\
682	r0 = 0;						\
683	exit;						\
684"	::: __clobber_all);
685}
686
687SEC("socket")
688__description("unpriv: cmp of frame pointer")
689__success __failure_unpriv __msg_unpriv("R10 pointer comparison")
690__retval(0)
691__naked void unpriv_cmp_of_frame_pointer(void)
692{
693	asm volatile ("					\
694	if r10 == 0 goto l0_%=;				\
695l0_%=:	r0 = 0;						\
696	exit;						\
697"	::: __clobber_all);
698}
699
700SEC("socket")
701__description("unpriv: adding of fp, reg")
702__success __failure_unpriv
703__msg_unpriv("R1 stack pointer arithmetic goes out of range")
704__retval(0)
705__naked void unpriv_adding_of_fp_reg(void)
706{
707	asm volatile ("					\
708	r0 = 0;						\
709	r1 = 0;						\
710	r1 += r10;					\
711	*(u64*)(r1 - 8) = r0;				\
712	exit;						\
713"	::: __clobber_all);
714}
715
716SEC("socket")
717__description("unpriv: adding of fp, imm")
718__success __failure_unpriv
719__msg_unpriv("R1 stack pointer arithmetic goes out of range")
720__retval(0)
721__naked void unpriv_adding_of_fp_imm(void)
722{
723	asm volatile ("					\
724	r0 = 0;						\
725	r1 = r10;					\
726	r1 += 0;					\
727	*(u64*)(r1 - 8) = r0;				\
728	exit;						\
729"	::: __clobber_all);
730}
731
732SEC("socket")
733__description("unpriv: cmp of stack pointer")
734__success __failure_unpriv __msg_unpriv("R2 pointer comparison")
735__retval(0)
736__naked void unpriv_cmp_of_stack_pointer(void)
737{
738	asm volatile ("					\
739	r2 = r10;					\
740	r2 += -8;					\
741	if r2 == 0 goto l0_%=;				\
742l0_%=:	r0 = 0;						\
743	exit;						\
744"	::: __clobber_all);
745}
746
747SEC("socket")
748__description("unpriv: Spectre v1 path-based type confusion of scalar as stack-ptr")
749__success __success_unpriv __retval(0)
750#ifdef SPEC_V1
751__xlated_unpriv("if r0 != 0x1 goto pc+2")
752/* This nospec prevents the exploit because it forces the mispredicted (not
753 * taken) `if r0 != 0x0 goto l0_%=` to resolve before using r6 as a pointer.
754 * This causes the CPU to realize that `r6 = r9` should have never executed. It
755 * ensures that r6 always contains a readable stack slot ptr when the insn after
756 * the nospec executes.
757 */
758__xlated_unpriv("nospec")
759__xlated_unpriv("r9 = *(u8 *)(r6 +0)")
760#endif
761__naked void unpriv_spec_v1_type_confusion(void)
762{
763	asm volatile ("					\
764	r1 = 0;						\
765	*(u64*)(r10 - 8) = r1;				\
766	r2 = r10;					\
767	r2 += -8;					\
768	r1 = %[map_hash_8b] ll;				\
769	call %[bpf_map_lookup_elem];			\
770	if r0 == 0 goto l2_%=;				\
771	/* r0: pointer to a map array entry */		\
772	r2 = r10;					\
773	r2 += -8;					\
774	r1 = %[map_hash_8b] ll;				\
775	/* r1, r2: prepared call args */		\
776	r6 = r10;					\
777	r6 += -8;					\
778	/* r6: pointer to readable stack slot */	\
779	r9 = 0xffffc900;				\
780	r9 <<= 32;					\
781	/* r9: scalar controlled by attacker */		\
782	r0 = *(u64 *)(r0 + 0); /* cache miss */		\
783	if r0 != 0x0 goto l0_%=;			\
784	r6 = r9;					\
785l0_%=:	if r0 != 0x1 goto l1_%=;			\
786	r9 = *(u8 *)(r6 + 0);				\
787l1_%=:  /* leak r9 */					\
788	r9 &= 1;					\
789	r9 <<= 9;					\
790	*(u64*)(r10 - 8) = r9;				\
791	call %[bpf_map_lookup_elem];			\
792	if r0 == 0 goto l2_%=;				\
793	/* leak secret into is_cached(map[0|512]): */	\
794	r0 = *(u64 *)(r0 + 0);				\
795l2_%=:							\
796	r0 = 0;						\
797	exit;						\
798"	:
799	: __imm(bpf_map_lookup_elem),
800	  __imm_addr(map_hash_8b)
801	: __clobber_all);
802}
803
804SEC("socket")
805__description("unpriv: ldimm64 before Spectre v4 barrier")
806__success __success_unpriv
807__retval(0)
808#ifdef SPEC_V4
809__xlated_unpriv("r1 = 0x2020200005642020") /* should not matter */
810__xlated_unpriv("*(u64 *)(r10 -8) = r1")
811__xlated_unpriv("nospec")
812#endif
813__naked void unpriv_ldimm64_spectre_v4(void)
814{
815	asm volatile ("					\
816	r1 = 0x2020200005642020 ll;			\
817	*(u64 *)(r10 -8) = r1;				\
818	r0 = 0;						\
819	exit;						\
820"	::: __clobber_all);
821}
822
823SEC("socket")
824__description("unpriv: Spectre v1 and v4 barrier")
825__success __success_unpriv
826__retval(0)
827#ifdef SPEC_V1
828#ifdef SPEC_V4
829/* starts with r0 == r8 == r9 == 0 */
830__xlated_unpriv("if r8 != 0x0 goto pc+1")
831__xlated_unpriv("goto pc+2")
832__xlated_unpriv("if r9 == 0x0 goto pc+4")
833__xlated_unpriv("r2 = r0")
834/* Following nospec required to prevent following dangerous `*(u64 *)(NOT_FP -64)
835 * = r1` iff `if r9 == 0 goto pc+4` was mispredicted because of Spectre v1. The
836 * test therefore ensures the Spectre-v4--induced nospec does not prevent the
837 * Spectre-v1--induced speculative path from being fully analyzed.
838 */
839__xlated_unpriv("nospec") /* Spectre v1 */
840__xlated_unpriv("*(u64 *)(r2 -64) = r1") /* could be used to leak r2 */
841__xlated_unpriv("nospec") /* Spectre v4 */
842#endif
843#endif
844__naked void unpriv_spectre_v1_and_v4(void)
845{
846	asm volatile ("					\
847	r1 = 0;						\
848	*(u64*)(r10 - 8) = r1;				\
849	r2 = r10;					\
850	r2 += -8;					\
851	r1 = %[map_hash_8b] ll;				\
852	call %[bpf_map_lookup_elem];			\
853	r8 = r0;					\
854	r2 = r10;					\
855	r2 += -8;					\
856	r1 = %[map_hash_8b] ll;				\
857	call %[bpf_map_lookup_elem];			\
858	r9 = r0;					\
859	r0 = r10;					\
860	r1 = 0;						\
861	r2 = r10;					\
862	if r8 != 0 goto l0_%=;				\
863	if r9 != 0 goto l0_%=;				\
864	r0 = 0;						\
865l0_%=:	if r8 != 0 goto l1_%=;				\
866	goto l2_%=;					\
867l1_%=:	if r9 == 0 goto l3_%=;				\
868	r2 = r0;					\
869l2_%=:	*(u64 *)(r2 -64) = r1;				\
870l3_%=:	r0 = 0;						\
871	exit;						\
872"	:
873	: __imm(bpf_map_lookup_elem),
874	  __imm_addr(map_hash_8b)
875	: __clobber_all);
876}
877
878SEC("socket")
879__description("unpriv: Spectre v1 and v4 barrier (simple)")
880__success __success_unpriv
881__retval(0)
882#ifdef SPEC_V1
883#ifdef SPEC_V4
884__xlated_unpriv("if r8 != 0x0 goto pc+1")
885__xlated_unpriv("goto pc+2")
886__xlated_unpriv("goto pc-1") /* if r9 == 0 goto l3_%= */
887__xlated_unpriv("goto pc-1") /* r2 = r0 */
888__xlated_unpriv("nospec")
889__xlated_unpriv("*(u64 *)(r2 -64) = r1")
890__xlated_unpriv("nospec")
891#endif
892#endif
893__naked void unpriv_spectre_v1_and_v4_simple(void)
894{
895	asm volatile ("					\
896	r8 = 0;						\
897	r9 = 0;						\
898	r0 = r10;					\
899	r1 = 0;						\
900	r2 = r10;					\
901	if r8 != 0 goto l0_%=;				\
902	if r9 != 0 goto l0_%=;				\
903	r0 = 0;						\
904l0_%=:	if r8 != 0 goto l1_%=;				\
905	goto l2_%=;					\
906l1_%=:	if r9 == 0 goto l3_%=;				\
907	r2 = r0;					\
908l2_%=:	*(u64 *)(r2 -64) = r1;				\
909l3_%=:	r0 = 0;						\
910	exit;						\
911"	::: __clobber_all);
912}
913
914SEC("socket")
915__description("unpriv: ldimm64 before Spectre v1 and v4 barrier (simple)")
916__success __success_unpriv
917__retval(0)
918#ifdef SPEC_V1
919#ifdef SPEC_V4
920__xlated_unpriv("if r8 != 0x0 goto pc+1")
921__xlated_unpriv("goto pc+4")
922__xlated_unpriv("goto pc-1") /* if r9 == 0 goto l3_%= */
923__xlated_unpriv("goto pc-1") /* r2 = r0 */
924__xlated_unpriv("goto pc-1") /* r1 = 0x2020200005642020 ll */
925__xlated_unpriv("goto pc-1") /* second part of ldimm64 */
926__xlated_unpriv("nospec")
927__xlated_unpriv("*(u64 *)(r2 -64) = r1")
928__xlated_unpriv("nospec")
929#endif
930#endif
931__naked void unpriv_ldimm64_spectre_v1_and_v4_simple(void)
932{
933	asm volatile ("					\
934	r8 = 0;						\
935	r9 = 0;						\
936	r0 = r10;					\
937	r1 = 0;						\
938	r2 = r10;					\
939	if r8 != 0 goto l0_%=;				\
940	if r9 != 0 goto l0_%=;				\
941	r0 = 0;						\
942l0_%=:	if r8 != 0 goto l1_%=;				\
943	goto l2_%=;					\
944l1_%=:	if r9 == 0 goto l3_%=;				\
945	r2 = r0;					\
946	r1 = 0x2020200005642020 ll;			\
947l2_%=:	*(u64 *)(r2 -64) = r1;				\
948l3_%=:	r0 = 0;						\
949	exit;						\
950"	::: __clobber_all);
951}
952
953char _license[] SEC("license") = "GPL";
~/ Read-only file preview.