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