Linux Audio

Check our new training course

Loading...
v6.13.7
   1// SPDX-License-Identifier: GPL-2.0
   2/* 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_unpriv
  19__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__failure
  49__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_unpriv
 144__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_unpriv
 175__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__failure
 303/* not actually fully unbounded, but the bound is very high */
 304__msg("value -4294967168 makes map_value pointer be out of bounds")
 305__failure_unpriv
 306__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_unpriv
 346__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_unpriv
 420__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_unpriv
 453__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_unpriv
 488__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_unpriv
 520__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_unpriv
 598__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_unpriv
 695__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_unpriv
 723__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_unpriv
 751__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_unpriv
 833__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_unpriv
 862__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";
v6.8
   1// SPDX-License-Identifier: GPL-2.0
   2/* 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_unpriv
  19__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__failure
  49__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_unpriv
 144__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_unpriv
 175__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__failure
 303/* not actually fully unbounded, but the bound is very high */
 304__msg("value -4294967168 makes map_value pointer be out of bounds")
 305__failure_unpriv
 306__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_unpriv
 346__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_unpriv
 420__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_unpriv
 453__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_unpriv
 488__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_unpriv
 520__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_unpriv
 598__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_unpriv
 695__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_unpriv
 723__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_unpriv
 751__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_unpriv
 833__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_unpriv
 862__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 checks after 32-bit truncation. test 1")
 890__success __failure_unpriv __msg_unpriv("R0 leaks addr")
 891__retval(0)
 892__naked void _32_bit_truncation_test_1(void)
 893{
 894	asm volatile ("					\
 895	r1 = 0;						\
 896	*(u64*)(r10 - 8) = r1;				\
 897	r2 = r10;					\
 898	r2 += -8;					\
 899	r1 = %[map_hash_8b] ll;				\
 900	call %[bpf_map_lookup_elem];			\
 901	if r0 == 0 goto l0_%=;				\
 902	r1 = *(u32*)(r0 + 0);				\
 903	/* This used to reduce the max bound to 0x7fffffff */\
 904	if r1 == 0 goto l1_%=;				\
 905	if r1 > 0x7fffffff goto l0_%=;			\
 906l1_%=:	r0 = 0;						\
 907l0_%=:	exit;						\
 908"	:
 909	: __imm(bpf_map_lookup_elem),
 910	  __imm_addr(map_hash_8b)
 911	: __clobber_all);
 912}
 913
 914SEC("socket")
 915__description("bounds checks after 32-bit truncation. test 2")
 916__success __failure_unpriv __msg_unpriv("R0 leaks addr")
 917__retval(0)
 918__naked void _32_bit_truncation_test_2(void)
 919{
 920	asm volatile ("					\
 921	r1 = 0;						\
 922	*(u64*)(r10 - 8) = r1;				\
 923	r2 = r10;					\
 924	r2 += -8;					\
 925	r1 = %[map_hash_8b] ll;				\
 926	call %[bpf_map_lookup_elem];			\
 927	if r0 == 0 goto l0_%=;				\
 928	r1 = *(u32*)(r0 + 0);				\
 929	if r1 s< 1 goto l1_%=;				\
 930	if w1 s< 0 goto l0_%=;				\
 931l1_%=:	r0 = 0;						\
 932l0_%=:	exit;						\
 933"	:
 934	: __imm(bpf_map_lookup_elem),
 935	  __imm_addr(map_hash_8b)
 936	: __clobber_all);
 937}
 938
 939SEC("xdp")
 940__description("bound check with JMP_JLT for crossing 64-bit signed boundary")
 941__success __retval(0)
 942__naked void crossing_64_bit_signed_boundary_1(void)
 943{
 944	asm volatile ("					\
 945	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
 946	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
 947	r1 = r2;					\
 948	r1 += 1;					\
 949	if r1 > r3 goto l0_%=;				\
 950	r1 = *(u8*)(r2 + 0);				\
 951	r0 = 0x7fffffffffffff10 ll;			\
 952	r1 += r0;					\
 953	r0 = 0x8000000000000000 ll;			\
 954l1_%=:	r0 += 1;					\
 955	/* r1 unsigned range is [0x7fffffffffffff10, 0x800000000000000f] */\
 956	if r0 < r1 goto l1_%=;				\
 957l0_%=:	r0 = 0;						\
 958	exit;						\
 959"	:
 960	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
 961	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
 962	: __clobber_all);
 963}
 964
 965SEC("xdp")
 966__description("bound check with JMP_JSLT for crossing 64-bit signed boundary")
 967__success __retval(0)
 968__flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */
 969__naked void crossing_64_bit_signed_boundary_2(void)
 970{
 971	asm volatile ("					\
 972	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
 973	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
 974	r1 = r2;					\
 975	r1 += 1;					\
 976	if r1 > r3 goto l0_%=;				\
 977	r1 = *(u8*)(r2 + 0);				\
 978	r0 = 0x7fffffffffffff10 ll;			\
 979	r1 += r0;					\
 980	r2 = 0x8000000000000fff ll;			\
 981	r0 = 0x8000000000000000 ll;			\
 982l1_%=:	r0 += 1;					\
 983	if r0 s> r2 goto l0_%=;				\
 984	/* r1 signed range is [S64_MIN, S64_MAX] */	\
 985	if r0 s< r1 goto l1_%=;				\
 986	r0 = 1;						\
 987	exit;						\
 988l0_%=:	r0 = 0;						\
 989	exit;						\
 990"	:
 991	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
 992	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
 993	: __clobber_all);
 994}
 995
 996SEC("xdp")
 997__description("bound check for loop upper bound greater than U32_MAX")
 998__success __retval(0)
 999__naked void bound_greater_than_u32_max(void)
1000{
1001	asm volatile ("					\
1002	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
1003	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
1004	r1 = r2;					\
1005	r1 += 1;					\
1006	if r1 > r3 goto l0_%=;				\
1007	r1 = *(u8*)(r2 + 0);				\
1008	r0 = 0x100000000 ll;				\
1009	r1 += r0;					\
1010	r0 = 0x100000000 ll;				\
1011l1_%=:	r0 += 1;					\
1012	if r0 < r1 goto l1_%=;				\
1013l0_%=:	r0 = 0;						\
1014	exit;						\
1015"	:
1016	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1017	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1018	: __clobber_all);
1019}
1020
1021SEC("xdp")
1022__description("bound check with JMP32_JLT for crossing 32-bit signed boundary")
1023__success __retval(0)
1024__naked void crossing_32_bit_signed_boundary_1(void)
1025{
1026	asm volatile ("					\
1027	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
1028	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
1029	r1 = r2;					\
1030	r1 += 1;					\
1031	if r1 > r3 goto l0_%=;				\
1032	r1 = *(u8*)(r2 + 0);				\
1033	w0 = 0x7fffff10;				\
1034	w1 += w0;					\
1035	w0 = 0x80000000;				\
1036l1_%=:	w0 += 1;					\
1037	/* r1 unsigned range is [0, 0x8000000f] */	\
1038	if w0 < w1 goto l1_%=;				\
1039l0_%=:	r0 = 0;						\
1040	exit;						\
1041"	:
1042	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1043	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1044	: __clobber_all);
1045}
1046
1047SEC("xdp")
1048__description("bound check with JMP32_JSLT for crossing 32-bit signed boundary")
1049__success __retval(0)
1050__flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */
1051__naked void crossing_32_bit_signed_boundary_2(void)
1052{
1053	asm volatile ("					\
1054	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
1055	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
1056	r1 = r2;					\
1057	r1 += 1;					\
1058	if r1 > r3 goto l0_%=;				\
1059	r1 = *(u8*)(r2 + 0);				\
1060	w0 = 0x7fffff10;				\
1061	w1 += w0;					\
1062	w2 = 0x80000fff;				\
1063	w0 = 0x80000000;				\
1064l1_%=:	w0 += 1;					\
1065	if w0 s> w2 goto l0_%=;				\
1066	/* r1 signed range is [S32_MIN, S32_MAX] */	\
1067	if w0 s< w1 goto l1_%=;				\
1068	r0 = 1;						\
1069	exit;						\
1070l0_%=:	r0 = 0;						\
1071	exit;						\
1072"	:
1073	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1074	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1075	: __clobber_all);
1076}
1077
1078SEC("tc")
1079__description("bounds check with JMP_NE for reg edge")
1080__success __retval(0)
1081__naked void reg_not_equal_const(void)
1082{
1083	asm volatile ("					\
1084	r6 = r1;					\
1085	r1 = 0;						\
1086	*(u64*)(r10 - 8) = r1;				\
1087	call %[bpf_get_prandom_u32];			\
1088	r4 = r0;					\
1089	r4 &= 7;					\
1090	if r4 != 0 goto l0_%=;				\
1091	r0 = 0;						\
1092	exit;						\
1093l0_%=:	r1 = r6;					\
1094	r2 = 0;						\
1095	r3 = r10;					\
1096	r3 += -8;					\
1097	r5 = 0;						\
1098	/* The 4th argument of bpf_skb_store_bytes is defined as \
1099	 * ARG_CONST_SIZE, so 0 is not allowed. The 'r4 != 0' \
1100	 * is providing us this exclusion of zero from initial \
1101	 * [0, 7] range.				\
1102	 */						\
1103	call %[bpf_skb_store_bytes];			\
1104	r0 = 0;						\
1105	exit;						\
1106"	:
1107	: __imm(bpf_get_prandom_u32),
1108	  __imm(bpf_skb_store_bytes)
1109	: __clobber_all);
1110}
1111
1112SEC("tc")
1113__description("bounds check with JMP_EQ for reg edge")
1114__success __retval(0)
1115__naked void reg_equal_const(void)
1116{
1117	asm volatile ("					\
1118	r6 = r1;					\
1119	r1 = 0;						\
1120	*(u64*)(r10 - 8) = r1;				\
1121	call %[bpf_get_prandom_u32];			\
1122	r4 = r0;					\
1123	r4 &= 7;					\
1124	if r4 == 0 goto l0_%=;				\
1125	r1 = r6;					\
1126	r2 = 0;						\
1127	r3 = r10;					\
1128	r3 += -8;					\
1129	r5 = 0;						\
1130	/* Just the same as what we do in reg_not_equal_const() */ \
1131	call %[bpf_skb_store_bytes];			\
1132l0_%=:	r0 = 0;						\
1133	exit;						\
1134"	:
1135	: __imm(bpf_get_prandom_u32),
1136	  __imm(bpf_skb_store_bytes)
1137	: __clobber_all);
1138}
1139
1140char _license[] SEC("license") = "GPL";