brintos

brintos / linux-shallow public Read only

0
0
Text · 29.5 KiB · a0bb7fb Raw
1204 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Converted from tools/testing/selftests/bpf/verifier/bounds.c */3 4#include <linux/bpf.h>5#include <bpf/bpf_helpers.h>6#include "bpf_misc.h"7 8struct {9	__uint(type, BPF_MAP_TYPE_HASH);10	__uint(max_entries, 1);11	__type(key, long long);12	__type(value, long long);13} map_hash_8b SEC(".maps");14 15SEC("socket")16__description("subtraction bounds (map value) variant 1")17__failure __msg("R0 max value is outside of the allowed memory range")18__failure_unpriv19__naked void bounds_map_value_variant_1(void)20{21	asm volatile ("					\22	r1 = 0;						\23	*(u64*)(r10 - 8) = r1;				\24	r2 = r10;					\25	r2 += -8;					\26	r1 = %[map_hash_8b] ll;				\27	call %[bpf_map_lookup_elem];			\28	if r0 == 0 goto l0_%=;				\29	r1 = *(u8*)(r0 + 0);				\30	if r1 > 0xff goto l0_%=;			\31	r3 = *(u8*)(r0 + 1);				\32	if r3 > 0xff goto l0_%=;			\33	r1 -= r3;					\34	r1 >>= 56;					\35	r0 += r1;					\36	r0 = *(u8*)(r0 + 0);				\37	exit;						\38l0_%=:	r0 = 0;						\39	exit;						\40"	:41	: __imm(bpf_map_lookup_elem),42	  __imm_addr(map_hash_8b)43	: __clobber_all);44}45 46SEC("socket")47__description("subtraction bounds (map value) variant 2")48__failure49__msg("R0 min value is negative, either use unsigned index or do a if (index >=0) check.")50__msg_unpriv("R1 has unknown scalar with mixed signed bounds")51__naked void bounds_map_value_variant_2(void)52{53	asm volatile ("					\54	r1 = 0;						\55	*(u64*)(r10 - 8) = r1;				\56	r2 = r10;					\57	r2 += -8;					\58	r1 = %[map_hash_8b] ll;				\59	call %[bpf_map_lookup_elem];			\60	if r0 == 0 goto l0_%=;				\61	r1 = *(u8*)(r0 + 0);				\62	if r1 > 0xff goto l0_%=;			\63	r3 = *(u8*)(r0 + 1);				\64	if r3 > 0xff goto l0_%=;			\65	r1 -= r3;					\66	r0 += r1;					\67	r0 = *(u8*)(r0 + 0);				\68	exit;						\69l0_%=:	r0 = 0;						\70	exit;						\71"	:72	: __imm(bpf_map_lookup_elem),73	  __imm_addr(map_hash_8b)74	: __clobber_all);75}76 77SEC("socket")78__description("check subtraction on pointers for unpriv")79__success __failure_unpriv __msg_unpriv("R9 pointer -= pointer prohibited")80__retval(0)81__naked void subtraction_on_pointers_for_unpriv(void)82{83	asm volatile ("					\84	r0 = 0;						\85	r1 = %[map_hash_8b] ll;				\86	r2 = r10;					\87	r2 += -8;					\88	r6 = 9;						\89	*(u64*)(r2 + 0) = r6;				\90	call %[bpf_map_lookup_elem];			\91	r9 = r10;					\92	r9 -= r0;					\93	r1 = %[map_hash_8b] ll;				\94	r2 = r10;					\95	r2 += -8;					\96	r6 = 0;						\97	*(u64*)(r2 + 0) = r6;				\98	call %[bpf_map_lookup_elem];			\99	if r0 != 0 goto l0_%=;				\100	exit;						\101l0_%=:	*(u64*)(r0 + 0) = r9;				\102	r0 = 0;						\103	exit;						\104"	:105	: __imm(bpf_map_lookup_elem),106	  __imm_addr(map_hash_8b)107	: __clobber_all);108}109 110SEC("socket")111__description("bounds check based on zero-extended MOV")112__success __success_unpriv __retval(0)113__naked void based_on_zero_extended_mov(void)114{115	asm volatile ("					\116	r1 = 0;						\117	*(u64*)(r10 - 8) = r1;				\118	r2 = r10;					\119	r2 += -8;					\120	r1 = %[map_hash_8b] ll;				\121	call %[bpf_map_lookup_elem];			\122	if r0 == 0 goto l0_%=;				\123	/* r2 = 0x0000'0000'ffff'ffff */		\124	w2 = 0xffffffff;				\125	/* r2 = 0 */					\126	r2 >>= 32;					\127	/* no-op */					\128	r0 += r2;					\129	/* access at offset 0 */			\130	r0 = *(u8*)(r0 + 0);				\131l0_%=:	/* exit */					\132	r0 = 0;						\133	exit;						\134"	:135	: __imm(bpf_map_lookup_elem),136	  __imm_addr(map_hash_8b)137	: __clobber_all);138}139 140SEC("socket")141__description("bounds check based on sign-extended MOV. test1")142__failure __msg("map_value pointer and 4294967295")143__failure_unpriv144__naked void on_sign_extended_mov_test1(void)145{146	asm volatile ("					\147	r1 = 0;						\148	*(u64*)(r10 - 8) = r1;				\149	r2 = r10;					\150	r2 += -8;					\151	r1 = %[map_hash_8b] ll;				\152	call %[bpf_map_lookup_elem];			\153	if r0 == 0 goto l0_%=;				\154	/* r2 = 0xffff'ffff'ffff'ffff */		\155	r2 = 0xffffffff;				\156	/* r2 = 0xffff'ffff */				\157	r2 >>= 32;					\158	/* r0 = <oob pointer> */			\159	r0 += r2;					\160	/* access to OOB pointer */			\161	r0 = *(u8*)(r0 + 0);				\162l0_%=:	/* exit */					\163	r0 = 0;						\164	exit;						\165"	:166	: __imm(bpf_map_lookup_elem),167	  __imm_addr(map_hash_8b)168	: __clobber_all);169}170 171SEC("socket")172__description("bounds check based on sign-extended MOV. test2")173__failure __msg("R0 min value is outside of the allowed memory range")174__failure_unpriv175__naked void on_sign_extended_mov_test2(void)176{177	asm volatile ("					\178	r1 = 0;						\179	*(u64*)(r10 - 8) = r1;				\180	r2 = r10;					\181	r2 += -8;					\182	r1 = %[map_hash_8b] ll;				\183	call %[bpf_map_lookup_elem];			\184	if r0 == 0 goto l0_%=;				\185	/* r2 = 0xffff'ffff'ffff'ffff */		\186	r2 = 0xffffffff;				\187	/* r2 = 0xfff'ffff */				\188	r2 >>= 36;					\189	/* r0 = <oob pointer> */			\190	r0 += r2;					\191	/* access to OOB pointer */			\192	r0 = *(u8*)(r0 + 0);				\193l0_%=:	/* exit */					\194	r0 = 0;						\195	exit;						\196"	:197	: __imm(bpf_map_lookup_elem),198	  __imm_addr(map_hash_8b)199	: __clobber_all);200}201 202SEC("tc")203__description("bounds check based on reg_off + var_off + insn_off. test1")204__failure __msg("value_size=8 off=1073741825")205__naked void var_off_insn_off_test1(void)206{207	asm volatile ("					\208	r6 = *(u32*)(r1 + %[__sk_buff_mark]);		\209	r1 = 0;						\210	*(u64*)(r10 - 8) = r1;				\211	r2 = r10;					\212	r2 += -8;					\213	r1 = %[map_hash_8b] ll;				\214	call %[bpf_map_lookup_elem];			\215	if r0 == 0 goto l0_%=;				\216	r6 &= 1;					\217	r6 += %[__imm_0];				\218	r0 += r6;					\219	r0 += %[__imm_0];				\220l0_%=:	r0 = *(u8*)(r0 + 3);				\221	r0 = 0;						\222	exit;						\223"	:224	: __imm(bpf_map_lookup_elem),225	  __imm_addr(map_hash_8b),226	  __imm_const(__imm_0, (1 << 29) - 1),227	  __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))228	: __clobber_all);229}230 231SEC("tc")232__description("bounds check based on reg_off + var_off + insn_off. test2")233__failure __msg("value 1073741823")234__naked void var_off_insn_off_test2(void)235{236	asm volatile ("					\237	r6 = *(u32*)(r1 + %[__sk_buff_mark]);		\238	r1 = 0;						\239	*(u64*)(r10 - 8) = r1;				\240	r2 = r10;					\241	r2 += -8;					\242	r1 = %[map_hash_8b] ll;				\243	call %[bpf_map_lookup_elem];			\244	if r0 == 0 goto l0_%=;				\245	r6 &= 1;					\246	r6 += %[__imm_0];				\247	r0 += r6;					\248	r0 += %[__imm_1];				\249l0_%=:	r0 = *(u8*)(r0 + 3);				\250	r0 = 0;						\251	exit;						\252"	:253	: __imm(bpf_map_lookup_elem),254	  __imm_addr(map_hash_8b),255	  __imm_const(__imm_0, (1 << 30) - 1),256	  __imm_const(__imm_1, (1 << 29) - 1),257	  __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))258	: __clobber_all);259}260 261SEC("socket")262__description("bounds check after truncation of non-boundary-crossing range")263__success __success_unpriv __retval(0)264__naked void of_non_boundary_crossing_range(void)265{266	asm volatile ("					\267	r1 = 0;						\268	*(u64*)(r10 - 8) = r1;				\269	r2 = r10;					\270	r2 += -8;					\271	r1 = %[map_hash_8b] ll;				\272	call %[bpf_map_lookup_elem];			\273	if r0 == 0 goto l0_%=;				\274	/* r1 = [0x00, 0xff] */				\275	r1 = *(u8*)(r0 + 0);				\276	r2 = 1;						\277	/* r2 = 0x10'0000'0000 */			\278	r2 <<= 36;					\279	/* r1 = [0x10'0000'0000, 0x10'0000'00ff] */	\280	r1 += r2;					\281	/* r1 = [0x10'7fff'ffff, 0x10'8000'00fe] */	\282	r1 += 0x7fffffff;				\283	/* r1 = [0x00, 0xff] */				\284	w1 -= 0x7fffffff;				\285	/* r1 = 0 */					\286	r1 >>= 8;					\287	/* no-op */					\288	r0 += r1;					\289	/* access at offset 0 */			\290	r0 = *(u8*)(r0 + 0);				\291l0_%=:	/* exit */					\292	r0 = 0;						\293	exit;						\294"	:295	: __imm(bpf_map_lookup_elem),296	  __imm_addr(map_hash_8b)297	: __clobber_all);298}299 300SEC("socket")301__description("bounds check after truncation of boundary-crossing range (1)")302__failure303/* not actually fully unbounded, but the bound is very high */304__msg("value -4294967168 makes map_value pointer be out of bounds")305__failure_unpriv306__naked void of_boundary_crossing_range_1(void)307{308	asm volatile ("					\309	r1 = 0;						\310	*(u64*)(r10 - 8) = r1;				\311	r2 = r10;					\312	r2 += -8;					\313	r1 = %[map_hash_8b] ll;				\314	call %[bpf_map_lookup_elem];			\315	if r0 == 0 goto l0_%=;				\316	/* r1 = [0x00, 0xff] */				\317	r1 = *(u8*)(r0 + 0);				\318	r1 += %[__imm_0];				\319	/* r1 = [0xffff'ff80, 0x1'0000'007f] */		\320	r1 += %[__imm_0];				\321	/* r1 = [0xffff'ff80, 0xffff'ffff] or		\322	 *      [0x0000'0000, 0x0000'007f]		\323	 */						\324	w1 += 0;					\325	r1 -= %[__imm_0];				\326	/* r1 = [0x00, 0xff] or				\327	 *      [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff]\328	 */						\329	r1 -= %[__imm_0];				\330	/* error on OOB pointer computation */		\331	r0 += r1;					\332	/* exit */					\333	r0 = 0;						\334l0_%=:	exit;						\335"	:336	: __imm(bpf_map_lookup_elem),337	  __imm_addr(map_hash_8b),338	  __imm_const(__imm_0, 0xffffff80 >> 1)339	: __clobber_all);340}341 342SEC("socket")343__description("bounds check after truncation of boundary-crossing range (2)")344__failure __msg("value -4294967168 makes map_value pointer be out of bounds")345__failure_unpriv346__naked void of_boundary_crossing_range_2(void)347{348	asm volatile ("					\349	r1 = 0;						\350	*(u64*)(r10 - 8) = r1;				\351	r2 = r10;					\352	r2 += -8;					\353	r1 = %[map_hash_8b] ll;				\354	call %[bpf_map_lookup_elem];			\355	if r0 == 0 goto l0_%=;				\356	/* r1 = [0x00, 0xff] */				\357	r1 = *(u8*)(r0 + 0);				\358	r1 += %[__imm_0];				\359	/* r1 = [0xffff'ff80, 0x1'0000'007f] */		\360	r1 += %[__imm_0];				\361	/* r1 = [0xffff'ff80, 0xffff'ffff] or		\362	 *      [0x0000'0000, 0x0000'007f]		\363	 * difference to previous test: truncation via MOV32\364	 * instead of ALU32.				\365	 */						\366	w1 = w1;					\367	r1 -= %[__imm_0];				\368	/* r1 = [0x00, 0xff] or				\369	 *      [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff]\370	 */						\371	r1 -= %[__imm_0];				\372	/* error on OOB pointer computation */		\373	r0 += r1;					\374	/* exit */					\375	r0 = 0;						\376l0_%=:	exit;						\377"	:378	: __imm(bpf_map_lookup_elem),379	  __imm_addr(map_hash_8b),380	  __imm_const(__imm_0, 0xffffff80 >> 1)381	: __clobber_all);382}383 384SEC("socket")385__description("bounds check after wrapping 32-bit addition")386__success __success_unpriv __retval(0)387__naked void after_wrapping_32_bit_addition(void)388{389	asm volatile ("					\390	r1 = 0;						\391	*(u64*)(r10 - 8) = r1;				\392	r2 = r10;					\393	r2 += -8;					\394	r1 = %[map_hash_8b] ll;				\395	call %[bpf_map_lookup_elem];			\396	if r0 == 0 goto l0_%=;				\397	/* r1 = 0x7fff'ffff */				\398	r1 = 0x7fffffff;				\399	/* r1 = 0xffff'fffe */				\400	r1 += 0x7fffffff;				\401	/* r1 = 0 */					\402	w1 += 2;					\403	/* no-op */					\404	r0 += r1;					\405	/* access at offset 0 */			\406	r0 = *(u8*)(r0 + 0);				\407l0_%=:	/* exit */					\408	r0 = 0;						\409	exit;						\410"	:411	: __imm(bpf_map_lookup_elem),412	  __imm_addr(map_hash_8b)413	: __clobber_all);414}415 416SEC("socket")417__description("bounds check after shift with oversized count operand")418__failure __msg("R0 max value is outside of the allowed memory range")419__failure_unpriv420__naked void shift_with_oversized_count_operand(void)421{422	asm volatile ("					\423	r1 = 0;						\424	*(u64*)(r10 - 8) = r1;				\425	r2 = r10;					\426	r2 += -8;					\427	r1 = %[map_hash_8b] ll;				\428	call %[bpf_map_lookup_elem];			\429	if r0 == 0 goto l0_%=;				\430	r2 = 32;					\431	r1 = 1;						\432	/* r1 = (u32)1 << (u32)32 = ? */		\433	w1 <<= w2;					\434	/* r1 = [0x0000, 0xffff] */			\435	r1 &= 0xffff;					\436	/* computes unknown pointer, potentially OOB */	\437	r0 += r1;					\438	/* potentially OOB access */			\439	r0 = *(u8*)(r0 + 0);				\440l0_%=:	/* exit */					\441	r0 = 0;						\442	exit;						\443"	:444	: __imm(bpf_map_lookup_elem),445	  __imm_addr(map_hash_8b)446	: __clobber_all);447}448 449SEC("socket")450__description("bounds check after right shift of maybe-negative number")451__failure __msg("R0 unbounded memory access")452__failure_unpriv453__naked void shift_of_maybe_negative_number(void)454{455	asm volatile ("					\456	r1 = 0;						\457	*(u64*)(r10 - 8) = r1;				\458	r2 = r10;					\459	r2 += -8;					\460	r1 = %[map_hash_8b] ll;				\461	call %[bpf_map_lookup_elem];			\462	if r0 == 0 goto l0_%=;				\463	/* r1 = [0x00, 0xff] */				\464	r1 = *(u8*)(r0 + 0);				\465	/* r1 = [-0x01, 0xfe] */			\466	r1 -= 1;					\467	/* r1 = 0 or 0xff'ffff'ffff'ffff */		\468	r1 >>= 8;					\469	/* r1 = 0 or 0xffff'ffff'ffff */		\470	r1 >>= 8;					\471	/* computes unknown pointer, potentially OOB */	\472	r0 += r1;					\473	/* potentially OOB access */			\474	r0 = *(u8*)(r0 + 0);				\475l0_%=:	/* exit */					\476	r0 = 0;						\477	exit;						\478"	:479	: __imm(bpf_map_lookup_elem),480	  __imm_addr(map_hash_8b)481	: __clobber_all);482}483 484SEC("socket")485__description("bounds check after 32-bit right shift with 64-bit input")486__failure __msg("math between map_value pointer and 4294967294 is not allowed")487__failure_unpriv488__naked void shift_with_64_bit_input(void)489{490	asm volatile ("					\491	r1 = 0;						\492	*(u64*)(r10 - 8) = r1;				\493	r2 = r10;					\494	r2 += -8;					\495	r1 = %[map_hash_8b] ll;				\496	call %[bpf_map_lookup_elem];			\497	if r0 == 0 goto l0_%=;				\498	r1 = 2;						\499	/* r1 = 1<<32 */				\500	r1 <<= 31;					\501	/* r1 = 0 (NOT 2!) */				\502	w1 >>= 31;					\503	/* r1 = 0xffff'fffe (NOT 0!) */			\504	w1 -= 2;					\505	/* error on computing OOB pointer */		\506	r0 += r1;					\507	/* exit */					\508	r0 = 0;						\509l0_%=:	exit;						\510"	:511	: __imm(bpf_map_lookup_elem),512	  __imm_addr(map_hash_8b)513	: __clobber_all);514}515 516SEC("socket")517__description("bounds check map access with off+size signed 32bit overflow. test1")518__failure __msg("map_value pointer and 2147483646")519__failure_unpriv520__naked void size_signed_32bit_overflow_test1(void)521{522	asm volatile ("					\523	r1 = 0;						\524	*(u64*)(r10 - 8) = r1;				\525	r2 = r10;					\526	r2 += -8;					\527	r1 = %[map_hash_8b] ll;				\528	call %[bpf_map_lookup_elem];			\529	if r0 != 0 goto l0_%=;				\530	exit;						\531l0_%=:	r0 += 0x7ffffffe;				\532	r0 = *(u64*)(r0 + 0);				\533	goto l1_%=;					\534l1_%=:	exit;						\535"	:536	: __imm(bpf_map_lookup_elem),537	  __imm_addr(map_hash_8b)538	: __clobber_all);539}540 541SEC("socket")542__description("bounds check map access with off+size signed 32bit overflow. test2")543__failure __msg("pointer offset 1073741822")544__msg_unpriv("R0 pointer arithmetic of map value goes out of range")545__naked void size_signed_32bit_overflow_test2(void)546{547	asm volatile ("					\548	r1 = 0;						\549	*(u64*)(r10 - 8) = r1;				\550	r2 = r10;					\551	r2 += -8;					\552	r1 = %[map_hash_8b] ll;				\553	call %[bpf_map_lookup_elem];			\554	if r0 != 0 goto l0_%=;				\555	exit;						\556l0_%=:	r0 += 0x1fffffff;				\557	r0 += 0x1fffffff;				\558	r0 += 0x1fffffff;				\559	r0 = *(u64*)(r0 + 0);				\560	goto l1_%=;					\561l1_%=:	exit;						\562"	:563	: __imm(bpf_map_lookup_elem),564	  __imm_addr(map_hash_8b)565	: __clobber_all);566}567 568SEC("socket")569__description("bounds check map access with off+size signed 32bit overflow. test3")570__failure __msg("pointer offset -1073741822")571__msg_unpriv("R0 pointer arithmetic of map value goes out of range")572__naked void size_signed_32bit_overflow_test3(void)573{574	asm volatile ("					\575	r1 = 0;						\576	*(u64*)(r10 - 8) = r1;				\577	r2 = r10;					\578	r2 += -8;					\579	r1 = %[map_hash_8b] ll;				\580	call %[bpf_map_lookup_elem];			\581	if r0 != 0 goto l0_%=;				\582	exit;						\583l0_%=:	r0 -= 0x1fffffff;				\584	r0 -= 0x1fffffff;				\585	r0 = *(u64*)(r0 + 2);				\586	goto l1_%=;					\587l1_%=:	exit;						\588"	:589	: __imm(bpf_map_lookup_elem),590	  __imm_addr(map_hash_8b)591	: __clobber_all);592}593 594SEC("socket")595__description("bounds check map access with off+size signed 32bit overflow. test4")596__failure __msg("map_value pointer and 1000000000000")597__failure_unpriv598__naked void size_signed_32bit_overflow_test4(void)599{600	asm volatile ("					\601	r1 = 0;						\602	*(u64*)(r10 - 8) = r1;				\603	r2 = r10;					\604	r2 += -8;					\605	r1 = %[map_hash_8b] ll;				\606	call %[bpf_map_lookup_elem];			\607	if r0 != 0 goto l0_%=;				\608	exit;						\609l0_%=:	r1 = 1000000;					\610	r1 *= 1000000;					\611	r0 += r1;					\612	r0 = *(u64*)(r0 + 2);				\613	goto l1_%=;					\614l1_%=:	exit;						\615"	:616	: __imm(bpf_map_lookup_elem),617	  __imm_addr(map_hash_8b)618	: __clobber_all);619}620 621SEC("socket")622__description("bounds check mixed 32bit and 64bit arithmetic. test1")623__success __failure_unpriv __msg_unpriv("R0 invalid mem access 'scalar'")624__retval(0)625__naked void _32bit_and_64bit_arithmetic_test1(void)626{627	asm volatile ("					\628	r0 = 0;						\629	r1 = -1;					\630	r1 <<= 32;					\631	r1 += 1;					\632	/* r1 = 0xffffFFFF00000001 */			\633	if w1 > 1 goto l0_%=;				\634	/* check ALU64 op keeps 32bit bounds */		\635	r1 += 1;					\636	if w1 > 2 goto l0_%=;				\637	goto l1_%=;					\638l0_%=:	/* invalid ldx if bounds are lost above */	\639	r0 = *(u64*)(r0 - 1);				\640l1_%=:	exit;						\641"	::: __clobber_all);642}643 644SEC("socket")645__description("bounds check mixed 32bit and 64bit arithmetic. test2")646__success __failure_unpriv __msg_unpriv("R0 invalid mem access 'scalar'")647__retval(0)648__naked void _32bit_and_64bit_arithmetic_test2(void)649{650	asm volatile ("					\651	r0 = 0;						\652	r1 = -1;					\653	r1 <<= 32;					\654	r1 += 1;					\655	/* r1 = 0xffffFFFF00000001 */			\656	r2 = 3;						\657	/* r1 = 0x2 */					\658	w1 += 1;					\659	/* check ALU32 op zero extends 64bit bounds */	\660	if r1 > r2 goto l0_%=;				\661	goto l1_%=;					\662l0_%=:	/* invalid ldx if bounds are lost above */	\663	r0 = *(u64*)(r0 - 1);				\664l1_%=:	exit;						\665"	::: __clobber_all);666}667 668SEC("tc")669__description("assigning 32bit bounds to 64bit for wA = 0, wB = wA")670__success __retval(0) __flag(BPF_F_ANY_ALIGNMENT)671__naked void for_wa_0_wb_wa(void)672{673	asm volatile ("					\674	r8 = *(u32*)(r1 + %[__sk_buff_data_end]);	\675	r7 = *(u32*)(r1 + %[__sk_buff_data]);		\676	w9 = 0;						\677	w2 = w9;					\678	r6 = r7;					\679	r6 += r2;					\680	r3 = r6;					\681	r3 += 8;					\682	if r3 > r8 goto l0_%=;				\683	r5 = *(u32*)(r6 + 0);				\684l0_%=:	r0 = 0;						\685	exit;						\686"	:687	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),688	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))689	: __clobber_all);690}691 692SEC("socket")693__description("bounds check for reg = 0, reg xor 1")694__success __failure_unpriv695__msg_unpriv("R0 min value is outside of the allowed memory range")696__retval(0)697__naked void reg_0_reg_xor_1(void)698{699	asm volatile ("					\700	r1 = 0;						\701	*(u64*)(r10 - 8) = r1;				\702	r2 = r10;					\703	r2 += -8;					\704	r1 = %[map_hash_8b] ll;				\705	call %[bpf_map_lookup_elem];			\706	if r0 != 0 goto l0_%=;				\707	exit;						\708l0_%=:	r1 = 0;						\709	r1 ^= 1;					\710	if r1 != 0 goto l1_%=;				\711	r0 = *(u64*)(r0 + 8);				\712l1_%=:	r0 = 0;						\713	exit;						\714"	:715	: __imm(bpf_map_lookup_elem),716	  __imm_addr(map_hash_8b)717	: __clobber_all);718}719 720SEC("socket")721__description("bounds check for reg32 = 0, reg32 xor 1")722__success __failure_unpriv723__msg_unpriv("R0 min value is outside of the allowed memory range")724__retval(0)725__naked void reg32_0_reg32_xor_1(void)726{727	asm volatile ("					\728	r1 = 0;						\729	*(u64*)(r10 - 8) = r1;				\730	r2 = r10;					\731	r2 += -8;					\732	r1 = %[map_hash_8b] ll;				\733	call %[bpf_map_lookup_elem];			\734	if r0 != 0 goto l0_%=;				\735	exit;						\736l0_%=:	w1 = 0;						\737	w1 ^= 1;					\738	if w1 != 0 goto l1_%=;				\739	r0 = *(u64*)(r0 + 8);				\740l1_%=:	r0 = 0;						\741	exit;						\742"	:743	: __imm(bpf_map_lookup_elem),744	  __imm_addr(map_hash_8b)745	: __clobber_all);746}747 748SEC("socket")749__description("bounds check for reg = 2, reg xor 3")750__success __failure_unpriv751__msg_unpriv("R0 min value is outside of the allowed memory range")752__retval(0)753__naked void reg_2_reg_xor_3(void)754{755	asm volatile ("					\756	r1 = 0;						\757	*(u64*)(r10 - 8) = r1;				\758	r2 = r10;					\759	r2 += -8;					\760	r1 = %[map_hash_8b] ll;				\761	call %[bpf_map_lookup_elem];			\762	if r0 != 0 goto l0_%=;				\763	exit;						\764l0_%=:	r1 = 2;						\765	r1 ^= 3;					\766	if r1 > 0 goto l1_%=;				\767	r0 = *(u64*)(r0 + 8);				\768l1_%=:	r0 = 0;						\769	exit;						\770"	:771	: __imm(bpf_map_lookup_elem),772	  __imm_addr(map_hash_8b)773	: __clobber_all);774}775 776SEC("socket")777__description("bounds check for reg = any, reg xor 3")778__failure __msg("invalid access to map value")779__msg_unpriv("invalid access to map value")780__naked void reg_any_reg_xor_3(void)781{782	asm volatile ("					\783	r1 = 0;						\784	*(u64*)(r10 - 8) = r1;				\785	r2 = r10;					\786	r2 += -8;					\787	r1 = %[map_hash_8b] ll;				\788	call %[bpf_map_lookup_elem];			\789	if r0 != 0 goto l0_%=;				\790	exit;						\791l0_%=:	r1 = *(u64*)(r0 + 0);				\792	r1 ^= 3;					\793	if r1 != 0 goto l1_%=;				\794	r0 = *(u64*)(r0 + 8);				\795l1_%=:	r0 = 0;						\796	exit;						\797"	:798	: __imm(bpf_map_lookup_elem),799	  __imm_addr(map_hash_8b)800	: __clobber_all);801}802 803SEC("socket")804__description("bounds check for reg32 = any, reg32 xor 3")805__failure __msg("invalid access to map value")806__msg_unpriv("invalid access to map value")807__naked void reg32_any_reg32_xor_3(void)808{809	asm volatile ("					\810	r1 = 0;						\811	*(u64*)(r10 - 8) = r1;				\812	r2 = r10;					\813	r2 += -8;					\814	r1 = %[map_hash_8b] ll;				\815	call %[bpf_map_lookup_elem];			\816	if r0 != 0 goto l0_%=;				\817	exit;						\818l0_%=:	r1 = *(u64*)(r0 + 0);				\819	w1 ^= 3;					\820	if w1 != 0 goto l1_%=;				\821	r0 = *(u64*)(r0 + 8);				\822l1_%=:	r0 = 0;						\823	exit;						\824"	:825	: __imm(bpf_map_lookup_elem),826	  __imm_addr(map_hash_8b)827	: __clobber_all);828}829 830SEC("socket")831__description("bounds check for reg > 0, reg xor 3")832__success __failure_unpriv833__msg_unpriv("R0 min value is outside of the allowed memory range")834__retval(0)835__naked void reg_0_reg_xor_3(void)836{837	asm volatile ("					\838	r1 = 0;						\839	*(u64*)(r10 - 8) = r1;				\840	r2 = r10;					\841	r2 += -8;					\842	r1 = %[map_hash_8b] ll;				\843	call %[bpf_map_lookup_elem];			\844	if r0 != 0 goto l0_%=;				\845	exit;						\846l0_%=:	r1 = *(u64*)(r0 + 0);				\847	if r1 <= 0 goto l1_%=;				\848	r1 ^= 3;					\849	if r1 >= 0 goto l1_%=;				\850	r0 = *(u64*)(r0 + 8);				\851l1_%=:	r0 = 0;						\852	exit;						\853"	:854	: __imm(bpf_map_lookup_elem),855	  __imm_addr(map_hash_8b)856	: __clobber_all);857}858 859SEC("socket")860__description("bounds check for reg32 > 0, reg32 xor 3")861__success __failure_unpriv862__msg_unpriv("R0 min value is outside of the allowed memory range")863__retval(0)864__naked void reg32_0_reg32_xor_3(void)865{866	asm volatile ("					\867	r1 = 0;						\868	*(u64*)(r10 - 8) = r1;				\869	r2 = r10;					\870	r2 += -8;					\871	r1 = %[map_hash_8b] ll;				\872	call %[bpf_map_lookup_elem];			\873	if r0 != 0 goto l0_%=;				\874	exit;						\875l0_%=:	r1 = *(u64*)(r0 + 0);				\876	if w1 <= 0 goto l1_%=;				\877	w1 ^= 3;					\878	if w1 >= 0 goto l1_%=;				\879	r0 = *(u64*)(r0 + 8);				\880l1_%=:	r0 = 0;						\881	exit;						\882"	:883	: __imm(bpf_map_lookup_elem),884	  __imm_addr(map_hash_8b)885	: __clobber_all);886}887 888SEC("socket")889__description("bounds check for non const xor src dst")890__success __log_level(2)891__msg("5: (af) r0 ^= r6                      ; R0_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=431,var_off=(0x0; 0x1af))")892__naked void non_const_xor_src_dst(void)893{894	asm volatile ("					\895	call %[bpf_get_prandom_u32];                    \896	r6 = r0;					\897	call %[bpf_get_prandom_u32];                    \898	r6 &= 0xaf;					\899	r0 &= 0x1a0;					\900	r0 ^= r6;					\901	exit;						\902"	:903	: __imm(bpf_map_lookup_elem),904	__imm_addr(map_hash_8b),905	__imm(bpf_get_prandom_u32)906	: __clobber_all);907}908 909SEC("socket")910__description("bounds check for non const or src dst")911__success __log_level(2)912__msg("5: (4f) r0 |= r6                      ; R0_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=431,var_off=(0x0; 0x1af))")913__naked void non_const_or_src_dst(void)914{915	asm volatile ("					\916	call %[bpf_get_prandom_u32];                    \917	r6 = r0;					\918	call %[bpf_get_prandom_u32];                    \919	r6 &= 0xaf;					\920	r0 &= 0x1a0;					\921	r0 |= r6;					\922	exit;						\923"	:924	: __imm(bpf_map_lookup_elem),925	__imm_addr(map_hash_8b),926	__imm(bpf_get_prandom_u32)927	: __clobber_all);928}929 930SEC("socket")931__description("bounds check for non const mul regs")932__success __log_level(2)933__msg("5: (2f) r0 *= r6                      ; R0_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=3825,var_off=(0x0; 0xfff))")934__naked void non_const_mul_regs(void)935{936	asm volatile ("					\937	call %[bpf_get_prandom_u32];                    \938	r6 = r0;					\939	call %[bpf_get_prandom_u32];                    \940	r6 &= 0xff;					\941	r0 &= 0x0f;					\942	r0 *= r6;					\943	exit;						\944"	:945	: __imm(bpf_map_lookup_elem),946	__imm_addr(map_hash_8b),947	__imm(bpf_get_prandom_u32)948	: __clobber_all);949}950 951SEC("socket")952__description("bounds checks after 32-bit truncation. test 1")953__success __failure_unpriv __msg_unpriv("R0 leaks addr")954__retval(0)955__naked void _32_bit_truncation_test_1(void)956{957	asm volatile ("					\958	r1 = 0;						\959	*(u64*)(r10 - 8) = r1;				\960	r2 = r10;					\961	r2 += -8;					\962	r1 = %[map_hash_8b] ll;				\963	call %[bpf_map_lookup_elem];			\964	if r0 == 0 goto l0_%=;				\965	r1 = *(u32*)(r0 + 0);				\966	/* This used to reduce the max bound to 0x7fffffff */\967	if r1 == 0 goto l1_%=;				\968	if r1 > 0x7fffffff goto l0_%=;			\969l1_%=:	r0 = 0;						\970l0_%=:	exit;						\971"	:972	: __imm(bpf_map_lookup_elem),973	  __imm_addr(map_hash_8b)974	: __clobber_all);975}976 977SEC("socket")978__description("bounds checks after 32-bit truncation. test 2")979__success __failure_unpriv __msg_unpriv("R0 leaks addr")980__retval(0)981__naked void _32_bit_truncation_test_2(void)982{983	asm volatile ("					\984	r1 = 0;						\985	*(u64*)(r10 - 8) = r1;				\986	r2 = r10;					\987	r2 += -8;					\988	r1 = %[map_hash_8b] ll;				\989	call %[bpf_map_lookup_elem];			\990	if r0 == 0 goto l0_%=;				\991	r1 = *(u32*)(r0 + 0);				\992	if r1 s< 1 goto l1_%=;				\993	if w1 s< 0 goto l0_%=;				\994l1_%=:	r0 = 0;						\995l0_%=:	exit;						\996"	:997	: __imm(bpf_map_lookup_elem),998	  __imm_addr(map_hash_8b)999	: __clobber_all);1000}1001 1002SEC("xdp")1003__description("bound check with JMP_JLT for crossing 64-bit signed boundary")1004__success __retval(0)1005__naked void crossing_64_bit_signed_boundary_1(void)1006{1007	asm volatile ("					\1008	r2 = *(u32*)(r1 + %[xdp_md_data]);		\1009	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\1010	r1 = r2;					\1011	r1 += 1;					\1012	if r1 > r3 goto l0_%=;				\1013	r1 = *(u8*)(r2 + 0);				\1014	r0 = 0x7fffffffffffff10 ll;			\1015	r1 += r0;					\1016	r0 = 0x8000000000000000 ll;			\1017l1_%=:	r0 += 1;					\1018	/* r1 unsigned range is [0x7fffffffffffff10, 0x800000000000000f] */\1019	if r0 < r1 goto l1_%=;				\1020l0_%=:	r0 = 0;						\1021	exit;						\1022"	:1023	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),1024	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))1025	: __clobber_all);1026}1027 1028SEC("xdp")1029__description("bound check with JMP_JSLT for crossing 64-bit signed boundary")1030__success __retval(0)1031__flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */1032__naked void crossing_64_bit_signed_boundary_2(void)1033{1034	asm volatile ("					\1035	r2 = *(u32*)(r1 + %[xdp_md_data]);		\1036	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\1037	r1 = r2;					\1038	r1 += 1;					\1039	if r1 > r3 goto l0_%=;				\1040	r1 = *(u8*)(r2 + 0);				\1041	r0 = 0x7fffffffffffff10 ll;			\1042	r1 += r0;					\1043	r2 = 0x8000000000000fff ll;			\1044	r0 = 0x8000000000000000 ll;			\1045l1_%=:	r0 += 1;					\1046	if r0 s> r2 goto l0_%=;				\1047	/* r1 signed range is [S64_MIN, S64_MAX] */	\1048	if r0 s< r1 goto l1_%=;				\1049	r0 = 1;						\1050	exit;						\1051l0_%=:	r0 = 0;						\1052	exit;						\1053"	:1054	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),1055	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))1056	: __clobber_all);1057}1058 1059SEC("xdp")1060__description("bound check for loop upper bound greater than U32_MAX")1061__success __retval(0)1062__naked void bound_greater_than_u32_max(void)1063{1064	asm volatile ("					\1065	r2 = *(u32*)(r1 + %[xdp_md_data]);		\1066	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\1067	r1 = r2;					\1068	r1 += 1;					\1069	if r1 > r3 goto l0_%=;				\1070	r1 = *(u8*)(r2 + 0);				\1071	r0 = 0x100000000 ll;				\1072	r1 += r0;					\1073	r0 = 0x100000000 ll;				\1074l1_%=:	r0 += 1;					\1075	if r0 < r1 goto l1_%=;				\1076l0_%=:	r0 = 0;						\1077	exit;						\1078"	:1079	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),1080	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))1081	: __clobber_all);1082}1083 1084SEC("xdp")1085__description("bound check with JMP32_JLT for crossing 32-bit signed boundary")1086__success __retval(0)1087__naked void crossing_32_bit_signed_boundary_1(void)1088{1089	asm volatile ("					\1090	r2 = *(u32*)(r1 + %[xdp_md_data]);		\1091	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\1092	r1 = r2;					\1093	r1 += 1;					\1094	if r1 > r3 goto l0_%=;				\1095	r1 = *(u8*)(r2 + 0);				\1096	w0 = 0x7fffff10;				\1097	w1 += w0;					\1098	w0 = 0x80000000;				\1099l1_%=:	w0 += 1;					\1100	/* r1 unsigned range is [0, 0x8000000f] */	\1101	if w0 < w1 goto l1_%=;				\1102l0_%=:	r0 = 0;						\1103	exit;						\1104"	:1105	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),1106	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))1107	: __clobber_all);1108}1109 1110SEC("xdp")1111__description("bound check with JMP32_JSLT for crossing 32-bit signed boundary")1112__success __retval(0)1113__flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */1114__naked void crossing_32_bit_signed_boundary_2(void)1115{1116	asm volatile ("					\1117	r2 = *(u32*)(r1 + %[xdp_md_data]);		\1118	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\1119	r1 = r2;					\1120	r1 += 1;					\1121	if r1 > r3 goto l0_%=;				\1122	r1 = *(u8*)(r2 + 0);				\1123	w0 = 0x7fffff10;				\1124	w1 += w0;					\1125	w2 = 0x80000fff;				\1126	w0 = 0x80000000;				\1127l1_%=:	w0 += 1;					\1128	if w0 s> w2 goto l0_%=;				\1129	/* r1 signed range is [S32_MIN, S32_MAX] */	\1130	if w0 s< w1 goto l1_%=;				\1131	r0 = 1;						\1132	exit;						\1133l0_%=:	r0 = 0;						\1134	exit;						\1135"	:1136	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),1137	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))1138	: __clobber_all);1139}1140 1141SEC("tc")1142__description("bounds check with JMP_NE for reg edge")1143__success __retval(0)1144__naked void reg_not_equal_const(void)1145{1146	asm volatile ("					\1147	r6 = r1;					\1148	r1 = 0;						\1149	*(u64*)(r10 - 8) = r1;				\1150	call %[bpf_get_prandom_u32];			\1151	r4 = r0;					\1152	r4 &= 7;					\1153	if r4 != 0 goto l0_%=;				\1154	r0 = 0;						\1155	exit;						\1156l0_%=:	r1 = r6;					\1157	r2 = 0;						\1158	r3 = r10;					\1159	r3 += -8;					\1160	r5 = 0;						\1161	/* The 4th argument of bpf_skb_store_bytes is defined as \1162	 * ARG_CONST_SIZE, so 0 is not allowed. The 'r4 != 0' \1163	 * is providing us this exclusion of zero from initial \1164	 * [0, 7] range.				\1165	 */						\1166	call %[bpf_skb_store_bytes];			\1167	r0 = 0;						\1168	exit;						\1169"	:1170	: __imm(bpf_get_prandom_u32),1171	  __imm(bpf_skb_store_bytes)1172	: __clobber_all);1173}1174 1175SEC("tc")1176__description("bounds check with JMP_EQ for reg edge")1177__success __retval(0)1178__naked void reg_equal_const(void)1179{1180	asm volatile ("					\1181	r6 = r1;					\1182	r1 = 0;						\1183	*(u64*)(r10 - 8) = r1;				\1184	call %[bpf_get_prandom_u32];			\1185	r4 = r0;					\1186	r4 &= 7;					\1187	if r4 == 0 goto l0_%=;				\1188	r1 = r6;					\1189	r2 = 0;						\1190	r3 = r10;					\1191	r3 += -8;					\1192	r5 = 0;						\1193	/* Just the same as what we do in reg_not_equal_const() */ \1194	call %[bpf_skb_store_bytes];			\1195l0_%=:	r0 = 0;						\1196	exit;						\1197"	:1198	: __imm(bpf_get_prandom_u32),1199	  __imm(bpf_skb_store_bytes)1200	: __clobber_all);1201}1202 1203char _license[] SEC("license") = "GPL";1204