831 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include <linux/bpf.h>4#include <bpf/bpf_helpers.h>5#include "bpf_misc.h"6 7/* Check that precision marks propagate through scalar IDs.8 * Registers r{0,1,2} have the same scalar ID.9 * Range information is propagated for scalars sharing same ID.10 * Check that precision mark for r0 causes precision marks for r{1,2}11 * when range information is propagated for 'if <reg> <op> <const>' insn.12 */13SEC("socket")14__success __log_level(2)15/* first 'if' branch */16__msg("6: (0f) r3 += r0")17__msg("frame0: regs=r0 stack= before 4: (25) if r1 > 0x7 goto pc+0")18__msg("frame0: parent state regs=r0,r1,r2 stack=:")19__msg("frame0: regs=r0,r1,r2 stack= before 3: (bf) r2 = r0")20/* second 'if' branch */21__msg("from 4 to 5: ")22__msg("6: (0f) r3 += r0")23__msg("frame0: regs=r0 stack= before 5: (bf) r3 = r10")24__msg("frame0: regs=r0 stack= before 4: (25) if r1 > 0x7 goto pc+0")25/* parent state already has r{0,1,2} as precise */26__msg("frame0: parent state regs= stack=:")27__flag(BPF_F_TEST_STATE_FREQ)28__naked void linked_regs_bpf_k(void)29{30 asm volatile (31 /* r0 = random number up to 0xff */32 "call %[bpf_ktime_get_ns];"33 "r0 &= 0xff;"34 /* tie r0.id == r1.id == r2.id */35 "r1 = r0;"36 "r2 = r0;"37 "if r1 > 7 goto +0;"38 /* force r0 to be precise, this eventually marks r1 and r2 as39 * precise as well because of shared IDs40 */41 "r3 = r10;"42 "r3 += r0;"43 "r0 = 0;"44 "exit;"45 :46 : __imm(bpf_ktime_get_ns)47 : __clobber_all);48}49 50/* Registers r{0,1,2} share same ID when 'if r1 > ...' insn is processed,51 * check that verifier marks r{1,2} as precise while backtracking52 * 'if r1 > ...' with r0 already marked.53 */54SEC("socket")55__success __log_level(2)56__flag(BPF_F_TEST_STATE_FREQ)57__msg("frame0: regs=r0 stack= before 5: (2d) if r1 > r3 goto pc+0")58__msg("frame0: parent state regs=r0,r1,r2,r3 stack=:")59__msg("frame0: regs=r0,r1,r2,r3 stack= before 4: (b7) r3 = 7")60__naked void linked_regs_bpf_x_src(void)61{62 asm volatile (63 /* r0 = random number up to 0xff */64 "call %[bpf_ktime_get_ns];"65 "r0 &= 0xff;"66 /* tie r0.id == r1.id == r2.id */67 "r1 = r0;"68 "r2 = r0;"69 "r3 = 7;"70 "if r1 > r3 goto +0;"71 /* force r0 to be precise, this eventually marks r1 and r2 as72 * precise as well because of shared IDs73 */74 "r4 = r10;"75 "r4 += r0;"76 "r0 = 0;"77 "exit;"78 :79 : __imm(bpf_ktime_get_ns)80 : __clobber_all);81}82 83/* Registers r{0,1,2} share same ID when 'if r1 > r3' insn is processed,84 * check that verifier marks r{0,1,2} as precise while backtracking85 * 'if r1 > r3' with r3 already marked.86 */87SEC("socket")88__success __log_level(2)89__flag(BPF_F_TEST_STATE_FREQ)90__msg("frame0: regs=r3 stack= before 5: (2d) if r1 > r3 goto pc+0")91__msg("frame0: parent state regs=r0,r1,r2,r3 stack=:")92__msg("frame0: regs=r0,r1,r2,r3 stack= before 4: (b7) r3 = 7")93__naked void linked_regs_bpf_x_dst(void)94{95 asm volatile (96 /* r0 = random number up to 0xff */97 "call %[bpf_ktime_get_ns];"98 "r0 &= 0xff;"99 /* tie r0.id == r1.id == r2.id */100 "r1 = r0;"101 "r2 = r0;"102 "r3 = 7;"103 "if r1 > r3 goto +0;"104 /* force r0 to be precise, this eventually marks r1 and r2 as105 * precise as well because of shared IDs106 */107 "r4 = r10;"108 "r4 += r3;"109 "r0 = 0;"110 "exit;"111 :112 : __imm(bpf_ktime_get_ns)113 : __clobber_all);114}115 116/* Same as linked_regs_bpf_k, but break one of the117 * links, note that r1 is absent from regs=... in __msg below.118 */119SEC("socket")120__success __log_level(2)121__msg("7: (0f) r3 += r0")122__msg("frame0: regs=r0 stack= before 6: (bf) r3 = r10")123__msg("frame0: parent state regs=r0 stack=:")124__msg("frame0: regs=r0 stack= before 5: (25) if r0 > 0x7 goto pc+0")125__msg("frame0: parent state regs=r0,r2 stack=:")126__flag(BPF_F_TEST_STATE_FREQ)127__naked void linked_regs_broken_link(void)128{129 asm volatile (130 /* r0 = random number up to 0xff */131 "call %[bpf_ktime_get_ns];"132 "r0 &= 0xff;"133 /* tie r0.id == r1.id == r2.id */134 "r1 = r0;"135 "r2 = r0;"136 /* break link for r1, this is the only line that differs137 * compared to the previous test138 */139 "r1 = 0;"140 "if r0 > 7 goto +0;"141 /* force r0 to be precise,142 * this eventually marks r2 as precise because of shared IDs143 */144 "r3 = r10;"145 "r3 += r0;"146 "r0 = 0;"147 "exit;"148 :149 : __imm(bpf_ktime_get_ns)150 : __clobber_all);151}152 153/* Check that precision marks propagate through scalar IDs.154 * Use the same scalar ID in multiple stack frames, check that155 * precision information is propagated up the call stack.156 */157SEC("socket")158__success __log_level(2)159__msg("12: (0f) r2 += r1")160/* Current state */161__msg("frame2: last_idx 12 first_idx 11 subseq_idx -1 ")162__msg("frame2: regs=r1 stack= before 11: (bf) r2 = r10")163__msg("frame2: parent state regs=r1 stack=")164__msg("frame1: parent state regs= stack=")165__msg("frame0: parent state regs= stack=")166/* Parent state */167__msg("frame2: last_idx 10 first_idx 10 subseq_idx 11 ")168__msg("frame2: regs=r1 stack= before 10: (25) if r1 > 0x7 goto pc+0")169__msg("frame2: parent state regs=r1 stack=")170/* frame1.r{6,7} are marked because mark_precise_scalar_ids()171 * looks for all registers with frame2.r1.id in the current state172 */173__msg("frame1: parent state regs=r6,r7 stack=")174__msg("frame0: parent state regs=r6 stack=")175/* Parent state */176__msg("frame2: last_idx 8 first_idx 8 subseq_idx 10")177__msg("frame2: regs=r1 stack= before 8: (85) call pc+1")178/* frame1.r1 is marked because of backtracking of call instruction */179__msg("frame1: parent state regs=r1,r6,r7 stack=")180__msg("frame0: parent state regs=r6 stack=")181/* Parent state */182__msg("frame1: last_idx 7 first_idx 6 subseq_idx 8")183__msg("frame1: regs=r1,r6,r7 stack= before 7: (bf) r7 = r1")184__msg("frame1: regs=r1,r6 stack= before 6: (bf) r6 = r1")185__msg("frame1: parent state regs=r1 stack=")186__msg("frame0: parent state regs=r6 stack=")187/* Parent state */188__msg("frame1: last_idx 4 first_idx 4 subseq_idx 6")189__msg("frame1: regs=r1 stack= before 4: (85) call pc+1")190__msg("frame0: parent state regs=r1,r6 stack=")191/* Parent state */192__msg("frame0: last_idx 3 first_idx 1 subseq_idx 4")193__msg("frame0: regs=r1,r6 stack= before 3: (bf) r6 = r0")194__msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0")195__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255")196__flag(BPF_F_TEST_STATE_FREQ)197__naked void precision_many_frames(void)198{199 asm volatile (200 /* r0 = random number up to 0xff */201 "call %[bpf_ktime_get_ns];"202 "r0 &= 0xff;"203 /* tie r0.id == r1.id == r6.id */204 "r1 = r0;"205 "r6 = r0;"206 "call precision_many_frames__foo;"207 "exit;"208 :209 : __imm(bpf_ktime_get_ns)210 : __clobber_all);211}212 213static __naked __noinline __used214void precision_many_frames__foo(void)215{216 asm volatile (217 /* conflate one of the register numbers (r6) with outer frame,218 * to verify that those are tracked independently219 */220 "r6 = r1;"221 "r7 = r1;"222 "call precision_many_frames__bar;"223 "exit"224 ::: __clobber_all);225}226 227static __naked __noinline __used228void precision_many_frames__bar(void)229{230 asm volatile (231 "if r1 > 7 goto +0;"232 /* force r1 to be precise, this eventually marks:233 * - bar frame r1234 * - foo frame r{1,6,7}235 * - main frame r{1,6}236 */237 "r2 = r10;"238 "r2 += r1;"239 "r0 = 0;"240 "exit;"241 ::: __clobber_all);242}243 244/* Check that scalars with the same IDs are marked precise on stack as245 * well as in registers.246 */247SEC("socket")248__success __log_level(2)249__msg("11: (0f) r2 += r1")250/* foo frame */251__msg("frame1: regs=r1 stack= before 10: (bf) r2 = r10")252__msg("frame1: regs=r1 stack= before 9: (25) if r1 > 0x7 goto pc+0")253__msg("frame1: regs=r1 stack=-8,-16 before 8: (7b) *(u64 *)(r10 -16) = r1")254__msg("frame1: regs=r1 stack=-8 before 7: (7b) *(u64 *)(r10 -8) = r1")255__msg("frame1: regs=r1 stack= before 4: (85) call pc+2")256/* main frame */257__msg("frame0: regs=r1 stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r1")258__msg("frame0: regs=r1 stack= before 2: (bf) r1 = r0")259__msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255")260__flag(BPF_F_TEST_STATE_FREQ)261__naked void precision_stack(void)262{263 asm volatile (264 /* r0 = random number up to 0xff */265 "call %[bpf_ktime_get_ns];"266 "r0 &= 0xff;"267 /* tie r0.id == r1.id == fp[-8].id */268 "r1 = r0;"269 "*(u64*)(r10 - 8) = r1;"270 "call precision_stack__foo;"271 "r0 = 0;"272 "exit;"273 :274 : __imm(bpf_ktime_get_ns)275 : __clobber_all);276}277 278static __naked __noinline __used279void precision_stack__foo(void)280{281 asm volatile (282 /* conflate one of the register numbers (r6) with outer frame,283 * to verify that those are tracked independently284 */285 "*(u64*)(r10 - 8) = r1;"286 "*(u64*)(r10 - 16) = r1;"287 "if r1 > 7 goto +0;"288 /* force r1 to be precise, this eventually marks:289 * - foo frame r1,fp{-8,-16}290 * - main frame r1,fp{-8}291 */292 "r2 = r10;"293 "r2 += r1;"294 "exit"295 ::: __clobber_all);296}297 298/* Use two separate scalar IDs to check that these are propagated299 * independently.300 */301SEC("socket")302__success __log_level(2)303/* r{6,7} */304__msg("12: (0f) r3 += r7")305__msg("frame0: regs=r7 stack= before 11: (bf) r3 = r10")306__msg("frame0: regs=r7 stack= before 9: (25) if r7 > 0x7 goto pc+0")307/* ... skip some insns ... */308__msg("frame0: regs=r6,r7 stack= before 3: (bf) r7 = r0")309__msg("frame0: regs=r0,r6 stack= before 2: (bf) r6 = r0")310/* r{8,9} */311__msg("13: (0f) r3 += r9")312__msg("frame0: regs=r9 stack= before 12: (0f) r3 += r7")313/* ... skip some insns ... */314__msg("frame0: regs=r9 stack= before 10: (25) if r9 > 0x7 goto pc+0")315__msg("frame0: regs=r8,r9 stack= before 7: (bf) r9 = r0")316__msg("frame0: regs=r0,r8 stack= before 6: (bf) r8 = r0")317__flag(BPF_F_TEST_STATE_FREQ)318__naked void precision_two_ids(void)319{320 asm volatile (321 /* r6 = random number up to 0xff322 * r6.id == r7.id323 */324 "call %[bpf_ktime_get_ns];"325 "r0 &= 0xff;"326 "r6 = r0;"327 "r7 = r0;"328 /* same, but for r{8,9} */329 "call %[bpf_ktime_get_ns];"330 "r0 &= 0xff;"331 "r8 = r0;"332 "r9 = r0;"333 /* clear r0 id */334 "r0 = 0;"335 /* propagate equal scalars precision */336 "if r7 > 7 goto +0;"337 "if r9 > 7 goto +0;"338 "r3 = r10;"339 /* force r7 to be precise, this also marks r6 */340 "r3 += r7;"341 /* force r9 to be precise, this also marks r8 */342 "r3 += r9;"343 "exit;"344 :345 : __imm(bpf_ktime_get_ns)346 : __clobber_all);347}348 349SEC("socket")350__success __log_level(2)351__flag(BPF_F_TEST_STATE_FREQ)352/* check thar r0 and r6 have different IDs after 'if',353 * collect_linked_regs() can't tie more than 6 registers for a single insn.354 */355__msg("8: (25) if r0 > 0x7 goto pc+0 ; R0=scalar(id=1")356__msg("9: (bf) r6 = r6 ; R6_w=scalar(id=2")357/* check that r{0-5} are marked precise after 'if' */358__msg("frame0: regs=r0 stack= before 8: (25) if r0 > 0x7 goto pc+0")359__msg("frame0: parent state regs=r0,r1,r2,r3,r4,r5 stack=:")360__naked void linked_regs_too_many_regs(void)361{362 asm volatile (363 /* r0 = random number up to 0xff */364 "call %[bpf_ktime_get_ns];"365 "r0 &= 0xff;"366 /* tie r{0-6} IDs */367 "r1 = r0;"368 "r2 = r0;"369 "r3 = r0;"370 "r4 = r0;"371 "r5 = r0;"372 "r6 = r0;"373 /* propagate range for r{0-6} */374 "if r0 > 7 goto +0;"375 /* make r6 appear in the log */376 "r6 = r6;"377 /* force r0 to be precise,378 * this would cause r{0-4} to be precise because of shared IDs379 */380 "r7 = r10;"381 "r7 += r0;"382 "r0 = 0;"383 "exit;"384 :385 : __imm(bpf_ktime_get_ns)386 : __clobber_all);387}388 389SEC("socket")390__failure __log_level(2)391__flag(BPF_F_TEST_STATE_FREQ)392__msg("regs=r7 stack= before 5: (3d) if r8 >= r0")393__msg("parent state regs=r0,r7,r8")394__msg("regs=r0,r7,r8 stack= before 4: (25) if r0 > 0x1")395__msg("div by zero")396__naked void linked_regs_broken_link_2(void)397{398 asm volatile (399 "call %[bpf_get_prandom_u32];"400 "r7 = r0;"401 "r8 = r0;"402 "call %[bpf_get_prandom_u32];"403 "if r0 > 1 goto +0;"404 /* r7.id == r8.id,405 * thus r7 precision implies r8 precision,406 * which implies r0 precision because of the conditional below.407 */408 "if r8 >= r0 goto 1f;"409 /* break id relation between r7 and r8 */410 "r8 += r8;"411 /* make r7 precise */412 "if r7 == 0 goto 1f;"413 "r0 /= 0;"414"1:"415 "r0 = 42;"416 "exit;"417 :418 : __imm(bpf_get_prandom_u32)419 : __clobber_all);420}421 422/* Check that mark_chain_precision() for one of the conditional jump423 * operands does not trigger equal scalars precision propagation.424 */425SEC("socket")426__success __log_level(2)427__msg("3: (25) if r1 > 0x100 goto pc+0")428__msg("frame0: regs=r1 stack= before 2: (bf) r1 = r0")429__naked void cjmp_no_linked_regs_trigger(void)430{431 asm volatile (432 /* r0 = random number up to 0xff */433 "call %[bpf_ktime_get_ns];"434 "r0 &= 0xff;"435 /* tie r0.id == r1.id */436 "r1 = r0;"437 /* the jump below would be predicted, thus r1 would be marked precise,438 * this should not imply precision mark for r0439 */440 "if r1 > 256 goto +0;"441 "r0 = 0;"442 "exit;"443 :444 : __imm(bpf_ktime_get_ns)445 : __clobber_all);446}447 448/* Verify that check_ids() is used by regsafe() for scalars.449 *450 * r9 = ... some pointer with range X ...451 * r6 = ... unbound scalar ID=a ...452 * r7 = ... unbound scalar ID=b ...453 * if (r6 > r7) goto +1454 * r7 = r6455 * if (r7 > X) goto exit456 * r9 += r6457 * ... access memory using r9 ...458 *459 * The memory access is safe only if r7 is bounded,460 * which is true for one branch and not true for another.461 */462SEC("socket")463__failure __msg("register with unbounded min value")464__flag(BPF_F_TEST_STATE_FREQ)465__naked void check_ids_in_regsafe(void)466{467 asm volatile (468 /* Bump allocated stack */469 "r1 = 0;"470 "*(u64*)(r10 - 8) = r1;"471 /* r9 = pointer to stack */472 "r9 = r10;"473 "r9 += -8;"474 /* r7 = ktime_get_ns() */475 "call %[bpf_ktime_get_ns];"476 "r7 = r0;"477 /* r6 = ktime_get_ns() */478 "call %[bpf_ktime_get_ns];"479 "r6 = r0;"480 /* if r6 > r7 is an unpredictable jump */481 "if r6 > r7 goto l1_%=;"482 "r7 = r6;"483"l1_%=:"484 /* if r7 > 4 ...; transfers range to r6 on one execution path485 * but does not transfer on another486 */487 "if r7 > 4 goto l2_%=;"488 /* Access memory at r9[r6], r6 is not always bounded */489 "r9 += r6;"490 "r0 = *(u8*)(r9 + 0);"491"l2_%=:"492 "r0 = 0;"493 "exit;"494 :495 : __imm(bpf_ktime_get_ns)496 : __clobber_all);497}498 499/* Similar to check_ids_in_regsafe.500 * The l0 could be reached in two states:501 *502 * (1) r6{.id=A}, r7{.id=A}, r8{.id=B}503 * (2) r6{.id=B}, r7{.id=A}, r8{.id=B}504 *505 * Where (2) is not safe, as "r7 > 4" check won't propagate range for it.506 * This example would be considered safe without changes to507 * mark_chain_precision() to track scalar values with equal IDs.508 */509SEC("socket")510__failure __msg("register with unbounded min value")511__flag(BPF_F_TEST_STATE_FREQ)512__naked void check_ids_in_regsafe_2(void)513{514 asm volatile (515 /* Bump allocated stack */516 "r1 = 0;"517 "*(u64*)(r10 - 8) = r1;"518 /* r9 = pointer to stack */519 "r9 = r10;"520 "r9 += -8;"521 /* r8 = ktime_get_ns() */522 "call %[bpf_ktime_get_ns];"523 "r8 = r0;"524 /* r7 = ktime_get_ns() */525 "call %[bpf_ktime_get_ns];"526 "r7 = r0;"527 /* r6 = ktime_get_ns() */528 "call %[bpf_ktime_get_ns];"529 "r6 = r0;"530 /* scratch .id from r0 */531 "r0 = 0;"532 /* if r6 > r7 is an unpredictable jump */533 "if r6 > r7 goto l1_%=;"534 /* tie r6 and r7 .id */535 "r6 = r7;"536"l0_%=:"537 /* if r7 > 4 exit(0) */538 "if r7 > 4 goto l2_%=;"539 /* Access memory at r9[r6] */540 "r9 += r6;"541 "r0 = *(u8*)(r9 + 0);"542"l2_%=:"543 "r0 = 0;"544 "exit;"545"l1_%=:"546 /* tie r6 and r8 .id */547 "r6 = r8;"548 "goto l0_%=;"549 :550 : __imm(bpf_ktime_get_ns)551 : __clobber_all);552}553 554/* Check that scalar IDs *are not* generated on register to register555 * assignments if source register is a constant.556 *557 * If such IDs *are* generated the 'l1' below would be reached in558 * two states:559 *560 * (1) r1{.id=A}, r2{.id=A}561 * (2) r1{.id=C}, r2{.id=C}562 *563 * Thus forcing 'if r1 == r2' verification twice.564 */565SEC("socket")566__success __log_level(2)567__msg("11: (1d) if r3 == r4 goto pc+0")568__msg("frame 0: propagating r3,r4")569__msg("11: safe")570__msg("processed 15 insns")571__flag(BPF_F_TEST_STATE_FREQ)572__naked void no_scalar_id_for_const(void)573{574 asm volatile (575 "call %[bpf_ktime_get_ns];"576 /* unpredictable jump */577 "if r0 > 7 goto l0_%=;"578 /* possibly generate same scalar ids for r3 and r4 */579 "r1 = 0;"580 "r1 = r1;"581 "r3 = r1;"582 "r4 = r1;"583 "goto l1_%=;"584"l0_%=:"585 /* possibly generate different scalar ids for r3 and r4 */586 "r1 = 0;"587 "r2 = 0;"588 "r3 = r1;"589 "r4 = r2;"590"l1_%=:"591 /* predictable jump, marks r3 and r4 precise */592 "if r3 == r4 goto +0;"593 "r0 = 0;"594 "exit;"595 :596 : __imm(bpf_ktime_get_ns)597 : __clobber_all);598}599 600/* Same as no_scalar_id_for_const() but for 32-bit values */601SEC("socket")602__success __log_level(2)603__msg("11: (1e) if w3 == w4 goto pc+0")604__msg("frame 0: propagating r3,r4")605__msg("11: safe")606__msg("processed 15 insns")607__flag(BPF_F_TEST_STATE_FREQ)608__naked void no_scalar_id_for_const32(void)609{610 asm volatile (611 "call %[bpf_ktime_get_ns];"612 /* unpredictable jump */613 "if r0 > 7 goto l0_%=;"614 /* possibly generate same scalar ids for r3 and r4 */615 "w1 = 0;"616 "w1 = w1;"617 "w3 = w1;"618 "w4 = w1;"619 "goto l1_%=;"620"l0_%=:"621 /* possibly generate different scalar ids for r3 and r4 */622 "w1 = 0;"623 "w2 = 0;"624 "w3 = w1;"625 "w4 = w2;"626"l1_%=:"627 /* predictable jump, marks r1 and r2 precise */628 "if w3 == w4 goto +0;"629 "r0 = 0;"630 "exit;"631 :632 : __imm(bpf_ktime_get_ns)633 : __clobber_all);634}635 636/* Check that unique scalar IDs are ignored when new verifier state is637 * compared to cached verifier state. For this test:638 * - cached state has no id on r1639 * - new state has a unique id on r1640 */641SEC("socket")642__success __log_level(2)643__msg("6: (25) if r6 > 0x7 goto pc+1")644__msg("7: (57) r1 &= 255")645__msg("8: (bf) r2 = r10")646__msg("from 6 to 8: safe")647__msg("processed 12 insns")648__flag(BPF_F_TEST_STATE_FREQ)649__naked void ignore_unique_scalar_ids_cur(void)650{651 asm volatile (652 "call %[bpf_ktime_get_ns];"653 "r6 = r0;"654 "call %[bpf_ktime_get_ns];"655 "r0 &= 0xff;"656 /* r1.id == r0.id */657 "r1 = r0;"658 /* make r1.id unique */659 "r0 = 0;"660 "if r6 > 7 goto l0_%=;"661 /* clear r1 id, but keep the range compatible */662 "r1 &= 0xff;"663"l0_%=:"664 /* get here in two states:665 * - first: r1 has no id (cached state)666 * - second: r1 has a unique id (should be considered equivalent)667 */668 "r2 = r10;"669 "r2 += r1;"670 "exit;"671 :672 : __imm(bpf_ktime_get_ns)673 : __clobber_all);674}675 676/* Check that unique scalar IDs are ignored when new verifier state is677 * compared to cached verifier state. For this test:678 * - cached state has a unique id on r1679 * - new state has no id on r1680 */681SEC("socket")682__success __log_level(2)683__msg("6: (25) if r6 > 0x7 goto pc+1")684__msg("7: (05) goto pc+1")685__msg("9: (bf) r2 = r10")686__msg("9: safe")687__msg("processed 13 insns")688__flag(BPF_F_TEST_STATE_FREQ)689__naked void ignore_unique_scalar_ids_old(void)690{691 asm volatile (692 "call %[bpf_ktime_get_ns];"693 "r6 = r0;"694 "call %[bpf_ktime_get_ns];"695 "r0 &= 0xff;"696 /* r1.id == r0.id */697 "r1 = r0;"698 /* make r1.id unique */699 "r0 = 0;"700 "if r6 > 7 goto l1_%=;"701 "goto l0_%=;"702"l1_%=:"703 /* clear r1 id, but keep the range compatible */704 "r1 &= 0xff;"705"l0_%=:"706 /* get here in two states:707 * - first: r1 has a unique id (cached state)708 * - second: r1 has no id (should be considered equivalent)709 */710 "r2 = r10;"711 "r2 += r1;"712 "exit;"713 :714 : __imm(bpf_ktime_get_ns)715 : __clobber_all);716}717 718/* Check that two different scalar IDs in a verified state can't be719 * mapped to the same scalar ID in current state.720 */721SEC("socket")722__success __log_level(2)723/* The exit instruction should be reachable from two states,724 * use two matches and "processed .. insns" to ensure this.725 */726__msg("13: (95) exit")727__msg("13: (95) exit")728__msg("processed 18 insns")729__flag(BPF_F_TEST_STATE_FREQ)730__naked void two_old_ids_one_cur_id(void)731{732 asm volatile (733 /* Give unique scalar IDs to r{6,7} */734 "call %[bpf_ktime_get_ns];"735 "r0 &= 0xff;"736 "r6 = r0;"737 "call %[bpf_ktime_get_ns];"738 "r0 &= 0xff;"739 "r7 = r0;"740 "r0 = 0;"741 /* Maybe make r{6,7} IDs identical */742 "if r6 > r7 goto l0_%=;"743 "goto l1_%=;"744"l0_%=:"745 "r6 = r7;"746"l1_%=:"747 /* Mark r{6,7} precise.748 * Get here in two states:749 * - first: r6{.id=A}, r7{.id=B} (cached state)750 * - second: r6{.id=A}, r7{.id=A}751 * Currently we don't want to consider such states equivalent.752 * Thus "exit;" would be verified twice.753 */754 "r2 = r10;"755 "r2 += r6;"756 "r2 += r7;"757 "exit;"758 :759 : __imm(bpf_ktime_get_ns)760 : __clobber_all);761}762 763SEC("socket")764/* Note the flag, see verifier.c:opt_subreg_zext_lo32_rnd_hi32() */765__flag(BPF_F_TEST_RND_HI32)766__success767/* This test was added because of a bug in verifier.c:sync_linked_regs(),768 * upon range propagation it destroyed subreg_def marks for registers.769 * The subreg_def mark is used to decide whether zero extension instructions770 * are needed when register is read. When BPF_F_TEST_RND_HI32 is set it771 * also causes generation of statements to randomize upper halves of772 * read registers.773 *774 * The test is written in a way to return an upper half of a register775 * that is affected by range propagation and must have it's subreg_def776 * preserved. This gives a return value of 0 and leads to undefined777 * return value if subreg_def mark is not preserved.778 */779__retval(0)780/* Check that verifier believes r1/r0 are zero at exit */781__log_level(2)782__msg("4: (77) r1 >>= 32 ; R1_w=0")783__msg("5: (bf) r0 = r1 ; R0_w=0 R1_w=0")784__msg("6: (95) exit")785__msg("from 3 to 4")786__msg("4: (77) r1 >>= 32 ; R1_w=0")787__msg("5: (bf) r0 = r1 ; R0_w=0 R1_w=0")788__msg("6: (95) exit")789/* Verify that statements to randomize upper half of r1 had not been790 * generated.791 */792__xlated("call unknown")793__xlated("r0 &= 2147483647")794__xlated("w1 = w0")795/* This is how disasm.c prints BPF_ZEXT_REG at the moment, x86 and arm796 * are the only CI archs that do not need zero extension for subregs.797 */798#if !defined(__TARGET_ARCH_x86) && !defined(__TARGET_ARCH_arm64)799__xlated("w1 = w1")800#endif801__xlated("if w0 < 0xa goto pc+0")802__xlated("r1 >>= 32")803__xlated("r0 = r1")804__xlated("exit")805__naked void linked_regs_and_subreg_def(void)806{807 asm volatile (808 "call %[bpf_ktime_get_ns];"809 /* make sure r0 is in 32-bit range, otherwise w1 = w0 won't810 * assign same IDs to registers.811 */812 "r0 &= 0x7fffffff;"813 /* link w1 and w0 via ID */814 "w1 = w0;"815 /* 'if' statement propagates range info from w0 to w1,816 * but should not affect w1->subreg_def property.817 */818 "if w0 < 10 goto +0;"819 /* r1 is read here, on archs that require subreg zero820 * extension this would cause zext patch generation.821 */822 "r1 >>= 32;"823 "r0 = r1;"824 "exit;"825 :826 : __imm(bpf_ktime_get_ns)827 : __clobber_all);828}829 830char _license[] SEC("license") = "GPL";831