File Index
Files and directories
Sign in
FILE

verifier_bounds.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/bpf/progs/verifier_bounds.c C
   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 <../../../include/linux/filter.h>
   6#include <bpf/bpf_helpers.h>
   7#include "bpf_misc.h"
   8
   9struct {
  10	__uint(type, BPF_MAP_TYPE_HASH);
  11	__uint(max_entries, 1);
  12	__type(key, long long);
  13	__type(value, long long);
  14} map_hash_8b SEC(".maps");
  15
  16SEC("socket")
  17__description("subtraction bounds (map value) variant 1")
  18__failure __msg("R0 max value is outside of the allowed memory range")
  19__failure_unpriv
  20__naked void bounds_map_value_variant_1(void)
  21{
  22	asm volatile ("					\
  23	r1 = 0;						\
  24	*(u64*)(r10 - 8) = r1;				\
  25	r2 = r10;					\
  26	r2 += -8;					\
  27	r1 = %[map_hash_8b] ll;				\
  28	call %[bpf_map_lookup_elem];			\
  29	if r0 == 0 goto l0_%=;				\
  30	r1 = *(u8*)(r0 + 0);				\
  31	if r1 > 0xff goto l0_%=;			\
  32	r3 = *(u8*)(r0 + 1);				\
  33	if r3 > 0xff goto l0_%=;			\
  34	r1 -= r3;					\
  35	r1 >>= 56;					\
  36	r0 += r1;					\
  37	r0 = *(u8*)(r0 + 0);				\
  38	exit;						\
  39l0_%=:	r0 = 0;						\
  40	exit;						\
  41"	:
  42	: __imm(bpf_map_lookup_elem),
  43	  __imm_addr(map_hash_8b)
  44	: __clobber_all);
  45}
  46
  47SEC("socket")
  48__description("subtraction bounds (map value) variant 2")
  49__failure
  50__msg("R0 min value is negative, either use unsigned index or do a if (index >=0) check.")
  51__msg_unpriv("R1 has unknown scalar with mixed signed bounds")
  52__naked void bounds_map_value_variant_2(void)
  53{
  54	asm volatile ("					\
  55	r1 = 0;						\
  56	*(u64*)(r10 - 8) = r1;				\
  57	r2 = r10;					\
  58	r2 += -8;					\
  59	r1 = %[map_hash_8b] ll;				\
  60	call %[bpf_map_lookup_elem];			\
  61	if r0 == 0 goto l0_%=;				\
  62	r1 = *(u8*)(r0 + 0);				\
  63	if r1 > 0xff goto l0_%=;			\
  64	r3 = *(u8*)(r0 + 1);				\
  65	if r3 > 0xff goto l0_%=;			\
  66	r1 -= r3;					\
  67	r0 += r1;					\
  68	r0 = *(u8*)(r0 + 0);				\
  69	exit;						\
  70l0_%=:	r0 = 0;						\
  71	exit;						\
  72"	:
  73	: __imm(bpf_map_lookup_elem),
  74	  __imm_addr(map_hash_8b)
  75	: __clobber_all);
  76}
  77
  78SEC("socket")
  79__description("check subtraction on pointers for unpriv")
  80__success __failure_unpriv __msg_unpriv("R9 pointer -= pointer prohibited")
  81__retval(0)
  82__naked void subtraction_on_pointers_for_unpriv(void)
  83{
  84	asm volatile ("					\
  85	r0 = 0;						\
  86	r1 = %[map_hash_8b] ll;				\
  87	r2 = r10;					\
  88	r2 += -8;					\
  89	r6 = 9;						\
  90	*(u64*)(r2 + 0) = r6;				\
  91	call %[bpf_map_lookup_elem];			\
  92	r9 = r10;					\
  93	r9 -= r0;					\
  94	r1 = %[map_hash_8b] ll;				\
  95	r2 = r10;					\
  96	r2 += -8;					\
  97	r6 = 0;						\
  98	*(u64*)(r2 + 0) = r6;				\
  99	call %[bpf_map_lookup_elem];			\
 100	if r0 != 0 goto l0_%=;				\
 101	exit;						\
 102l0_%=:	*(u64*)(r0 + 0) = r9;				\
 103	r0 = 0;						\
 104	exit;						\
 105"	:
 106	: __imm(bpf_map_lookup_elem),
 107	  __imm_addr(map_hash_8b)
 108	: __clobber_all);
 109}
 110
 111SEC("socket")
 112__description("bounds check based on zero-extended MOV")
 113__success __success_unpriv __retval(0)
 114__naked void based_on_zero_extended_mov(void)
 115{
 116	asm volatile ("					\
 117	r1 = 0;						\
 118	*(u64*)(r10 - 8) = r1;				\
 119	r2 = r10;					\
 120	r2 += -8;					\
 121	r1 = %[map_hash_8b] ll;				\
 122	call %[bpf_map_lookup_elem];			\
 123	if r0 == 0 goto l0_%=;				\
 124	/* r2 = 0x0000'0000'ffff'ffff */		\
 125	w2 = 0xffffffff;				\
 126	/* r2 = 0 */					\
 127	r2 >>= 32;					\
 128	/* no-op */					\
 129	r0 += r2;					\
 130	/* access at offset 0 */			\
 131	r0 = *(u8*)(r0 + 0);				\
 132l0_%=:	/* exit */					\
 133	r0 = 0;						\
 134	exit;						\
 135"	:
 136	: __imm(bpf_map_lookup_elem),
 137	  __imm_addr(map_hash_8b)
 138	: __clobber_all);
 139}
 140
 141SEC("socket")
 142__description("bounds check based on sign-extended MOV. test1")
 143__failure __msg("map_value pointer and 4294967295")
 144__failure_unpriv
 145__naked void on_sign_extended_mov_test1(void)
 146{
 147	asm volatile ("					\
 148	r1 = 0;						\
 149	*(u64*)(r10 - 8) = r1;				\
 150	r2 = r10;					\
 151	r2 += -8;					\
 152	r1 = %[map_hash_8b] ll;				\
 153	call %[bpf_map_lookup_elem];			\
 154	if r0 == 0 goto l0_%=;				\
 155	/* r2 = 0xffff'ffff'ffff'ffff */		\
 156	r2 = 0xffffffff;				\
 157	/* r2 = 0xffff'ffff */				\
 158	r2 >>= 32;					\
 159	/* r0 = <oob pointer> */			\
 160	r0 += r2;					\
 161	/* access to OOB pointer */			\
 162	r0 = *(u8*)(r0 + 0);				\
 163l0_%=:	/* exit */					\
 164	r0 = 0;						\
 165	exit;						\
 166"	:
 167	: __imm(bpf_map_lookup_elem),
 168	  __imm_addr(map_hash_8b)
 169	: __clobber_all);
 170}
 171
 172SEC("socket")
 173__description("bounds check based on sign-extended MOV. test2")
 174__failure __msg("R0 min value is outside of the allowed memory range")
 175__failure_unpriv
 176__naked void on_sign_extended_mov_test2(void)
 177{
 178	asm volatile ("					\
 179	r1 = 0;						\
 180	*(u64*)(r10 - 8) = r1;				\
 181	r2 = r10;					\
 182	r2 += -8;					\
 183	r1 = %[map_hash_8b] ll;				\
 184	call %[bpf_map_lookup_elem];			\
 185	if r0 == 0 goto l0_%=;				\
 186	/* r2 = 0xffff'ffff'ffff'ffff */		\
 187	r2 = 0xffffffff;				\
 188	/* r2 = 0xfff'ffff */				\
 189	r2 >>= 36;					\
 190	/* r0 = <oob pointer> */			\
 191	r0 += r2;					\
 192	/* access to OOB pointer */			\
 193	r0 = *(u8*)(r0 + 0);				\
 194l0_%=:	/* exit */					\
 195	r0 = 0;						\
 196	exit;						\
 197"	:
 198	: __imm(bpf_map_lookup_elem),
 199	  __imm_addr(map_hash_8b)
 200	: __clobber_all);
 201}
 202
 203SEC("tc")
 204__description("bounds check based on reg_off + var_off + insn_off. test1")
 205__failure __msg("value_size=8 off=1073741825")
 206__naked void var_off_insn_off_test1(void)
 207{
 208	asm volatile ("					\
 209	r6 = *(u32*)(r1 + %[__sk_buff_mark]);		\
 210	r1 = 0;						\
 211	*(u64*)(r10 - 8) = r1;				\
 212	r2 = r10;					\
 213	r2 += -8;					\
 214	r1 = %[map_hash_8b] ll;				\
 215	call %[bpf_map_lookup_elem];			\
 216	if r0 == 0 goto l0_%=;				\
 217	r6 &= 1;					\
 218	r6 += %[__imm_0];				\
 219	r0 += r6;					\
 220	r0 += %[__imm_0];				\
 221l0_%=:	r0 = *(u8*)(r0 + 3);				\
 222	r0 = 0;						\
 223	exit;						\
 224"	:
 225	: __imm(bpf_map_lookup_elem),
 226	  __imm_addr(map_hash_8b),
 227	  __imm_const(__imm_0, (1 << 29) - 1),
 228	  __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
 229	: __clobber_all);
 230}
 231
 232SEC("tc")
 233__description("bounds check based on reg_off + var_off + insn_off. test2")
 234__failure __msg("value 1073741823")
 235__naked void var_off_insn_off_test2(void)
 236{
 237	asm volatile ("					\
 238	r6 = *(u32*)(r1 + %[__sk_buff_mark]);		\
 239	r1 = 0;						\
 240	*(u64*)(r10 - 8) = r1;				\
 241	r2 = r10;					\
 242	r2 += -8;					\
 243	r1 = %[map_hash_8b] ll;				\
 244	call %[bpf_map_lookup_elem];			\
 245	if r0 == 0 goto l0_%=;				\
 246	r6 &= 1;					\
 247	r6 += %[__imm_0];				\
 248	r0 += r6;					\
 249	r0 += %[__imm_1];				\
 250l0_%=:	r0 = *(u8*)(r0 + 3);				\
 251	r0 = 0;						\
 252	exit;						\
 253"	:
 254	: __imm(bpf_map_lookup_elem),
 255	  __imm_addr(map_hash_8b),
 256	  __imm_const(__imm_0, (1 << 30) - 1),
 257	  __imm_const(__imm_1, (1 << 29) - 1),
 258	  __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
 259	: __clobber_all);
 260}
 261
 262SEC("socket")
 263__description("bounds check after truncation of non-boundary-crossing range")
 264__success __success_unpriv __retval(0)
 265__naked void of_non_boundary_crossing_range(void)
 266{
 267	asm volatile ("					\
 268	r1 = 0;						\
 269	*(u64*)(r10 - 8) = r1;				\
 270	r2 = r10;					\
 271	r2 += -8;					\
 272	r1 = %[map_hash_8b] ll;				\
 273	call %[bpf_map_lookup_elem];			\
 274	if r0 == 0 goto l0_%=;				\
 275	/* r1 = [0x00, 0xff] */				\
 276	r1 = *(u8*)(r0 + 0);				\
 277	r2 = 1;						\
 278	/* r2 = 0x10'0000'0000 */			\
 279	r2 <<= 36;					\
 280	/* r1 = [0x10'0000'0000, 0x10'0000'00ff] */	\
 281	r1 += r2;					\
 282	/* r1 = [0x10'7fff'ffff, 0x10'8000'00fe] */	\
 283	r1 += 0x7fffffff;				\
 284	/* r1 = [0x00, 0xff] */				\
 285	w1 -= 0x7fffffff;				\
 286	/* r1 = 0 */					\
 287	r1 >>= 8;					\
 288	/* no-op */					\
 289	r0 += r1;					\
 290	/* access at offset 0 */			\
 291	r0 = *(u8*)(r0 + 0);				\
 292l0_%=:	/* exit */					\
 293	r0 = 0;						\
 294	exit;						\
 295"	:
 296	: __imm(bpf_map_lookup_elem),
 297	  __imm_addr(map_hash_8b)
 298	: __clobber_all);
 299}
 300
 301SEC("socket")
 302__description("bounds check after truncation of boundary-crossing range (1)")
 303__failure
 304/* not actually fully unbounded, but the bound is very high */
 305__msg("value -4294967168 makes map_value pointer be out of bounds")
 306__failure_unpriv
 307__naked void of_boundary_crossing_range_1(void)
 308{
 309	asm volatile ("					\
 310	r1 = 0;						\
 311	*(u64*)(r10 - 8) = r1;				\
 312	r2 = r10;					\
 313	r2 += -8;					\
 314	r1 = %[map_hash_8b] ll;				\
 315	call %[bpf_map_lookup_elem];			\
 316	if r0 == 0 goto l0_%=;				\
 317	/* r1 = [0x00, 0xff] */				\
 318	r1 = *(u8*)(r0 + 0);				\
 319	r1 += %[__imm_0];				\
 320	/* r1 = [0xffff'ff80, 0x1'0000'007f] */		\
 321	r1 += %[__imm_0];				\
 322	/* r1 = [0xffff'ff80, 0xffff'ffff] or		\
 323	 *      [0x0000'0000, 0x0000'007f]		\
 324	 */						\
 325	w1 += 0;					\
 326	r1 -= %[__imm_0];				\
 327	/* r1 = [0x00, 0xff] or				\
 328	 *      [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff]\
 329	 */						\
 330	r1 -= %[__imm_0];				\
 331	/* error on OOB pointer computation */		\
 332	r0 += r1;					\
 333	/* exit */					\
 334	r0 = 0;						\
 335l0_%=:	exit;						\
 336"	:
 337	: __imm(bpf_map_lookup_elem),
 338	  __imm_addr(map_hash_8b),
 339	  __imm_const(__imm_0, 0xffffff80 >> 1)
 340	: __clobber_all);
 341}
 342
 343SEC("socket")
 344__description("bounds check after truncation of boundary-crossing range (2)")
 345__failure __msg("value -4294967168 makes map_value pointer be out of bounds")
 346__failure_unpriv
 347__naked void of_boundary_crossing_range_2(void)
 348{
 349	asm volatile ("					\
 350	r1 = 0;						\
 351	*(u64*)(r10 - 8) = r1;				\
 352	r2 = r10;					\
 353	r2 += -8;					\
 354	r1 = %[map_hash_8b] ll;				\
 355	call %[bpf_map_lookup_elem];			\
 356	if r0 == 0 goto l0_%=;				\
 357	/* r1 = [0x00, 0xff] */				\
 358	r1 = *(u8*)(r0 + 0);				\
 359	r1 += %[__imm_0];				\
 360	/* r1 = [0xffff'ff80, 0x1'0000'007f] */		\
 361	r1 += %[__imm_0];				\
 362	/* r1 = [0xffff'ff80, 0xffff'ffff] or		\
 363	 *      [0x0000'0000, 0x0000'007f]		\
 364	 * difference to previous test: truncation via MOV32\
 365	 * instead of ALU32.				\
 366	 */						\
 367	w1 = w1;					\
 368	r1 -= %[__imm_0];				\
 369	/* r1 = [0x00, 0xff] or				\
 370	 *      [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff]\
 371	 */						\
 372	r1 -= %[__imm_0];				\
 373	/* error on OOB pointer computation */		\
 374	r0 += r1;					\
 375	/* exit */					\
 376	r0 = 0;						\
 377l0_%=:	exit;						\
 378"	:
 379	: __imm(bpf_map_lookup_elem),
 380	  __imm_addr(map_hash_8b),
 381	  __imm_const(__imm_0, 0xffffff80 >> 1)
 382	: __clobber_all);
 383}
 384
 385SEC("socket")
 386__description("bounds check after wrapping 32-bit addition")
 387__success __success_unpriv __retval(0)
 388__naked void after_wrapping_32_bit_addition(void)
 389{
 390	asm volatile ("					\
 391	r1 = 0;						\
 392	*(u64*)(r10 - 8) = r1;				\
 393	r2 = r10;					\
 394	r2 += -8;					\
 395	r1 = %[map_hash_8b] ll;				\
 396	call %[bpf_map_lookup_elem];			\
 397	if r0 == 0 goto l0_%=;				\
 398	/* r1 = 0x7fff'ffff */				\
 399	r1 = 0x7fffffff;				\
 400	/* r1 = 0xffff'fffe */				\
 401	r1 += 0x7fffffff;				\
 402	/* r1 = 0 */					\
 403	w1 += 2;					\
 404	/* no-op */					\
 405	r0 += r1;					\
 406	/* access at offset 0 */			\
 407	r0 = *(u8*)(r0 + 0);				\
 408l0_%=:	/* exit */					\
 409	r0 = 0;						\
 410	exit;						\
 411"	:
 412	: __imm(bpf_map_lookup_elem),
 413	  __imm_addr(map_hash_8b)
 414	: __clobber_all);
 415}
 416
 417SEC("socket")
 418__description("bounds check after shift with oversized count operand")
 419__failure __msg("R0 max value is outside of the allowed memory range")
 420__failure_unpriv
 421__naked void shift_with_oversized_count_operand(void)
 422{
 423	asm volatile ("					\
 424	r1 = 0;						\
 425	*(u64*)(r10 - 8) = r1;				\
 426	r2 = r10;					\
 427	r2 += -8;					\
 428	r1 = %[map_hash_8b] ll;				\
 429	call %[bpf_map_lookup_elem];			\
 430	if r0 == 0 goto l0_%=;				\
 431	r2 = 32;					\
 432	r1 = 1;						\
 433	/* r1 = (u32)1 << (u32)32 = ? */		\
 434	w1 <<= w2;					\
 435	/* r1 = [0x0000, 0xffff] */			\
 436	r1 &= 0xffff;					\
 437	/* computes unknown pointer, potentially OOB */	\
 438	r0 += r1;					\
 439	/* potentially OOB access */			\
 440	r0 = *(u8*)(r0 + 0);				\
 441l0_%=:	/* exit */					\
 442	r0 = 0;						\
 443	exit;						\
 444"	:
 445	: __imm(bpf_map_lookup_elem),
 446	  __imm_addr(map_hash_8b)
 447	: __clobber_all);
 448}
 449
 450SEC("socket")
 451__description("bounds check after right shift of maybe-negative number")
 452__failure __msg("R0 unbounded memory access")
 453__failure_unpriv
 454__naked void shift_of_maybe_negative_number(void)
 455{
 456	asm volatile ("					\
 457	r1 = 0;						\
 458	*(u64*)(r10 - 8) = r1;				\
 459	r2 = r10;					\
 460	r2 += -8;					\
 461	r1 = %[map_hash_8b] ll;				\
 462	call %[bpf_map_lookup_elem];			\
 463	if r0 == 0 goto l0_%=;				\
 464	/* r1 = [0x00, 0xff] */				\
 465	r1 = *(u8*)(r0 + 0);				\
 466	/* r1 = [-0x01, 0xfe] */			\
 467	r1 -= 1;					\
 468	/* r1 = 0 or 0xff'ffff'ffff'ffff */		\
 469	r1 >>= 8;					\
 470	/* r1 = 0 or 0xffff'ffff'ffff */		\
 471	r1 >>= 8;					\
 472	/* computes unknown pointer, potentially OOB */	\
 473	r0 += r1;					\
 474	/* potentially OOB access */			\
 475	r0 = *(u8*)(r0 + 0);				\
 476l0_%=:	/* exit */					\
 477	r0 = 0;						\
 478	exit;						\
 479"	:
 480	: __imm(bpf_map_lookup_elem),
 481	  __imm_addr(map_hash_8b)
 482	: __clobber_all);
 483}
 484
 485SEC("socket")
 486__description("bounds check after 32-bit right shift with 64-bit input")
 487__failure __msg("math between map_value pointer and 4294967294 is not allowed")
 488__failure_unpriv
 489__naked void shift_with_64_bit_input(void)
 490{
 491	asm volatile ("					\
 492	r1 = 0;						\
 493	*(u64*)(r10 - 8) = r1;				\
 494	r2 = r10;					\
 495	r2 += -8;					\
 496	r1 = %[map_hash_8b] ll;				\
 497	call %[bpf_map_lookup_elem];			\
 498	if r0 == 0 goto l0_%=;				\
 499	r1 = 2;						\
 500	/* r1 = 1<<32 */				\
 501	r1 <<= 31;					\
 502	/* r1 = 0 (NOT 2!) */				\
 503	w1 >>= 31;					\
 504	/* r1 = 0xffff'fffe (NOT 0!) */			\
 505	w1 -= 2;					\
 506	/* error on computing OOB pointer */		\
 507	r0 += r1;					\
 508	/* exit */					\
 509	r0 = 0;						\
 510l0_%=:	exit;						\
 511"	:
 512	: __imm(bpf_map_lookup_elem),
 513	  __imm_addr(map_hash_8b)
 514	: __clobber_all);
 515}
 516
 517SEC("socket")
 518__description("bounds check map access with off+size signed 32bit overflow. test1")
 519__failure __msg("map_value pointer and 2147483646")
 520__failure_unpriv
 521__naked void size_signed_32bit_overflow_test1(void)
 522{
 523	asm volatile ("					\
 524	r1 = 0;						\
 525	*(u64*)(r10 - 8) = r1;				\
 526	r2 = r10;					\
 527	r2 += -8;					\
 528	r1 = %[map_hash_8b] ll;				\
 529	call %[bpf_map_lookup_elem];			\
 530	if r0 != 0 goto l0_%=;				\
 531	exit;						\
 532l0_%=:	r0 += 0x7ffffffe;				\
 533	r0 = *(u64*)(r0 + 0);				\
 534	goto l1_%=;					\
 535l1_%=:	exit;						\
 536"	:
 537	: __imm(bpf_map_lookup_elem),
 538	  __imm_addr(map_hash_8b)
 539	: __clobber_all);
 540}
 541
 542SEC("socket")
 543__description("bounds check map access with off+size signed 32bit overflow. test2")
 544__failure __msg("pointer offset 1073741822")
 545__msg_unpriv("R0 pointer arithmetic of map value goes out of range")
 546__naked void size_signed_32bit_overflow_test2(void)
 547{
 548	asm volatile ("					\
 549	r1 = 0;						\
 550	*(u64*)(r10 - 8) = r1;				\
 551	r2 = r10;					\
 552	r2 += -8;					\
 553	r1 = %[map_hash_8b] ll;				\
 554	call %[bpf_map_lookup_elem];			\
 555	if r0 != 0 goto l0_%=;				\
 556	exit;						\
 557l0_%=:	r0 += 0x1fffffff;				\
 558	r0 += 0x1fffffff;				\
 559	r0 += 0x1fffffff;				\
 560	r0 = *(u64*)(r0 + 0);				\
 561	goto l1_%=;					\
 562l1_%=:	exit;						\
 563"	:
 564	: __imm(bpf_map_lookup_elem),
 565	  __imm_addr(map_hash_8b)
 566	: __clobber_all);
 567}
 568
 569SEC("socket")
 570__description("bounds check map access with off+size signed 32bit overflow. test3")
 571__failure __msg("pointer offset -1073741822")
 572__msg_unpriv("R0 pointer arithmetic of map value goes out of range")
 573__naked void size_signed_32bit_overflow_test3(void)
 574{
 575	asm volatile ("					\
 576	r1 = 0;						\
 577	*(u64*)(r10 - 8) = r1;				\
 578	r2 = r10;					\
 579	r2 += -8;					\
 580	r1 = %[map_hash_8b] ll;				\
 581	call %[bpf_map_lookup_elem];			\
 582	if r0 != 0 goto l0_%=;				\
 583	exit;						\
 584l0_%=:	r0 -= 0x1fffffff;				\
 585	r0 -= 0x1fffffff;				\
 586	r0 = *(u64*)(r0 + 2);				\
 587	goto l1_%=;					\
 588l1_%=:	exit;						\
 589"	:
 590	: __imm(bpf_map_lookup_elem),
 591	  __imm_addr(map_hash_8b)
 592	: __clobber_all);
 593}
 594
 595SEC("socket")
 596__description("bounds check map access with off+size signed 32bit overflow. test4")
 597__failure __msg("map_value pointer and 1000000000000")
 598__failure_unpriv
 599__naked void size_signed_32bit_overflow_test4(void)
 600{
 601	asm volatile ("					\
 602	r1 = 0;						\
 603	*(u64*)(r10 - 8) = r1;				\
 604	r2 = r10;					\
 605	r2 += -8;					\
 606	r1 = %[map_hash_8b] ll;				\
 607	call %[bpf_map_lookup_elem];			\
 608	if r0 != 0 goto l0_%=;				\
 609	exit;						\
 610l0_%=:	r1 = 1000000;					\
 611	r1 *= 1000000;					\
 612	r0 += r1;					\
 613	r0 = *(u64*)(r0 + 2);				\
 614	goto l1_%=;					\
 615l1_%=:	exit;						\
 616"	:
 617	: __imm(bpf_map_lookup_elem),
 618	  __imm_addr(map_hash_8b)
 619	: __clobber_all);
 620}
 621
 622SEC("socket")
 623__description("bounds check mixed 32bit and 64bit arithmetic. test1")
 624__success __success_unpriv
 625__retval(0)
 626#ifdef SPEC_V1
 627__xlated_unpriv("goto pc+2")
 628__xlated_unpriv("nospec") /* inserted to prevent `R0 invalid mem access 'scalar'` */
 629__xlated_unpriv("goto pc-1") /* sanitized dead code */
 630__xlated_unpriv("exit")
 631#endif
 632__naked void _32bit_and_64bit_arithmetic_test1(void)
 633{
 634	asm volatile ("					\
 635	r0 = 0;						\
 636	r1 = -1;					\
 637	r1 <<= 32;					\
 638	r1 += 1;					\
 639	/* r1 = 0xffffFFFF00000001 */			\
 640	if w1 > 1 goto l0_%=;				\
 641	/* check ALU64 op keeps 32bit bounds */		\
 642	r1 += 1;					\
 643	if w1 > 2 goto l0_%=;				\
 644	goto l1_%=;					\
 645l0_%=:	/* invalid ldx if bounds are lost above */	\
 646	r0 = *(u64*)(r0 - 1);				\
 647l1_%=:	exit;						\
 648"	::: __clobber_all);
 649}
 650
 651SEC("socket")
 652__description("bounds check mixed 32bit and 64bit arithmetic. test2")
 653__success __success_unpriv
 654__retval(0)
 655#ifdef SPEC_V1
 656__xlated_unpriv("goto pc+2")
 657__xlated_unpriv("nospec") /* inserted to prevent `R0 invalid mem access 'scalar'` */
 658__xlated_unpriv("goto pc-1") /* sanitized dead code */
 659__xlated_unpriv("exit")
 660#endif
 661__naked void _32bit_and_64bit_arithmetic_test2(void)
 662{
 663	asm volatile ("					\
 664	r0 = 0;						\
 665	r1 = -1;					\
 666	r1 <<= 32;					\
 667	r1 += 1;					\
 668	/* r1 = 0xffffFFFF00000001 */			\
 669	r2 = 3;						\
 670	/* r1 = 0x2 */					\
 671	w1 += 1;					\
 672	/* check ALU32 op zero extends 64bit bounds */	\
 673	if r1 > r2 goto l0_%=;				\
 674	goto l1_%=;					\
 675l0_%=:	/* invalid ldx if bounds are lost above */	\
 676	r0 = *(u64*)(r0 - 1);				\
 677l1_%=:	exit;						\
 678"	::: __clobber_all);
 679}
 680
 681SEC("tc")
 682__description("assigning 32bit bounds to 64bit for wA = 0, wB = wA")
 683__success __retval(0) __flag(BPF_F_ANY_ALIGNMENT)
 684__naked void for_wa_0_wb_wa(void)
 685{
 686	asm volatile ("					\
 687	r8 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
 688	r7 = *(u32*)(r1 + %[__sk_buff_data]);		\
 689	w9 = 0;						\
 690	w2 = w9;					\
 691	r6 = r7;					\
 692	r6 += r2;					\
 693	r3 = r6;					\
 694	r3 += 8;					\
 695	if r3 > r8 goto l0_%=;				\
 696	r5 = *(u32*)(r6 + 0);				\
 697l0_%=:	r0 = 0;						\
 698	exit;						\
 699"	:
 700	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
 701	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
 702	: __clobber_all);
 703}
 704
 705SEC("socket")
 706__description("bounds check for reg = 0, reg xor 1")
 707__success __success_unpriv
 708__retval(0)
 709#ifdef SPEC_V1
 710__xlated_unpriv("if r1 != 0x0 goto pc+2")
 711__xlated_unpriv("nospec") /* inserted to prevent `R0 min value is outside of the allowed memory range` */
 712__xlated_unpriv("goto pc-1") /* sanitized dead code */
 713__xlated_unpriv("r0 = 0")
 714#endif
 715__naked void reg_0_reg_xor_1(void)
 716{
 717	asm volatile ("					\
 718	r1 = 0;						\
 719	*(u64*)(r10 - 8) = r1;				\
 720	r2 = r10;					\
 721	r2 += -8;					\
 722	r1 = %[map_hash_8b] ll;				\
 723	call %[bpf_map_lookup_elem];			\
 724	if r0 != 0 goto l0_%=;				\
 725	exit;						\
 726l0_%=:	r1 = 0;						\
 727	r1 ^= 1;					\
 728	if r1 != 0 goto l1_%=;				\
 729	r0 = *(u64*)(r0 + 8);				\
 730l1_%=:	r0 = 0;						\
 731	exit;						\
 732"	:
 733	: __imm(bpf_map_lookup_elem),
 734	  __imm_addr(map_hash_8b)
 735	: __clobber_all);
 736}
 737
 738SEC("socket")
 739__description("bounds check for reg32 = 0, reg32 xor 1")
 740__success __success_unpriv
 741__retval(0)
 742#ifdef SPEC_V1
 743__xlated_unpriv("if w1 != 0x0 goto pc+2")
 744__xlated_unpriv("nospec") /* inserted to prevent `R0 min value is outside of the allowed memory range` */
 745__xlated_unpriv("goto pc-1") /* sanitized dead code */
 746__xlated_unpriv("r0 = 0")
 747#endif
 748__naked void reg32_0_reg32_xor_1(void)
 749{
 750	asm volatile ("					\
 751	r1 = 0;						\
 752	*(u64*)(r10 - 8) = r1;				\
 753	r2 = r10;					\
 754	r2 += -8;					\
 755	r1 = %[map_hash_8b] ll;				\
 756	call %[bpf_map_lookup_elem];			\
 757	if r0 != 0 goto l0_%=;				\
 758	exit;						\
 759l0_%=:	w1 = 0;						\
 760	w1 ^= 1;					\
 761	if w1 != 0 goto l1_%=;				\
 762	r0 = *(u64*)(r0 + 8);				\
 763l1_%=:	r0 = 0;						\
 764	exit;						\
 765"	:
 766	: __imm(bpf_map_lookup_elem),
 767	  __imm_addr(map_hash_8b)
 768	: __clobber_all);
 769}
 770
 771SEC("socket")
 772__description("bounds check for reg = 2, reg xor 3")
 773__success __success_unpriv
 774__retval(0)
 775#ifdef SPEC_V1
 776__xlated_unpriv("if r1 > 0x0 goto pc+2")
 777__xlated_unpriv("nospec") /* inserted to prevent `R0 min value is outside of the allowed memory range` */
 778__xlated_unpriv("goto pc-1") /* sanitized dead code */
 779__xlated_unpriv("r0 = 0")
 780#endif
 781__naked void reg_2_reg_xor_3(void)
 782{
 783	asm volatile ("					\
 784	r1 = 0;						\
 785	*(u64*)(r10 - 8) = r1;				\
 786	r2 = r10;					\
 787	r2 += -8;					\
 788	r1 = %[map_hash_8b] ll;				\
 789	call %[bpf_map_lookup_elem];			\
 790	if r0 != 0 goto l0_%=;				\
 791	exit;						\
 792l0_%=:	r1 = 2;						\
 793	r1 ^= 3;					\
 794	if r1 > 0 goto l1_%=;				\
 795	r0 = *(u64*)(r0 + 8);				\
 796l1_%=:	r0 = 0;						\
 797	exit;						\
 798"	:
 799	: __imm(bpf_map_lookup_elem),
 800	  __imm_addr(map_hash_8b)
 801	: __clobber_all);
 802}
 803
 804SEC("socket")
 805__description("bounds check for reg = any, reg xor 3")
 806__failure __msg("invalid access to map value")
 807__msg_unpriv("invalid access to map value")
 808__naked void reg_any_reg_xor_3(void)
 809{
 810	asm volatile ("					\
 811	r1 = 0;						\
 812	*(u64*)(r10 - 8) = r1;				\
 813	r2 = r10;					\
 814	r2 += -8;					\
 815	r1 = %[map_hash_8b] ll;				\
 816	call %[bpf_map_lookup_elem];			\
 817	if r0 != 0 goto l0_%=;				\
 818	exit;						\
 819l0_%=:	r1 = *(u64*)(r0 + 0);				\
 820	r1 ^= 3;					\
 821	if r1 != 0 goto l1_%=;				\
 822	r0 = *(u64*)(r0 + 8);				\
 823l1_%=:	r0 = 0;						\
 824	exit;						\
 825"	:
 826	: __imm(bpf_map_lookup_elem),
 827	  __imm_addr(map_hash_8b)
 828	: __clobber_all);
 829}
 830
 831SEC("socket")
 832__description("bounds check for reg32 = any, reg32 xor 3")
 833__failure __msg("invalid access to map value")
 834__msg_unpriv("invalid access to map value")
 835__naked void reg32_any_reg32_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	w1 ^= 3;					\
 848	if w1 != 0 goto l1_%=;				\
 849	r0 = *(u64*)(r0 + 8);				\
 850l1_%=:	r0 = 0;						\
 851	exit;						\
 852"	:
 853	: __imm(bpf_map_lookup_elem),
 854	  __imm_addr(map_hash_8b)
 855	: __clobber_all);
 856}
 857
 858SEC("socket")
 859__description("bounds check for reg > 0, reg xor 3")
 860__success __success_unpriv
 861__retval(0)
 862#ifdef SPEC_V1
 863__xlated_unpriv("if r1 >= 0x0 goto pc+2")
 864__xlated_unpriv("nospec") /* inserted to prevent `R0 min value is outside of the allowed memory range` */
 865__xlated_unpriv("goto pc-1") /* sanitized dead code */
 866__xlated_unpriv("r0 = 0")
 867#endif
 868__naked void reg_0_reg_xor_3(void)
 869{
 870	asm volatile ("					\
 871	r1 = 0;						\
 872	*(u64*)(r10 - 8) = r1;				\
 873	r2 = r10;					\
 874	r2 += -8;					\
 875	r1 = %[map_hash_8b] ll;				\
 876	call %[bpf_map_lookup_elem];			\
 877	if r0 != 0 goto l0_%=;				\
 878	exit;						\
 879l0_%=:	r1 = *(u64*)(r0 + 0);				\
 880	if r1 <= 0 goto l1_%=;				\
 881	r1 ^= 3;					\
 882	if r1 >= 0 goto l1_%=;				\
 883	r0 = *(u64*)(r0 + 8);				\
 884l1_%=:	r0 = 0;						\
 885	exit;						\
 886"	:
 887	: __imm(bpf_map_lookup_elem),
 888	  __imm_addr(map_hash_8b)
 889	: __clobber_all);
 890}
 891
 892SEC("socket")
 893__description("bounds check for reg32 > 0, reg32 xor 3")
 894__success __success_unpriv
 895__retval(0)
 896#ifdef SPEC_V1
 897__xlated_unpriv("if w1 >= 0x0 goto pc+2")
 898__xlated_unpriv("nospec") /* inserted to prevent `R0 min value is outside of the allowed memory range` */
 899__xlated_unpriv("goto pc-1") /* sanitized dead code */
 900__xlated_unpriv("r0 = 0")
 901#endif
 902__naked void reg32_0_reg32_xor_3(void)
 903{
 904	asm volatile ("					\
 905	r1 = 0;						\
 906	*(u64*)(r10 - 8) = r1;				\
 907	r2 = r10;					\
 908	r2 += -8;					\
 909	r1 = %[map_hash_8b] ll;				\
 910	call %[bpf_map_lookup_elem];			\
 911	if r0 != 0 goto l0_%=;				\
 912	exit;						\
 913l0_%=:	r1 = *(u64*)(r0 + 0);				\
 914	if w1 <= 0 goto l1_%=;				\
 915	w1 ^= 3;					\
 916	if w1 >= 0 goto l1_%=;				\
 917	r0 = *(u64*)(r0 + 8);				\
 918l1_%=:	r0 = 0;						\
 919	exit;						\
 920"	:
 921	: __imm(bpf_map_lookup_elem),
 922	  __imm_addr(map_hash_8b)
 923	: __clobber_all);
 924}
 925
 926SEC("socket")
 927__description("bounds check for non const xor src dst")
 928__success __log_level(2)
 929__msg("5: (af) r0 ^= r6                      ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=431,var_off=(0x0; 0x1af))")
 930__naked void non_const_xor_src_dst(void)
 931{
 932	asm volatile ("					\
 933	call %[bpf_get_prandom_u32];                    \
 934	r6 = r0;					\
 935	call %[bpf_get_prandom_u32];                    \
 936	r6 &= 0xaf;					\
 937	r0 &= 0x1a0;					\
 938	r0 ^= r6;					\
 939	exit;						\
 940"	:
 941	: __imm(bpf_map_lookup_elem),
 942	__imm_addr(map_hash_8b),
 943	__imm(bpf_get_prandom_u32)
 944	: __clobber_all);
 945}
 946
 947SEC("socket")
 948__description("bounds check for non const or src dst")
 949__success __log_level(2)
 950__msg("5: (4f) r0 |= r6                      ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=431,var_off=(0x0; 0x1af))")
 951__naked void non_const_or_src_dst(void)
 952{
 953	asm volatile ("					\
 954	call %[bpf_get_prandom_u32];                    \
 955	r6 = r0;					\
 956	call %[bpf_get_prandom_u32];                    \
 957	r6 &= 0xaf;					\
 958	r0 &= 0x1a0;					\
 959	r0 |= r6;					\
 960	exit;						\
 961"	:
 962	: __imm(bpf_map_lookup_elem),
 963	__imm_addr(map_hash_8b),
 964	__imm(bpf_get_prandom_u32)
 965	: __clobber_all);
 966}
 967
 968SEC("socket")
 969__description("bounds check for non const mul regs")
 970__success __log_level(2)
 971__msg("5: (2f) r0 *= r6                      ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=3825,var_off=(0x0; 0xfff))")
 972__naked void non_const_mul_regs(void)
 973{
 974	asm volatile ("					\
 975	call %[bpf_get_prandom_u32];                    \
 976	r6 = r0;					\
 977	call %[bpf_get_prandom_u32];                    \
 978	r6 &= 0xff;					\
 979	r0 &= 0x0f;					\
 980	r0 *= r6;					\
 981	exit;						\
 982"	:
 983	: __imm(bpf_map_lookup_elem),
 984	__imm_addr(map_hash_8b),
 985	__imm(bpf_get_prandom_u32)
 986	: __clobber_all);
 987}
 988
 989SEC("socket")
 990__description("bounds checks after 32-bit truncation. test 1")
 991__success __failure_unpriv __msg_unpriv("R0 leaks addr")
 992__retval(0)
 993__naked void _32_bit_truncation_test_1(void)
 994{
 995	asm volatile ("					\
 996	r1 = 0;						\
 997	*(u64*)(r10 - 8) = r1;				\
 998	r2 = r10;					\
 999	r2 += -8;					\
1000	r1 = %[map_hash_8b] ll;				\
1001	call %[bpf_map_lookup_elem];			\
1002	if r0 == 0 goto l0_%=;				\
1003	r1 = *(u32*)(r0 + 0);				\
1004	/* This used to reduce the max bound to 0x7fffffff */\
1005	if r1 == 0 goto l1_%=;				\
1006	if r1 > 0x7fffffff goto l0_%=;			\
1007l1_%=:	r0 = 0;						\
1008l0_%=:	exit;						\
1009"	:
1010	: __imm(bpf_map_lookup_elem),
1011	  __imm_addr(map_hash_8b)
1012	: __clobber_all);
1013}
1014
1015SEC("socket")
1016__description("bounds checks after 32-bit truncation. test 2")
1017__success __failure_unpriv __msg_unpriv("R0 leaks addr")
1018__retval(0)
1019__naked void _32_bit_truncation_test_2(void)
1020{
1021	asm volatile ("					\
1022	r1 = 0;						\
1023	*(u64*)(r10 - 8) = r1;				\
1024	r2 = r10;					\
1025	r2 += -8;					\
1026	r1 = %[map_hash_8b] ll;				\
1027	call %[bpf_map_lookup_elem];			\
1028	if r0 == 0 goto l0_%=;				\
1029	r1 = *(u32*)(r0 + 0);				\
1030	if r1 s< 1 goto l1_%=;				\
1031	if w1 s< 0 goto l0_%=;				\
1032l1_%=:	r0 = 0;						\
1033l0_%=:	exit;						\
1034"	:
1035	: __imm(bpf_map_lookup_elem),
1036	  __imm_addr(map_hash_8b)
1037	: __clobber_all);
1038}
1039
1040SEC("xdp")
1041__description("bound check with JMP_JLT for crossing 64-bit signed boundary")
1042__success __retval(0)
1043__naked void crossing_64_bit_signed_boundary_1(void)
1044{
1045	asm volatile ("					\
1046	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
1047	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
1048	r1 = r2;					\
1049	r1 += 1;					\
1050	if r1 > r3 goto l0_%=;				\
1051	r1 = *(u8*)(r2 + 0);				\
1052	r0 = 0x7fffffffffffff10 ll;			\
1053	r1 += r0;					\
1054	r0 = 0x8000000000000000 ll;			\
1055l1_%=:	r0 += 1;					\
1056	/* r1 unsigned range is [0x7fffffffffffff10, 0x800000000000000f] */\
1057	if r0 < r1 goto l1_%=;				\
1058l0_%=:	r0 = 0;						\
1059	exit;						\
1060"	:
1061	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1062	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1063	: __clobber_all);
1064}
1065
1066SEC("xdp")
1067__description("bound check with JMP_JSLT for crossing 64-bit signed boundary")
1068__success __retval(0)
1069__flag(BPF_F_TEST_REG_INVARIANTS)
1070__naked void crossing_64_bit_signed_boundary_2(void)
1071{
1072	asm volatile ("					\
1073	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
1074	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
1075	r1 = r2;					\
1076	r1 += 1;					\
1077	if r1 > r3 goto l0_%=;				\
1078	r1 = *(u8*)(r2 + 0);				\
1079	r0 = 0x7fffffffffffff10 ll;			\
1080	r1 += r0;					\
1081	r2 = 0x8000000000000fff ll;			\
1082	r0 = 0x8000000000000000 ll;			\
1083l1_%=:	r0 += 1;					\
1084	if r0 s> r2 goto l0_%=;				\
1085	/* r1 signed range is [S64_MIN, S64_MAX] */	\
1086	if r0 s< r1 goto l1_%=;				\
1087	r0 = 1;						\
1088	exit;						\
1089l0_%=:	r0 = 0;						\
1090	exit;						\
1091"	:
1092	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1093	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1094	: __clobber_all);
1095}
1096
1097SEC("xdp")
1098__description("bound check for loop upper bound greater than U32_MAX")
1099__success __retval(0)
1100__naked void bound_greater_than_u32_max(void)
1101{
1102	asm volatile ("					\
1103	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
1104	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
1105	r1 = r2;					\
1106	r1 += 1;					\
1107	if r1 > r3 goto l0_%=;				\
1108	r1 = *(u8*)(r2 + 0);				\
1109	r0 = 0x100000000 ll;				\
1110	r1 += r0;					\
1111	r0 = 0x100000000 ll;				\
1112l1_%=:	r0 += 1;					\
1113	if r0 < r1 goto l1_%=;				\
1114l0_%=:	r0 = 0;						\
1115	exit;						\
1116"	:
1117	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1118	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1119	: __clobber_all);
1120}
1121
1122SEC("xdp")
1123__description("bound check with JMP32_JLT for crossing 32-bit signed boundary")
1124__success __retval(0)
1125__naked void crossing_32_bit_signed_boundary_1(void)
1126{
1127	asm volatile ("					\
1128	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
1129	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
1130	r1 = r2;					\
1131	r1 += 1;					\
1132	if r1 > r3 goto l0_%=;				\
1133	r1 = *(u8*)(r2 + 0);				\
1134	w0 = 0x7fffff10;				\
1135	w1 += w0;					\
1136	w0 = 0x80000000;				\
1137l1_%=:	w0 += 1;					\
1138	/* r1 unsigned range is [0, 0x8000000f] */	\
1139	if w0 < w1 goto l1_%=;				\
1140l0_%=:	r0 = 0;						\
1141	exit;						\
1142"	:
1143	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1144	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1145	: __clobber_all);
1146}
1147
1148SEC("xdp")
1149__description("bound check with JMP32_JSLT for crossing 32-bit signed boundary")
1150__success __retval(0)
1151__flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */
1152__naked void crossing_32_bit_signed_boundary_2(void)
1153{
1154	asm volatile ("					\
1155	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
1156	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
1157	r1 = r2;					\
1158	r1 += 1;					\
1159	if r1 > r3 goto l0_%=;				\
1160	r1 = *(u8*)(r2 + 0);				\
1161	w0 = 0x7fffff10;				\
1162	w1 += w0;					\
1163	w2 = 0x80000fff;				\
1164	w0 = 0x80000000;				\
1165l1_%=:	w0 += 1;					\
1166	if w0 s> w2 goto l0_%=;				\
1167	/* r1 signed range is [S32_MIN, S32_MAX] */	\
1168	if w0 s< w1 goto l1_%=;				\
1169	r0 = 1;						\
1170	exit;						\
1171l0_%=:	r0 = 0;						\
1172	exit;						\
1173"	:
1174	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1175	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1176	: __clobber_all);
1177}
1178
1179SEC("tc")
1180__description("bounds check with JMP_NE for reg edge")
1181__success __retval(0)
1182__naked void reg_not_equal_const(void)
1183{
1184	asm volatile ("					\
1185	r6 = r1;					\
1186	r1 = 0;						\
1187	*(u64*)(r10 - 8) = r1;				\
1188	call %[bpf_get_prandom_u32];			\
1189	r4 = r0;					\
1190	r4 &= 7;					\
1191	if r4 != 0 goto l0_%=;				\
1192	r0 = 0;						\
1193	exit;						\
1194l0_%=:	r1 = r6;					\
1195	r2 = 0;						\
1196	r3 = r10;					\
1197	r3 += -8;					\
1198	r5 = 0;						\
1199	/* The 4th argument of bpf_skb_store_bytes is defined as \
1200	 * ARG_CONST_SIZE, so 0 is not allowed. The 'r4 != 0' \
1201	 * is providing us this exclusion of zero from initial \
1202	 * [0, 7] range.				\
1203	 */						\
1204	call %[bpf_skb_store_bytes];			\
1205	r0 = 0;						\
1206	exit;						\
1207"	:
1208	: __imm(bpf_get_prandom_u32),
1209	  __imm(bpf_skb_store_bytes)
1210	: __clobber_all);
1211}
1212
1213SEC("tc")
1214__description("bounds check with JMP_EQ for reg edge")
1215__success __retval(0)
1216__naked void reg_equal_const(void)
1217{
1218	asm volatile ("					\
1219	r6 = r1;					\
1220	r1 = 0;						\
1221	*(u64*)(r10 - 8) = r1;				\
1222	call %[bpf_get_prandom_u32];			\
1223	r4 = r0;					\
1224	r4 &= 7;					\
1225	if r4 == 0 goto l0_%=;				\
1226	r1 = r6;					\
1227	r2 = 0;						\
1228	r3 = r10;					\
1229	r3 += -8;					\
1230	r5 = 0;						\
1231	/* Just the same as what we do in reg_not_equal_const() */ \
1232	call %[bpf_skb_store_bytes];			\
1233l0_%=:	r0 = 0;						\
1234	exit;						\
1235"	:
1236	: __imm(bpf_get_prandom_u32),
1237	  __imm(bpf_skb_store_bytes)
1238	: __clobber_all);
1239}
1240
1241SEC("tc")
1242__description("multiply mixed sign bounds. test 1")
1243__success __log_level(2)
1244__msg("r6 *= r7 {{.*}}; R6=scalar(smin=umin=0x1bc16d5cd4927ee1,smax=umax=0x1bc16d674ec80000,smax32=0x7ffffeff,umax32=0xfffffeff,var_off=(0x1bc16d4000000000; 0x3ffffffeff))")
1245__naked void mult_mixed0_sign(void)
1246{
1247	asm volatile (
1248	"call %[bpf_get_prandom_u32];"
1249	"r6 = r0;"
1250	"call %[bpf_get_prandom_u32];"
1251	"r7 = r0;"
1252	"r6 &= 0xf;"
1253	"r6 -= 1000000000;"
1254	"r7 &= 0xf;"
1255	"r7 -= 2000000000;"
1256	"r6 *= r7;"
1257	"exit"
1258	:
1259	: __imm(bpf_get_prandom_u32),
1260	  __imm(bpf_skb_store_bytes)
1261	: __clobber_all);
1262}
1263
1264SEC("tc")
1265__description("multiply mixed sign bounds. test 2")
1266__success __log_level(2)
1267__msg("r6 *= r7 {{.*}}; R6=scalar(smin=smin32=-100,smax=smax32=200)")
1268__naked void mult_mixed1_sign(void)
1269{
1270	asm volatile (
1271	"call %[bpf_get_prandom_u32];"
1272	"r6 = r0;"
1273	"call %[bpf_get_prandom_u32];"
1274	"r7 = r0;"
1275	"r6 &= 0xf;"
1276	"r6 -= 0xa;"
1277	"r7 &= 0xf;"
1278	"r7 -= 0x14;"
1279	"r6 *= r7;"
1280	"exit"
1281	:
1282	: __imm(bpf_get_prandom_u32),
1283	  __imm(bpf_skb_store_bytes)
1284	: __clobber_all);
1285}
1286
1287SEC("tc")
1288__description("multiply negative bounds")
1289__success __log_level(2)
1290__msg("r6 *= r7 {{.*}}; R6=scalar(smin=umin=smin32=umin32=0x3ff280b0,smax=umax=smax32=umax32=0x3fff0001,var_off=(0x3ff00000; 0xf81ff))")
1291__naked void mult_sign_bounds(void)
1292{
1293	asm volatile (
1294	"r8 = 0x7fff;"
1295	"call %[bpf_get_prandom_u32];"
1296	"r6 = r0;"
1297	"call %[bpf_get_prandom_u32];"
1298	"r7 = r0;"
1299	"r6 &= 0xa;"
1300	"r6 -= r8;"
1301	"r7 &= 0xf;"
1302	"r7 -= r8;"
1303	"r6 *= r7;"
1304	"exit"
1305	:
1306	: __imm(bpf_get_prandom_u32),
1307	  __imm(bpf_skb_store_bytes)
1308	: __clobber_all);
1309}
1310
1311SEC("tc")
1312__description("multiply bounds that don't cross signed boundary")
1313__success __log_level(2)
1314__msg("r8 *= r6 {{.*}}; R6=scalar(smin=smin32=0,smax=umax=smax32=umax32=11,var_off=(0x0; 0xb)) R8=scalar(smin=0,smax=umax=0x7b96bb0a94a3a7cd,var_off=(0x0; 0x7fffffffffffffff))")
1315__naked void mult_no_sign_crossing(void)
1316{
1317	asm volatile (
1318	"r6 = 0xb;"
1319	"r8 = 0xb3c3f8c99262687 ll;"
1320	"call %[bpf_get_prandom_u32];"
1321	"r7 = r0;"
1322	"r6 &= r7;"
1323	"r8 *= r6;"
1324	"exit"
1325	:
1326	: __imm(bpf_get_prandom_u32),
1327	  __imm(bpf_skb_store_bytes)
1328	: __clobber_all);
1329}
1330
1331SEC("tc")
1332__description("multiplication overflow, result in unbounded reg. test 1")
1333__success __log_level(2)
1334__msg("r6 *= r7 {{.*}}; R6=scalar()")
1335__naked void mult_unsign_ovf(void)
1336{
1337	asm volatile (
1338	"r8 = 0x7ffffffffff ll;"
1339	"call %[bpf_get_prandom_u32];"
1340	"r6 = r0;"
1341	"call %[bpf_get_prandom_u32];"
1342	"r7 = r0;"
1343	"r6 &= 0x7fffffff;"
1344	"r7 &= r8;"
1345	"r6 *= r7;"
1346	"exit"
1347	:
1348	: __imm(bpf_get_prandom_u32),
1349	  __imm(bpf_skb_store_bytes)
1350	: __clobber_all);
1351}
1352
1353SEC("tc")
1354__description("multiplication overflow, result in unbounded reg. test 2")
1355__success __log_level(2)
1356__msg("r6 *= r7 {{.*}}; R6=scalar()")
1357__naked void mult_sign_ovf(void)
1358{
1359	asm volatile (
1360	"r8 = 0x7ffffffff ll;"
1361	"call %[bpf_get_prandom_u32];"
1362	"r6 = r0;"
1363	"call %[bpf_get_prandom_u32];"
1364	"r7 = r0;"
1365	"r6 &= 0xa;"
1366	"r6 -= r8;"
1367	"r7 &= 0x7fffffff;"
1368	"r6 *= r7;"
1369	"exit"
1370	:
1371	: __imm(bpf_get_prandom_u32),
1372	  __imm(bpf_skb_store_bytes)
1373	: __clobber_all);
1374}
1375
1376SEC("socket")
1377__description("64-bit addition, all outcomes overflow")
1378__success __log_level(2)
1379__msg("5: (0f) r3 += r3 {{.*}} R3=scalar(umin=0x4000000000000000,umax=0xfffffffffffffffe)")
1380__retval(0)
1381__naked void add64_full_overflow(void)
1382{
1383	asm volatile (
1384	"call %[bpf_get_prandom_u32];"
1385	"r4 = r0;"
1386	"r3 = 0xa000000000000000 ll;"
1387	"r3 |= r4;"
1388	"r3 += r3;"
1389	"r0 = 0;"
1390	"exit"
1391	:
1392	: __imm(bpf_get_prandom_u32)
1393	: __clobber_all);
1394}
1395
1396SEC("socket")
1397__description("64-bit addition, partial overflow, result in unbounded reg")
1398__success __log_level(2)
1399__msg("4: (0f) r3 += r3 {{.*}} R3=scalar()")
1400__retval(0)
1401__naked void add64_partial_overflow(void)
1402{
1403	asm volatile (
1404	"call %[bpf_get_prandom_u32];"
1405	"r4 = r0;"
1406	"r3 = 2;"
1407	"r3 |= r4;"
1408	"r3 += r3;"
1409	"r0 = 0;"
1410	"exit"
1411	:
1412	: __imm(bpf_get_prandom_u32)
1413	: __clobber_all);
1414}
1415
1416SEC("socket")
1417__description("32-bit addition overflow, all outcomes overflow")
1418__success __log_level(2)
1419__msg("4: (0c) w3 += w3 {{.*}} R3=scalar(smin=umin=umin32=0x40000000,smax=umax=umax32=0xfffffffe,var_off=(0x0; 0xffffffff))")
1420__retval(0)
1421__naked void add32_full_overflow(void)
1422{
1423	asm volatile (
1424	"call %[bpf_get_prandom_u32];"
1425	"w4 = w0;"
1426	"w3 = 0xa0000000;"
1427	"w3 |= w4;"
1428	"w3 += w3;"
1429	"r0 = 0;"
1430	"exit"
1431	:
1432	: __imm(bpf_get_prandom_u32)
1433	: __clobber_all);
1434}
1435
1436SEC("socket")
1437__description("32-bit addition, partial overflow, result in unbounded u32 bounds")
1438__success __log_level(2)
1439__msg("4: (0c) w3 += w3 {{.*}} R3=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))")
1440__retval(0)
1441__naked void add32_partial_overflow(void)
1442{
1443	asm volatile (
1444	"call %[bpf_get_prandom_u32];"
1445	"w4 = w0;"
1446	"w3 = 2;"
1447	"w3 |= w4;"
1448	"w3 += w3;"
1449	"r0 = 0;"
1450	"exit"
1451	:
1452	: __imm(bpf_get_prandom_u32)
1453	: __clobber_all);
1454}
1455
1456SEC("socket")
1457__description("64-bit subtraction, all outcomes underflow")
1458__success __log_level(2)
1459__msg("6: (1f) r3 -= r1 {{.*}} R3=scalar(umin=1,umax=0x8000000000000000)")
1460__retval(0)
1461__naked void sub64_full_overflow(void)
1462{
1463	asm volatile (
1464	"call %[bpf_get_prandom_u32];"
1465	"r1 = r0;"
1466	"r2 = 0x8000000000000000 ll;"
1467	"r1 |= r2;"
1468	"r3 = 0;"
1469	"r3 -= r1;"
1470	"r0 = 0;"
1471	"exit"
1472	:
1473	: __imm(bpf_get_prandom_u32)
1474	: __clobber_all);
1475}
1476
1477SEC("socket")
1478__description("64-bit subtraction, partial overflow, result in unbounded reg")
1479__success __log_level(2)
1480__msg("3: (1f) r3 -= r2 {{.*}} R3=scalar()")
1481__retval(0)
1482__naked void sub64_partial_overflow(void)
1483{
1484	asm volatile (
1485	"call %[bpf_get_prandom_u32];"
1486	"r3 = r0;"
1487	"r2 = 1;"
1488	"r3 -= r2;"
1489	"r0 = 0;"
1490	"exit"
1491	:
1492	: __imm(bpf_get_prandom_u32)
1493	: __clobber_all);
1494}
1495
1496SEC("socket")
1497__description("32-bit subtraction overflow, all outcomes underflow")
1498__success __log_level(2)
1499__msg("5: (1c) w3 -= w1 {{.*}} R3=scalar(smin=umin=umin32=1,smax=umax=umax32=0x80000000,var_off=(0x0; 0xffffffff))")
1500__retval(0)
1501__naked void sub32_full_overflow(void)
1502{
1503	asm volatile (
1504	"call %[bpf_get_prandom_u32];"
1505	"w1 = w0;"
1506	"w2 = 0x80000000;"
1507	"w1 |= w2;"
1508	"w3 = 0;"
1509	"w3 -= w1;"
1510	"r0 = 0;"
1511	"exit"
1512	:
1513	: __imm(bpf_get_prandom_u32)
1514	: __clobber_all);
1515}
1516
1517SEC("socket")
1518__description("32-bit subtraction, partial overflow, result in unbounded u32 bounds")
1519__success __log_level(2)
1520__msg("3: (1c) w3 -= w2 {{.*}} R3=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))")
1521__retval(0)
1522__naked void sub32_partial_overflow(void)
1523{
1524	asm volatile (
1525	"call %[bpf_get_prandom_u32];"
1526	"w3 = w0;"
1527	"w2 = 1;"
1528	"w3 -= w2;"
1529	"r0 = 0;"
1530	"exit"
1531	:
1532	: __imm(bpf_get_prandom_u32)
1533	: __clobber_all);
1534}
1535
1536SEC("socket")
1537__description("dead branch on jset, does not result in invariants violation error")
1538__success __log_level(2)
1539__retval(0) __flag(BPF_F_TEST_REG_INVARIANTS)
1540__naked void jset_range_analysis(void)
1541{
1542	asm volatile ("			\
1543	call %[bpf_get_netns_cookie];	\
1544	if r0 == 0 goto l0_%=;		\
1545	if r0 & 0xffffffff goto +0; 	\
1546l0_%=:	r0 = 0;				\
1547	exit;				\
1548"	:
1549	: __imm(bpf_get_netns_cookie)
1550	: __clobber_all);
1551}
1552
1553/* This test covers the bounds deduction on 64bits when the s64 and u64 ranges
1554 * overlap on the negative side. At instruction 7, the ranges look as follows:
1555 *
1556 * 0          umin=0xfffffcf1                 umax=0xff..ff6e  U64_MAX
1557 * |                [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]        |
1558 * |----------------------------|------------------------------|
1559 * |xxxxxxxxxx]                                   [xxxxxxxxxxxx|
1560 * 0    smax=0xeffffeee                       smin=-655        -1
1561 *
1562 * We should therefore deduce the following new bounds:
1563 *
1564 * 0                             u64=[0xff..ffd71;0xff..ff6e]  U64_MAX
1565 * |                                              [xxx]        |
1566 * |----------------------------|------------------------------|
1567 * |                                              [xxx]        |
1568 * 0                                        s64=[-655;-146]    -1
1569 *
1570 * Without the deduction cross sign boundary, we end up with an invariant
1571 * violation error.
1572 */
1573SEC("socket")
1574__description("bounds deduction cross sign boundary, negative overlap")
1575__success __log_level(2) __flag(BPF_F_TEST_REG_INVARIANTS)
1576__msg("7: (1f) r0 -= r6 {{.*}} R0=scalar(smin=smin32=-655,smax=smax32=-146,umin=0xfffffffffffffd71,umax=0xffffffffffffff6e,umin32=0xfffffd71,umax32=0xffffff6e,var_off=(0xfffffffffffffc00; 0x3ff))")
1577__retval(0)
1578__naked void bounds_deduct_negative_overlap(void)
1579{
1580	asm volatile("			\
1581	call %[bpf_get_prandom_u32];	\
1582	w3 = w0;			\
1583	w6 = (s8)w0;			\
1584	r0 = (s8)r0;			\
1585	if w6 >= 0xf0000000 goto l0_%=;	\
1586	r0 += r6;			\
1587	r6 += 400;			\
1588	r0 -= r6;			\
1589	if r3 < r0 goto l0_%=;		\
1590l0_%=:	r0 = 0;				\
1591	exit;				\
1592"	:
1593	: __imm(bpf_get_prandom_u32)
1594	: __clobber_all);
1595}
1596
1597/* This test covers the bounds deduction on 64bits when the s64 and u64 ranges
1598 * overlap on the positive side. At instruction 3, the ranges look as follows:
1599 *
1600 * 0 umin=0                      umax=0xffffffffffffff00       U64_MAX
1601 * [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]            |
1602 * |----------------------------|------------------------------|
1603 * |xxxxxxxx]                                         [xxxxxxxx|
1604 * 0      smax=127                                smin=-128    -1
1605 *
1606 * We should therefore deduce the following new bounds:
1607 *
1608 * 0  u64=[0;127]                                              U64_MAX
1609 * [xxxxxxxx]                                                  |
1610 * |----------------------------|------------------------------|
1611 * [xxxxxxxx]                                                  |
1612 * 0  s64=[0;127]                                              -1
1613 *
1614 * Without the deduction cross sign boundary, the program is rejected due to
1615 * the frame pointer write.
1616 */
1617SEC("socket")
1618__description("bounds deduction cross sign boundary, positive overlap")
1619__success __log_level(2) __flag(BPF_F_TEST_REG_INVARIANTS)
1620__msg("3: (2d) if r0 > r1 {{.*}} R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=127,var_off=(0x0; 0x7f))")
1621__retval(0)
1622__naked void bounds_deduct_positive_overlap(void)
1623{
1624	asm volatile("			\
1625	call %[bpf_get_prandom_u32];	\
1626	r0 = (s8)r0;			\
1627	r1 = 0xffffffffffffff00;	\
1628	if r0 > r1 goto l0_%=;		\
1629	if r0 < 128 goto l0_%=;		\
1630	r10 = 0;			\
1631l0_%=:	r0 = 0;				\
1632	exit;				\
1633"	:
1634	: __imm(bpf_get_prandom_u32)
1635	: __clobber_all);
1636}
1637
1638/* This test is the same as above, but the s64 and u64 ranges overlap in two
1639 * places. At instruction 3, the ranges look as follows:
1640 *
1641 * 0 umin=0                           umax=0xffffffffffffff80  U64_MAX
1642 * [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]        |
1643 * |----------------------------|------------------------------|
1644 * |xxxxxxxx]                                         [xxxxxxxx|
1645 * 0      smax=127                                smin=-128    -1
1646 *
1647 * 0xffffffffffffff80 = (u64)-128. We therefore can't deduce anything new and
1648 * the program should fail due to the frame pointer write.
1649 */
1650SEC("socket")
1651__description("bounds deduction cross sign boundary, two overlaps")
1652__failure __flag(BPF_F_TEST_REG_INVARIANTS)
1653__msg("3: (2d) if r0 > r1 {{.*}} R0=scalar(smin=smin32=-128,smax=smax32=127,umax=0xffffffffffffff80)")
1654__msg("frame pointer is read only")
1655__naked void bounds_deduct_two_overlaps(void)
1656{
1657	asm volatile("			\
1658	call %[bpf_get_prandom_u32];	\
1659	r0 = (s8)r0;			\
1660	r1 = 0xffffffffffffff80;	\
1661	if r0 > r1 goto l0_%=;		\
1662	if r0 < 128 goto l0_%=;		\
1663	r10 = 0;			\
1664l0_%=:	r0 = 0;				\
1665	exit;				\
1666"	:
1667	: __imm(bpf_get_prandom_u32)
1668	: __clobber_all);
1669}
1670
1671SEC("socket")
1672__description("dead jne branch due to disagreeing tnums")
1673__success __log_level(2)
1674__naked void jne_disagreeing_tnums(void *ctx)
1675{
1676	asm volatile("			\
1677	call %[bpf_get_prandom_u32];	\
1678	w0 = w0;			\
1679	r0 >>= 30;			\
1680	r0 <<= 30;			\
1681	r1 = r0;			\
1682	r1 += 1024;			\
1683	if r1 != r0 goto +1;		\
1684	r10 = 0;			\
1685	exit;				\
1686"	:
1687	: __imm(bpf_get_prandom_u32)
1688	: __clobber_all);
1689}
1690
1691SEC("socket")
1692__description("dead jeq branch due to disagreeing tnums")
1693__success __log_level(2)
1694__naked void jeq_disagreeing_tnums(void *ctx)
1695{
1696	asm volatile("			\
1697	call %[bpf_get_prandom_u32];	\
1698	w0 = w0;			\
1699	r0 >>= 30;			\
1700	r0 <<= 30;			\
1701	r1 = r0;			\
1702	r1 += 1024;			\
1703	if r1 == r0 goto +1;		\
1704	exit;				\
1705	r10 = 0;			\
1706	exit;				\
1707"	:
1708	: __imm(bpf_get_prandom_u32)
1709	: __clobber_all);
1710}
1711
1712SEC("socket")
1713__description("conditional jump on same register, branch taken")
1714__not_msg("20: (b7) r0 = 1 {{.*}} R0=1")
1715__success __log_level(2)
1716__retval(0) __flag(BPF_F_TEST_REG_INVARIANTS)
1717__naked void condition_jump_on_same_register(void *ctx)
1718{
1719	asm volatile("			\
1720	call %[bpf_get_prandom_u32];	\
1721	w8 = 0x80000000;		\
1722	r0 &= r8;			\
1723	if r0 == r0 goto +1;		\
1724	goto l1_%=;			\
1725	if r0 >= r0 goto +1;		\
1726	goto l1_%=;			\
1727	if r0 s>= r0 goto +1;		\
1728	goto l1_%=;			\
1729	if r0 <= r0 goto +1;		\
1730	goto l1_%=;			\
1731	if r0 s<= r0 goto +1;		\
1732	goto l1_%=;			\
1733	if r0 != r0 goto l1_%=;		\
1734	if r0 >  r0 goto l1_%=;		\
1735	if r0 s> r0 goto l1_%=;		\
1736	if r0 <  r0 goto l1_%=;		\
1737	if r0 s< r0 goto l1_%=;		\
1738l0_%=:	r0 = 0;				\
1739	exit;				\
1740l1_%=:	r0 = 1;				\
1741	exit;				\
1742"	:
1743	: __imm(bpf_get_prandom_u32)
1744	: __clobber_all);
1745}
1746
1747SEC("socket")
1748__description("jset on same register, constant value branch taken")
1749__not_msg("7: (b7) r0 = 1 {{.*}} R0=1")
1750__success __log_level(2)
1751__retval(0) __flag(BPF_F_TEST_REG_INVARIANTS)
1752__naked void jset_on_same_register_1(void *ctx)
1753{
1754	asm volatile("			\
1755	r0 = 0;				\
1756	if r0 & r0 goto l1_%=;		\
1757	r0 = 1;				\
1758	if r0 & r0 goto +1;		\
1759	goto l1_%=;			\
1760l0_%=:	r0 = 0;				\
1761	exit;				\
1762l1_%=:	r0 = 1;				\
1763	exit;				\
1764"	:
1765	: __imm(bpf_get_prandom_u32)
1766	: __clobber_all);
1767}
1768
1769SEC("socket")
1770__description("jset on same register, scalar value branch taken")
1771__not_msg("12: (b7) r0 = 1 {{.*}} R0=1")
1772__success __log_level(2)
1773__retval(0) __flag(BPF_F_TEST_REG_INVARIANTS)
1774__naked void jset_on_same_register_2(void *ctx)
1775{
1776	asm volatile("			\
1777	/* range [1;2] */		\
1778	call %[bpf_get_prandom_u32];	\
1779	r0 &= 0x1;			\
1780	r0 += 1;			\
1781	if r0 & r0 goto +1;		\
1782	goto l1_%=;			\
1783	/* range [-2;-1] */		\
1784	call %[bpf_get_prandom_u32];	\
1785	r0 &= 0x1;			\
1786	r0 -= 2;			\
1787	if r0 & r0 goto +1;		\
1788	goto l1_%=;			\
1789l0_%=:	r0 = 0;				\
1790	exit;				\
1791l1_%=:	r0 = 1;				\
1792	exit;				\
1793"	:
1794	: __imm(bpf_get_prandom_u32)
1795	: __clobber_all);
1796}
1797
1798SEC("socket")
1799__description("jset on same register, scalar value unknown branch 1")
1800__msg("3: (b7) r0 = 0 {{.*}} R0=0")
1801__msg("5: (b7) r0 = 1 {{.*}} R0=1")
1802__success __log_level(2)
1803__flag(BPF_F_TEST_REG_INVARIANTS)
1804__naked void jset_on_same_register_3(void *ctx)
1805{
1806	asm volatile("			\
1807	/* range [0;1] */		\
1808	call %[bpf_get_prandom_u32];	\
1809	r0 &= 0x1;			\
1810	if r0 & r0 goto l1_%=;		\
1811l0_%=:	r0 = 0;				\
1812	exit;				\
1813l1_%=:	r0 = 1;				\
1814	exit;				\
1815"	:
1816	: __imm(bpf_get_prandom_u32)
1817	: __clobber_all);
1818}
1819
1820SEC("socket")
1821__description("jset on same register, scalar value unknown branch 2")
1822__msg("4: (b7) r0 = 0 {{.*}} R0=0")
1823__msg("6: (b7) r0 = 1 {{.*}} R0=1")
1824__success __log_level(2)
1825__flag(BPF_F_TEST_REG_INVARIANTS)
1826__naked void jset_on_same_register_4(void *ctx)
1827{
1828	asm volatile("			\
1829	/* range [-1;0] */		\
1830	call %[bpf_get_prandom_u32];	\
1831	r0 &= 0x1;			\
1832	r0 -= 1;			\
1833	if r0 & r0 goto l1_%=;		\
1834l0_%=:	r0 = 0;				\
1835	exit;				\
1836l1_%=:	r0 = 1;				\
1837	exit;				\
1838"	:
1839	: __imm(bpf_get_prandom_u32)
1840	: __clobber_all);
1841}
1842
1843SEC("socket")
1844__description("jset on same register, scalar value unknown branch 3")
1845__msg("4: (b7) r0 = 0 {{.*}} R0=0")
1846__msg("6: (b7) r0 = 1 {{.*}} R0=1")
1847__success __log_level(2)
1848__flag(BPF_F_TEST_REG_INVARIANTS)
1849__naked void jset_on_same_register_5(void *ctx)
1850{
1851	asm volatile("			\
1852	/* range [-1;1] */		\
1853	call %[bpf_get_prandom_u32];	\
1854	r0 &= 0x2;			\
1855	r0 -= 1;			\
1856	if r0 & r0 goto l1_%=;		\
1857l0_%=:	r0 = 0;				\
1858	exit;				\
1859l1_%=:	r0 = 1;				\
1860	exit;				\
1861"	:
1862	: __imm(bpf_get_prandom_u32)
1863	: __clobber_all);
1864}
1865
1866/* This test covers the bounds deduction when the u64 range and the tnum
1867 * overlap only at umax. After instruction 3, the ranges look as follows:
1868 *
1869 * 0    umin=0xe01     umax=0xf00                              U64_MAX
1870 * |    [xxxxxxxxxxxxxx]                                       |
1871 * |----------------------------|------------------------------|
1872 * |   x               x                                       | tnum values
1873 *
1874 * The verifier can therefore deduce that the R0=0xf0=240.
1875 */
1876SEC("socket")
1877__description("bounds refinement with single-value tnum on umax")
1878__msg("3: (15) if r0 == 0xe0 {{.*}} R0=240")
1879__success __log_level(2)
1880__flag(BPF_F_TEST_REG_INVARIANTS)
1881__naked void bounds_refinement_tnum_umax(void *ctx)
1882{
1883	asm volatile("			\
1884	call %[bpf_get_prandom_u32];	\
1885	r0 |= 0xe0;			\
1886	r0 &= 0xf0;			\
1887	if r0 == 0xe0 goto +2;		\
1888	if r0 == 0xf0 goto +1;		\
1889	r10 = 0;			\
1890	exit;				\
1891"	:
1892	: __imm(bpf_get_prandom_u32)
1893	: __clobber_all);
1894}
1895
1896/* This test covers the bounds deduction when the u64 range and the tnum
1897 * overlap only at umin. After instruction 3, the ranges look as follows:
1898 *
1899 * 0    umin=0xe00     umax=0xeff                              U64_MAX
1900 * |    [xxxxxxxxxxxxxx]                                       |
1901 * |----------------------------|------------------------------|
1902 * |    x               x                                      | tnum values
1903 *
1904 * The verifier can therefore deduce that the R0=0xe0=224.
1905 */
1906SEC("socket")
1907__description("bounds refinement with single-value tnum on umin")
1908__msg("3: (15) if r0 == 0xf0 {{.*}} R0=224")
1909__success __log_level(2)
1910__flag(BPF_F_TEST_REG_INVARIANTS)
1911__naked void bounds_refinement_tnum_umin(void *ctx)
1912{
1913	asm volatile("			\
1914	call %[bpf_get_prandom_u32];	\
1915	r0 |= 0xe0;			\
1916	r0 &= 0xf0;			\
1917	if r0 == 0xf0 goto +2;		\
1918	if r0 == 0xe0 goto +1;		\
1919	r10 = 0;			\
1920	exit;				\
1921"	:
1922	: __imm(bpf_get_prandom_u32)
1923	: __clobber_all);
1924}
1925
1926/* This test covers the bounds deduction when the only possible tnum value is
1927 * in the middle of the u64 range. After instruction 3, the ranges look as
1928 * follows:
1929 *
1930 * 0    umin=0x7cf   umax=0x7df                                U64_MAX
1931 * |    [xxxxxxxxxxxx]                                         |
1932 * |----------------------------|------------------------------|
1933 * |     x            x            x            x            x | tnum values
1934 *       |            +--- 0x7e0
1935 *       +--- 0x7d0
1936 *
1937 * Since the lower four bits are zero, the tnum and the u64 range only overlap
1938 * in R0=0x7d0=2000. Instruction 5 is therefore dead code.
1939 */
1940SEC("socket")
1941__description("bounds refinement with single-value tnum in middle of range")
1942__msg("3: (a5) if r0 < 0x7cf {{.*}} R0=2000")
1943__success __log_level(2)
1944__naked void bounds_refinement_tnum_middle(void *ctx)
1945{
1946	asm volatile("			\
1947	call %[bpf_get_prandom_u32];	\
1948	if r0 & 0x0f goto +4;		\
1949	if r0 > 0x7df goto +3;		\
1950	if r0 < 0x7cf goto +2;		\
1951	if r0 == 0x7d0 goto +1;		\
1952	r10 = 0;			\
1953	exit;				\
1954"	:
1955	: __imm(bpf_get_prandom_u32)
1956	: __clobber_all);
1957}
1958
1959/* This test cover the negative case for the tnum/u64 overlap. Since
1960 * they contain the same two values (i.e., {0, 1}), we can't deduce
1961 * anything more.
1962 */
1963SEC("socket")
1964__description("bounds refinement: several overlaps between tnum and u64")
1965__msg("2: (25) if r0 > 0x1 {{.*}} R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=1,var_off=(0x0; 0x1))")
1966__failure __log_level(2)
1967__naked void bounds_refinement_several_overlaps(void *ctx)
1968{
1969	asm volatile("			\
1970	call %[bpf_get_prandom_u32];	\
1971	if r0 < 0 goto +3;		\
1972	if r0 > 1 goto +2;		\
1973	if r0 == 1 goto +1;		\
1974	r10 = 0;			\
1975	exit;				\
1976"	:
1977	: __imm(bpf_get_prandom_u32)
1978	: __clobber_all);
1979}
1980
1981/* This test cover the negative case for the tnum/u64 overlap. Since
1982 * they overlap in the two values contained by the u64 range (i.e.,
1983 * {0xf, 0x10}), we can't deduce anything more.
1984 */
1985SEC("socket")
1986__description("bounds refinement: multiple overlaps between tnum and u64")
1987__msg("2: (25) if r0 > 0x10 {{.*}} R0=scalar(smin=umin=smin32=umin32=15,smax=umax=smax32=umax32=16,var_off=(0x0; 0x1f))")
1988__failure __log_level(2)
1989__naked void bounds_refinement_multiple_overlaps(void *ctx)
1990{
1991	asm volatile("			\
1992	call %[bpf_get_prandom_u32];	\
1993	if r0 < 0xf goto +3;		\
1994	if r0 > 0x10 goto +2;		\
1995	if r0 == 0x10 goto +1;		\
1996	r10 = 0;			\
1997	exit;				\
1998"	:
1999	: __imm(bpf_get_prandom_u32)
2000	: __clobber_all);
2001}
2002
2003char _license[] SEC("license") = "GPL";
~/ Read-only file preview.