1 // SPDX-License-Identifier: GPL-2.0 2 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 at the moment when r0 is 9 * marked to be precise, this mark is immediately propagated to r{1,2}. 10 */ 11 SEC("socket") 12 __success __log_level(2) 13 __msg("frame0: regs=r0,r1,r2 stack= before 4: (bf) r3 = r10") 14 __msg("frame0: regs=r0,r1,r2 stack= before 3: (bf) r2 = r0") 15 __msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") 16 __msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") 17 __msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") 18 __flag(BPF_F_TEST_STATE_FREQ) 19 __naked void precision_same_state(void) 20 { 21 asm volatile ( 22 /* r0 = random number up to 0xff */ 23 "call %[bpf_ktime_get_ns];" 24 "r0 &= 0xff;" 25 /* tie r0.id == r1.id == r2.id */ 26 "r1 = r0;" 27 "r2 = r0;" 28 /* force r0 to be precise, this immediately marks r1 and r2 as 29 * precise as well because of shared IDs 30 */ 31 "r3 = r10;" 32 "r3 += r0;" 33 "r0 = 0;" 34 "exit;" 35 : 36 : __imm(bpf_ktime_get_ns) 37 : __clobber_all); 38 } 39 40 /* Same as precision_same_state, but mark propagates through state / 41 * parent state boundary. 42 */ 43 SEC("socket") 44 __success __log_level(2) 45 __msg("frame0: last_idx 6 first_idx 5 subseq_idx -1") 46 __msg("frame0: regs=r0,r1,r2 stack= before 5: (bf) r3 = r10") 47 __msg("frame0: parent state regs=r0,r1,r2 stack=:") 48 __msg("frame0: regs=r0,r1,r2 stack= before 4: (05) goto pc+0") 49 __msg("frame0: regs=r0,r1,r2 stack= before 3: (bf) r2 = r0") 50 __msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") 51 __msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") 52 __msg("frame0: parent state regs=r0 stack=:") 53 __msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") 54 __flag(BPF_F_TEST_STATE_FREQ) 55 __naked void precision_cross_state(void) 56 { 57 asm volatile ( 58 /* r0 = random number up to 0xff */ 59 "call %[bpf_ktime_get_ns];" 60 "r0 &= 0xff;" 61 /* tie r0.id == r1.id == r2.id */ 62 "r1 = r0;" 63 "r2 = r0;" 64 /* force checkpoint */ 65 "goto +0;" 66 /* force r0 to be precise, this immediately marks r1 and r2 as 67 * precise as well because of shared IDs 68 */ 69 "r3 = r10;" 70 "r3 += r0;" 71 "r0 = 0;" 72 "exit;" 73 : 74 : __imm(bpf_ktime_get_ns) 75 : __clobber_all); 76 } 77 78 /* Same as precision_same_state, but break one of the 79 * links, note that r1 is absent from regs=... in __msg below. 80 */ 81 SEC("socket") 82 __success __log_level(2) 83 __msg("frame0: regs=r0,r2 stack= before 5: (bf) r3 = r10") 84 __msg("frame0: regs=r0,r2 stack= before 4: (b7) r1 = 0") 85 __msg("frame0: regs=r0,r2 stack= before 3: (bf) r2 = r0") 86 __msg("frame0: regs=r0 stack= before 2: (bf) r1 = r0") 87 __msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") 88 __msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") 89 __flag(BPF_F_TEST_STATE_FREQ) 90 __naked void precision_same_state_broken_link(void) 91 { 92 asm volatile ( 93 /* r0 = random number up to 0xff */ 94 "call %[bpf_ktime_get_ns];" 95 "r0 &= 0xff;" 96 /* tie r0.id == r1.id == r2.id */ 97 "r1 = r0;" 98 "r2 = r0;" 99 /* break link for r1, this is the only line that differs 100 * compared to the previous test 101 */ 102 "r1 = 0;" 103 /* force r0 to be precise, this immediately marks r1 and r2 as 104 * precise as well because of shared IDs 105 */ 106 "r3 = r10;" 107 "r3 += r0;" 108 "r0 = 0;" 109 "exit;" 110 : 111 : __imm(bpf_ktime_get_ns) 112 : __clobber_all); 113 } 114 115 /* Same as precision_same_state_broken_link, but with state / 116 * parent state boundary. 117 */ 118 SEC("socket") 119 __success __log_level(2) 120 __msg("frame0: regs=r0,r2 stack= before 6: (bf) r3 = r10") 121 __msg("frame0: regs=r0,r2 stack= before 5: (b7) r1 = 0") 122 __msg("frame0: parent state regs=r0,r2 stack=:") 123 __msg("frame0: regs=r0,r1,r2 stack= before 4: (05) goto pc+0") 124 __msg("frame0: regs=r0,r1,r2 stack= before 3: (bf) r2 = r0") 125 __msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") 126 __msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") 127 __msg("frame0: parent state regs=r0 stack=:") 128 __msg("frame0: regs=r0 stack= before 0: (85) call bpf_ktime_get_ns") 129 __flag(BPF_F_TEST_STATE_FREQ) 130 __naked void precision_cross_state_broken_link(void) 131 { 132 asm volatile ( 133 /* r0 = random number up to 0xff */ 134 "call %[bpf_ktime_get_ns];" 135 "r0 &= 0xff;" 136 /* tie r0.id == r1.id == r2.id */ 137 "r1 = r0;" 138 "r2 = r0;" 139 /* force checkpoint, although link between r1 and r{0,2} is 140 * broken by the next statement current precision tracking 141 * algorithm can't react to it and propagates mark for r1 to 142 * the parent state. 143 */ 144 "goto +0;" 145 /* break link for r1, this is the only line that differs 146 * compared to precision_cross_state() 147 */ 148 "r1 = 0;" 149 /* force r0 to be precise, this immediately marks r1 and r2 as 150 * precise as well because of shared IDs 151 */ 152 "r3 = r10;" 153 "r3 += r0;" 154 "r0 = 0;" 155 "exit;" 156 : 157 : __imm(bpf_ktime_get_ns) 158 : __clobber_all); 159 } 160 161 /* Check that precision marks propagate through scalar IDs. 162 * Use the same scalar ID in multiple stack frames, check that 163 * precision information is propagated up the call stack. 164 */ 165 SEC("socket") 166 __success __log_level(2) 167 __msg("11: (0f) r2 += r1") 168 /* Current state */ 169 __msg("frame2: last_idx 11 first_idx 10 subseq_idx -1") 170 __msg("frame2: regs=r1 stack= before 10: (bf) r2 = r10") 171 __msg("frame2: parent state regs=r1 stack=") 172 /* frame1.r{6,7} are marked because mark_precise_scalar_ids() 173 * looks for all registers with frame2.r1.id in the current state 174 */ 175 __msg("frame1: parent state regs=r6,r7 stack=") 176 __msg("frame0: parent state regs=r6 stack=") 177 /* Parent state */ 178 __msg("frame2: last_idx 8 first_idx 8 subseq_idx 10") 179 __msg("frame2: regs=r1 stack= before 8: (85) call pc+1") 180 /* frame1.r1 is marked because of backtracking of call instruction */ 181 __msg("frame1: parent state regs=r1,r6,r7 stack=") 182 __msg("frame0: parent state regs=r6 stack=") 183 /* Parent state */ 184 __msg("frame1: last_idx 7 first_idx 6 subseq_idx 8") 185 __msg("frame1: regs=r1,r6,r7 stack= before 7: (bf) r7 = r1") 186 __msg("frame1: regs=r1,r6 stack= before 6: (bf) r6 = r1") 187 __msg("frame1: parent state regs=r1 stack=") 188 __msg("frame0: parent state regs=r6 stack=") 189 /* Parent state */ 190 __msg("frame1: last_idx 4 first_idx 4 subseq_idx 6") 191 __msg("frame1: regs=r1 stack= before 4: (85) call pc+1") 192 __msg("frame0: parent state regs=r1,r6 stack=") 193 /* Parent state */ 194 __msg("frame0: last_idx 3 first_idx 1 subseq_idx 4") 195 __msg("frame0: regs=r0,r1,r6 stack= before 3: (bf) r6 = r0") 196 __msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") 197 __msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") 198 __flag(BPF_F_TEST_STATE_FREQ) 199 __naked void precision_many_frames(void) 200 { 201 asm volatile ( 202 /* r0 = random number up to 0xff */ 203 "call %[bpf_ktime_get_ns];" 204 "r0 &= 0xff;" 205 /* tie r0.id == r1.id == r6.id */ 206 "r1 = r0;" 207 "r6 = r0;" 208 "call precision_many_frames__foo;" 209 "exit;" 210 : 211 : __imm(bpf_ktime_get_ns) 212 : __clobber_all); 213 } 214 215 static __naked __noinline __used 216 void precision_many_frames__foo(void) 217 { 218 asm volatile ( 219 /* conflate one of the register numbers (r6) with outer frame, 220 * to verify that those are tracked independently 221 */ 222 "r6 = r1;" 223 "r7 = r1;" 224 "call precision_many_frames__bar;" 225 "exit" 226 ::: __clobber_all); 227 } 228 229 static __naked __noinline __used 230 void precision_many_frames__bar(void) 231 { 232 asm volatile ( 233 /* force r1 to be precise, this immediately marks: 234 * - bar frame r1 235 * - foo frame r{1,6,7} 236 * - main frame r{1,6} 237 */ 238 "r2 = r10;" 239 "r2 += r1;" 240 "r0 = 0;" 241 "exit;" 242 ::: __clobber_all); 243 } 244 245 /* Check that scalars with the same IDs are marked precise on stack as 246 * well as in registers. 247 */ 248 SEC("socket") 249 __success __log_level(2) 250 /* foo frame */ 251 __msg("frame1: regs=r1 stack=-8,-16 before 9: (bf) r2 = r10") 252 __msg("frame1: regs=r1 stack=-8,-16 before 8: (7b) *(u64 *)(r10 -16) = r1") 253 __msg("frame1: regs=r1 stack=-8 before 7: (7b) *(u64 *)(r10 -8) = r1") 254 __msg("frame1: regs=r1 stack= before 4: (85) call pc+2") 255 /* main frame */ 256 __msg("frame0: regs=r0,r1 stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r1") 257 __msg("frame0: regs=r0,r1 stack= before 2: (bf) r1 = r0") 258 __msg("frame0: regs=r0 stack= before 1: (57) r0 &= 255") 259 __flag(BPF_F_TEST_STATE_FREQ) 260 __naked void precision_stack(void) 261 { 262 asm volatile ( 263 /* r0 = random number up to 0xff */ 264 "call %[bpf_ktime_get_ns];" 265 "r0 &= 0xff;" 266 /* tie r0.id == r1.id == fp[-8].id */ 267 "r1 = r0;" 268 "*(u64*)(r10 - 8) = r1;" 269 "call precision_stack__foo;" 270 "r0 = 0;" 271 "exit;" 272 : 273 : __imm(bpf_ktime_get_ns) 274 : __clobber_all); 275 } 276 277 static __naked __noinline __used 278 void precision_stack__foo(void) 279 { 280 asm volatile ( 281 /* conflate one of the register numbers (r6) with outer frame, 282 * to verify that those are tracked independently 283 */ 284 "*(u64*)(r10 - 8) = r1;" 285 "*(u64*)(r10 - 16) = r1;" 286 /* force r1 to be precise, this immediately marks: 287 * - foo frame r1,fp{-8,-16} 288 * - main frame r1,fp{-8} 289 */ 290 "r2 = r10;" 291 "r2 += r1;" 292 "exit" 293 ::: __clobber_all); 294 } 295 296 /* Use two separate scalar IDs to check that these are propagated 297 * independently. 298 */ 299 SEC("socket") 300 __success __log_level(2) 301 /* r{6,7} */ 302 __msg("11: (0f) r3 += r7") 303 __msg("frame0: regs=r6,r7 stack= before 10: (bf) r3 = r10") 304 /* ... skip some insns ... */ 305 __msg("frame0: regs=r6,r7 stack= before 3: (bf) r7 = r0") 306 __msg("frame0: regs=r0,r6 stack= before 2: (bf) r6 = r0") 307 /* r{8,9} */ 308 __msg("12: (0f) r3 += r9") 309 __msg("frame0: regs=r8,r9 stack= before 11: (0f) r3 += r7") 310 /* ... skip some insns ... */ 311 __msg("frame0: regs=r8,r9 stack= before 7: (bf) r9 = r0") 312 __msg("frame0: regs=r0,r8 stack= before 6: (bf) r8 = r0") 313 __flag(BPF_F_TEST_STATE_FREQ) 314 __naked void precision_two_ids(void) 315 { 316 asm volatile ( 317 /* r6 = random number up to 0xff 318 * r6.id == r7.id 319 */ 320 "call %[bpf_ktime_get_ns];" 321 "r0 &= 0xff;" 322 "r6 = r0;" 323 "r7 = r0;" 324 /* same, but for r{8,9} */ 325 "call %[bpf_ktime_get_ns];" 326 "r0 &= 0xff;" 327 "r8 = r0;" 328 "r9 = r0;" 329 /* clear r0 id */ 330 "r0 = 0;" 331 /* force checkpoint */ 332 "goto +0;" 333 "r3 = r10;" 334 /* force r7 to be precise, this also marks r6 */ 335 "r3 += r7;" 336 /* force r9 to be precise, this also marks r8 */ 337 "r3 += r9;" 338 "exit;" 339 : 340 : __imm(bpf_ktime_get_ns) 341 : __clobber_all); 342 } 343 344 /* Verify that check_ids() is used by regsafe() for scalars. 345 * 346 * r9 = ... some pointer with range X ... 347 * r6 = ... unbound scalar ID=a ... 348 * r7 = ... unbound scalar ID=b ... 349 * if (r6 > r7) goto +1 350 * r7 = r6 351 * if (r7 > X) goto exit 352 * r9 += r6 353 * ... access memory using r9 ... 354 * 355 * The memory access is safe only if r7 is bounded, 356 * which is true for one branch and not true for another. 357 */ 358 SEC("socket") 359 __failure __msg("register with unbounded min value") 360 __flag(BPF_F_TEST_STATE_FREQ) 361 __naked void check_ids_in_regsafe(void) 362 { 363 asm volatile ( 364 /* Bump allocated stack */ 365 "r1 = 0;" 366 "*(u64*)(r10 - 8) = r1;" 367 /* r9 = pointer to stack */ 368 "r9 = r10;" 369 "r9 += -8;" 370 /* r7 = ktime_get_ns() */ 371 "call %[bpf_ktime_get_ns];" 372 "r7 = r0;" 373 /* r6 = ktime_get_ns() */ 374 "call %[bpf_ktime_get_ns];" 375 "r6 = r0;" 376 /* if r6 > r7 is an unpredictable jump */ 377 "if r6 > r7 goto l1_%=;" 378 "r7 = r6;" 379 "l1_%=:" 380 /* if r7 > 4 ...; transfers range to r6 on one execution path 381 * but does not transfer on another 382 */ 383 "if r7 > 4 goto l2_%=;" 384 /* Access memory at r9[r6], r6 is not always bounded */ 385 "r9 += r6;" 386 "r0 = *(u8*)(r9 + 0);" 387 "l2_%=:" 388 "r0 = 0;" 389 "exit;" 390 : 391 : __imm(bpf_ktime_get_ns) 392 : __clobber_all); 393 } 394 395 /* Similar to check_ids_in_regsafe. 396 * The l0 could be reached in two states: 397 * 398 * (1) r6{.id=A}, r7{.id=A}, r8{.id=B} 399 * (2) r6{.id=B}, r7{.id=A}, r8{.id=B} 400 * 401 * Where (2) is not safe, as "r7 > 4" check won't propagate range for it. 402 * This example would be considered safe without changes to 403 * mark_chain_precision() to track scalar values with equal IDs. 404 */ 405 SEC("socket") 406 __failure __msg("register with unbounded min value") 407 __flag(BPF_F_TEST_STATE_FREQ) 408 __naked void check_ids_in_regsafe_2(void) 409 { 410 asm volatile ( 411 /* Bump allocated stack */ 412 "r1 = 0;" 413 "*(u64*)(r10 - 8) = r1;" 414 /* r9 = pointer to stack */ 415 "r9 = r10;" 416 "r9 += -8;" 417 /* r8 = ktime_get_ns() */ 418 "call %[bpf_ktime_get_ns];" 419 "r8 = r0;" 420 /* r7 = ktime_get_ns() */ 421 "call %[bpf_ktime_get_ns];" 422 "r7 = r0;" 423 /* r6 = ktime_get_ns() */ 424 "call %[bpf_ktime_get_ns];" 425 "r6 = r0;" 426 /* scratch .id from r0 */ 427 "r0 = 0;" 428 /* if r6 > r7 is an unpredictable jump */ 429 "if r6 > r7 goto l1_%=;" 430 /* tie r6 and r7 .id */ 431 "r6 = r7;" 432 "l0_%=:" 433 /* if r7 > 4 exit(0) */ 434 "if r7 > 4 goto l2_%=;" 435 /* Access memory at r9[r6] */ 436 "r9 += r6;" 437 "r0 = *(u8*)(r9 + 0);" 438 "l2_%=:" 439 "r0 = 0;" 440 "exit;" 441 "l1_%=:" 442 /* tie r6 and r8 .id */ 443 "r6 = r8;" 444 "goto l0_%=;" 445 : 446 : __imm(bpf_ktime_get_ns) 447 : __clobber_all); 448 } 449 450 /* Check that scalar IDs *are not* generated on register to register 451 * assignments if source register is a constant. 452 * 453 * If such IDs *are* generated the 'l1' below would be reached in 454 * two states: 455 * 456 * (1) r1{.id=A}, r2{.id=A} 457 * (2) r1{.id=C}, r2{.id=C} 458 * 459 * Thus forcing 'if r1 == r2' verification twice. 460 */ 461 SEC("socket") 462 __success __log_level(2) 463 __msg("11: (1d) if r3 == r4 goto pc+0") 464 __msg("frame 0: propagating r3,r4") 465 __msg("11: safe") 466 __msg("processed 15 insns") 467 __flag(BPF_F_TEST_STATE_FREQ) 468 __naked void no_scalar_id_for_const(void) 469 { 470 asm volatile ( 471 "call %[bpf_ktime_get_ns];" 472 /* unpredictable jump */ 473 "if r0 > 7 goto l0_%=;" 474 /* possibly generate same scalar ids for r3 and r4 */ 475 "r1 = 0;" 476 "r1 = r1;" 477 "r3 = r1;" 478 "r4 = r1;" 479 "goto l1_%=;" 480 "l0_%=:" 481 /* possibly generate different scalar ids for r3 and r4 */ 482 "r1 = 0;" 483 "r2 = 0;" 484 "r3 = r1;" 485 "r4 = r2;" 486 "l1_%=:" 487 /* predictable jump, marks r3 and r4 precise */ 488 "if r3 == r4 goto +0;" 489 "r0 = 0;" 490 "exit;" 491 : 492 : __imm(bpf_ktime_get_ns) 493 : __clobber_all); 494 } 495 496 /* Same as no_scalar_id_for_const() but for 32-bit values */ 497 SEC("socket") 498 __success __log_level(2) 499 __msg("11: (1e) if w3 == w4 goto pc+0") 500 __msg("frame 0: propagating r3,r4") 501 __msg("11: safe") 502 __msg("processed 15 insns") 503 __flag(BPF_F_TEST_STATE_FREQ) 504 __naked void no_scalar_id_for_const32(void) 505 { 506 asm volatile ( 507 "call %[bpf_ktime_get_ns];" 508 /* unpredictable jump */ 509 "if r0 > 7 goto l0_%=;" 510 /* possibly generate same scalar ids for r3 and r4 */ 511 "w1 = 0;" 512 "w1 = w1;" 513 "w3 = w1;" 514 "w4 = w1;" 515 "goto l1_%=;" 516 "l0_%=:" 517 /* possibly generate different scalar ids for r3 and r4 */ 518 "w1 = 0;" 519 "w2 = 0;" 520 "w3 = w1;" 521 "w4 = w2;" 522 "l1_%=:" 523 /* predictable jump, marks r1 and r2 precise */ 524 "if w3 == w4 goto +0;" 525 "r0 = 0;" 526 "exit;" 527 : 528 : __imm(bpf_ktime_get_ns) 529 : __clobber_all); 530 } 531 532 /* Check that unique scalar IDs are ignored when new verifier state is 533 * compared to cached verifier state. For this test: 534 * - cached state has no id on r1 535 * - new state has a unique id on r1 536 */ 537 SEC("socket") 538 __success __log_level(2) 539 __msg("6: (25) if r6 > 0x7 goto pc+1") 540 __msg("7: (57) r1 &= 255") 541 __msg("8: (bf) r2 = r10") 542 __msg("from 6 to 8: safe") 543 __msg("processed 12 insns") 544 __flag(BPF_F_TEST_STATE_FREQ) 545 __naked void ignore_unique_scalar_ids_cur(void) 546 { 547 asm volatile ( 548 "call %[bpf_ktime_get_ns];" 549 "r6 = r0;" 550 "call %[bpf_ktime_get_ns];" 551 "r0 &= 0xff;" 552 /* r1.id == r0.id */ 553 "r1 = r0;" 554 /* make r1.id unique */ 555 "r0 = 0;" 556 "if r6 > 7 goto l0_%=;" 557 /* clear r1 id, but keep the range compatible */ 558 "r1 &= 0xff;" 559 "l0_%=:" 560 /* get here in two states: 561 * - first: r1 has no id (cached state) 562 * - second: r1 has a unique id (should be considered equivalent) 563 */ 564 "r2 = r10;" 565 "r2 += r1;" 566 "exit;" 567 : 568 : __imm(bpf_ktime_get_ns) 569 : __clobber_all); 570 } 571 572 /* Check that unique scalar IDs are ignored when new verifier state is 573 * compared to cached verifier state. For this test: 574 * - cached state has a unique id on r1 575 * - new state has no id on r1 576 */ 577 SEC("socket") 578 __success __log_level(2) 579 __msg("6: (25) if r6 > 0x7 goto pc+1") 580 __msg("7: (05) goto pc+1") 581 __msg("9: (bf) r2 = r10") 582 __msg("9: safe") 583 __msg("processed 13 insns") 584 __flag(BPF_F_TEST_STATE_FREQ) 585 __naked void ignore_unique_scalar_ids_old(void) 586 { 587 asm volatile ( 588 "call %[bpf_ktime_get_ns];" 589 "r6 = r0;" 590 "call %[bpf_ktime_get_ns];" 591 "r0 &= 0xff;" 592 /* r1.id == r0.id */ 593 "r1 = r0;" 594 /* make r1.id unique */ 595 "r0 = 0;" 596 "if r6 > 7 goto l1_%=;" 597 "goto l0_%=;" 598 "l1_%=:" 599 /* clear r1 id, but keep the range compatible */ 600 "r1 &= 0xff;" 601 "l0_%=:" 602 /* get here in two states: 603 * - first: r1 has a unique id (cached state) 604 * - second: r1 has no id (should be considered equivalent) 605 */ 606 "r2 = r10;" 607 "r2 += r1;" 608 "exit;" 609 : 610 : __imm(bpf_ktime_get_ns) 611 : __clobber_all); 612 } 613 614 /* Check that two different scalar IDs in a verified state can't be 615 * mapped to the same scalar ID in current state. 616 */ 617 SEC("socket") 618 __success __log_level(2) 619 /* The exit instruction should be reachable from two states, 620 * use two matches and "processed .. insns" to ensure this. 621 */ 622 __msg("13: (95) exit") 623 __msg("13: (95) exit") 624 __msg("processed 18 insns") 625 __flag(BPF_F_TEST_STATE_FREQ) 626 __naked void two_old_ids_one_cur_id(void) 627 { 628 asm volatile ( 629 /* Give unique scalar IDs to r{6,7} */ 630 "call %[bpf_ktime_get_ns];" 631 "r0 &= 0xff;" 632 "r6 = r0;" 633 "call %[bpf_ktime_get_ns];" 634 "r0 &= 0xff;" 635 "r7 = r0;" 636 "r0 = 0;" 637 /* Maybe make r{6,7} IDs identical */ 638 "if r6 > r7 goto l0_%=;" 639 "goto l1_%=;" 640 "l0_%=:" 641 "r6 = r7;" 642 "l1_%=:" 643 /* Mark r{6,7} precise. 644 * Get here in two states: 645 * - first: r6{.id=A}, r7{.id=B} (cached state) 646 * - second: r6{.id=A}, r7{.id=A} 647 * Currently we don't want to consider such states equivalent. 648 * Thus "exit;" would be verified twice. 649 */ 650 "r2 = r10;" 651 "r2 += r6;" 652 "r2 += r7;" 653 "exit;" 654 : 655 : __imm(bpf_ktime_get_ns) 656 : __clobber_all); 657 } 658 659 char _license[] SEC("license") = "GPL"; 660