Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'bpf-replace-path-sensitive-with-path-insensitive-live-stack-analysis'

Eduard Zingerman says:

====================
bpf: replace path-sensitive with path-insensitive live stack analysis

Consider the following program, assuming checkpoint is created for a
state at instruction (3):

1: call bpf_get_prandom_u32()
2: *(u64 *)(r10 - 8) = 42
-- checkpoint #1 --
3: if r0 != 0 goto +1
4: exit;
5: r0 = *(u64 *)(r10 - 8)
6: exit

The verifier processes this program by exploring two paths:
- 1 -> 2 -> 3 -> 4
- 1 -> 2 -> 3 -> 5 -> 6

When instruction (5) is processed, the current liveness tracking
mechanism moves up the register parent links and records a "read" mark
for stack slot -8 at checkpoint #1, stopping because of the "write"
mark recorded at instruction (2).

This patch set replaces the existing liveness tracking mechanism with
a path-insensitive data flow analysis. The program above is processed
as follows:
- a data structure representing live stack slots for
instructions 1-6 in frame #0 is allocated;
- when instruction (2) is processed, record that slot -8 is written at
instruction (2) in frame #0;
- when instruction (5) is processed, record that slot -8 is read at
instruction (5) in frame #0;
- when instruction (6) is processed, propagate read mark for slot -8
up the control flow graph to instructions 3 and 2.

The key difference is that the new mechanism operates on a control
flow graph and associates read and write marks with pairs of (call
chain, instruction index). In contrast, the old mechanism operates on
verifier states and register parent links, associating read and write
marks with verifier states.

Motivation
==========

As it stands, this patch set makes liveness tracking slightly less
precise, as it no longer distinguishes individual program paths taken
by the verifier during symbolic execution.
See the "Impact on verification performance" section for details.

However, this change is intended as a stepping stone toward the
following goals:
- Short term, integrate precision tracking into liveness analysis and
remove the following code:
- verifier backedge states accumulation in is_state_visited();
- most of the logic for precision tracking;
- jump history tracking.
- Long term, help with more efficient loop verification handling.

Why integrating precision tracking?
-----------------------------------

In a sense, precision tracking is very similar to liveness tracking.
The data flow equations for liveness tracking look as follows:

live_after =
U [state[s].live_before for s in insn_successors(i)]

state[i].live_before =
(live_after / state[i].must_write) U state[i].may_read

While data flow equations for precision tracking look as follows:

precise_after =
U [state[s].precise_before for s in insn_successors(i)]

// if some of the instruction outputs are precise,
// assume its inputs to be precise
induced_precise =
⎧ state[i].may_read if (state[i].may_write ∩ precise_after) ≠ ∅

⎩ ∅ otherwise

state[i].precise_before =
(precise_after / state[i].must_write) ∩ induced_precise

Where:
- `may_read` set represents a union of all possibly read slots
(any slot in `may_read` set might be by the instruction);
- `must_write` set represents an intersection of all possibly written slots
(any slot in `must_write` set is guaranteed to be written by the instruction).
- `may_write` set represents a union of all possibly written slots
(any slot in `may_write` set might be written by the instruction).

This means that precision tracking can be implemented as a logical
extension of liveness tracking:
- track registers as well as stack slots;
- add bit masks to represent `precise_before` and `may_write`;
- add above equations for `precise_before` computation;
- (linked registers require some additional consideration).

Such extension would allow removal of:
- precision propagation logic in verifier.c:
- backtrack_insn()
- mark_chain_precision()
- propagate_{precision,backedges}()
- push_jmp_history() and related data structures, which are only used
by precision tracking;
- add_scc_backedge() and related backedge state accumulation in
is_state_visited(), superseded by per-callchain function state
accumulated by liveness analysis.

The hope here is that unifying liveness and precision tracking will
reduce overall amount of code and make it easier to reason about.

How this helps with loops?
--------------------------

As it stands, this patch set shares the same deficiency as the current
liveness tracking mechanism. Liveness marks on stack slots cannot be
used to prune states when processing iterator-based loops:
- such states still have branches to be explored;
- meaning that not all stack slot reads have been discovered.

For example:

1: while(iter_next()) {
2: if (...)
3: r0 = *(u64 *)(r10 - 8)
4: if (...)
5: r0 = *(u64 *)(r10 - 16)
6: ...
7: }

For any checkpoint state created at instruction (1), it is only
possible to rely on read marks for slots fp[-8] and fp[-16] once all
child states of (1) have been explored. Thus, when the verifier
transitions from (7) to (1), it cannot rely on read marks.

However, sacrificing path-sensitivity makes it possible to run
analysis defined in this patch set before main verification pass,
if estimates for value ranges are available.
E.g. for the following program:

1: while(iter_next()) {
2: r0 = r10
3: r0 += r2
4: r0 = *(u64 *)(r2 + 0)
5: ...
6: }

If an estimate for `r2` range is available before the main
verification pass, it can be used to populate read marks at
instruction (4) and run the liveness analysis. Thus making
conservative liveness information available during loops verification.

Such estimates can be provided by some form of value range analysis.
Value range analysis is also necessary to address loop verification
from another angle: computing boundaries for loop induction variables
and iteration counts.

The hope here is that the new liveness tracking mechanism will support
the broader goal of making loop verification more efficient.

Validation
==========

The change was tested on three program sets:
- bpf selftests
- sched_ext
- Meta's internal set of programs

Commit [#8] enables a special mode where both the current and new
liveness analyses are enabled simultaneously. This mode signals an
error if the new algorithm considers a stack slot dead while the
current algorithm assumes it is alive. This mode was very useful for
debugging. At the time of posting, no such errors have been reported
for the above program sets.

[#8] "bpf: signal error if old liveness is more conservative than new"

Impact on memory consumption
============================

Debug patch [1] extends the kernel and veristat to count the amount of
memory allocated for storing analysis data. This patch is not included
in the submission. The maximal observed impact for the above program
sets is 2.6Mb.

Data below is shown in bytes.

For bpf selftests top 5 consumers look as follows:

File Program liveness mem
----------------------- ---------------- ------------
pyperf180.bpf.o on_event 2629740
pyperf600.bpf.o on_event 2287662
pyperf100.bpf.o on_event 1427022
test_verif_scale3.bpf.o balancer_ingress 1121283
pyperf_subprogs.bpf.o on_event 756900

For sched_ext top 5 consumers loog as follows:

File Program liveness mem
--------- ------------------------------- ------------
bpf.bpf.o lavd_enqueue 164686
bpf.bpf.o lavd_select_cpu 157393
bpf.bpf.o layered_enqueue 154817
bpf.bpf.o lavd_init 127865
bpf.bpf.o layered_dispatch 110129

For Meta's internal set of programs top consumer is 1Mb.

[1] https://github.com/kernel-patches/bpf/commit/085588e787b7998a296eb320666897d80bca7c08

Impact on verification performance
==================================

Veristat results below are reported using
`-f insns_pct>1 -f !insns<500` filter and -t option
(BPF_F_TEST_STATE_FREQ flag).

master vs patch-set, selftests (out of ~4K programs)
----------------------------------------------------

File Program Insns (A) Insns (B) Insns (DIFF)
-------------------------------- -------------------------------------- --------- --------- ---------------
cpumask_success.bpf.o test_global_mask_nested_deep_array_rcu 1622 1655 +33 (+2.03%)
strobemeta_bpf_loop.bpf.o on_event 2163 2684 +521 (+24.09%)
test_cls_redirect.bpf.o cls_redirect 36001 42515 +6514 (+18.09%)
test_cls_redirect_dynptr.bpf.o cls_redirect 2299 2339 +40 (+1.74%)
test_cls_redirect_subprogs.bpf.o cls_redirect 69545 78497 +8952 (+12.87%)
test_l4lb_noinline.bpf.o balancer_ingress 2993 3084 +91 (+3.04%)
test_xdp_noinline.bpf.o balancer_ingress_v4 3539 3616 +77 (+2.18%)
test_xdp_noinline.bpf.o balancer_ingress_v6 3608 3685 +77 (+2.13%)

master vs patch-set, sched_ext (out of 148 programs)
----------------------------------------------------

File Program Insns (A) Insns (B) Insns (DIFF)
--------- ---------------- --------- --------- ---------------
bpf.bpf.o chaos_dispatch 2257 2287 +30 (+1.33%)
bpf.bpf.o lavd_enqueue 20735 22101 +1366 (+6.59%)
bpf.bpf.o lavd_select_cpu 22100 24409 +2309 (+10.45%)
bpf.bpf.o layered_dispatch 25051 25606 +555 (+2.22%)
bpf.bpf.o p2dq_dispatch 961 990 +29 (+3.02%)
bpf.bpf.o rusty_quiescent 526 534 +8 (+1.52%)
bpf.bpf.o rusty_runnable 541 547 +6 (+1.11%)

Perf report
===========

In relative terms, the analysis does not consume much CPU time.
For example, here is a perf report collected for pyperf180 selftest:

# Children Self Command Shared Object Symbol
# ........ ........ ........ .................... ........................................
...
1.22% 1.22% veristat [kernel.kallsyms] [k] bpf_update_live_stack
...

Changelog
=========

v1: https://lore.kernel.org/bpf/20250911010437.2779173-1-eddyz87@gmail.com/T/
v1 -> v2:
- compute_postorder() fixed to handle jumps with offset -1 (syzbot).
- is_state_visited() in patch #9 fixed access to uninitialized `err`
(kernel test robot, Dan Carpenter).
- Selftests added.
- Fixed bug with write marks propagation from callee to caller,
see verifier_live_stack.c:caller_stack_write() test case.
- Added a patch for __not_msg() annotation for test_loader based
tests.

v2: https://lore.kernel.org/bpf/20250918-callchain-sensitive-liveness-v2-0-214ed2653eee@gmail.com/
v2 -> v3:
- Added __diag_ignore_all("-Woverride-init", ...) in liveness.c for
bpf_insn_successors() (suggested by Alexei).

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
====================

Link: https://patch.msgid.link/20250918-callchain-sensitive-liveness-v3-0-c3cd27bacc60@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+1717 -978
-264
Documentation/bpf/verifier.rst
··· 347 347 verification. The goal of the liveness tracking algorithm is to spot this fact 348 348 and figure out that both states are actually equivalent. 349 349 350 - Data structures 351 - ~~~~~~~~~~~~~~~ 352 - 353 - Liveness is tracked using the following data structures:: 354 - 355 - enum bpf_reg_liveness { 356 - REG_LIVE_NONE = 0, 357 - REG_LIVE_READ32 = 0x1, 358 - REG_LIVE_READ64 = 0x2, 359 - REG_LIVE_READ = REG_LIVE_READ32 | REG_LIVE_READ64, 360 - REG_LIVE_WRITTEN = 0x4, 361 - REG_LIVE_DONE = 0x8, 362 - }; 363 - 364 - struct bpf_reg_state { 365 - ... 366 - struct bpf_reg_state *parent; 367 - ... 368 - enum bpf_reg_liveness live; 369 - ... 370 - }; 371 - 372 - struct bpf_stack_state { 373 - struct bpf_reg_state spilled_ptr; 374 - ... 375 - }; 376 - 377 - struct bpf_func_state { 378 - struct bpf_reg_state regs[MAX_BPF_REG]; 379 - ... 380 - struct bpf_stack_state *stack; 381 - } 382 - 383 - struct bpf_verifier_state { 384 - struct bpf_func_state *frame[MAX_CALL_FRAMES]; 385 - struct bpf_verifier_state *parent; 386 - ... 387 - } 388 - 389 - * ``REG_LIVE_NONE`` is an initial value assigned to ``->live`` fields upon new 390 - verifier state creation; 391 - 392 - * ``REG_LIVE_WRITTEN`` means that the value of the register (or stack slot) is 393 - defined by some instruction verified between this verifier state's parent and 394 - verifier state itself; 395 - 396 - * ``REG_LIVE_READ{32,64}`` means that the value of the register (or stack slot) 397 - is read by a some child state of this verifier state; 398 - 399 - * ``REG_LIVE_DONE`` is a marker used by ``clean_verifier_state()`` to avoid 400 - processing same verifier state multiple times and for some sanity checks; 401 - 402 - * ``->live`` field values are formed by combining ``enum bpf_reg_liveness`` 403 - values using bitwise or. 404 - 405 - Register parentage chains 406 - ~~~~~~~~~~~~~~~~~~~~~~~~~ 407 - 408 - In order to propagate information between parent and child states, a *register 409 - parentage chain* is established. Each register or stack slot is linked to a 410 - corresponding register or stack slot in its parent state via a ``->parent`` 411 - pointer. This link is established upon state creation in ``is_state_visited()`` 412 - and might be modified by ``set_callee_state()`` called from 413 - ``__check_func_call()``. 414 - 415 - The rules for correspondence between registers / stack slots are as follows: 416 - 417 - * For the current stack frame, registers and stack slots of the new state are 418 - linked to the registers and stack slots of the parent state with the same 419 - indices. 420 - 421 - * For the outer stack frames, only callee saved registers (r6-r9) and stack 422 - slots are linked to the registers and stack slots of the parent state with the 423 - same indices. 424 - 425 - * When function call is processed a new ``struct bpf_func_state`` instance is 426 - allocated, it encapsulates a new set of registers and stack slots. For this 427 - new frame, parent links for r6-r9 and stack slots are set to nil, parent links 428 - for r1-r5 are set to match caller r1-r5 parent links. 429 - 430 - This could be illustrated by the following diagram (arrows stand for 431 - ``->parent`` pointers):: 432 - 433 - ... ; Frame #0, some instructions 434 - --- checkpoint #0 --- 435 - 1 : r6 = 42 ; Frame #0 436 - --- checkpoint #1 --- 437 - 2 : call foo() ; Frame #0 438 - ... ; Frame #1, instructions from foo() 439 - --- checkpoint #2 --- 440 - ... ; Frame #1, instructions from foo() 441 - --- checkpoint #3 --- 442 - exit ; Frame #1, return from foo() 443 - 3 : r1 = r6 ; Frame #0 <- current state 444 - 445 - +-------------------------------+-------------------------------+ 446 - | Frame #0 | Frame #1 | 447 - Checkpoint +-------------------------------+-------------------------------+ 448 - #0 | r0 | r1-r5 | r6-r9 | fp-8 ... | 449 - +-------------------------------+ 450 - ^ ^ ^ ^ 451 - | | | | 452 - Checkpoint +-------------------------------+ 453 - #1 | r0 | r1-r5 | r6-r9 | fp-8 ... | 454 - +-------------------------------+ 455 - ^ ^ ^ 456 - |_______|_______|_______________ 457 - | | | 458 - nil nil | | | nil nil 459 - | | | | | | | 460 - Checkpoint +-------------------------------+-------------------------------+ 461 - #2 | r0 | r1-r5 | r6-r9 | fp-8 ... | r0 | r1-r5 | r6-r9 | fp-8 ... | 462 - +-------------------------------+-------------------------------+ 463 - ^ ^ ^ ^ ^ 464 - nil nil | | | | | 465 - | | | | | | | 466 - Checkpoint +-------------------------------+-------------------------------+ 467 - #3 | r0 | r1-r5 | r6-r9 | fp-8 ... | r0 | r1-r5 | r6-r9 | fp-8 ... | 468 - +-------------------------------+-------------------------------+ 469 - ^ ^ 470 - nil nil | | 471 - | | | | 472 - Current +-------------------------------+ 473 - state | r0 | r1-r5 | r6-r9 | fp-8 ... | 474 - +-------------------------------+ 475 - \ 476 - r6 read mark is propagated via these links 477 - all the way up to checkpoint #1. 478 - The checkpoint #1 contains a write mark for r6 479 - because of instruction (1), thus read propagation 480 - does not reach checkpoint #0 (see section below). 481 - 482 - Liveness marks tracking 483 - ~~~~~~~~~~~~~~~~~~~~~~~ 484 - 485 - For each processed instruction, the verifier tracks read and written registers 486 - and stack slots. The main idea of the algorithm is that read marks propagate 487 - back along the state parentage chain until they hit a write mark, which 'screens 488 - off' earlier states from the read. The information about reads is propagated by 489 - function ``mark_reg_read()`` which could be summarized as follows:: 490 - 491 - mark_reg_read(struct bpf_reg_state *state, ...): 492 - parent = state->parent 493 - while parent: 494 - if state->live & REG_LIVE_WRITTEN: 495 - break 496 - if parent->live & REG_LIVE_READ64: 497 - break 498 - parent->live |= REG_LIVE_READ64 499 - state = parent 500 - parent = state->parent 501 - 502 - Notes: 503 - 504 - * The read marks are applied to the **parent** state while write marks are 505 - applied to the **current** state. The write mark on a register or stack slot 506 - means that it is updated by some instruction in the straight-line code leading 507 - from the parent state to the current state. 508 - 509 - * Details about REG_LIVE_READ32 are omitted. 510 - 511 - * Function ``propagate_liveness()`` (see section :ref:`read_marks_for_cache_hits`) 512 - might override the first parent link. Please refer to the comments in the 513 - ``propagate_liveness()`` and ``mark_reg_read()`` source code for further 514 - details. 515 - 516 - Because stack writes could have different sizes ``REG_LIVE_WRITTEN`` marks are 517 - applied conservatively: stack slots are marked as written only if write size 518 - corresponds to the size of the register, e.g. see function ``save_register_state()``. 519 - 520 - Consider the following example:: 521 - 522 - 0: (*u64)(r10 - 8) = 0 ; define 8 bytes of fp-8 523 - --- checkpoint #0 --- 524 - 1: (*u32)(r10 - 8) = 1 ; redefine lower 4 bytes 525 - 2: r1 = (*u32)(r10 - 8) ; read lower 4 bytes defined at (1) 526 - 3: r2 = (*u32)(r10 - 4) ; read upper 4 bytes defined at (0) 527 - 528 - As stated above, the write at (1) does not count as ``REG_LIVE_WRITTEN``. Should 529 - it be otherwise, the algorithm above wouldn't be able to propagate the read mark 530 - from (3) to checkpoint #0. 531 - 532 - Once the ``BPF_EXIT`` instruction is reached ``update_branch_counts()`` is 533 - called to update the ``->branches`` counter for each verifier state in a chain 534 - of parent verifier states. When the ``->branches`` counter reaches zero the 535 - verifier state becomes a valid entry in a set of cached verifier states. 536 - 537 - Each entry of the verifier states cache is post-processed by a function 538 - ``clean_live_states()``. This function marks all registers and stack slots 539 - without ``REG_LIVE_READ{32,64}`` marks as ``NOT_INIT`` or ``STACK_INVALID``. 540 - Registers/stack slots marked in this way are ignored in function ``stacksafe()`` 541 - called from ``states_equal()`` when a state cache entry is considered for 542 - equivalence with a current state. 543 - 544 - Now it is possible to explain how the example from the beginning of the section 545 - works:: 546 - 547 - 0: call bpf_get_prandom_u32() 548 - 1: r1 = 0 549 - 2: if r0 == 0 goto +1 550 - 3: r0 = 1 551 - --- checkpoint[0] --- 552 - 4: r0 = r1 553 - 5: exit 554 - 555 - * At instruction #2 branching point is reached and state ``{ r0 == 0, r1 == 0, pc == 4 }`` 556 - is pushed to states processing queue (pc stands for program counter). 557 - 558 - * At instruction #4: 559 - 560 - * ``checkpoint[0]`` states cache entry is created: ``{ r0 == 1, r1 == 0, pc == 4 }``; 561 - * ``checkpoint[0].r0`` is marked as written; 562 - * ``checkpoint[0].r1`` is marked as read; 563 - 564 - * At instruction #5 exit is reached and ``checkpoint[0]`` can now be processed 565 - by ``clean_live_states()``. After this processing ``checkpoint[0].r1`` has a 566 - read mark and all other registers and stack slots are marked as ``NOT_INIT`` 567 - or ``STACK_INVALID`` 568 - 569 - * The state ``{ r0 == 0, r1 == 0, pc == 4 }`` is popped from the states queue 570 - and is compared against a cached state ``{ r1 == 0, pc == 4 }``, the states 571 - are considered equivalent. 572 - 573 - .. _read_marks_for_cache_hits: 574 - 575 - Read marks propagation for cache hits 576 - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 577 - 578 - Another point is the handling of read marks when a previously verified state is 579 - found in the states cache. Upon cache hit verifier must behave in the same way 580 - as if the current state was verified to the program exit. This means that all 581 - read marks, present on registers and stack slots of the cached state, must be 582 - propagated over the parentage chain of the current state. Example below shows 583 - why this is important. Function ``propagate_liveness()`` handles this case. 584 - 585 - Consider the following state parentage chain (S is a starting state, A-E are 586 - derived states, -> arrows show which state is derived from which):: 587 - 588 - r1 read 589 - <------------- A[r1] == 0 590 - C[r1] == 0 591 - S ---> A ---> B ---> exit E[r1] == 1 592 - | 593 - ` ---> C ---> D 594 - | 595 - ` ---> E ^ 596 - |___ suppose all these 597 - ^ states are at insn #Y 598 - | 599 - suppose all these 600 - states are at insn #X 601 - 602 - * Chain of states ``S -> A -> B -> exit`` is verified first. 603 - 604 - * While ``B -> exit`` is verified, register ``r1`` is read and this read mark is 605 - propagated up to state ``A``. 606 - 607 - * When chain of states ``C -> D`` is verified the state ``D`` turns out to be 608 - equivalent to state ``B``. 609 - 610 - * The read mark for ``r1`` has to be propagated to state ``C``, otherwise state 611 - ``C`` might get mistakenly marked as equivalent to state ``E`` even though 612 - values for register ``r1`` differ between ``C`` and ``E``. 613 - 614 350 Understanding eBPF verifier messages 615 351 ==================================== 616 352
+26 -26
include/linux/bpf_verifier.h
··· 26 26 /* Patch buffer size */ 27 27 #define INSN_BUF_SIZE 32 28 28 29 - /* Liveness marks, used for registers and spilled-regs (in stack slots). 30 - * Read marks propagate upwards until they find a write mark; they record that 31 - * "one of this state's descendants read this reg" (and therefore the reg is 32 - * relevant for states_equal() checks). 33 - * Write marks collect downwards and do not propagate; they record that "the 34 - * straight-line code that reached this state (from its parent) wrote this reg" 35 - * (and therefore that reads propagated from this state or its descendants 36 - * should not propagate to its parent). 37 - * A state with a write mark can receive read marks; it just won't propagate 38 - * them to its parent, since the write mark is a property, not of the state, 39 - * but of the link between it and its parent. See mark_reg_read() and 40 - * mark_stack_slot_read() in kernel/bpf/verifier.c. 41 - */ 42 - enum bpf_reg_liveness { 43 - REG_LIVE_NONE = 0, /* reg hasn't been read or written this branch */ 44 - REG_LIVE_READ32 = 0x1, /* reg was read, so we're sensitive to initial value */ 45 - REG_LIVE_READ64 = 0x2, /* likewise, but full 64-bit content matters */ 46 - REG_LIVE_READ = REG_LIVE_READ32 | REG_LIVE_READ64, 47 - REG_LIVE_WRITTEN = 0x4, /* reg was written first, screening off later reads */ 48 - REG_LIVE_DONE = 0x8, /* liveness won't be updating this register anymore */ 49 - }; 50 - 51 29 #define ITER_PREFIX "bpf_iter_" 52 30 53 31 enum bpf_iter_state { ··· 190 212 * allowed and has the same effect as bpf_sk_release(sk). 191 213 */ 192 214 u32 ref_obj_id; 193 - /* parentage chain for liveness checking */ 194 - struct bpf_reg_state *parent; 195 215 /* Inside the callee two registers can be both PTR_TO_STACK like 196 216 * R1=fp-8 and R2=fp-8, but one of them points to this function stack 197 217 * while another to the caller's stack. To differentiate them 'frameno' ··· 202 226 * patching which only happens after main verification finished. 203 227 */ 204 228 s32 subreg_def; 205 - enum bpf_reg_liveness live; 206 229 /* if (!precise && SCALAR_VALUE) min/max/tnum don't affect safety */ 207 230 bool precise; 208 231 }; ··· 420 445 421 446 bool speculative; 422 447 bool in_sleepable; 448 + bool cleaned; 423 449 424 450 /* first and last insn idx of this verifier state */ 425 451 u32 first_insn_idx; ··· 641 665 /* 'start' has to be the first field otherwise find_subprog() won't work */ 642 666 u32 start; /* insn idx of function entry point */ 643 667 u32 linfo_idx; /* The idx to the main_prog->aux->linfo */ 668 + u32 postorder_start; /* The idx to the env->cfg.insn_postorder */ 644 669 u16 stack_depth; /* max. stack depth used by this function */ 645 670 u16 stack_extra; 646 671 /* offsets in range [stack_depth .. fastcall_stack_off) ··· 721 744 struct bpf_scc_visit visits[]; 722 745 }; 723 746 747 + struct bpf_liveness; 748 + 724 749 /* single container for all structs 725 750 * one verifier_env per bpf_check() call 726 751 */ ··· 773 794 struct { 774 795 int *insn_state; 775 796 int *insn_stack; 776 - /* vector of instruction indexes sorted in post-order */ 797 + /* 798 + * vector of instruction indexes sorted in post-order, grouped by subprogram, 799 + * see bpf_subprog_info->postorder_start. 800 + */ 777 801 int *insn_postorder; 778 802 int cur_stack; 779 803 /* current position in the insn_postorder vector */ ··· 824 842 struct bpf_insn insn_buf[INSN_BUF_SIZE]; 825 843 struct bpf_insn epilogue_buf[INSN_BUF_SIZE]; 826 844 struct bpf_scc_callchain callchain_buf; 845 + struct bpf_liveness *liveness; 827 846 /* array of pointers to bpf_scc_info indexed by SCC id */ 828 847 struct bpf_scc_info **scc_info; 829 848 u32 scc_cnt; ··· 1047 1064 u32 frameno, bool print_all); 1048 1065 void print_insn_state(struct bpf_verifier_env *env, const struct bpf_verifier_state *vstate, 1049 1066 u32 frameno); 1067 + 1068 + struct bpf_subprog_info *bpf_find_containing_subprog(struct bpf_verifier_env *env, int off); 1069 + int bpf_jmp_offset(struct bpf_insn *insn); 1070 + int bpf_insn_successors(struct bpf_prog *prog, u32 idx, u32 succ[2]); 1071 + void bpf_fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask); 1072 + bool bpf_calls_callback(struct bpf_verifier_env *env, int insn_idx); 1073 + 1074 + int bpf_stack_liveness_init(struct bpf_verifier_env *env); 1075 + void bpf_stack_liveness_free(struct bpf_verifier_env *env); 1076 + int bpf_update_live_stack(struct bpf_verifier_env *env); 1077 + int bpf_mark_stack_read(struct bpf_verifier_env *env, u32 frameno, u32 insn_idx, u64 mask); 1078 + void bpf_mark_stack_write(struct bpf_verifier_env *env, u32 frameno, u64 mask); 1079 + int bpf_reset_stack_write_marks(struct bpf_verifier_env *env, u32 insn_idx); 1080 + int bpf_commit_stack_write_marks(struct bpf_verifier_env *env); 1081 + int bpf_live_stack_query_init(struct bpf_verifier_env *env, struct bpf_verifier_state *st); 1082 + bool bpf_stack_slot_alive(struct bpf_verifier_env *env, u32 frameno, u32 spi); 1083 + void bpf_reset_live_stack_callchain(struct bpf_verifier_env *env); 1050 1084 1051 1085 #endif /* _LINUX_BPF_VERIFIER_H */
+1 -1
kernel/bpf/Makefile
··· 6 6 endif 7 7 CFLAGS_core.o += -Wno-override-init $(cflags-nogcse-yy) 8 8 9 - obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o token.o 9 + obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o tnum.o log.o token.o liveness.o 10 10 obj-$(CONFIG_BPF_SYSCALL) += bpf_iter.o map_iter.o task_iter.o prog_iter.o link_iter.o 11 11 obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o bpf_lru_list.o lpm_trie.o map_in_map.o bloom_filter.o 12 12 obj-$(CONFIG_BPF_SYSCALL) += local_storage.o queue_stack_maps.o ringbuf.o
+733
kernel/bpf/liveness.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include <linux/bpf_verifier.h> 5 + #include <linux/hashtable.h> 6 + #include <linux/jhash.h> 7 + #include <linux/slab.h> 8 + 9 + /* 10 + * This file implements live stack slots analysis. After accumulating 11 + * stack usage data, the analysis answers queries about whether a 12 + * particular stack slot may be read by an instruction or any of it's 13 + * successors. This data is consumed by the verifier states caching 14 + * mechanism to decide which stack slots are important when looking for a 15 + * visited state corresponding to the current state. 16 + * 17 + * The analysis is call chain sensitive, meaning that data is collected 18 + * and queried for tuples (call chain, subprogram instruction index). 19 + * Such sensitivity allows identifying if some subprogram call always 20 + * leads to writes in the caller's stack. 21 + * 22 + * The basic idea is as follows: 23 + * - As the verifier accumulates a set of visited states, the analysis instance 24 + * accumulates a conservative estimate of stack slots that can be read 25 + * or must be written for each visited tuple (call chain, instruction index). 26 + * - If several states happen to visit the same instruction with the same 27 + * call chain, stack usage information for the corresponding tuple is joined: 28 + * - "may_read" set represents a union of all possibly read slots 29 + * (any slot in "may_read" set might be read at or after the instruction); 30 + * - "must_write" set represents an intersection of all possibly written slots 31 + * (any slot in "must_write" set is guaranteed to be written by the instruction). 32 + * - The analysis is split into two phases: 33 + * - read and write marks accumulation; 34 + * - read and write marks propagation. 35 + * - The propagation phase is a textbook live variable data flow analysis: 36 + * 37 + * state[cc, i].live_after = U [state[cc, s].live_before for s in insn_successors(i)] 38 + * state[cc, i].live_before = 39 + * (state[cc, i].live_after / state[cc, i].must_write) U state[i].may_read 40 + * 41 + * Where: 42 + * - `U` stands for set union 43 + * - `/` stands for set difference; 44 + * - `cc` stands for a call chain; 45 + * - `i` and `s` are instruction indexes; 46 + * 47 + * The above equations are computed for each call chain and instruction 48 + * index until state stops changing. 49 + * - Additionally, in order to transfer "must_write" information from a 50 + * subprogram to call instructions invoking this subprogram, 51 + * the "must_write_acc" set is tracked for each (cc, i) tuple. 52 + * A set of stack slots that are guaranteed to be written by this 53 + * instruction or any of its successors (within the subprogram). 54 + * The equation for "must_write_acc" propagation looks as follows: 55 + * 56 + * state[cc, i].must_write_acc = 57 + * ∩ [state[cc, s].must_write_acc for s in insn_successors(i)] 58 + * U state[cc, i].must_write 59 + * 60 + * (An intersection of all "must_write_acc" for instruction successors 61 + * plus all "must_write" slots for the instruction itself). 62 + * - After the propagation phase completes for a subprogram, information from 63 + * (cc, 0) tuple (subprogram entry) is transferred to the caller's call chain: 64 + * - "must_write_acc" set is intersected with the call site's "must_write" set; 65 + * - "may_read" set is added to the call site's "may_read" set. 66 + * - Any live stack queries must be taken after the propagation phase. 67 + * - Accumulation and propagation phases can be entered multiple times, 68 + * at any point in time: 69 + * - "may_read" set only grows; 70 + * - "must_write" set only shrinks; 71 + * - for each visited verifier state with zero branches, all relevant 72 + * read and write marks are already recorded by the analysis instance. 73 + * 74 + * Technically, the analysis is facilitated by the following data structures: 75 + * - Call chain: for given verifier state, the call chain is a tuple of call 76 + * instruction indexes leading to the current subprogram plus the subprogram 77 + * entry point index. 78 + * - Function instance: for a given call chain, for each instruction in 79 + * the current subprogram, a mapping between instruction index and a 80 + * set of "may_read", "must_write" and other marks accumulated for this 81 + * instruction. 82 + * - A hash table mapping call chains to function instances. 83 + */ 84 + 85 + struct callchain { 86 + u32 callsites[MAX_CALL_FRAMES]; /* instruction pointer for each frame */ 87 + /* cached subprog_info[*].start for functions owning the frames: 88 + * - sp_starts[curframe] used to get insn relative index within current function; 89 + * - sp_starts[0..current-1] used for fast callchain_frame_up(). 90 + */ 91 + u32 sp_starts[MAX_CALL_FRAMES]; 92 + u32 curframe; /* depth of callsites and sp_starts arrays */ 93 + }; 94 + 95 + struct per_frame_masks { 96 + u64 may_read; /* stack slots that may be read by this instruction */ 97 + u64 must_write; /* stack slots written by this instruction */ 98 + u64 must_write_acc; /* stack slots written by this instruction and its successors */ 99 + u64 live_before; /* stack slots that may be read by this insn and its successors */ 100 + }; 101 + 102 + /* 103 + * A function instance created for a specific callchain. 104 + * Encapsulates read and write marks for each instruction in the function. 105 + * Marks are tracked for each frame in the callchain. 106 + */ 107 + struct func_instance { 108 + struct hlist_node hl_node; 109 + struct callchain callchain; 110 + u32 insn_cnt; /* cached number of insns in the function */ 111 + bool updated; 112 + bool must_write_dropped; 113 + /* Per frame, per instruction masks, frames allocated lazily. */ 114 + struct per_frame_masks *frames[MAX_CALL_FRAMES]; 115 + /* For each instruction a flag telling if "must_write" had been initialized for it. */ 116 + bool *must_write_set; 117 + }; 118 + 119 + struct live_stack_query { 120 + struct func_instance *instances[MAX_CALL_FRAMES]; /* valid in range [0..curframe] */ 121 + u32 curframe; 122 + u32 insn_idx; 123 + }; 124 + 125 + struct bpf_liveness { 126 + DECLARE_HASHTABLE(func_instances, 8); /* maps callchain to func_instance */ 127 + struct live_stack_query live_stack_query; /* cache to avoid repetitive ht lookups */ 128 + /* Cached instance corresponding to env->cur_state, avoids per-instruction ht lookup */ 129 + struct func_instance *cur_instance; 130 + /* 131 + * Below fields are used to accumulate stack write marks for instruction at 132 + * @write_insn_idx before submitting the marks to @cur_instance. 133 + */ 134 + u64 write_masks_acc[MAX_CALL_FRAMES]; 135 + u32 write_insn_idx; 136 + }; 137 + 138 + /* Compute callchain corresponding to state @st at depth @frameno */ 139 + static void compute_callchain(struct bpf_verifier_env *env, struct bpf_verifier_state *st, 140 + struct callchain *callchain, u32 frameno) 141 + { 142 + struct bpf_subprog_info *subprog_info = env->subprog_info; 143 + u32 i; 144 + 145 + memset(callchain, 0, sizeof(*callchain)); 146 + for (i = 0; i <= frameno; i++) { 147 + callchain->sp_starts[i] = subprog_info[st->frame[i]->subprogno].start; 148 + if (i < st->curframe) 149 + callchain->callsites[i] = st->frame[i + 1]->callsite; 150 + } 151 + callchain->curframe = frameno; 152 + callchain->callsites[callchain->curframe] = callchain->sp_starts[callchain->curframe]; 153 + } 154 + 155 + static u32 hash_callchain(struct callchain *callchain) 156 + { 157 + return jhash2(callchain->callsites, callchain->curframe, 0); 158 + } 159 + 160 + static bool same_callsites(struct callchain *a, struct callchain *b) 161 + { 162 + int i; 163 + 164 + if (a->curframe != b->curframe) 165 + return false; 166 + for (i = a->curframe; i >= 0; i--) 167 + if (a->callsites[i] != b->callsites[i]) 168 + return false; 169 + return true; 170 + } 171 + 172 + /* 173 + * Find existing or allocate new function instance corresponding to @callchain. 174 + * Instances are accumulated in env->liveness->func_instances and persist 175 + * until the end of the verification process. 176 + */ 177 + static struct func_instance *__lookup_instance(struct bpf_verifier_env *env, 178 + struct callchain *callchain) 179 + { 180 + struct bpf_liveness *liveness = env->liveness; 181 + struct bpf_subprog_info *subprog; 182 + struct func_instance *result; 183 + u32 subprog_sz, size, key; 184 + 185 + key = hash_callchain(callchain); 186 + hash_for_each_possible(liveness->func_instances, result, hl_node, key) 187 + if (same_callsites(&result->callchain, callchain)) 188 + return result; 189 + 190 + subprog = bpf_find_containing_subprog(env, callchain->sp_starts[callchain->curframe]); 191 + subprog_sz = (subprog + 1)->start - subprog->start; 192 + size = sizeof(struct func_instance); 193 + result = kvzalloc(size, GFP_KERNEL_ACCOUNT); 194 + if (!result) 195 + return ERR_PTR(-ENOMEM); 196 + result->must_write_set = kvcalloc(subprog_sz, sizeof(*result->must_write_set), 197 + GFP_KERNEL_ACCOUNT); 198 + if (!result->must_write_set) 199 + return ERR_PTR(-ENOMEM); 200 + memcpy(&result->callchain, callchain, sizeof(*callchain)); 201 + result->insn_cnt = subprog_sz; 202 + hash_add(liveness->func_instances, &result->hl_node, key); 203 + return result; 204 + } 205 + 206 + static struct func_instance *lookup_instance(struct bpf_verifier_env *env, 207 + struct bpf_verifier_state *st, 208 + u32 frameno) 209 + { 210 + struct callchain callchain; 211 + 212 + compute_callchain(env, st, &callchain, frameno); 213 + return __lookup_instance(env, &callchain); 214 + } 215 + 216 + int bpf_stack_liveness_init(struct bpf_verifier_env *env) 217 + { 218 + env->liveness = kvzalloc(sizeof(*env->liveness), GFP_KERNEL_ACCOUNT); 219 + if (!env->liveness) 220 + return -ENOMEM; 221 + hash_init(env->liveness->func_instances); 222 + return 0; 223 + } 224 + 225 + void bpf_stack_liveness_free(struct bpf_verifier_env *env) 226 + { 227 + struct func_instance *instance; 228 + struct hlist_node *tmp; 229 + int bkt, i; 230 + 231 + if (!env->liveness) 232 + return; 233 + hash_for_each_safe(env->liveness->func_instances, bkt, tmp, instance, hl_node) { 234 + for (i = 0; i <= instance->callchain.curframe; i++) 235 + kvfree(instance->frames[i]); 236 + kvfree(instance->must_write_set); 237 + kvfree(instance); 238 + } 239 + kvfree(env->liveness); 240 + } 241 + 242 + /* 243 + * Convert absolute instruction index @insn_idx to an index relative 244 + * to start of the function corresponding to @instance. 245 + */ 246 + static int relative_idx(struct func_instance *instance, u32 insn_idx) 247 + { 248 + return insn_idx - instance->callchain.sp_starts[instance->callchain.curframe]; 249 + } 250 + 251 + static struct per_frame_masks *get_frame_masks(struct func_instance *instance, 252 + u32 frame, u32 insn_idx) 253 + { 254 + if (!instance->frames[frame]) 255 + return NULL; 256 + 257 + return &instance->frames[frame][relative_idx(instance, insn_idx)]; 258 + } 259 + 260 + static struct per_frame_masks *alloc_frame_masks(struct bpf_verifier_env *env, 261 + struct func_instance *instance, 262 + u32 frame, u32 insn_idx) 263 + { 264 + struct per_frame_masks *arr; 265 + 266 + if (!instance->frames[frame]) { 267 + arr = kvcalloc(instance->insn_cnt, sizeof(*arr), GFP_KERNEL_ACCOUNT); 268 + instance->frames[frame] = arr; 269 + if (!arr) 270 + return ERR_PTR(-ENOMEM); 271 + } 272 + return get_frame_masks(instance, frame, insn_idx); 273 + } 274 + 275 + void bpf_reset_live_stack_callchain(struct bpf_verifier_env *env) 276 + { 277 + env->liveness->cur_instance = NULL; 278 + } 279 + 280 + /* If @env->liveness->cur_instance is null, set it to instance corresponding to @env->cur_state. */ 281 + static int ensure_cur_instance(struct bpf_verifier_env *env) 282 + { 283 + struct bpf_liveness *liveness = env->liveness; 284 + struct func_instance *instance; 285 + 286 + if (liveness->cur_instance) 287 + return 0; 288 + 289 + instance = lookup_instance(env, env->cur_state, env->cur_state->curframe); 290 + if (IS_ERR(instance)) 291 + return PTR_ERR(instance); 292 + 293 + liveness->cur_instance = instance; 294 + return 0; 295 + } 296 + 297 + /* Accumulate may_read masks for @frame at @insn_idx */ 298 + static int mark_stack_read(struct bpf_verifier_env *env, 299 + struct func_instance *instance, u32 frame, u32 insn_idx, u64 mask) 300 + { 301 + struct per_frame_masks *masks; 302 + u64 new_may_read; 303 + 304 + masks = alloc_frame_masks(env, instance, frame, insn_idx); 305 + if (IS_ERR(masks)) 306 + return PTR_ERR(masks); 307 + new_may_read = masks->may_read | mask; 308 + if (new_may_read != masks->may_read && 309 + ((new_may_read | masks->live_before) != masks->live_before)) 310 + instance->updated = true; 311 + masks->may_read |= mask; 312 + return 0; 313 + } 314 + 315 + int bpf_mark_stack_read(struct bpf_verifier_env *env, u32 frame, u32 insn_idx, u64 mask) 316 + { 317 + int err; 318 + 319 + err = ensure_cur_instance(env); 320 + err = err ?: mark_stack_read(env, env->liveness->cur_instance, frame, insn_idx, mask); 321 + return err; 322 + } 323 + 324 + static void reset_stack_write_marks(struct bpf_verifier_env *env, 325 + struct func_instance *instance, u32 insn_idx) 326 + { 327 + struct bpf_liveness *liveness = env->liveness; 328 + int i; 329 + 330 + liveness->write_insn_idx = insn_idx; 331 + for (i = 0; i <= instance->callchain.curframe; i++) 332 + liveness->write_masks_acc[i] = 0; 333 + } 334 + 335 + int bpf_reset_stack_write_marks(struct bpf_verifier_env *env, u32 insn_idx) 336 + { 337 + struct bpf_liveness *liveness = env->liveness; 338 + int err; 339 + 340 + err = ensure_cur_instance(env); 341 + if (err) 342 + return err; 343 + 344 + reset_stack_write_marks(env, liveness->cur_instance, insn_idx); 345 + return 0; 346 + } 347 + 348 + void bpf_mark_stack_write(struct bpf_verifier_env *env, u32 frame, u64 mask) 349 + { 350 + env->liveness->write_masks_acc[frame] |= mask; 351 + } 352 + 353 + static int commit_stack_write_marks(struct bpf_verifier_env *env, 354 + struct func_instance *instance) 355 + { 356 + struct bpf_liveness *liveness = env->liveness; 357 + u32 idx, frame, curframe, old_must_write; 358 + struct per_frame_masks *masks; 359 + u64 mask; 360 + 361 + if (!instance) 362 + return 0; 363 + 364 + curframe = instance->callchain.curframe; 365 + idx = relative_idx(instance, liveness->write_insn_idx); 366 + for (frame = 0; frame <= curframe; frame++) { 367 + mask = liveness->write_masks_acc[frame]; 368 + /* avoid allocating frames for zero masks */ 369 + if (mask == 0 && !instance->must_write_set[idx]) 370 + continue; 371 + masks = alloc_frame_masks(env, instance, frame, liveness->write_insn_idx); 372 + if (IS_ERR(masks)) 373 + return PTR_ERR(masks); 374 + old_must_write = masks->must_write; 375 + /* 376 + * If instruction at this callchain is seen for a first time, set must_write equal 377 + * to @mask. Otherwise take intersection with the previous value. 378 + */ 379 + if (instance->must_write_set[idx]) 380 + mask &= old_must_write; 381 + if (old_must_write != mask) { 382 + masks->must_write = mask; 383 + instance->updated = true; 384 + } 385 + if (old_must_write & ~mask) 386 + instance->must_write_dropped = true; 387 + } 388 + instance->must_write_set[idx] = true; 389 + liveness->write_insn_idx = 0; 390 + return 0; 391 + } 392 + 393 + /* 394 + * Merge stack writes marks in @env->liveness->write_masks_acc 395 + * with information already in @env->liveness->cur_instance. 396 + */ 397 + int bpf_commit_stack_write_marks(struct bpf_verifier_env *env) 398 + { 399 + return commit_stack_write_marks(env, env->liveness->cur_instance); 400 + } 401 + 402 + static char *fmt_callchain(struct bpf_verifier_env *env, struct callchain *callchain) 403 + { 404 + char *buf_end = env->tmp_str_buf + sizeof(env->tmp_str_buf); 405 + char *buf = env->tmp_str_buf; 406 + int i; 407 + 408 + buf += snprintf(buf, buf_end - buf, "("); 409 + for (i = 0; i <= callchain->curframe; i++) 410 + buf += snprintf(buf, buf_end - buf, "%s%d", i ? "," : "", callchain->callsites[i]); 411 + snprintf(buf, buf_end - buf, ")"); 412 + return env->tmp_str_buf; 413 + } 414 + 415 + static void log_mask_change(struct bpf_verifier_env *env, struct callchain *callchain, 416 + char *pfx, u32 frame, u32 insn_idx, u64 old, u64 new) 417 + { 418 + u64 changed_bits = old ^ new; 419 + u64 new_ones = new & changed_bits; 420 + u64 new_zeros = ~new & changed_bits; 421 + 422 + if (!changed_bits) 423 + return; 424 + bpf_log(&env->log, "%s frame %d insn %d ", fmt_callchain(env, callchain), frame, insn_idx); 425 + if (new_ones) { 426 + bpf_fmt_stack_mask(env->tmp_str_buf, sizeof(env->tmp_str_buf), new_ones); 427 + bpf_log(&env->log, "+%s %s ", pfx, env->tmp_str_buf); 428 + } 429 + if (new_zeros) { 430 + bpf_fmt_stack_mask(env->tmp_str_buf, sizeof(env->tmp_str_buf), new_zeros); 431 + bpf_log(&env->log, "-%s %s", pfx, env->tmp_str_buf); 432 + } 433 + bpf_log(&env->log, "\n"); 434 + } 435 + 436 + int bpf_jmp_offset(struct bpf_insn *insn) 437 + { 438 + u8 code = insn->code; 439 + 440 + if (code == (BPF_JMP32 | BPF_JA)) 441 + return insn->imm; 442 + return insn->off; 443 + } 444 + 445 + __diag_push(); 446 + __diag_ignore_all("-Woverride-init", "Allow field initialization overrides for opcode_info_tbl"); 447 + 448 + inline int bpf_insn_successors(struct bpf_prog *prog, u32 idx, u32 succ[2]) 449 + { 450 + static const struct opcode_info { 451 + bool can_jump; 452 + bool can_fallthrough; 453 + } opcode_info_tbl[256] = { 454 + [0 ... 255] = {.can_jump = false, .can_fallthrough = true}, 455 + #define _J(code, ...) \ 456 + [BPF_JMP | code] = __VA_ARGS__, \ 457 + [BPF_JMP32 | code] = __VA_ARGS__ 458 + 459 + _J(BPF_EXIT, {.can_jump = false, .can_fallthrough = false}), 460 + _J(BPF_JA, {.can_jump = true, .can_fallthrough = false}), 461 + _J(BPF_JEQ, {.can_jump = true, .can_fallthrough = true}), 462 + _J(BPF_JNE, {.can_jump = true, .can_fallthrough = true}), 463 + _J(BPF_JLT, {.can_jump = true, .can_fallthrough = true}), 464 + _J(BPF_JLE, {.can_jump = true, .can_fallthrough = true}), 465 + _J(BPF_JGT, {.can_jump = true, .can_fallthrough = true}), 466 + _J(BPF_JGE, {.can_jump = true, .can_fallthrough = true}), 467 + _J(BPF_JSGT, {.can_jump = true, .can_fallthrough = true}), 468 + _J(BPF_JSGE, {.can_jump = true, .can_fallthrough = true}), 469 + _J(BPF_JSLT, {.can_jump = true, .can_fallthrough = true}), 470 + _J(BPF_JSLE, {.can_jump = true, .can_fallthrough = true}), 471 + _J(BPF_JCOND, {.can_jump = true, .can_fallthrough = true}), 472 + _J(BPF_JSET, {.can_jump = true, .can_fallthrough = true}), 473 + #undef _J 474 + }; 475 + struct bpf_insn *insn = &prog->insnsi[idx]; 476 + const struct opcode_info *opcode_info; 477 + int i = 0, insn_sz; 478 + 479 + opcode_info = &opcode_info_tbl[BPF_CLASS(insn->code) | BPF_OP(insn->code)]; 480 + insn_sz = bpf_is_ldimm64(insn) ? 2 : 1; 481 + if (opcode_info->can_fallthrough) 482 + succ[i++] = idx + insn_sz; 483 + 484 + if (opcode_info->can_jump) 485 + succ[i++] = idx + bpf_jmp_offset(insn) + 1; 486 + 487 + return i; 488 + } 489 + 490 + __diag_pop(); 491 + 492 + static struct func_instance *get_outer_instance(struct bpf_verifier_env *env, 493 + struct func_instance *instance) 494 + { 495 + struct callchain callchain = instance->callchain; 496 + 497 + /* Adjust @callchain to represent callchain one frame up */ 498 + callchain.callsites[callchain.curframe] = 0; 499 + callchain.sp_starts[callchain.curframe] = 0; 500 + callchain.curframe--; 501 + callchain.callsites[callchain.curframe] = callchain.sp_starts[callchain.curframe]; 502 + return __lookup_instance(env, &callchain); 503 + } 504 + 505 + static u32 callchain_subprog_start(struct callchain *callchain) 506 + { 507 + return callchain->sp_starts[callchain->curframe]; 508 + } 509 + 510 + /* 511 + * Transfer @may_read and @must_write_acc marks from the first instruction of @instance, 512 + * to the call instruction in function instance calling @instance. 513 + */ 514 + static int propagate_to_outer_instance(struct bpf_verifier_env *env, 515 + struct func_instance *instance) 516 + { 517 + struct callchain *callchain = &instance->callchain; 518 + u32 this_subprog_start, callsite, frame; 519 + struct func_instance *outer_instance; 520 + struct per_frame_masks *insn; 521 + int err; 522 + 523 + this_subprog_start = callchain_subprog_start(callchain); 524 + outer_instance = get_outer_instance(env, instance); 525 + callsite = callchain->callsites[callchain->curframe - 1]; 526 + 527 + reset_stack_write_marks(env, outer_instance, callsite); 528 + for (frame = 0; frame < callchain->curframe; frame++) { 529 + insn = get_frame_masks(instance, frame, this_subprog_start); 530 + if (!insn) 531 + continue; 532 + bpf_mark_stack_write(env, frame, insn->must_write_acc); 533 + err = mark_stack_read(env, outer_instance, frame, callsite, insn->live_before); 534 + if (err) 535 + return err; 536 + } 537 + commit_stack_write_marks(env, outer_instance); 538 + return 0; 539 + } 540 + 541 + static inline bool update_insn(struct bpf_verifier_env *env, 542 + struct func_instance *instance, u32 frame, u32 insn_idx) 543 + { 544 + struct bpf_insn_aux_data *aux = env->insn_aux_data; 545 + u64 new_before, new_after, must_write_acc; 546 + struct per_frame_masks *insn, *succ_insn; 547 + u32 succ_num, s, succ[2]; 548 + bool changed; 549 + 550 + succ_num = bpf_insn_successors(env->prog, insn_idx, succ); 551 + if (unlikely(succ_num == 0)) 552 + return false; 553 + 554 + changed = false; 555 + insn = get_frame_masks(instance, frame, insn_idx); 556 + new_before = 0; 557 + new_after = 0; 558 + /* 559 + * New "must_write_acc" is an intersection of all "must_write_acc" 560 + * of successors plus all "must_write" slots of instruction itself. 561 + */ 562 + must_write_acc = U64_MAX; 563 + for (s = 0; s < succ_num; ++s) { 564 + succ_insn = get_frame_masks(instance, frame, succ[s]); 565 + new_after |= succ_insn->live_before; 566 + must_write_acc &= succ_insn->must_write_acc; 567 + } 568 + must_write_acc |= insn->must_write; 569 + /* 570 + * New "live_before" is a union of all "live_before" of successors 571 + * minus slots written by instruction plus slots read by instruction. 572 + */ 573 + new_before = (new_after & ~insn->must_write) | insn->may_read; 574 + changed |= new_before != insn->live_before; 575 + changed |= must_write_acc != insn->must_write_acc; 576 + if (unlikely(env->log.level & BPF_LOG_LEVEL2) && 577 + (insn->may_read || insn->must_write || 578 + insn_idx == callchain_subprog_start(&instance->callchain) || 579 + aux[insn_idx].prune_point)) { 580 + log_mask_change(env, &instance->callchain, "live", 581 + frame, insn_idx, insn->live_before, new_before); 582 + log_mask_change(env, &instance->callchain, "written", 583 + frame, insn_idx, insn->must_write_acc, must_write_acc); 584 + } 585 + insn->live_before = new_before; 586 + insn->must_write_acc = must_write_acc; 587 + return changed; 588 + } 589 + 590 + /* Fixed-point computation of @live_before and @must_write_acc marks */ 591 + static int update_instance(struct bpf_verifier_env *env, struct func_instance *instance) 592 + { 593 + u32 i, frame, po_start, po_end, cnt, this_subprog_start; 594 + struct callchain *callchain = &instance->callchain; 595 + int *insn_postorder = env->cfg.insn_postorder; 596 + struct bpf_subprog_info *subprog; 597 + struct per_frame_masks *insn; 598 + bool changed; 599 + int err; 600 + 601 + this_subprog_start = callchain_subprog_start(callchain); 602 + /* 603 + * If must_write marks were updated must_write_acc needs to be reset 604 + * (to account for the case when new must_write sets became smaller). 605 + */ 606 + if (instance->must_write_dropped) { 607 + for (frame = 0; frame <= callchain->curframe; frame++) { 608 + if (!instance->frames[frame]) 609 + continue; 610 + 611 + for (i = 0; i < instance->insn_cnt; i++) { 612 + insn = get_frame_masks(instance, frame, this_subprog_start + i); 613 + insn->must_write_acc = 0; 614 + } 615 + } 616 + } 617 + 618 + subprog = bpf_find_containing_subprog(env, this_subprog_start); 619 + po_start = subprog->postorder_start; 620 + po_end = (subprog + 1)->postorder_start; 621 + cnt = 0; 622 + /* repeat until fixed point is reached */ 623 + do { 624 + cnt++; 625 + changed = false; 626 + for (frame = 0; frame <= instance->callchain.curframe; frame++) { 627 + if (!instance->frames[frame]) 628 + continue; 629 + 630 + for (i = po_start; i < po_end; i++) 631 + changed |= update_insn(env, instance, frame, insn_postorder[i]); 632 + } 633 + } while (changed); 634 + 635 + if (env->log.level & BPF_LOG_LEVEL2) 636 + bpf_log(&env->log, "%s live stack update done in %d iterations\n", 637 + fmt_callchain(env, callchain), cnt); 638 + 639 + /* transfer marks accumulated for outer frames to outer func instance (caller) */ 640 + if (callchain->curframe > 0) { 641 + err = propagate_to_outer_instance(env, instance); 642 + if (err) 643 + return err; 644 + } 645 + 646 + return 0; 647 + } 648 + 649 + /* 650 + * Prepare all callchains within @env->cur_state for querying. 651 + * This function should be called after each verifier.c:pop_stack() 652 + * and whenever verifier.c:do_check_insn() processes subprogram exit. 653 + * This would guarantee that visited verifier states with zero branches 654 + * have their bpf_mark_stack_{read,write}() effects propagated in 655 + * @env->liveness. 656 + */ 657 + int bpf_update_live_stack(struct bpf_verifier_env *env) 658 + { 659 + struct func_instance *instance; 660 + int err, frame; 661 + 662 + bpf_reset_live_stack_callchain(env); 663 + for (frame = env->cur_state->curframe; frame >= 0; --frame) { 664 + instance = lookup_instance(env, env->cur_state, frame); 665 + if (IS_ERR(instance)) 666 + return PTR_ERR(instance); 667 + 668 + if (instance->updated) { 669 + err = update_instance(env, instance); 670 + if (err) 671 + return err; 672 + instance->updated = false; 673 + instance->must_write_dropped = false; 674 + } 675 + } 676 + return 0; 677 + } 678 + 679 + static bool is_live_before(struct func_instance *instance, u32 insn_idx, u32 frameno, u32 spi) 680 + { 681 + struct per_frame_masks *masks; 682 + 683 + masks = get_frame_masks(instance, frameno, insn_idx); 684 + return masks && (masks->live_before & BIT(spi)); 685 + } 686 + 687 + int bpf_live_stack_query_init(struct bpf_verifier_env *env, struct bpf_verifier_state *st) 688 + { 689 + struct live_stack_query *q = &env->liveness->live_stack_query; 690 + struct func_instance *instance; 691 + u32 frame; 692 + 693 + memset(q, 0, sizeof(*q)); 694 + for (frame = 0; frame <= st->curframe; frame++) { 695 + instance = lookup_instance(env, st, frame); 696 + if (IS_ERR(instance)) 697 + return PTR_ERR(instance); 698 + q->instances[frame] = instance; 699 + } 700 + q->curframe = st->curframe; 701 + q->insn_idx = st->insn_idx; 702 + return 0; 703 + } 704 + 705 + bool bpf_stack_slot_alive(struct bpf_verifier_env *env, u32 frameno, u32 spi) 706 + { 707 + /* 708 + * Slot is alive if it is read before q->st->insn_idx in current func instance, 709 + * or if for some outer func instance: 710 + * - alive before callsite if callsite calls callback, otherwise 711 + * - alive after callsite 712 + */ 713 + struct live_stack_query *q = &env->liveness->live_stack_query; 714 + struct func_instance *instance, *curframe_instance; 715 + u32 i, callsite; 716 + bool alive; 717 + 718 + curframe_instance = q->instances[q->curframe]; 719 + if (is_live_before(curframe_instance, q->insn_idx, frameno, spi)) 720 + return true; 721 + 722 + for (i = frameno; i < q->curframe; i++) { 723 + callsite = curframe_instance->callchain.callsites[i]; 724 + instance = q->instances[i]; 725 + alive = bpf_calls_callback(env, callsite) 726 + ? is_live_before(instance, callsite, frameno, spi) 727 + : is_live_before(instance, callsite + 1, frameno, spi); 728 + if (alive) 729 + return true; 730 + } 731 + 732 + return false; 733 + }
+4 -24
kernel/bpf/log.c
··· 542 542 [STACK_IRQ_FLAG] = 'f' 543 543 }; 544 544 545 - static void print_liveness(struct bpf_verifier_env *env, 546 - enum bpf_reg_liveness live) 547 - { 548 - if (live & (REG_LIVE_READ | REG_LIVE_WRITTEN | REG_LIVE_DONE)) 549 - verbose(env, "_"); 550 - if (live & REG_LIVE_READ) 551 - verbose(env, "r"); 552 - if (live & REG_LIVE_WRITTEN) 553 - verbose(env, "w"); 554 - if (live & REG_LIVE_DONE) 555 - verbose(env, "D"); 556 - } 557 - 558 545 #define UNUM_MAX_DECIMAL U16_MAX 559 546 #define SNUM_MAX_DECIMAL S16_MAX 560 547 #define SNUM_MIN_DECIMAL S16_MIN ··· 759 772 if (!print_all && !reg_scratched(env, i)) 760 773 continue; 761 774 verbose(env, " R%d", i); 762 - print_liveness(env, reg->live); 763 775 verbose(env, "="); 764 776 print_reg_state(env, state, reg); 765 777 } ··· 791 805 break; 792 806 types_buf[j] = '\0'; 793 807 794 - verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); 795 - print_liveness(env, reg->live); 796 - verbose(env, "=%s", types_buf); 808 + verbose(env, " fp%d=%s", (-i - 1) * BPF_REG_SIZE, types_buf); 797 809 print_reg_state(env, state, reg); 798 810 break; 799 811 case STACK_DYNPTR: ··· 800 816 reg = &state->stack[i].spilled_ptr; 801 817 802 818 verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); 803 - print_liveness(env, reg->live); 804 819 verbose(env, "=dynptr_%s(", dynptr_type_str(reg->dynptr.type)); 805 820 if (reg->id) 806 821 verbose_a("id=%d", reg->id); ··· 814 831 if (!reg->ref_obj_id) 815 832 continue; 816 833 817 - verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); 818 - print_liveness(env, reg->live); 819 - verbose(env, "=iter_%s(ref_id=%d,state=%s,depth=%u)", 834 + verbose(env, " fp%d=iter_%s(ref_id=%d,state=%s,depth=%u)", 835 + (-i - 1) * BPF_REG_SIZE, 820 836 iter_type_str(reg->iter.btf, reg->iter.btf_id), 821 837 reg->ref_obj_id, iter_state_str(reg->iter.state), 822 838 reg->iter.depth); ··· 823 841 case STACK_MISC: 824 842 case STACK_ZERO: 825 843 default: 826 - verbose(env, " fp%d", (-i - 1) * BPF_REG_SIZE); 827 - print_liveness(env, reg->live); 828 - verbose(env, "=%s", types_buf); 844 + verbose(env, " fp%d=%s", (-i - 1) * BPF_REG_SIZE, types_buf); 829 845 break; 830 846 } 831 847 }
+155 -413
kernel/bpf/verifier.c
··· 787 787 state->stack[spi - 1].spilled_ptr.ref_obj_id = id; 788 788 } 789 789 790 - state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN; 791 - state->stack[spi - 1].spilled_ptr.live |= REG_LIVE_WRITTEN; 790 + bpf_mark_stack_write(env, state->frameno, BIT(spi - 1) | BIT(spi)); 792 791 793 792 return 0; 794 793 } ··· 804 805 __mark_reg_not_init(env, &state->stack[spi].spilled_ptr); 805 806 __mark_reg_not_init(env, &state->stack[spi - 1].spilled_ptr); 806 807 807 - /* Why do we need to set REG_LIVE_WRITTEN for STACK_INVALID slot? 808 - * 809 - * While we don't allow reading STACK_INVALID, it is still possible to 810 - * do <8 byte writes marking some but not all slots as STACK_MISC. Then, 811 - * helpers or insns can do partial read of that part without failing, 812 - * but check_stack_range_initialized, check_stack_read_var_off, and 813 - * check_stack_read_fixed_off will do mark_reg_read for all 8-bytes of 814 - * the slot conservatively. Hence we need to prevent those liveness 815 - * marking walks. 816 - * 817 - * This was not a problem before because STACK_INVALID is only set by 818 - * default (where the default reg state has its reg->parent as NULL), or 819 - * in clean_live_states after REG_LIVE_DONE (at which point 820 - * mark_reg_read won't walk reg->parent chain), but not randomly during 821 - * verifier state exploration (like we did above). Hence, for our case 822 - * parentage chain will still be live (i.e. reg->parent may be 823 - * non-NULL), while earlier reg->parent was NULL, so we need 824 - * REG_LIVE_WRITTEN to screen off read marker propagation when it is 825 - * done later on reads or by mark_dynptr_read as well to unnecessary 826 - * mark registers in verifier state. 827 - */ 828 - state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN; 829 - state->stack[spi - 1].spilled_ptr.live |= REG_LIVE_WRITTEN; 808 + bpf_mark_stack_write(env, state->frameno, BIT(spi - 1) | BIT(spi)); 830 809 } 831 810 832 811 static int unmark_stack_slots_dynptr(struct bpf_verifier_env *env, struct bpf_reg_state *reg) ··· 913 936 __mark_reg_not_init(env, &state->stack[spi].spilled_ptr); 914 937 __mark_reg_not_init(env, &state->stack[spi - 1].spilled_ptr); 915 938 916 - /* Same reason as unmark_stack_slots_dynptr above */ 917 - state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN; 918 - state->stack[spi - 1].spilled_ptr.live |= REG_LIVE_WRITTEN; 939 + bpf_mark_stack_write(env, state->frameno, BIT(spi - 1) | BIT(spi)); 919 940 920 941 return 0; 921 942 } ··· 1031 1056 else 1032 1057 st->type |= PTR_UNTRUSTED; 1033 1058 } 1034 - st->live |= REG_LIVE_WRITTEN; 1035 1059 st->ref_obj_id = i == 0 ? id : 0; 1036 1060 st->iter.btf = btf; 1037 1061 st->iter.btf_id = btf_id; ··· 1040 1066 for (j = 0; j < BPF_REG_SIZE; j++) 1041 1067 slot->slot_type[j] = STACK_ITER; 1042 1068 1069 + bpf_mark_stack_write(env, state->frameno, BIT(spi - i)); 1043 1070 mark_stack_slot_scratched(env, spi - i); 1044 1071 } 1045 1072 ··· 1066 1091 1067 1092 __mark_reg_not_init(env, st); 1068 1093 1069 - /* see unmark_stack_slots_dynptr() for why we need to set REG_LIVE_WRITTEN */ 1070 - st->live |= REG_LIVE_WRITTEN; 1071 - 1072 1094 for (j = 0; j < BPF_REG_SIZE; j++) 1073 1095 slot->slot_type[j] = STACK_INVALID; 1074 1096 1097 + bpf_mark_stack_write(env, state->frameno, BIT(spi - i)); 1075 1098 mark_stack_slot_scratched(env, spi - i); 1076 1099 } 1077 1100 ··· 1159 1186 slot = &state->stack[spi]; 1160 1187 st = &slot->spilled_ptr; 1161 1188 1189 + bpf_mark_stack_write(env, reg->frameno, BIT(spi)); 1162 1190 __mark_reg_known_zero(st); 1163 1191 st->type = PTR_TO_STACK; /* we don't have dedicated reg type */ 1164 - st->live |= REG_LIVE_WRITTEN; 1165 1192 st->ref_obj_id = id; 1166 1193 st->irq.kfunc_class = kfunc_class; 1167 1194 ··· 1215 1242 1216 1243 __mark_reg_not_init(env, st); 1217 1244 1218 - /* see unmark_stack_slots_dynptr() for why we need to set REG_LIVE_WRITTEN */ 1219 - st->live |= REG_LIVE_WRITTEN; 1245 + bpf_mark_stack_write(env, reg->frameno, BIT(spi)); 1220 1246 1221 1247 for (i = 0; i < BPF_REG_SIZE; i++) 1222 1248 slot->slot_type[i] = STACK_INVALID; ··· 1730 1758 return err; 1731 1759 dst_state->speculative = src->speculative; 1732 1760 dst_state->in_sleepable = src->in_sleepable; 1761 + dst_state->cleaned = src->cleaned; 1733 1762 dst_state->curframe = src->curframe; 1734 1763 dst_state->branches = src->branches; 1735 1764 dst_state->parent = src->parent; ··· 2866 2893 2867 2894 for (i = 0; i < MAX_BPF_REG; i++) { 2868 2895 mark_reg_not_init(env, regs, i); 2869 - regs[i].live = REG_LIVE_NONE; 2870 - regs[i].parent = NULL; 2871 2896 regs[i].subreg_def = DEF_NOT_SUBREG; 2872 2897 } 2873 2898 ··· 2949 2978 } 2950 2979 2951 2980 /* Find subprogram that contains instruction at 'off' */ 2952 - static struct bpf_subprog_info *find_containing_subprog(struct bpf_verifier_env *env, int off) 2981 + struct bpf_subprog_info *bpf_find_containing_subprog(struct bpf_verifier_env *env, int off) 2953 2982 { 2954 2983 struct bpf_subprog_info *vals = env->subprog_info; 2955 2984 int l, r, m; ··· 2974 3003 { 2975 3004 struct bpf_subprog_info *p; 2976 3005 2977 - p = find_containing_subprog(env, off); 3006 + p = bpf_find_containing_subprog(env, off); 2978 3007 if (!p || p->start != off) 2979 3008 return -ENOENT; 2980 3009 return p - env->subprog_info; ··· 3485 3514 return 0; 3486 3515 } 3487 3516 3488 - static int jmp_offset(struct bpf_insn *insn) 3489 - { 3490 - u8 code = insn->code; 3491 - 3492 - if (code == (BPF_JMP32 | BPF_JA)) 3493 - return insn->imm; 3494 - return insn->off; 3495 - } 3496 - 3497 3517 static int check_subprogs(struct bpf_verifier_env *env) 3498 3518 { 3499 3519 int i, subprog_start, subprog_end, off, cur_subprog = 0; ··· 3511 3549 goto next; 3512 3550 if (BPF_OP(code) == BPF_EXIT || BPF_OP(code) == BPF_CALL) 3513 3551 goto next; 3514 - off = i + jmp_offset(&insn[i]) + 1; 3552 + off = i + bpf_jmp_offset(&insn[i]) + 1; 3515 3553 if (off < subprog_start || off >= subprog_end) { 3516 3554 verbose(env, "jump out of range from insn %d to %d\n", i, off); 3517 3555 return -EINVAL; ··· 3537 3575 return 0; 3538 3576 } 3539 3577 3540 - /* Parentage chain of this register (or stack slot) should take care of all 3541 - * issues like callee-saved registers, stack slot allocation time, etc. 3542 - */ 3543 - static int mark_reg_read(struct bpf_verifier_env *env, 3544 - const struct bpf_reg_state *state, 3545 - struct bpf_reg_state *parent, u8 flag) 3546 - { 3547 - bool writes = parent == state->parent; /* Observe write marks */ 3548 - int cnt = 0; 3549 - 3550 - while (parent) { 3551 - /* if read wasn't screened by an earlier write ... */ 3552 - if (writes && state->live & REG_LIVE_WRITTEN) 3553 - break; 3554 - if (verifier_bug_if(parent->live & REG_LIVE_DONE, env, 3555 - "type %s var_off %lld off %d", 3556 - reg_type_str(env, parent->type), 3557 - parent->var_off.value, parent->off)) 3558 - return -EFAULT; 3559 - /* The first condition is more likely to be true than the 3560 - * second, checked it first. 3561 - */ 3562 - if ((parent->live & REG_LIVE_READ) == flag || 3563 - parent->live & REG_LIVE_READ64) 3564 - /* The parentage chain never changes and 3565 - * this parent was already marked as LIVE_READ. 3566 - * There is no need to keep walking the chain again and 3567 - * keep re-marking all parents as LIVE_READ. 3568 - * This case happens when the same register is read 3569 - * multiple times without writes into it in-between. 3570 - * Also, if parent has the stronger REG_LIVE_READ64 set, 3571 - * then no need to set the weak REG_LIVE_READ32. 3572 - */ 3573 - break; 3574 - /* ... then we depend on parent's value */ 3575 - parent->live |= flag; 3576 - /* REG_LIVE_READ64 overrides REG_LIVE_READ32. */ 3577 - if (flag == REG_LIVE_READ64) 3578 - parent->live &= ~REG_LIVE_READ32; 3579 - state = parent; 3580 - parent = state->parent; 3581 - writes = true; 3582 - cnt++; 3583 - } 3584 - 3585 - if (env->longest_mark_read_walk < cnt) 3586 - env->longest_mark_read_walk = cnt; 3587 - return 0; 3588 - } 3589 - 3590 3578 static int mark_stack_slot_obj_read(struct bpf_verifier_env *env, struct bpf_reg_state *reg, 3591 3579 int spi, int nr_slots) 3592 3580 { 3593 - struct bpf_func_state *state = func(env, reg); 3594 3581 int err, i; 3595 3582 3596 3583 for (i = 0; i < nr_slots; i++) { 3597 - struct bpf_reg_state *st = &state->stack[spi - i].spilled_ptr; 3598 - 3599 - err = mark_reg_read(env, st, st->parent, REG_LIVE_READ64); 3584 + err = bpf_mark_stack_read(env, reg->frameno, env->insn_idx, BIT(spi - i)); 3600 3585 if (err) 3601 3586 return err; 3602 - 3603 3587 mark_stack_slot_scratched(env, spi - i); 3604 3588 } 3605 3589 return 0; ··· 3754 3846 if (rw64) 3755 3847 mark_insn_zext(env, reg); 3756 3848 3757 - return mark_reg_read(env, reg, reg->parent, 3758 - rw64 ? REG_LIVE_READ64 : REG_LIVE_READ32); 3849 + return 0; 3759 3850 } else { 3760 3851 /* check whether register used as dest operand can be written to */ 3761 3852 if (regno == BPF_REG_FP) { 3762 3853 verbose(env, "frame pointer is read only\n"); 3763 3854 return -EACCES; 3764 3855 } 3765 - reg->live |= REG_LIVE_WRITTEN; 3766 3856 reg->subreg_def = rw64 ? DEF_NOT_SUBREG : env->insn_idx + 1; 3767 3857 if (t == DST_OP) 3768 3858 mark_reg_unknown(env, regs, regno); ··· 4121 4215 } 4122 4216 } 4123 4217 /* format stack slots bitmask, e.g., "-8,-24,-40" for 0x15 mask */ 4124 - static void fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask) 4218 + void bpf_fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask) 4125 4219 { 4126 4220 DECLARE_BITMAP(mask, 64); 4127 4221 bool first = true; ··· 4176 4270 } 4177 4271 } 4178 4272 4179 - static bool calls_callback(struct bpf_verifier_env *env, int insn_idx); 4180 - 4181 4273 /* For given verifier state backtrack_insn() is called from the last insn to 4182 4274 * the first insn. Its purpose is to compute a bitmask of registers and 4183 4275 * stack slots that needs precision in the parent verifier state. ··· 4202 4298 fmt_reg_mask(env->tmp_str_buf, TMP_STR_BUF_LEN, bt_reg_mask(bt)); 4203 4299 verbose(env, "mark_precise: frame%d: regs=%s ", 4204 4300 bt->frame, env->tmp_str_buf); 4205 - fmt_stack_mask(env->tmp_str_buf, TMP_STR_BUF_LEN, bt_stack_mask(bt)); 4301 + bpf_fmt_stack_mask(env->tmp_str_buf, TMP_STR_BUF_LEN, bt_stack_mask(bt)); 4206 4302 verbose(env, "stack=%s before ", env->tmp_str_buf); 4207 4303 verbose(env, "%d: ", idx); 4208 4304 verbose_insn(env, insn); ··· 4403 4499 * backtracking, as these registers are set by the function 4404 4500 * invoking callback. 4405 4501 */ 4406 - if (subseq_idx >= 0 && calls_callback(env, subseq_idx)) 4502 + if (subseq_idx >= 0 && bpf_calls_callback(env, subseq_idx)) 4407 4503 for (i = BPF_REG_1; i <= BPF_REG_5; i++) 4408 4504 bt_clear_reg(bt, i); 4409 4505 if (bt_reg_mask(bt) & BPF_REGMASK_ARGS) { ··· 4842 4938 bt_frame_reg_mask(bt, fr)); 4843 4939 verbose(env, "mark_precise: frame%d: parent state regs=%s ", 4844 4940 fr, env->tmp_str_buf); 4845 - fmt_stack_mask(env->tmp_str_buf, TMP_STR_BUF_LEN, 4941 + bpf_fmt_stack_mask(env->tmp_str_buf, TMP_STR_BUF_LEN, 4846 4942 bt_frame_stack_mask(bt, fr)); 4847 4943 verbose(env, "stack=%s: ", env->tmp_str_buf); 4848 4944 print_verifier_state(env, st, fr, true); ··· 4965 5061 /* Copy src state preserving dst->parent and dst->live fields */ 4966 5062 static void copy_register_state(struct bpf_reg_state *dst, const struct bpf_reg_state *src) 4967 5063 { 4968 - struct bpf_reg_state *parent = dst->parent; 4969 - enum bpf_reg_liveness live = dst->live; 4970 - 4971 5064 *dst = *src; 4972 - dst->parent = parent; 4973 - dst->live = live; 4974 5065 } 4975 5066 4976 5067 static void save_register_state(struct bpf_verifier_env *env, ··· 4976 5077 int i; 4977 5078 4978 5079 copy_register_state(&state->stack[spi].spilled_ptr, reg); 4979 - if (size == BPF_REG_SIZE) 4980 - state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN; 4981 5080 4982 5081 for (i = BPF_REG_SIZE; i > BPF_REG_SIZE - size; i--) 4983 5082 state->stack[spi].slot_type[i - 1] = STACK_SPILL; ··· 5069 5172 if (err) 5070 5173 return err; 5071 5174 5175 + if (!(off % BPF_REG_SIZE) && size == BPF_REG_SIZE) { 5176 + /* only mark the slot as written if all 8 bytes were written 5177 + * otherwise read propagation may incorrectly stop too soon 5178 + * when stack slots are partially written. 5179 + * This heuristic means that read propagation will be 5180 + * conservative, since it will add reg_live_read marks 5181 + * to stack slots all the way to first state when programs 5182 + * writes+reads less than 8 bytes 5183 + */ 5184 + bpf_mark_stack_write(env, state->frameno, BIT(spi)); 5185 + } 5186 + 5072 5187 check_fastcall_stack_contract(env, state, insn_idx, off); 5073 5188 mark_stack_slot_scratched(env, spi); 5074 5189 if (reg && !(off % BPF_REG_SIZE) && reg->type == SCALAR_VALUE && env->bpf_capable) { ··· 5123 5214 if (is_stack_slot_special(&state->stack[spi])) 5124 5215 for (i = 0; i < BPF_REG_SIZE; i++) 5125 5216 scrub_spilled_slot(&state->stack[spi].slot_type[i]); 5126 - 5127 - /* only mark the slot as written if all 8 bytes were written 5128 - * otherwise read propagation may incorrectly stop too soon 5129 - * when stack slots are partially written. 5130 - * This heuristic means that read propagation will be 5131 - * conservative, since it will add reg_live_read marks 5132 - * to stack slots all the way to first state when programs 5133 - * writes+reads less than 8 bytes 5134 - */ 5135 - if (size == BPF_REG_SIZE) 5136 - state->stack[spi].spilled_ptr.live |= REG_LIVE_WRITTEN; 5137 5217 5138 5218 /* when we zero initialize stack slots mark them as such */ 5139 5219 if ((reg && register_is_null(reg)) || ··· 5316 5418 /* have read misc data from the stack */ 5317 5419 mark_reg_unknown(env, state->regs, dst_regno); 5318 5420 } 5319 - state->regs[dst_regno].live |= REG_LIVE_WRITTEN; 5320 5421 } 5321 5422 5322 5423 /* Read the stack at 'off' and put the results into the register indicated by ··· 5338 5441 struct bpf_reg_state *reg; 5339 5442 u8 *stype, type; 5340 5443 int insn_flags = insn_stack_access_flags(reg_state->frameno, spi); 5444 + int err; 5341 5445 5342 5446 stype = reg_state->stack[spi].slot_type; 5343 5447 reg = &reg_state->stack[spi].spilled_ptr; 5344 5448 5345 5449 mark_stack_slot_scratched(env, spi); 5346 5450 check_fastcall_stack_contract(env, state, env->insn_idx, off); 5451 + err = bpf_mark_stack_read(env, reg_state->frameno, env->insn_idx, BIT(spi)); 5452 + if (err) 5453 + return err; 5347 5454 5348 5455 if (is_spilled_reg(&reg_state->stack[spi])) { 5349 5456 u8 spill_size = 1; ··· 5362 5461 return -EACCES; 5363 5462 } 5364 5463 5365 - mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64); 5366 5464 if (dst_regno < 0) 5367 5465 return 0; 5368 5466 ··· 5415 5515 insn_flags = 0; /* not restoring original register state */ 5416 5516 } 5417 5517 } 5418 - state->regs[dst_regno].live |= REG_LIVE_WRITTEN; 5419 5518 } else if (dst_regno >= 0) { 5420 5519 /* restore register state from stack */ 5421 5520 copy_register_state(&state->regs[dst_regno], reg); ··· 5422 5523 * has its liveness marks cleared by is_state_visited() 5423 5524 * which resets stack/reg liveness for state transitions 5424 5525 */ 5425 - state->regs[dst_regno].live |= REG_LIVE_WRITTEN; 5426 5526 } else if (__is_pointer_value(env->allow_ptr_leaks, reg)) { 5427 5527 /* If dst_regno==-1, the caller is asking us whether 5428 5528 * it is acceptable to use this value as a SCALAR_VALUE ··· 5433 5535 off); 5434 5536 return -EACCES; 5435 5537 } 5436 - mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64); 5437 5538 } else { 5438 5539 for (i = 0; i < size; i++) { 5439 5540 type = stype[(slot - i) % BPF_REG_SIZE]; ··· 5446 5549 off, i, size); 5447 5550 return -EACCES; 5448 5551 } 5449 - mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64); 5450 5552 if (dst_regno >= 0) 5451 5553 mark_reg_stack_read(env, reg_state, off, off + size, dst_regno); 5452 5554 insn_flags = 0; /* we are not restoring spilled register */ ··· 8073 8177 /* reading any byte out of 8-byte 'spill_slot' will cause 8074 8178 * the whole slot to be marked as 'read' 8075 8179 */ 8076 - mark_reg_read(env, &state->stack[spi].spilled_ptr, 8077 - state->stack[spi].spilled_ptr.parent, 8078 - REG_LIVE_READ64); 8079 - /* We do not set REG_LIVE_WRITTEN for stack slot, as we can not 8180 + err = bpf_mark_stack_read(env, reg->frameno, env->insn_idx, BIT(spi)); 8181 + if (err) 8182 + return err; 8183 + /* We do not call bpf_mark_stack_write(), as we can not 8080 8184 * be sure that whether stack slot is written to or not. Hence, 8081 8185 * we must still conservatively propagate reads upwards even if 8082 8186 * helper may write to the entire memory range. ··· 10637 10741 /* and go analyze first insn of the callee */ 10638 10742 *insn_idx = env->subprog_info[subprog].start - 1; 10639 10743 10744 + bpf_reset_live_stack_callchain(env); 10745 + 10640 10746 if (env->log.level & BPF_LOG_LEVEL) { 10641 10747 verbose(env, "caller:\n"); 10642 10748 print_verifier_state(env, state, caller->frameno, true); ··· 10914 11016 } 10915 11017 10916 11018 /* we are going to rely on register's precise value */ 10917 - err = mark_reg_read(env, r0, r0->parent, REG_LIVE_READ64); 10918 - err = err ?: mark_chain_precision(env, BPF_REG_0); 11019 + err = mark_chain_precision(env, BPF_REG_0); 10919 11020 if (err) 10920 11021 return err; 10921 11022 ··· 10924 11027 "At callback return", "R0"); 10925 11028 return -EINVAL; 10926 11029 } 10927 - if (!calls_callback(env, callee->callsite)) { 11030 + if (!bpf_calls_callback(env, callee->callsite)) { 10928 11031 verifier_bug(env, "in callback at %d, callsite %d !calls_callback", 10929 11032 *insn_idx, callee->callsite); 10930 11033 return -EFAULT; ··· 11818 11921 11819 11922 if (regno == BPF_REG_0) { 11820 11923 /* Function return value */ 11821 - reg->live |= REG_LIVE_WRITTEN; 11822 11924 reg->subreg_def = reg_size == sizeof(u64) ? 11823 11925 DEF_NOT_SUBREG : env->insn_idx + 1; 11824 - } else { 11926 + } else if (reg_size == sizeof(u64)) { 11825 11927 /* Function argument */ 11826 - if (reg_size == sizeof(u64)) { 11827 - mark_insn_zext(env, reg); 11828 - mark_reg_read(env, reg, reg->parent, REG_LIVE_READ64); 11829 - } else { 11830 - mark_reg_read(env, reg, reg->parent, REG_LIVE_READ32); 11831 - } 11928 + mark_insn_zext(env, reg); 11832 11929 } 11833 11930 } 11834 11931 ··· 15576 15685 */ 15577 15686 assign_scalar_id_before_mov(env, src_reg); 15578 15687 copy_register_state(dst_reg, src_reg); 15579 - dst_reg->live |= REG_LIVE_WRITTEN; 15580 15688 dst_reg->subreg_def = DEF_NOT_SUBREG; 15581 15689 } else { 15582 15690 /* case: R1 = (s8, s16 s32)R2 */ ··· 15594 15704 if (!no_sext) 15595 15705 dst_reg->id = 0; 15596 15706 coerce_reg_to_size_sx(dst_reg, insn->off >> 3); 15597 - dst_reg->live |= REG_LIVE_WRITTEN; 15598 15707 dst_reg->subreg_def = DEF_NOT_SUBREG; 15599 15708 } else { 15600 15709 mark_reg_unknown(env, regs, insn->dst_reg); ··· 15619 15730 */ 15620 15731 if (!is_src_reg_u32) 15621 15732 dst_reg->id = 0; 15622 - dst_reg->live |= REG_LIVE_WRITTEN; 15623 15733 dst_reg->subreg_def = env->insn_idx + 1; 15624 15734 } else { 15625 15735 /* case: W1 = (s8, s16)W2 */ ··· 15629 15741 copy_register_state(dst_reg, src_reg); 15630 15742 if (!no_sext) 15631 15743 dst_reg->id = 0; 15632 - dst_reg->live |= REG_LIVE_WRITTEN; 15633 15744 dst_reg->subreg_def = env->insn_idx + 1; 15634 15745 coerce_subreg_to_size_sx(dst_reg, insn->off >> 3); 15635 15746 } ··· 17189 17302 { 17190 17303 struct bpf_subprog_info *subprog; 17191 17304 17192 - subprog = find_containing_subprog(env, off); 17305 + subprog = bpf_find_containing_subprog(env, off); 17193 17306 subprog->changes_pkt_data = true; 17194 17307 } 17195 17308 ··· 17197 17310 { 17198 17311 struct bpf_subprog_info *subprog; 17199 17312 17200 - subprog = find_containing_subprog(env, off); 17313 + subprog = bpf_find_containing_subprog(env, off); 17201 17314 subprog->might_sleep = true; 17202 17315 } 17203 17316 ··· 17211 17324 { 17212 17325 struct bpf_subprog_info *caller, *callee; 17213 17326 17214 - caller = find_containing_subprog(env, t); 17215 - callee = find_containing_subprog(env, w); 17327 + caller = bpf_find_containing_subprog(env, t); 17328 + callee = bpf_find_containing_subprog(env, w); 17216 17329 caller->changes_pkt_data |= callee->changes_pkt_data; 17217 17330 caller->might_sleep |= callee->might_sleep; 17218 17331 } ··· 17282 17395 env->insn_aux_data[idx].calls_callback = true; 17283 17396 } 17284 17397 17285 - static bool calls_callback(struct bpf_verifier_env *env, int insn_idx) 17398 + bool bpf_calls_callback(struct bpf_verifier_env *env, int insn_idx) 17286 17399 { 17287 17400 return env->insn_aux_data[insn_idx].calls_callback; 17288 17401 } ··· 17756 17869 static int check_cfg(struct bpf_verifier_env *env) 17757 17870 { 17758 17871 int insn_cnt = env->prog->len; 17759 - int *insn_stack, *insn_state, *insn_postorder; 17872 + int *insn_stack, *insn_state; 17760 17873 int ex_insn_beg, i, ret = 0; 17761 17874 17762 17875 insn_state = env->cfg.insn_state = kvcalloc(insn_cnt, sizeof(int), GFP_KERNEL_ACCOUNT); ··· 17766 17879 insn_stack = env->cfg.insn_stack = kvcalloc(insn_cnt, sizeof(int), GFP_KERNEL_ACCOUNT); 17767 17880 if (!insn_stack) { 17768 17881 kvfree(insn_state); 17769 - return -ENOMEM; 17770 - } 17771 - 17772 - insn_postorder = env->cfg.insn_postorder = 17773 - kvcalloc(insn_cnt, sizeof(int), GFP_KERNEL_ACCOUNT); 17774 - if (!insn_postorder) { 17775 - kvfree(insn_state); 17776 - kvfree(insn_stack); 17777 17882 return -ENOMEM; 17778 17883 } 17779 17884 ··· 17786 17907 case DONE_EXPLORING: 17787 17908 insn_state[t] = EXPLORED; 17788 17909 env->cfg.cur_stack--; 17789 - insn_postorder[env->cfg.cur_postorder++] = t; 17790 17910 break; 17791 17911 case KEEP_EXPLORING: 17792 17912 break; ··· 17837 17959 kvfree(insn_stack); 17838 17960 env->cfg.insn_state = env->cfg.insn_stack = NULL; 17839 17961 return ret; 17962 + } 17963 + 17964 + /* 17965 + * For each subprogram 'i' fill array env->cfg.insn_subprogram sub-range 17966 + * [env->subprog_info[i].postorder_start, env->subprog_info[i+1].postorder_start) 17967 + * with indices of 'i' instructions in postorder. 17968 + */ 17969 + static int compute_postorder(struct bpf_verifier_env *env) 17970 + { 17971 + u32 cur_postorder, i, top, stack_sz, s, succ_cnt, succ[2]; 17972 + int *stack = NULL, *postorder = NULL, *state = NULL; 17973 + 17974 + postorder = kvcalloc(env->prog->len, sizeof(int), GFP_KERNEL_ACCOUNT); 17975 + state = kvcalloc(env->prog->len, sizeof(int), GFP_KERNEL_ACCOUNT); 17976 + stack = kvcalloc(env->prog->len, sizeof(int), GFP_KERNEL_ACCOUNT); 17977 + if (!postorder || !state || !stack) { 17978 + kvfree(postorder); 17979 + kvfree(state); 17980 + kvfree(stack); 17981 + return -ENOMEM; 17982 + } 17983 + cur_postorder = 0; 17984 + for (i = 0; i < env->subprog_cnt; i++) { 17985 + env->subprog_info[i].postorder_start = cur_postorder; 17986 + stack[0] = env->subprog_info[i].start; 17987 + stack_sz = 1; 17988 + do { 17989 + top = stack[stack_sz - 1]; 17990 + state[top] |= DISCOVERED; 17991 + if (state[top] & EXPLORED) { 17992 + postorder[cur_postorder++] = top; 17993 + stack_sz--; 17994 + continue; 17995 + } 17996 + succ_cnt = bpf_insn_successors(env->prog, top, succ); 17997 + for (s = 0; s < succ_cnt; ++s) { 17998 + if (!state[succ[s]]) { 17999 + stack[stack_sz++] = succ[s]; 18000 + state[succ[s]] |= DISCOVERED; 18001 + } 18002 + } 18003 + state[top] |= EXPLORED; 18004 + } while (stack_sz); 18005 + } 18006 + env->subprog_info[i].postorder_start = cur_postorder; 18007 + env->cfg.insn_postorder = postorder; 18008 + env->cfg.cur_postorder = cur_postorder; 18009 + kvfree(stack); 18010 + kvfree(state); 18011 + return 0; 17840 18012 } 17841 18013 17842 18014 static int check_abnormal_return(struct bpf_verifier_env *env) ··· 18421 18493 } 18422 18494 18423 18495 static void clean_func_state(struct bpf_verifier_env *env, 18424 - struct bpf_func_state *st) 18496 + struct bpf_func_state *st, 18497 + u32 ip) 18425 18498 { 18426 - enum bpf_reg_liveness live; 18499 + u16 live_regs = env->insn_aux_data[ip].live_regs_before; 18427 18500 int i, j; 18428 18501 18429 18502 for (i = 0; i < BPF_REG_FP; i++) { 18430 - live = st->regs[i].live; 18431 18503 /* liveness must not touch this register anymore */ 18432 - st->regs[i].live |= REG_LIVE_DONE; 18433 - if (!(live & REG_LIVE_READ)) 18504 + if (!(live_regs & BIT(i))) 18434 18505 /* since the register is unused, clear its state 18435 18506 * to make further comparison simpler 18436 18507 */ ··· 18437 18510 } 18438 18511 18439 18512 for (i = 0; i < st->allocated_stack / BPF_REG_SIZE; i++) { 18440 - live = st->stack[i].spilled_ptr.live; 18441 - /* liveness must not touch this stack slot anymore */ 18442 - st->stack[i].spilled_ptr.live |= REG_LIVE_DONE; 18443 - if (!(live & REG_LIVE_READ)) { 18513 + if (!bpf_stack_slot_alive(env, st->frameno, i)) { 18444 18514 __mark_reg_not_init(env, &st->stack[i].spilled_ptr); 18445 18515 for (j = 0; j < BPF_REG_SIZE; j++) 18446 18516 st->stack[i].slot_type[j] = STACK_INVALID; ··· 18448 18524 static void clean_verifier_state(struct bpf_verifier_env *env, 18449 18525 struct bpf_verifier_state *st) 18450 18526 { 18451 - int i; 18527 + int i, ip; 18452 18528 18453 - for (i = 0; i <= st->curframe; i++) 18454 - clean_func_state(env, st->frame[i]); 18529 + bpf_live_stack_query_init(env, st); 18530 + st->cleaned = true; 18531 + for (i = 0; i <= st->curframe; i++) { 18532 + ip = frame_insn_idx(st, i); 18533 + clean_func_state(env, st->frame[i], ip); 18534 + } 18455 18535 } 18456 18536 18457 18537 /* the parentage chains form a tree. ··· 18466 18538 * but a lot of states will get revised from liveness point of view when 18467 18539 * the verifier explores other branches. 18468 18540 * Example: 18469 - * 1: r0 = 1 18541 + * 1: *(u64)(r10 - 8) = 1 18470 18542 * 2: if r1 == 100 goto pc+1 18471 - * 3: r0 = 2 18472 - * 4: exit 18473 - * when the verifier reaches exit insn the register r0 in the state list of 18474 - * insn 2 will be seen as !REG_LIVE_READ. Then the verifier pops the other_branch 18475 - * of insn 2 and goes exploring further. At the insn 4 it will walk the 18476 - * parentage chain from insn 4 into insn 2 and will mark r0 as REG_LIVE_READ. 18543 + * 3: *(u64)(r10 - 8) = 2 18544 + * 4: r0 = *(u64)(r10 - 8) 18545 + * 5: exit 18546 + * when the verifier reaches exit insn the stack slot -8 in the state list of 18547 + * insn 2 is not yet marked alive. Then the verifier pops the other_branch 18548 + * of insn 2 and goes exploring further. After the insn 4 read, liveness 18549 + * analysis would propagate read mark for -8 at insn 2. 18477 18550 * 18478 18551 * Since the verifier pushes the branch states as it sees them while exploring 18479 18552 * the program the condition of walking the branch instruction for the second 18480 18553 * time means that all states below this branch were already explored and 18481 18554 * their final liveness marks are already propagated. 18482 18555 * Hence when the verifier completes the search of state list in is_state_visited() 18483 - * we can call this clean_live_states() function to mark all liveness states 18484 - * as REG_LIVE_DONE to indicate that 'parent' pointers of 'struct bpf_reg_state' 18485 - * will not be used. 18486 - * This function also clears the registers and stack for states that !READ 18487 - * to simplify state merging. 18556 + * we can call this clean_live_states() function to clear dead the registers and stack 18557 + * slots to simplify state merging. 18488 18558 * 18489 18559 * Important note here that walking the same branch instruction in the callee 18490 18560 * doesn't meant that the states are DONE. The verifier has to compare ··· 18502 18576 if (sl->state.insn_idx != insn || 18503 18577 !same_callsites(&sl->state, cur)) 18504 18578 continue; 18505 - if (sl->state.frame[0]->regs[0].live & REG_LIVE_DONE) 18579 + if (sl->state.cleaned) 18506 18580 /* all regs in this state in all frames were already marked */ 18507 18581 continue; 18508 18582 if (incomplete_read_marks(env, &sl->state)) ··· 18534 18608 if (exact == EXACT) 18535 18609 return regs_exact(rold, rcur, idmap); 18536 18610 18537 - if (!(rold->live & REG_LIVE_READ) && exact == NOT_EXACT) 18538 - /* explored state didn't use this */ 18539 - return true; 18540 18611 if (rold->type == NOT_INIT) { 18541 18612 if (exact == NOT_EXACT || rcur->type == NOT_INIT) 18542 18613 /* explored state can't have used this */ ··· 18657 18734 static __init int unbound_reg_init(void) 18658 18735 { 18659 18736 __mark_reg_unknown_imprecise(&unbound_reg); 18660 - unbound_reg.live |= REG_LIVE_READ; 18661 18737 return 0; 18662 18738 } 18663 18739 late_initcall(unbound_reg_init); ··· 18708 18786 old->stack[spi].slot_type[i % BPF_REG_SIZE] != 18709 18787 cur->stack[spi].slot_type[i % BPF_REG_SIZE])) 18710 18788 return false; 18711 - 18712 - if (!(old->stack[spi].spilled_ptr.live & REG_LIVE_READ) 18713 - && exact == NOT_EXACT) { 18714 - i += BPF_REG_SIZE - 1; 18715 - /* explored state didn't use this */ 18716 - continue; 18717 - } 18718 18789 18719 18790 if (old->stack[spi].slot_type[i % BPF_REG_SIZE] == STACK_INVALID) 18720 18791 continue; ··· 18951 19036 return true; 18952 19037 } 18953 19038 18954 - /* Return 0 if no propagation happened. Return negative error code if error 18955 - * happened. Otherwise, return the propagated bit. 18956 - */ 18957 - static int propagate_liveness_reg(struct bpf_verifier_env *env, 18958 - struct bpf_reg_state *reg, 18959 - struct bpf_reg_state *parent_reg) 18960 - { 18961 - u8 parent_flag = parent_reg->live & REG_LIVE_READ; 18962 - u8 flag = reg->live & REG_LIVE_READ; 18963 - int err; 18964 - 18965 - /* When comes here, read flags of PARENT_REG or REG could be any of 18966 - * REG_LIVE_READ64, REG_LIVE_READ32, REG_LIVE_NONE. There is no need 18967 - * of propagation if PARENT_REG has strongest REG_LIVE_READ64. 18968 - */ 18969 - if (parent_flag == REG_LIVE_READ64 || 18970 - /* Or if there is no read flag from REG. */ 18971 - !flag || 18972 - /* Or if the read flag from REG is the same as PARENT_REG. */ 18973 - parent_flag == flag) 18974 - return 0; 18975 - 18976 - err = mark_reg_read(env, reg, parent_reg, flag); 18977 - if (err) 18978 - return err; 18979 - 18980 - return flag; 18981 - } 18982 - 18983 - /* A write screens off any subsequent reads; but write marks come from the 18984 - * straight-line code between a state and its parent. When we arrive at an 18985 - * equivalent state (jump target or such) we didn't arrive by the straight-line 18986 - * code, so read marks in the state must propagate to the parent regardless 18987 - * of the state's write marks. That's what 'parent == state->parent' comparison 18988 - * in mark_reg_read() is for. 18989 - */ 18990 - static int propagate_liveness(struct bpf_verifier_env *env, 18991 - const struct bpf_verifier_state *vstate, 18992 - struct bpf_verifier_state *vparent, 18993 - bool *changed) 18994 - { 18995 - struct bpf_reg_state *state_reg, *parent_reg; 18996 - struct bpf_func_state *state, *parent; 18997 - int i, frame, err = 0; 18998 - bool tmp = false; 18999 - 19000 - changed = changed ?: &tmp; 19001 - if (vparent->curframe != vstate->curframe) { 19002 - WARN(1, "propagate_live: parent frame %d current frame %d\n", 19003 - vparent->curframe, vstate->curframe); 19004 - return -EFAULT; 19005 - } 19006 - /* Propagate read liveness of registers... */ 19007 - BUILD_BUG_ON(BPF_REG_FP + 1 != MAX_BPF_REG); 19008 - for (frame = 0; frame <= vstate->curframe; frame++) { 19009 - parent = vparent->frame[frame]; 19010 - state = vstate->frame[frame]; 19011 - parent_reg = parent->regs; 19012 - state_reg = state->regs; 19013 - /* We don't need to worry about FP liveness, it's read-only */ 19014 - for (i = frame < vstate->curframe ? BPF_REG_6 : 0; i < BPF_REG_FP; i++) { 19015 - err = propagate_liveness_reg(env, &state_reg[i], 19016 - &parent_reg[i]); 19017 - if (err < 0) 19018 - return err; 19019 - *changed |= err > 0; 19020 - if (err == REG_LIVE_READ64) 19021 - mark_insn_zext(env, &parent_reg[i]); 19022 - } 19023 - 19024 - /* Propagate stack slots. */ 19025 - for (i = 0; i < state->allocated_stack / BPF_REG_SIZE && 19026 - i < parent->allocated_stack / BPF_REG_SIZE; i++) { 19027 - parent_reg = &parent->stack[i].spilled_ptr; 19028 - state_reg = &state->stack[i].spilled_ptr; 19029 - err = propagate_liveness_reg(env, state_reg, 19030 - parent_reg); 19031 - *changed |= err > 0; 19032 - if (err < 0) 19033 - return err; 19034 - } 19035 - } 19036 - return 0; 19037 - } 19038 - 19039 19039 /* find precise scalars in the previous equivalent state and 19040 19040 * propagate them into the current state 19041 19041 */ ··· 18970 19140 first = true; 18971 19141 for (i = 0; i < BPF_REG_FP; i++, state_reg++) { 18972 19142 if (state_reg->type != SCALAR_VALUE || 18973 - !state_reg->precise || 18974 - !(state_reg->live & REG_LIVE_READ)) 19143 + !state_reg->precise) 18975 19144 continue; 18976 19145 if (env->log.level & BPF_LOG_LEVEL2) { 18977 19146 if (first) ··· 18987 19158 continue; 18988 19159 state_reg = &state->stack[i].spilled_ptr; 18989 19160 if (state_reg->type != SCALAR_VALUE || 18990 - !state_reg->precise || 18991 - !(state_reg->live & REG_LIVE_READ)) 19161 + !state_reg->precise) 18992 19162 continue; 18993 19163 if (env->log.level & BPF_LOG_LEVEL2) { 18994 19164 if (first) ··· 19037 19209 changed = false; 19038 19210 for (backedge = visit->backedges; backedge; backedge = backedge->next) { 19039 19211 st = &backedge->state; 19040 - err = propagate_liveness(env, st->equal_state, st, &changed); 19041 - if (err) 19042 - return err; 19043 19212 err = propagate_precision(env, st->equal_state, st, &changed); 19044 19213 if (err) 19045 19214 return err; ··· 19060 19235 fcur = cur->frame[fr]; 19061 19236 for (i = 0; i < MAX_BPF_REG; i++) 19062 19237 if (memcmp(&fold->regs[i], &fcur->regs[i], 19063 - offsetof(struct bpf_reg_state, parent))) 19238 + offsetof(struct bpf_reg_state, frameno))) 19064 19239 return false; 19065 19240 return true; 19066 19241 } ··· 19158 19333 struct bpf_verifier_state_list *sl; 19159 19334 struct bpf_verifier_state *cur = env->cur_state, *new; 19160 19335 bool force_new_state, add_new_state, loop; 19161 - int i, j, n, err, states_cnt = 0; 19336 + int n, err, states_cnt = 0; 19162 19337 struct list_head *pos, *tmp, *head; 19163 19338 19164 19339 force_new_state = env->test_state_freq || is_force_checkpoint(env, insn_idx) || ··· 19273 19448 goto hit; 19274 19449 } 19275 19450 } 19276 - if (calls_callback(env, insn_idx)) { 19451 + if (bpf_calls_callback(env, insn_idx)) { 19277 19452 if (states_equal(env, &sl->state, cur, RANGE_WITHIN)) 19278 19453 goto hit; 19279 19454 goto skip_inf_loop_check; ··· 19316 19491 if (states_equal(env, &sl->state, cur, loop ? RANGE_WITHIN : NOT_EXACT)) { 19317 19492 hit: 19318 19493 sl->hit_cnt++; 19319 - /* reached equivalent register/stack state, 19320 - * prune the search. 19321 - * Registers read by the continuation are read by us. 19322 - * If we have any write marks in env->cur_state, they 19323 - * will prevent corresponding reads in the continuation 19324 - * from reaching our parent (an explored_state). Our 19325 - * own state will get the read marks recorded, but 19326 - * they'll be immediately forgotten as we're pruning 19327 - * this state and will pop a new one. 19328 - */ 19329 - err = propagate_liveness(env, &sl->state, cur, NULL); 19330 19494 19331 19495 /* if previous state reached the exit with precision and 19332 19496 * current state is equivalent to it (except precision marks) 19333 19497 * the precision needs to be propagated back in 19334 19498 * the current state. 19335 19499 */ 19500 + err = 0; 19336 19501 if (is_jmp_point(env, env->insn_idx)) 19337 - err = err ? : push_jmp_history(env, cur, 0, 0); 19502 + err = push_jmp_history(env, cur, 0, 0); 19338 19503 err = err ? : propagate_precision(env, &sl->state, cur, NULL); 19339 19504 if (err) 19340 19505 return err; ··· 19504 19689 cur->dfs_depth = new->dfs_depth + 1; 19505 19690 clear_jmp_history(cur); 19506 19691 list_add(&new_sl->node, head); 19507 - 19508 - /* connect new state to parentage chain. Current frame needs all 19509 - * registers connected. Only r6 - r9 of the callers are alive (pushed 19510 - * to the stack implicitly by JITs) so in callers' frames connect just 19511 - * r6 - r9 as an optimization. Callers will have r1 - r5 connected to 19512 - * the state of the call instruction (with WRITTEN set), and r0 comes 19513 - * from callee with its full parentage chain, anyway. 19514 - */ 19515 - /* clear write marks in current state: the writes we did are not writes 19516 - * our child did, so they don't screen off its reads from us. 19517 - * (There are no read marks in current state, because reads always mark 19518 - * their parent and current state never has children yet. Only 19519 - * explored_states can get read marks.) 19520 - */ 19521 - for (j = 0; j <= cur->curframe; j++) { 19522 - for (i = j < cur->curframe ? BPF_REG_6 : 0; i < BPF_REG_FP; i++) 19523 - cur->frame[j]->regs[i].parent = &new->frame[j]->regs[i]; 19524 - for (i = 0; i < BPF_REG_FP; i++) 19525 - cur->frame[j]->regs[i].live = REG_LIVE_NONE; 19526 - } 19527 - 19528 - /* all stack frames are accessible from callee, clear them all */ 19529 - for (j = 0; j <= cur->curframe; j++) { 19530 - struct bpf_func_state *frame = cur->frame[j]; 19531 - struct bpf_func_state *newframe = new->frame[j]; 19532 - 19533 - for (i = 0; i < frame->allocated_stack / BPF_REG_SIZE; i++) { 19534 - frame->stack[i].spilled_ptr.live = REG_LIVE_NONE; 19535 - frame->stack[i].spilled_ptr.parent = 19536 - &newframe->stack[i].spilled_ptr; 19537 - } 19538 - } 19539 19692 return 0; 19540 19693 } 19541 19694 ··· 19639 19856 return PROCESS_BPF_EXIT; 19640 19857 19641 19858 if (env->cur_state->curframe) { 19859 + err = bpf_update_live_stack(env); 19860 + if (err) 19861 + return err; 19642 19862 /* exit from nested function */ 19643 19863 err = prepare_func_exit(env, &env->insn_idx); 19644 19864 if (err) ··· 19827 20041 for (;;) { 19828 20042 struct bpf_insn *insn; 19829 20043 struct bpf_insn_aux_data *insn_aux; 19830 - int err; 20044 + int err, marks_err; 19831 20045 19832 20046 /* reset current history entry on each new instruction */ 19833 20047 env->cur_hist_ent = NULL; ··· 19920 20134 if (state->speculative && insn_aux->nospec) 19921 20135 goto process_bpf_exit; 19922 20136 20137 + err = bpf_reset_stack_write_marks(env, env->insn_idx); 20138 + if (err) 20139 + return err; 19923 20140 err = do_check_insn(env, &do_print_state); 20141 + if (err >= 0 || error_recoverable_with_nospec(err)) { 20142 + marks_err = bpf_commit_stack_write_marks(env); 20143 + if (marks_err) 20144 + return marks_err; 20145 + } 19924 20146 if (error_recoverable_with_nospec(err) && state->speculative) { 19925 20147 /* Prevent this speculative path from ever reaching the 19926 20148 * insn that would have been unsafe to execute. ··· 19967 20173 process_bpf_exit: 19968 20174 mark_verifier_state_scratched(env); 19969 20175 err = update_branch_counts(env, env->cur_state); 20176 + if (err) 20177 + return err; 20178 + err = bpf_update_live_stack(env); 19970 20179 if (err) 19971 20180 return err; 19972 20181 err = pop_stack(env, &prev_insn_idx, &env->insn_idx, ··· 23935 24138 return 0; 23936 24139 } 23937 24140 23938 - static bool can_fallthrough(struct bpf_insn *insn) 23939 - { 23940 - u8 class = BPF_CLASS(insn->code); 23941 - u8 opcode = BPF_OP(insn->code); 23942 - 23943 - if (class != BPF_JMP && class != BPF_JMP32) 23944 - return true; 23945 - 23946 - if (opcode == BPF_EXIT || opcode == BPF_JA) 23947 - return false; 23948 - 23949 - return true; 23950 - } 23951 - 23952 - static bool can_jump(struct bpf_insn *insn) 23953 - { 23954 - u8 class = BPF_CLASS(insn->code); 23955 - u8 opcode = BPF_OP(insn->code); 23956 - 23957 - if (class != BPF_JMP && class != BPF_JMP32) 23958 - return false; 23959 - 23960 - switch (opcode) { 23961 - case BPF_JA: 23962 - case BPF_JEQ: 23963 - case BPF_JNE: 23964 - case BPF_JLT: 23965 - case BPF_JLE: 23966 - case BPF_JGT: 23967 - case BPF_JGE: 23968 - case BPF_JSGT: 23969 - case BPF_JSGE: 23970 - case BPF_JSLT: 23971 - case BPF_JSLE: 23972 - case BPF_JCOND: 23973 - case BPF_JSET: 23974 - return true; 23975 - } 23976 - 23977 - return false; 23978 - } 23979 - 23980 - static int insn_successors(struct bpf_prog *prog, u32 idx, u32 succ[2]) 23981 - { 23982 - struct bpf_insn *insn = &prog->insnsi[idx]; 23983 - int i = 0, insn_sz; 23984 - u32 dst; 23985 - 23986 - insn_sz = bpf_is_ldimm64(insn) ? 2 : 1; 23987 - if (can_fallthrough(insn) && idx + 1 < prog->len) 23988 - succ[i++] = idx + insn_sz; 23989 - 23990 - if (can_jump(insn)) { 23991 - dst = idx + jmp_offset(insn) + 1; 23992 - if (i == 0 || succ[0] != dst) 23993 - succ[i++] = dst; 23994 - } 23995 - 23996 - return i; 23997 - } 23998 - 23999 24141 /* Each field is a register bitmask */ 24000 24142 struct insn_live_regs { 24001 24143 u16 use; /* registers read by instruction */ ··· 24132 24396 u16 new_out = 0; 24133 24397 u16 new_in = 0; 24134 24398 24135 - succ_num = insn_successors(env->prog, insn_idx, succ); 24399 + succ_num = bpf_insn_successors(env->prog, insn_idx, succ); 24136 24400 for (int s = 0; s < succ_num; ++s) 24137 24401 new_out |= state[succ[s]].in; 24138 24402 new_in = (new_out & ~live->def) | live->use; ··· 24169 24433 24170 24434 out: 24171 24435 kvfree(state); 24172 - kvfree(env->cfg.insn_postorder); 24173 - env->cfg.insn_postorder = NULL; 24174 - env->cfg.cur_postorder = 0; 24175 24436 return err; 24176 24437 } 24177 24438 ··· 24298 24565 stack[stack_sz++] = w; 24299 24566 } 24300 24567 /* Visit 'w' successors */ 24301 - succ_cnt = insn_successors(env->prog, w, succ); 24568 + succ_cnt = bpf_insn_successors(env->prog, w, succ); 24302 24569 for (j = 0; j < succ_cnt; ++j) { 24303 24570 if (pre[succ[j]]) { 24304 24571 low[w] = min(low[w], low[succ[j]]); ··· 24471 24738 if (ret < 0) 24472 24739 goto skip_full_check; 24473 24740 24741 + ret = compute_postorder(env); 24742 + if (ret < 0) 24743 + goto skip_full_check; 24744 + 24745 + ret = bpf_stack_liveness_init(env); 24746 + if (ret) 24747 + goto skip_full_check; 24748 + 24474 24749 ret = check_attach_btf_id(env); 24475 24750 if (ret) 24476 24751 goto skip_full_check; ··· 24628 24887 mutex_unlock(&bpf_verifier_lock); 24629 24888 vfree(env->insn_aux_data); 24630 24889 err_free_env: 24890 + bpf_stack_liveness_free(env); 24631 24891 kvfree(env->cfg.insn_postorder); 24632 24892 kvfree(env->scc_info); 24633 24893 kvfree(env);
+89 -89
tools/testing/selftests/bpf/prog_tests/align.c
··· 42 42 .matches = { 43 43 {0, "R1", "ctx()"}, 44 44 {0, "R10", "fp0"}, 45 - {0, "R3_w", "2"}, 46 - {1, "R3_w", "4"}, 47 - {2, "R3_w", "8"}, 48 - {3, "R3_w", "16"}, 49 - {4, "R3_w", "32"}, 45 + {0, "R3", "2"}, 46 + {1, "R3", "4"}, 47 + {2, "R3", "8"}, 48 + {3, "R3", "16"}, 49 + {4, "R3", "32"}, 50 50 }, 51 51 }, 52 52 { ··· 70 70 .matches = { 71 71 {0, "R1", "ctx()"}, 72 72 {0, "R10", "fp0"}, 73 - {0, "R3_w", "1"}, 74 - {1, "R3_w", "2"}, 75 - {2, "R3_w", "4"}, 76 - {3, "R3_w", "8"}, 77 - {4, "R3_w", "16"}, 78 - {5, "R3_w", "1"}, 79 - {6, "R4_w", "32"}, 80 - {7, "R4_w", "16"}, 81 - {8, "R4_w", "8"}, 82 - {9, "R4_w", "4"}, 83 - {10, "R4_w", "2"}, 73 + {0, "R3", "1"}, 74 + {1, "R3", "2"}, 75 + {2, "R3", "4"}, 76 + {3, "R3", "8"}, 77 + {4, "R3", "16"}, 78 + {5, "R3", "1"}, 79 + {6, "R4", "32"}, 80 + {7, "R4", "16"}, 81 + {8, "R4", "8"}, 82 + {9, "R4", "4"}, 83 + {10, "R4", "2"}, 84 84 }, 85 85 }, 86 86 { ··· 99 99 .matches = { 100 100 {0, "R1", "ctx()"}, 101 101 {0, "R10", "fp0"}, 102 - {0, "R3_w", "4"}, 103 - {1, "R3_w", "8"}, 104 - {2, "R3_w", "10"}, 105 - {3, "R4_w", "8"}, 106 - {4, "R4_w", "12"}, 107 - {5, "R4_w", "14"}, 102 + {0, "R3", "4"}, 103 + {1, "R3", "8"}, 104 + {2, "R3", "10"}, 105 + {3, "R4", "8"}, 106 + {4, "R4", "12"}, 107 + {5, "R4", "14"}, 108 108 }, 109 109 }, 110 110 { ··· 121 121 .matches = { 122 122 {0, "R1", "ctx()"}, 123 123 {0, "R10", "fp0"}, 124 - {0, "R3_w", "7"}, 125 - {1, "R3_w", "7"}, 126 - {2, "R3_w", "14"}, 127 - {3, "R3_w", "56"}, 124 + {0, "R3", "7"}, 125 + {1, "R3", "7"}, 126 + {2, "R3", "14"}, 127 + {3, "R3", "56"}, 128 128 }, 129 129 }, 130 130 ··· 162 162 }, 163 163 .prog_type = BPF_PROG_TYPE_SCHED_CLS, 164 164 .matches = { 165 - {6, "R0_w", "pkt(off=8,r=8)"}, 166 - {6, "R3_w", "var_off=(0x0; 0xff)"}, 167 - {7, "R3_w", "var_off=(0x0; 0x1fe)"}, 168 - {8, "R3_w", "var_off=(0x0; 0x3fc)"}, 169 - {9, "R3_w", "var_off=(0x0; 0x7f8)"}, 170 - {10, "R3_w", "var_off=(0x0; 0xff0)"}, 171 - {12, "R3_w", "pkt_end()"}, 172 - {17, "R4_w", "var_off=(0x0; 0xff)"}, 173 - {18, "R4_w", "var_off=(0x0; 0x1fe0)"}, 174 - {19, "R4_w", "var_off=(0x0; 0xff0)"}, 175 - {20, "R4_w", "var_off=(0x0; 0x7f8)"}, 176 - {21, "R4_w", "var_off=(0x0; 0x3fc)"}, 177 - {22, "R4_w", "var_off=(0x0; 0x1fe)"}, 165 + {6, "R0", "pkt(off=8,r=8)"}, 166 + {6, "R3", "var_off=(0x0; 0xff)"}, 167 + {7, "R3", "var_off=(0x0; 0x1fe)"}, 168 + {8, "R3", "var_off=(0x0; 0x3fc)"}, 169 + {9, "R3", "var_off=(0x0; 0x7f8)"}, 170 + {10, "R3", "var_off=(0x0; 0xff0)"}, 171 + {12, "R3", "pkt_end()"}, 172 + {17, "R4", "var_off=(0x0; 0xff)"}, 173 + {18, "R4", "var_off=(0x0; 0x1fe0)"}, 174 + {19, "R4", "var_off=(0x0; 0xff0)"}, 175 + {20, "R4", "var_off=(0x0; 0x7f8)"}, 176 + {21, "R4", "var_off=(0x0; 0x3fc)"}, 177 + {22, "R4", "var_off=(0x0; 0x1fe)"}, 178 178 }, 179 179 }, 180 180 { ··· 195 195 }, 196 196 .prog_type = BPF_PROG_TYPE_SCHED_CLS, 197 197 .matches = { 198 - {6, "R3_w", "var_off=(0x0; 0xff)"}, 199 - {7, "R4_w", "var_off=(0x0; 0xff)"}, 200 - {8, "R4_w", "var_off=(0x0; 0xff)"}, 201 - {9, "R4_w", "var_off=(0x0; 0xff)"}, 202 - {10, "R4_w", "var_off=(0x0; 0x1fe)"}, 203 - {11, "R4_w", "var_off=(0x0; 0xff)"}, 204 - {12, "R4_w", "var_off=(0x0; 0x3fc)"}, 205 - {13, "R4_w", "var_off=(0x0; 0xff)"}, 206 - {14, "R4_w", "var_off=(0x0; 0x7f8)"}, 207 - {15, "R4_w", "var_off=(0x0; 0xff0)"}, 198 + {6, "R3", "var_off=(0x0; 0xff)"}, 199 + {7, "R4", "var_off=(0x0; 0xff)"}, 200 + {8, "R4", "var_off=(0x0; 0xff)"}, 201 + {9, "R4", "var_off=(0x0; 0xff)"}, 202 + {10, "R4", "var_off=(0x0; 0x1fe)"}, 203 + {11, "R4", "var_off=(0x0; 0xff)"}, 204 + {12, "R4", "var_off=(0x0; 0x3fc)"}, 205 + {13, "R4", "var_off=(0x0; 0xff)"}, 206 + {14, "R4", "var_off=(0x0; 0x7f8)"}, 207 + {15, "R4", "var_off=(0x0; 0xff0)"}, 208 208 }, 209 209 }, 210 210 { ··· 235 235 }, 236 236 .prog_type = BPF_PROG_TYPE_SCHED_CLS, 237 237 .matches = { 238 - {2, "R5_w", "pkt(r=0)"}, 239 - {4, "R5_w", "pkt(off=14,r=0)"}, 240 - {5, "R4_w", "pkt(off=14,r=0)"}, 238 + {2, "R5", "pkt(r=0)"}, 239 + {4, "R5", "pkt(off=14,r=0)"}, 240 + {5, "R4", "pkt(off=14,r=0)"}, 241 241 {9, "R2", "pkt(r=18)"}, 242 242 {10, "R5", "pkt(off=14,r=18)"}, 243 - {10, "R4_w", "var_off=(0x0; 0xff)"}, 244 - {13, "R4_w", "var_off=(0x0; 0xffff)"}, 245 - {14, "R4_w", "var_off=(0x0; 0xffff)"}, 243 + {10, "R4", "var_off=(0x0; 0xff)"}, 244 + {13, "R4", "var_off=(0x0; 0xffff)"}, 245 + {14, "R4", "var_off=(0x0; 0xffff)"}, 246 246 }, 247 247 }, 248 248 { ··· 299 299 /* Calculated offset in R6 has unknown value, but known 300 300 * alignment of 4. 301 301 */ 302 - {6, "R2_w", "pkt(r=8)"}, 303 - {7, "R6_w", "var_off=(0x0; 0x3fc)"}, 302 + {6, "R2", "pkt(r=8)"}, 303 + {7, "R6", "var_off=(0x0; 0x3fc)"}, 304 304 /* Offset is added to packet pointer R5, resulting in 305 305 * known fixed offset, and variable offset from R6. 306 306 */ 307 - {11, "R5_w", "pkt(id=1,off=14,"}, 307 + {11, "R5", "pkt(id=1,off=14,"}, 308 308 /* At the time the word size load is performed from R5, 309 309 * it's total offset is NET_IP_ALIGN + reg->off (0) + 310 310 * reg->aux_off (14) which is 16. Then the variable ··· 320 320 * instruction to validate R5 state. We also check 321 321 * that R4 is what it should be in such case. 322 322 */ 323 - {18, "R4_w", "var_off=(0x0; 0x3fc)"}, 324 - {18, "R5_w", "var_off=(0x0; 0x3fc)"}, 323 + {18, "R4", "var_off=(0x0; 0x3fc)"}, 324 + {18, "R5", "var_off=(0x0; 0x3fc)"}, 325 325 /* Constant offset is added to R5, resulting in 326 326 * reg->off of 14. 327 327 */ 328 - {19, "R5_w", "pkt(id=2,off=14,"}, 328 + {19, "R5", "pkt(id=2,off=14,"}, 329 329 /* At the time the word size load is performed from R5, 330 330 * its total fixed offset is NET_IP_ALIGN + reg->off 331 331 * (14) which is 16. Then the variable offset is 4-byte ··· 337 337 /* Constant offset is added to R5 packet pointer, 338 338 * resulting in reg->off value of 14. 339 339 */ 340 - {26, "R5_w", "pkt(off=14,r=8)"}, 340 + {26, "R5", "pkt(off=14,r=8)"}, 341 341 /* Variable offset is added to R5, resulting in a 342 342 * variable offset of (4n). See comment for insn #18 343 343 * for R4 = R5 trick. 344 344 */ 345 - {28, "R4_w", "var_off=(0x0; 0x3fc)"}, 346 - {28, "R5_w", "var_off=(0x0; 0x3fc)"}, 345 + {28, "R4", "var_off=(0x0; 0x3fc)"}, 346 + {28, "R5", "var_off=(0x0; 0x3fc)"}, 347 347 /* Constant is added to R5 again, setting reg->off to 18. */ 348 - {29, "R5_w", "pkt(id=3,off=18,"}, 348 + {29, "R5", "pkt(id=3,off=18,"}, 349 349 /* And once more we add a variable; resulting var_off 350 350 * is still (4n), fixed offset is not changed. 351 351 * Also, we create a new reg->id. 352 352 */ 353 - {31, "R4_w", "var_off=(0x0; 0x7fc)"}, 354 - {31, "R5_w", "var_off=(0x0; 0x7fc)"}, 353 + {31, "R4", "var_off=(0x0; 0x7fc)"}, 354 + {31, "R5", "var_off=(0x0; 0x7fc)"}, 355 355 /* At the time the word size load is performed from R5, 356 356 * its total fixed offset is NET_IP_ALIGN + reg->off (18) 357 357 * which is 20. Then the variable offset is (4n), so ··· 397 397 /* Calculated offset in R6 has unknown value, but known 398 398 * alignment of 4. 399 399 */ 400 - {6, "R2_w", "pkt(r=8)"}, 401 - {7, "R6_w", "var_off=(0x0; 0x3fc)"}, 400 + {6, "R2", "pkt(r=8)"}, 401 + {7, "R6", "var_off=(0x0; 0x3fc)"}, 402 402 /* Adding 14 makes R6 be (4n+2) */ 403 - {8, "R6_w", "var_off=(0x2; 0x7fc)"}, 403 + {8, "R6", "var_off=(0x2; 0x7fc)"}, 404 404 /* Packet pointer has (4n+2) offset */ 405 - {11, "R5_w", "var_off=(0x2; 0x7fc)"}, 405 + {11, "R5", "var_off=(0x2; 0x7fc)"}, 406 406 {12, "R4", "var_off=(0x2; 0x7fc)"}, 407 407 /* At the time the word size load is performed from R5, 408 408 * its total fixed offset is NET_IP_ALIGN + reg->off (0) ··· 414 414 /* Newly read value in R6 was shifted left by 2, so has 415 415 * known alignment of 4. 416 416 */ 417 - {17, "R6_w", "var_off=(0x0; 0x3fc)"}, 417 + {17, "R6", "var_off=(0x0; 0x3fc)"}, 418 418 /* Added (4n) to packet pointer's (4n+2) var_off, giving 419 419 * another (4n+2). 420 420 */ 421 - {19, "R5_w", "var_off=(0x2; 0xffc)"}, 421 + {19, "R5", "var_off=(0x2; 0xffc)"}, 422 422 {20, "R4", "var_off=(0x2; 0xffc)"}, 423 423 /* At the time the word size load is performed from R5, 424 424 * its total fixed offset is NET_IP_ALIGN + reg->off (0) ··· 459 459 .prog_type = BPF_PROG_TYPE_SCHED_CLS, 460 460 .result = REJECT, 461 461 .matches = { 462 - {3, "R5_w", "pkt_end()"}, 462 + {3, "R5", "pkt_end()"}, 463 463 /* (ptr - ptr) << 2 == unknown, (4n) */ 464 - {5, "R5_w", "var_off=(0x0; 0xfffffffffffffffc)"}, 464 + {5, "R5", "var_off=(0x0; 0xfffffffffffffffc)"}, 465 465 /* (4n) + 14 == (4n+2). We blow our bounds, because 466 466 * the add could overflow. 467 467 */ 468 - {6, "R5_w", "var_off=(0x2; 0xfffffffffffffffc)"}, 468 + {6, "R5", "var_off=(0x2; 0xfffffffffffffffc)"}, 469 469 /* Checked s>=0 */ 470 470 {9, "R5", "var_off=(0x2; 0x7ffffffffffffffc)"}, 471 471 /* packet pointer + nonnegative (4n+2) */ 472 - {11, "R6_w", "var_off=(0x2; 0x7ffffffffffffffc)"}, 473 - {12, "R4_w", "var_off=(0x2; 0x7ffffffffffffffc)"}, 472 + {11, "R6", "var_off=(0x2; 0x7ffffffffffffffc)"}, 473 + {12, "R4", "var_off=(0x2; 0x7ffffffffffffffc)"}, 474 474 /* NET_IP_ALIGN + (4n+2) == (4n), alignment is fine. 475 475 * We checked the bounds, but it might have been able 476 476 * to overflow if the packet pointer started in the ··· 478 478 * So we did not get a 'range' on R6, and the access 479 479 * attempt will fail. 480 480 */ 481 - {15, "R6_w", "var_off=(0x2; 0x7ffffffffffffffc)"}, 481 + {15, "R6", "var_off=(0x2; 0x7ffffffffffffffc)"}, 482 482 } 483 483 }, 484 484 { ··· 513 513 /* Calculated offset in R6 has unknown value, but known 514 514 * alignment of 4. 515 515 */ 516 - {6, "R2_w", "pkt(r=8)"}, 517 - {8, "R6_w", "var_off=(0x0; 0x3fc)"}, 516 + {6, "R2", "pkt(r=8)"}, 517 + {8, "R6", "var_off=(0x0; 0x3fc)"}, 518 518 /* Adding 14 makes R6 be (4n+2) */ 519 - {9, "R6_w", "var_off=(0x2; 0x7fc)"}, 519 + {9, "R6", "var_off=(0x2; 0x7fc)"}, 520 520 /* New unknown value in R7 is (4n) */ 521 - {10, "R7_w", "var_off=(0x0; 0x3fc)"}, 521 + {10, "R7", "var_off=(0x0; 0x3fc)"}, 522 522 /* Subtracting it from R6 blows our unsigned bounds */ 523 523 {11, "R6", "var_off=(0x2; 0xfffffffffffffffc)"}, 524 524 /* Checked s>= 0 */ ··· 566 566 /* Calculated offset in R6 has unknown value, but known 567 567 * alignment of 4. 568 568 */ 569 - {6, "R2_w", "pkt(r=8)"}, 570 - {9, "R6_w", "var_off=(0x0; 0x3c)"}, 569 + {6, "R2", "pkt(r=8)"}, 570 + {9, "R6", "var_off=(0x0; 0x3c)"}, 571 571 /* Adding 14 makes R6 be (4n+2) */ 572 - {10, "R6_w", "var_off=(0x2; 0x7c)"}, 572 + {10, "R6", "var_off=(0x2; 0x7c)"}, 573 573 /* Subtracting from packet pointer overflows ubounds */ 574 - {13, "R5_w", "var_off=(0xffffffffffffff82; 0x7c)"}, 574 + {13, "R5", "var_off=(0xffffffffffffff82; 0x7c)"}, 575 575 /* New unknown value in R7 is (4n), >= 76 */ 576 - {14, "R7_w", "var_off=(0x0; 0x7fc)"}, 576 + {14, "R7", "var_off=(0x0; 0x7fc)"}, 577 577 /* Adding it to packet pointer gives nice bounds again */ 578 - {16, "R5_w", "var_off=(0x2; 0x7fc)"}, 578 + {16, "R5", "var_off=(0x2; 0x7fc)"}, 579 579 /* At the time the word size load is performed from R5, 580 580 * its total fixed offset is NET_IP_ALIGN + reg->off (0) 581 581 * which is 2. Then the variable offset is (4n+2), so
+125
tools/testing/selftests/bpf/prog_tests/prog_tests_framework.c
··· 54 54 return; 55 55 clear_test_state(state); 56 56 } 57 + 58 + static void dummy_emit(const char *buf, bool force) {} 59 + 60 + void test_prog_tests_framework_expected_msgs(void) 61 + { 62 + struct expected_msgs msgs; 63 + int i, j, error_cnt; 64 + const struct { 65 + const char *name; 66 + const char *log; 67 + const char *expected; 68 + struct expect_msg *pats; 69 + } cases[] = { 70 + { 71 + .name = "simple-ok", 72 + .log = "aaabbbccc", 73 + .pats = (struct expect_msg[]) { 74 + { .substr = "aaa" }, 75 + { .substr = "ccc" }, 76 + {} 77 + } 78 + }, 79 + { 80 + .name = "simple-fail", 81 + .log = "aaabbbddd", 82 + .expected = "MATCHED SUBSTR: 'aaa'\n" 83 + "EXPECTED SUBSTR: 'ccc'\n", 84 + .pats = (struct expect_msg[]) { 85 + { .substr = "aaa" }, 86 + { .substr = "ccc" }, 87 + {} 88 + } 89 + }, 90 + { 91 + .name = "negative-ok-mid", 92 + .log = "aaabbbccc", 93 + .pats = (struct expect_msg[]) { 94 + { .substr = "aaa" }, 95 + { .substr = "foo", .negative = true }, 96 + { .substr = "bar", .negative = true }, 97 + { .substr = "ccc" }, 98 + {} 99 + } 100 + }, 101 + { 102 + .name = "negative-ok-tail", 103 + .log = "aaabbbccc", 104 + .pats = (struct expect_msg[]) { 105 + { .substr = "aaa" }, 106 + { .substr = "foo", .negative = true }, 107 + {} 108 + } 109 + }, 110 + { 111 + .name = "negative-ok-head", 112 + .log = "aaabbbccc", 113 + .pats = (struct expect_msg[]) { 114 + { .substr = "foo", .negative = true }, 115 + { .substr = "ccc" }, 116 + {} 117 + } 118 + }, 119 + { 120 + .name = "negative-fail-head", 121 + .log = "aaabbbccc", 122 + .expected = "UNEXPECTED SUBSTR: 'aaa'\n", 123 + .pats = (struct expect_msg[]) { 124 + { .substr = "aaa", .negative = true }, 125 + { .substr = "bbb" }, 126 + {} 127 + } 128 + }, 129 + { 130 + .name = "negative-fail-tail", 131 + .log = "aaabbbccc", 132 + .expected = "UNEXPECTED SUBSTR: 'ccc'\n", 133 + .pats = (struct expect_msg[]) { 134 + { .substr = "bbb" }, 135 + { .substr = "ccc", .negative = true }, 136 + {} 137 + } 138 + }, 139 + { 140 + .name = "negative-fail-mid-1", 141 + .log = "aaabbbccc", 142 + .expected = "UNEXPECTED SUBSTR: 'bbb'\n", 143 + .pats = (struct expect_msg[]) { 144 + { .substr = "aaa" }, 145 + { .substr = "bbb", .negative = true }, 146 + { .substr = "ccc" }, 147 + {} 148 + } 149 + }, 150 + { 151 + .name = "negative-fail-mid-2", 152 + .log = "aaabbb222ccc", 153 + .expected = "UNEXPECTED SUBSTR: '222'\n", 154 + .pats = (struct expect_msg[]) { 155 + { .substr = "aaa" }, 156 + { .substr = "222", .negative = true }, 157 + { .substr = "bbb", .negative = true }, 158 + { .substr = "ccc" }, 159 + {} 160 + } 161 + } 162 + }; 163 + 164 + for (i = 0; i < ARRAY_SIZE(cases); i++) { 165 + if (test__start_subtest(cases[i].name)) { 166 + error_cnt = env.subtest_state->error_cnt; 167 + msgs.patterns = cases[i].pats; 168 + msgs.cnt = 0; 169 + for (j = 0; cases[i].pats[j].substr; j++) 170 + msgs.cnt++; 171 + validate_msgs(cases[i].log, &msgs, dummy_emit); 172 + fflush(stderr); 173 + env.subtest_state->error_cnt = error_cnt; 174 + if (cases[i].expected) 175 + ASSERT_HAS_SUBSTR(env.subtest_state->log_buf, cases[i].expected, "expected output"); 176 + else 177 + ASSERT_STREQ(env.subtest_state->log_buf, "", "expected no output"); 178 + test__end_subtest(); 179 + } 180 + } 181 + }
+6 -6
tools/testing/selftests/bpf/prog_tests/spin_lock.c
··· 13 13 const char *err_msg; 14 14 } spin_lock_fail_tests[] = { 15 15 { "lock_id_kptr_preserve", 16 - "5: (bf) r1 = r0 ; R0_w=ptr_foo(id=2,ref_obj_id=2) " 17 - "R1_w=ptr_foo(id=2,ref_obj_id=2) refs=2\n6: (85) call bpf_this_cpu_ptr#154\n" 16 + "5: (bf) r1 = r0 ; R0=ptr_foo(id=2,ref_obj_id=2) " 17 + "R1=ptr_foo(id=2,ref_obj_id=2) refs=2\n6: (85) call bpf_this_cpu_ptr#154\n" 18 18 "R1 type=ptr_ expected=percpu_ptr_" }, 19 19 { "lock_id_global_zero", 20 - "; R1_w=map_value(map=.data.A,ks=4,vs=4)\n2: (85) call bpf_this_cpu_ptr#154\n" 20 + "; R1=map_value(map=.data.A,ks=4,vs=4)\n2: (85) call bpf_this_cpu_ptr#154\n" 21 21 "R1 type=map_value expected=percpu_ptr_" }, 22 22 { "lock_id_mapval_preserve", 23 23 "[0-9]\\+: (bf) r1 = r0 ;" 24 - " R0_w=map_value(id=1,map=array_map,ks=4,vs=8)" 25 - " R1_w=map_value(id=1,map=array_map,ks=4,vs=8)\n" 24 + " R0=map_value(id=1,map=array_map,ks=4,vs=8)" 25 + " R1=map_value(id=1,map=array_map,ks=4,vs=8)\n" 26 26 "[0-9]\\+: (85) call bpf_this_cpu_ptr#154\n" 27 27 "R1 type=map_value expected=percpu_ptr_" }, 28 28 { "lock_id_innermapval_preserve", 29 29 "[0-9]\\+: (bf) r1 = r0 ;" 30 30 " R0=map_value(id=2,ks=4,vs=8)" 31 - " R1_w=map_value(id=2,ks=4,vs=8)\n" 31 + " R1=map_value(id=2,ks=4,vs=8)\n" 32 32 "[0-9]\\+: (85) call bpf_this_cpu_ptr#154\n" 33 33 "R1 type=map_value expected=percpu_ptr_" }, 34 34 { "lock_id_mismatch_kptr_kptr", "bpf_spin_unlock of different lock" },
+22 -22
tools/testing/selftests/bpf/prog_tests/test_veristat.c
··· 75 75 " -vl2 > %s", fix->veristat, fix->tmpfile); 76 76 77 77 read(fix->fd, fix->output, fix->sz); 78 - __CHECK_STR("_w=0xf000000000000001 ", "var_s64 = 0xf000000000000001"); 79 - __CHECK_STR("_w=0xfedcba9876543210 ", "var_u64 = 0xfedcba9876543210"); 80 - __CHECK_STR("_w=0x80000000 ", "var_s32 = -0x80000000"); 81 - __CHECK_STR("_w=0x76543210 ", "var_u32 = 0x76543210"); 82 - __CHECK_STR("_w=0x8000 ", "var_s16 = -32768"); 83 - __CHECK_STR("_w=0xecec ", "var_u16 = 60652"); 84 - __CHECK_STR("_w=128 ", "var_s8 = -128"); 85 - __CHECK_STR("_w=255 ", "var_u8 = 255"); 86 - __CHECK_STR("_w=11 ", "var_ea = EA2"); 87 - __CHECK_STR("_w=12 ", "var_eb = EB2"); 88 - __CHECK_STR("_w=13 ", "var_ec = EC2"); 89 - __CHECK_STR("_w=1 ", "var_b = 1"); 90 - __CHECK_STR("_w=170 ", "struct1[2].struct2[1][2].u.var_u8[2]=170"); 91 - __CHECK_STR("_w=0xaaaa ", "union1.var_u16 = 0xaaaa"); 92 - __CHECK_STR("_w=171 ", "arr[3]= 171"); 93 - __CHECK_STR("_w=172 ", "arr[EA2] =172"); 94 - __CHECK_STR("_w=10 ", "enum_arr[EC2]=EA3"); 95 - __CHECK_STR("_w=173 ", "matrix[31][7][11]=173"); 96 - __CHECK_STR("_w=174 ", "struct1[2].struct2[1][2].u.mat[5][3]=174"); 97 - __CHECK_STR("_w=175 ", "struct11[7][5].struct2[0][1].u.mat[3][0]=175"); 78 + __CHECK_STR("=0xf000000000000001 ", "var_s64 = 0xf000000000000001"); 79 + __CHECK_STR("=0xfedcba9876543210 ", "var_u64 = 0xfedcba9876543210"); 80 + __CHECK_STR("=0x80000000 ", "var_s32 = -0x80000000"); 81 + __CHECK_STR("=0x76543210 ", "var_u32 = 0x76543210"); 82 + __CHECK_STR("=0x8000 ", "var_s16 = -32768"); 83 + __CHECK_STR("=0xecec ", "var_u16 = 60652"); 84 + __CHECK_STR("=128 ", "var_s8 = -128"); 85 + __CHECK_STR("=255 ", "var_u8 = 255"); 86 + __CHECK_STR("=11 ", "var_ea = EA2"); 87 + __CHECK_STR("=12 ", "var_eb = EB2"); 88 + __CHECK_STR("=13 ", "var_ec = EC2"); 89 + __CHECK_STR("=1 ", "var_b = 1"); 90 + __CHECK_STR("=170 ", "struct1[2].struct2[1][2].u.var_u8[2]=170"); 91 + __CHECK_STR("=0xaaaa ", "union1.var_u16 = 0xaaaa"); 92 + __CHECK_STR("=171 ", "arr[3]= 171"); 93 + __CHECK_STR("=172 ", "arr[EA2] =172"); 94 + __CHECK_STR("=10 ", "enum_arr[EC2]=EA3"); 95 + __CHECK_STR("=173 ", "matrix[31][7][11]=173"); 96 + __CHECK_STR("=174 ", "struct1[2].struct2[1][2].u.mat[5][3]=174"); 97 + __CHECK_STR("=175 ", "struct11[7][5].struct2[0][1].u.mat[3][0]=175"); 98 98 99 99 out: 100 100 teardown_fixture(fix); ··· 117 117 SYS(out, "%s set_global_vars.bpf.o -G \"@%s\" -vl2 > %s", 118 118 fix->veristat, input_file, fix->tmpfile); 119 119 read(fix->fd, fix->output, fix->sz); 120 - __CHECK_STR("_w=0x8000 ", "var_s16 = -32768"); 121 - __CHECK_STR("_w=0xecec ", "var_u16 = 60652"); 120 + __CHECK_STR("=0x8000 ", "var_s16 = -32768"); 121 + __CHECK_STR("=0xecec ", "var_u16 = 60652"); 122 122 123 123 out: 124 124 close(fd);
+2
tools/testing/selftests/bpf/prog_tests/verifier.c
··· 46 46 #include "verifier_ldsx.skel.h" 47 47 #include "verifier_leak_ptr.skel.h" 48 48 #include "verifier_linked_scalars.skel.h" 49 + #include "verifier_live_stack.skel.h" 49 50 #include "verifier_load_acquire.skel.h" 50 51 #include "verifier_loops1.skel.h" 51 52 #include "verifier_lwt.skel.h" ··· 185 184 void test_verifier_ldsx(void) { RUN(verifier_ldsx); } 186 185 void test_verifier_leak_ptr(void) { RUN(verifier_leak_ptr); } 187 186 void test_verifier_linked_scalars(void) { RUN(verifier_linked_scalars); } 187 + void test_verifier_live_stack(void) { RUN(verifier_live_stack); } 188 188 void test_verifier_loops1(void) { RUN(verifier_loops1); } 189 189 void test_verifier_lwt(void) { RUN(verifier_lwt); } 190 190 void test_verifier_map_in_map(void) { RUN(verifier_map_in_map); }
+9
tools/testing/selftests/bpf/progs/bpf_misc.h
··· 33 33 * e.g. "foo{{[0-9]+}}" matches strings like "foo007". 34 34 * Extended POSIX regular expression syntax is allowed 35 35 * inside the brackets. 36 + * __not_msg Message not expected to be found in verifier log. 37 + * If __msg_not is situated between __msg tags 38 + * framework matches __msg tags first, and then 39 + * checks that __msg_not is not present in a portion of 40 + * a log between bracketing __msg tags. 41 + * Same regex syntax as for __msg is supported. 36 42 * __msg_unpriv Same as __msg but for unprivileged mode. 43 + * __not_msg_unpriv Same as __not_msg but for unprivileged mode. 37 44 * 38 45 * __stderr Message expected to be found in bpf stderr stream. The 39 46 * same regex rules apply like __msg. ··· 128 121 * __caps_unpriv Specify the capabilities that should be set when running the test. 129 122 */ 130 123 #define __msg(msg) __attribute__((btf_decl_tag("comment:test_expect_msg=" XSTR(__COUNTER__) "=" msg))) 124 + #define __not_msg(msg) __attribute__((btf_decl_tag("comment:test_expect_not_msg=" XSTR(__COUNTER__) "=" msg))) 131 125 #define __xlated(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated=" XSTR(__COUNTER__) "=" msg))) 132 126 #define __jited(msg) __attribute__((btf_decl_tag("comment:test_jited=" XSTR(__COUNTER__) "=" msg))) 133 127 #define __failure __attribute__((btf_decl_tag("comment:test_expect_failure"))) 134 128 #define __success __attribute__((btf_decl_tag("comment:test_expect_success"))) 135 129 #define __description(desc) __attribute__((btf_decl_tag("comment:test_description=" desc))) 136 130 #define __msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_msg_unpriv=" XSTR(__COUNTER__) "=" msg))) 131 + #define __not_msg_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_not_msg_unpriv=" XSTR(__COUNTER__) "=" msg))) 137 132 #define __xlated_unpriv(msg) __attribute__((btf_decl_tag("comment:test_expect_xlated_unpriv=" XSTR(__COUNTER__) "=" msg))) 138 133 #define __jited_unpriv(msg) __attribute__((btf_decl_tag("comment:test_jited=" XSTR(__COUNTER__) "=" msg))) 139 134 #define __failure_unpriv __attribute__((btf_decl_tag("comment:test_expect_failure_unpriv")))
+17 -17
tools/testing/selftests/bpf/progs/exceptions_assert.c
··· 18 18 return *(u64 *)num; \ 19 19 } 20 20 21 - __msg(": R0_w=0xffffffff80000000") 21 + __msg(": R0=0xffffffff80000000") 22 22 check_assert(s64, ==, eq_int_min, INT_MIN); 23 - __msg(": R0_w=0x7fffffff") 23 + __msg(": R0=0x7fffffff") 24 24 check_assert(s64, ==, eq_int_max, INT_MAX); 25 - __msg(": R0_w=0") 25 + __msg(": R0=0") 26 26 check_assert(s64, ==, eq_zero, 0); 27 - __msg(": R0_w=0x8000000000000000 R1_w=0x8000000000000000") 27 + __msg(": R0=0x8000000000000000 R1=0x8000000000000000") 28 28 check_assert(s64, ==, eq_llong_min, LLONG_MIN); 29 - __msg(": R0_w=0x7fffffffffffffff R1_w=0x7fffffffffffffff") 29 + __msg(": R0=0x7fffffffffffffff R1=0x7fffffffffffffff") 30 30 check_assert(s64, ==, eq_llong_max, LLONG_MAX); 31 31 32 - __msg(": R0_w=scalar(id=1,smax=0x7ffffffe)") 32 + __msg(": R0=scalar(id=1,smax=0x7ffffffe)") 33 33 check_assert(s64, <, lt_pos, INT_MAX); 34 - __msg(": R0_w=scalar(id=1,smax=-1,umin=0x8000000000000000,var_off=(0x8000000000000000; 0x7fffffffffffffff))") 34 + __msg(": R0=scalar(id=1,smax=-1,umin=0x8000000000000000,var_off=(0x8000000000000000; 0x7fffffffffffffff))") 35 35 check_assert(s64, <, lt_zero, 0); 36 - __msg(": R0_w=scalar(id=1,smax=0xffffffff7fffffff") 36 + __msg(": R0=scalar(id=1,smax=0xffffffff7fffffff") 37 37 check_assert(s64, <, lt_neg, INT_MIN); 38 38 39 - __msg(": R0_w=scalar(id=1,smax=0x7fffffff)") 39 + __msg(": R0=scalar(id=1,smax=0x7fffffff)") 40 40 check_assert(s64, <=, le_pos, INT_MAX); 41 - __msg(": R0_w=scalar(id=1,smax=0)") 41 + __msg(": R0=scalar(id=1,smax=0)") 42 42 check_assert(s64, <=, le_zero, 0); 43 - __msg(": R0_w=scalar(id=1,smax=0xffffffff80000000") 43 + __msg(": R0=scalar(id=1,smax=0xffffffff80000000") 44 44 check_assert(s64, <=, le_neg, INT_MIN); 45 45 46 - __msg(": R0_w=scalar(id=1,smin=umin=0x80000000,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 46 + __msg(": R0=scalar(id=1,smin=umin=0x80000000,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 47 47 check_assert(s64, >, gt_pos, INT_MAX); 48 - __msg(": R0_w=scalar(id=1,smin=umin=1,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 48 + __msg(": R0=scalar(id=1,smin=umin=1,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 49 49 check_assert(s64, >, gt_zero, 0); 50 - __msg(": R0_w=scalar(id=1,smin=0xffffffff80000001") 50 + __msg(": R0=scalar(id=1,smin=0xffffffff80000001") 51 51 check_assert(s64, >, gt_neg, INT_MIN); 52 52 53 - __msg(": R0_w=scalar(id=1,smin=umin=0x7fffffff,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 53 + __msg(": R0=scalar(id=1,smin=umin=0x7fffffff,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 54 54 check_assert(s64, >=, ge_pos, INT_MAX); 55 - __msg(": R0_w=scalar(id=1,smin=0,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 55 + __msg(": R0=scalar(id=1,smin=0,umax=0x7fffffffffffffff,var_off=(0x0; 0x7fffffffffffffff))") 56 56 check_assert(s64, >=, ge_zero, 0); 57 - __msg(": R0_w=scalar(id=1,smin=0xffffffff80000000") 57 + __msg(": R0=scalar(id=1,smin=0xffffffff80000000") 58 58 check_assert(s64, >=, ge_neg, INT_MIN); 59 59 60 60 SEC("?tc")
+2 -2
tools/testing/selftests/bpf/progs/iters_state_safety.c
··· 30 30 31 31 SEC("?raw_tp") 32 32 __success __log_level(2) 33 - __msg("fp-8_w=iter_num(ref_id=1,state=active,depth=0)") 33 + __msg("fp-8=iter_num(ref_id=1,state=active,depth=0)") 34 34 int create_and_destroy(void *ctx) 35 35 { 36 36 struct bpf_iter_num iter; ··· 196 196 197 197 SEC("?raw_tp") 198 198 __success __log_level(2) 199 - __msg("fp-8_w=iter_num(ref_id=1,state=active,depth=0)") 199 + __msg("fp-8=iter_num(ref_id=1,state=active,depth=0)") 200 200 int valid_stack_reuse(void *ctx) 201 201 { 202 202 struct bpf_iter_num iter;
+3 -3
tools/testing/selftests/bpf/progs/iters_testmod_seq.c
··· 20 20 21 21 SEC("raw_tp/sys_enter") 22 22 __success __log_level(2) 23 - __msg("fp-16_w=iter_testmod_seq(ref_id=1,state=active,depth=0)") 23 + __msg("fp-16=iter_testmod_seq(ref_id=1,state=active,depth=0)") 24 24 __msg("fp-16=iter_testmod_seq(ref_id=1,state=drained,depth=0)") 25 25 __msg("call bpf_iter_testmod_seq_destroy") 26 26 int testmod_seq_empty(const void *ctx) ··· 38 38 39 39 SEC("raw_tp/sys_enter") 40 40 __success __log_level(2) 41 - __msg("fp-16_w=iter_testmod_seq(ref_id=1,state=active,depth=0)") 41 + __msg("fp-16=iter_testmod_seq(ref_id=1,state=active,depth=0)") 42 42 __msg("fp-16=iter_testmod_seq(ref_id=1,state=drained,depth=0)") 43 43 __msg("call bpf_iter_testmod_seq_destroy") 44 44 int testmod_seq_full(const void *ctx) ··· 58 58 59 59 SEC("raw_tp/sys_enter") 60 60 __success __log_level(2) 61 - __msg("fp-16_w=iter_testmod_seq(ref_id=1,state=active,depth=0)") 61 + __msg("fp-16=iter_testmod_seq(ref_id=1,state=active,depth=0)") 62 62 __msg("fp-16=iter_testmod_seq(ref_id=1,state=drained,depth=0)") 63 63 __msg("call bpf_iter_testmod_seq_destroy") 64 64 int testmod_seq_truncated(const void *ctx)
+2 -2
tools/testing/selftests/bpf/progs/mem_rdonly_untrusted.c
··· 8 8 SEC("tp_btf/sys_enter") 9 9 __success 10 10 __log_level(2) 11 - __msg("r8 = *(u64 *)(r7 +0) ; R7_w=ptr_nameidata(off={{[0-9]+}}) R8_w=rdonly_untrusted_mem(sz=0)") 12 - __msg("r9 = *(u8 *)(r8 +0) ; R8_w=rdonly_untrusted_mem(sz=0) R9_w=scalar") 11 + __msg("r8 = *(u64 *)(r7 +0) ; R7=ptr_nameidata(off={{[0-9]+}}) R8=rdonly_untrusted_mem(sz=0)") 12 + __msg("r9 = *(u8 *)(r8 +0) ; R8=rdonly_untrusted_mem(sz=0) R9=scalar") 13 13 int btf_id_to_ptr_mem(void *ctx) 14 14 { 15 15 struct task_struct *task;
+19 -19
tools/testing/selftests/bpf/progs/verifier_bounds.c
··· 926 926 SEC("socket") 927 927 __description("bounds check for non const xor src dst") 928 928 __success __log_level(2) 929 - __msg("5: (af) r0 ^= r6 ; R0_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=431,var_off=(0x0; 0x1af))") 929 + __msg("5: (af) r0 ^= r6 ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=431,var_off=(0x0; 0x1af))") 930 930 __naked void non_const_xor_src_dst(void) 931 931 { 932 932 asm volatile (" \ ··· 947 947 SEC("socket") 948 948 __description("bounds check for non const or src dst") 949 949 __success __log_level(2) 950 - __msg("5: (4f) r0 |= r6 ; R0_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=431,var_off=(0x0; 0x1af))") 950 + __msg("5: (4f) r0 |= r6 ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=431,var_off=(0x0; 0x1af))") 951 951 __naked void non_const_or_src_dst(void) 952 952 { 953 953 asm volatile (" \ ··· 968 968 SEC("socket") 969 969 __description("bounds check for non const mul regs") 970 970 __success __log_level(2) 971 - __msg("5: (2f) r0 *= r6 ; R0_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=3825,var_off=(0x0; 0xfff))") 971 + __msg("5: (2f) r0 *= r6 ; R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=3825,var_off=(0x0; 0xfff))") 972 972 __naked void non_const_mul_regs(void) 973 973 { 974 974 asm volatile (" \ ··· 1241 1241 SEC("tc") 1242 1242 __description("multiply mixed sign bounds. test 1") 1243 1243 __success __log_level(2) 1244 - __msg("r6 *= r7 {{.*}}; R6_w=scalar(smin=umin=0x1bc16d5cd4927ee1,smax=umax=0x1bc16d674ec80000,smax32=0x7ffffeff,umax32=0xfffffeff,var_off=(0x1bc16d4000000000; 0x3ffffffeff))") 1244 + __msg("r6 *= r7 {{.*}}; R6=scalar(smin=umin=0x1bc16d5cd4927ee1,smax=umax=0x1bc16d674ec80000,smax32=0x7ffffeff,umax32=0xfffffeff,var_off=(0x1bc16d4000000000; 0x3ffffffeff))") 1245 1245 __naked void mult_mixed0_sign(void) 1246 1246 { 1247 1247 asm volatile ( ··· 1264 1264 SEC("tc") 1265 1265 __description("multiply mixed sign bounds. test 2") 1266 1266 __success __log_level(2) 1267 - __msg("r6 *= r7 {{.*}}; R6_w=scalar(smin=smin32=-100,smax=smax32=200)") 1267 + __msg("r6 *= r7 {{.*}}; R6=scalar(smin=smin32=-100,smax=smax32=200)") 1268 1268 __naked void mult_mixed1_sign(void) 1269 1269 { 1270 1270 asm volatile ( ··· 1287 1287 SEC("tc") 1288 1288 __description("multiply negative bounds") 1289 1289 __success __log_level(2) 1290 - __msg("r6 *= r7 {{.*}}; R6_w=scalar(smin=umin=smin32=umin32=0x3ff280b0,smax=umax=smax32=umax32=0x3fff0001,var_off=(0x3ff00000; 0xf81ff))") 1290 + __msg("r6 *= r7 {{.*}}; R6=scalar(smin=umin=smin32=umin32=0x3ff280b0,smax=umax=smax32=umax32=0x3fff0001,var_off=(0x3ff00000; 0xf81ff))") 1291 1291 __naked void mult_sign_bounds(void) 1292 1292 { 1293 1293 asm volatile ( ··· 1311 1311 SEC("tc") 1312 1312 __description("multiply bounds that don't cross signed boundary") 1313 1313 __success __log_level(2) 1314 - __msg("r8 *= r6 {{.*}}; R6_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=11,var_off=(0x0; 0xb)) R8_w=scalar(smin=0,smax=umax=0x7b96bb0a94a3a7cd,var_off=(0x0; 0x7fffffffffffffff))") 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 1315 __naked void mult_no_sign_crossing(void) 1316 1316 { 1317 1317 asm volatile ( ··· 1331 1331 SEC("tc") 1332 1332 __description("multiplication overflow, result in unbounded reg. test 1") 1333 1333 __success __log_level(2) 1334 - __msg("r6 *= r7 {{.*}}; R6_w=scalar()") 1334 + __msg("r6 *= r7 {{.*}}; R6=scalar()") 1335 1335 __naked void mult_unsign_ovf(void) 1336 1336 { 1337 1337 asm volatile ( ··· 1353 1353 SEC("tc") 1354 1354 __description("multiplication overflow, result in unbounded reg. test 2") 1355 1355 __success __log_level(2) 1356 - __msg("r6 *= r7 {{.*}}; R6_w=scalar()") 1356 + __msg("r6 *= r7 {{.*}}; R6=scalar()") 1357 1357 __naked void mult_sign_ovf(void) 1358 1358 { 1359 1359 asm volatile ( ··· 1376 1376 SEC("socket") 1377 1377 __description("64-bit addition, all outcomes overflow") 1378 1378 __success __log_level(2) 1379 - __msg("5: (0f) r3 += r3 {{.*}} R3_w=scalar(umin=0x4000000000000000,umax=0xfffffffffffffffe)") 1379 + __msg("5: (0f) r3 += r3 {{.*}} R3=scalar(umin=0x4000000000000000,umax=0xfffffffffffffffe)") 1380 1380 __retval(0) 1381 1381 __naked void add64_full_overflow(void) 1382 1382 { ··· 1396 1396 SEC("socket") 1397 1397 __description("64-bit addition, partial overflow, result in unbounded reg") 1398 1398 __success __log_level(2) 1399 - __msg("4: (0f) r3 += r3 {{.*}} R3_w=scalar()") 1399 + __msg("4: (0f) r3 += r3 {{.*}} R3=scalar()") 1400 1400 __retval(0) 1401 1401 __naked void add64_partial_overflow(void) 1402 1402 { ··· 1416 1416 SEC("socket") 1417 1417 __description("32-bit addition overflow, all outcomes overflow") 1418 1418 __success __log_level(2) 1419 - __msg("4: (0c) w3 += w3 {{.*}} R3_w=scalar(smin=umin=umin32=0x40000000,smax=umax=umax32=0xfffffffe,var_off=(0x0; 0xffffffff))") 1419 + __msg("4: (0c) w3 += w3 {{.*}} R3=scalar(smin=umin=umin32=0x40000000,smax=umax=umax32=0xfffffffe,var_off=(0x0; 0xffffffff))") 1420 1420 __retval(0) 1421 1421 __naked void add32_full_overflow(void) 1422 1422 { ··· 1436 1436 SEC("socket") 1437 1437 __description("32-bit addition, partial overflow, result in unbounded u32 bounds") 1438 1438 __success __log_level(2) 1439 - __msg("4: (0c) w3 += w3 {{.*}} R3_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))") 1439 + __msg("4: (0c) w3 += w3 {{.*}} R3=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))") 1440 1440 __retval(0) 1441 1441 __naked void add32_partial_overflow(void) 1442 1442 { ··· 1456 1456 SEC("socket") 1457 1457 __description("64-bit subtraction, all outcomes underflow") 1458 1458 __success __log_level(2) 1459 - __msg("6: (1f) r3 -= r1 {{.*}} R3_w=scalar(umin=1,umax=0x8000000000000000)") 1459 + __msg("6: (1f) r3 -= r1 {{.*}} R3=scalar(umin=1,umax=0x8000000000000000)") 1460 1460 __retval(0) 1461 1461 __naked void sub64_full_overflow(void) 1462 1462 { ··· 1477 1477 SEC("socket") 1478 1478 __description("64-bit subtraction, partial overflow, result in unbounded reg") 1479 1479 __success __log_level(2) 1480 - __msg("3: (1f) r3 -= r2 {{.*}} R3_w=scalar()") 1480 + __msg("3: (1f) r3 -= r2 {{.*}} R3=scalar()") 1481 1481 __retval(0) 1482 1482 __naked void sub64_partial_overflow(void) 1483 1483 { ··· 1496 1496 SEC("socket") 1497 1497 __description("32-bit subtraction overflow, all outcomes underflow") 1498 1498 __success __log_level(2) 1499 - __msg("5: (1c) w3 -= w1 {{.*}} R3_w=scalar(smin=umin=umin32=1,smax=umax=umax32=0x80000000,var_off=(0x0; 0xffffffff))") 1499 + __msg("5: (1c) w3 -= w1 {{.*}} R3=scalar(smin=umin=umin32=1,smax=umax=umax32=0x80000000,var_off=(0x0; 0xffffffff))") 1500 1500 __retval(0) 1501 1501 __naked void sub32_full_overflow(void) 1502 1502 { ··· 1517 1517 SEC("socket") 1518 1518 __description("32-bit subtraction, partial overflow, result in unbounded u32 bounds") 1519 1519 __success __log_level(2) 1520 - __msg("3: (1c) w3 -= w2 {{.*}} R3_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))") 1520 + __msg("3: (1c) w3 -= w2 {{.*}} R3=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))") 1521 1521 __retval(0) 1522 1522 __naked void sub32_partial_overflow(void) 1523 1523 { ··· 1617 1617 SEC("socket") 1618 1618 __description("bounds deduction cross sign boundary, positive overlap") 1619 1619 __success __log_level(2) __flag(BPF_F_TEST_REG_INVARIANTS) 1620 - __msg("3: (2d) if r0 > r1 {{.*}} R0_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=127,var_off=(0x0; 0x7f))") 1620 + __msg("3: (2d) if r0 > r1 {{.*}} R0=scalar(smin=smin32=0,smax=umax=smax32=umax32=127,var_off=(0x0; 0x7f))") 1621 1621 __retval(0) 1622 1622 __naked void bounds_deduct_positive_overlap(void) 1623 1623 { ··· 1650 1650 SEC("socket") 1651 1651 __description("bounds deduction cross sign boundary, two overlaps") 1652 1652 __failure __flag(BPF_F_TEST_REG_INVARIANTS) 1653 - __msg("3: (2d) if r0 > r1 {{.*}} R0_w=scalar(smin=smin32=-128,smax=smax32=127,umax=0xffffffffffffff80)") 1653 + __msg("3: (2d) if r0 > r1 {{.*}} R0=scalar(smin=smin32=-128,smax=smax32=127,umax=0xffffffffffffff80)") 1654 1654 __msg("frame pointer is read only") 1655 1655 __naked void bounds_deduct_two_overlaps(void) 1656 1656 {
+2 -2
tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c
··· 215 215 SEC("tp_btf/sys_enter") 216 216 __success 217 217 __log_level(2) 218 - __msg("r1 = {{.*}}; {{.*}}R1_w=trusted_ptr_task_struct()") 218 + __msg("r1 = {{.*}}; {{.*}}R1=trusted_ptr_task_struct()") 219 219 __msg("Func#1 ('subprog_untrusted') is global and assumed valid.") 220 220 __msg("Validating subprog_untrusted() func#1...") 221 221 __msg(": R1=untrusted_ptr_task_struct") ··· 278 278 SEC("tp_btf/sys_enter") 279 279 __success 280 280 __log_level(2) 281 - __msg("r1 = {{.*}}; {{.*}}R1_w=trusted_ptr_task_struct()") 281 + __msg("r1 = {{.*}}; {{.*}}R1=trusted_ptr_task_struct()") 282 282 __msg("Func#1 ('subprog_void_untrusted') is global and assumed valid.") 283 283 __msg("Validating subprog_void_untrusted() func#1...") 284 284 __msg(": R1=rdonly_untrusted_mem(sz=0)")
+1 -1
tools/testing/selftests/bpf/progs/verifier_ldsx.c
··· 65 65 SEC("socket") 66 66 __description("LDSX, S8 range checking, privileged") 67 67 __log_level(2) __success __retval(1) 68 - __msg("R1_w=scalar(smin=smin32=-128,smax=smax32=127)") 68 + __msg("R1=scalar(smin=smin32=-128,smax=smax32=127)") 69 69 __naked void ldsx_s8_range_priv(void) 70 70 { 71 71 asm volatile (
+294
tools/testing/selftests/bpf/progs/verifier_live_stack.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include <linux/bpf.h> 5 + #include <bpf/bpf_helpers.h> 6 + #include "bpf_misc.h" 7 + 8 + struct { 9 + __uint(type, BPF_MAP_TYPE_HASH); 10 + __uint(max_entries, 1); 11 + __type(key, int); 12 + __type(value, long long); 13 + } map SEC(".maps"); 14 + 15 + SEC("socket") 16 + __log_level(2) 17 + __msg("(0) frame 0 insn 2 +written -8") 18 + __msg("(0) frame 0 insn 1 +live -24") 19 + __msg("(0) frame 0 insn 1 +written -8") 20 + __msg("(0) frame 0 insn 0 +live -8,-24") 21 + __msg("(0) frame 0 insn 0 +written -8") 22 + __msg("(0) live stack update done in 2 iterations") 23 + __naked void simple_read_simple_write(void) 24 + { 25 + asm volatile ( 26 + "r1 = *(u64 *)(r10 - 8);" 27 + "r2 = *(u64 *)(r10 - 24);" 28 + "*(u64 *)(r10 - 8) = r1;" 29 + "r0 = 0;" 30 + "exit;" 31 + ::: __clobber_all); 32 + } 33 + 34 + SEC("socket") 35 + __log_level(2) 36 + __msg("(0) frame 0 insn 1 +live -8") 37 + __not_msg("(0) frame 0 insn 1 +written") 38 + __msg("(0) live stack update done in 2 iterations") 39 + __msg("(0) frame 0 insn 1 +live -16") 40 + __msg("(0) frame 0 insn 1 +written -32") 41 + __msg("(0) live stack update done in 2 iterations") 42 + __naked void read_write_join(void) 43 + { 44 + asm volatile ( 45 + "call %[bpf_get_prandom_u32];" 46 + "if r0 > 42 goto 1f;" 47 + "r0 = *(u64 *)(r10 - 8);" 48 + "*(u64 *)(r10 - 32) = r0;" 49 + "*(u64 *)(r10 - 40) = r0;" 50 + "exit;" 51 + "1:" 52 + "r0 = *(u64 *)(r10 - 16);" 53 + "*(u64 *)(r10 - 32) = r0;" 54 + "exit;" 55 + :: __imm(bpf_get_prandom_u32) 56 + : __clobber_all); 57 + } 58 + 59 + SEC("socket") 60 + __log_level(2) 61 + __msg("2: (25) if r0 > 0x2a goto pc+1") 62 + __msg("7: (95) exit") 63 + __msg("(0) frame 0 insn 2 +written -16") 64 + __msg("(0) live stack update done in 2 iterations") 65 + __msg("7: (95) exit") 66 + __not_msg("(0) frame 0 insn 2") 67 + __msg("(0) live stack update done in 1 iterations") 68 + __naked void must_write_not_same_slot(void) 69 + { 70 + asm volatile ( 71 + "call %[bpf_get_prandom_u32];" 72 + "r1 = -8;" 73 + "if r0 > 42 goto 1f;" 74 + "r1 = -16;" 75 + "1:" 76 + "r2 = r10;" 77 + "r2 += r1;" 78 + "*(u64 *)(r2 + 0) = r0;" 79 + "exit;" 80 + :: __imm(bpf_get_prandom_u32) 81 + : __clobber_all); 82 + } 83 + 84 + SEC("socket") 85 + __log_level(2) 86 + __msg("(0) frame 0 insn 0 +written -8,-16") 87 + __msg("(0) live stack update done in 2 iterations") 88 + __msg("(0) frame 0 insn 0 +written -8") 89 + __msg("(0) live stack update done in 2 iterations") 90 + __naked void must_write_not_same_type(void) 91 + { 92 + asm volatile ( 93 + "*(u64*)(r10 - 8) = 0;" 94 + "r2 = r10;" 95 + "r2 += -8;" 96 + "r1 = %[map] ll;" 97 + "call %[bpf_map_lookup_elem];" 98 + "if r0 != 0 goto 1f;" 99 + "r0 = r10;" 100 + "r0 += -16;" 101 + "1:" 102 + "*(u64 *)(r0 + 0) = 42;" 103 + "exit;" 104 + : 105 + : __imm(bpf_get_prandom_u32), 106 + __imm(bpf_map_lookup_elem), 107 + __imm_addr(map) 108 + : __clobber_all); 109 + } 110 + 111 + SEC("socket") 112 + __log_level(2) 113 + __msg("(2,4) frame 0 insn 4 +written -8") 114 + __msg("(2,4) live stack update done in 2 iterations") 115 + __msg("(0) frame 0 insn 2 +written -8") 116 + __msg("(0) live stack update done in 2 iterations") 117 + __naked void caller_stack_write(void) 118 + { 119 + asm volatile ( 120 + "r1 = r10;" 121 + "r1 += -8;" 122 + "call write_first_param;" 123 + "exit;" 124 + ::: __clobber_all); 125 + } 126 + 127 + static __used __naked void write_first_param(void) 128 + { 129 + asm volatile ( 130 + "*(u64 *)(r1 + 0) = 7;" 131 + "r0 = 0;" 132 + "exit;" 133 + ::: __clobber_all); 134 + } 135 + 136 + SEC("socket") 137 + __log_level(2) 138 + /* caller_stack_read() function */ 139 + __msg("2: .12345.... (85) call pc+4") 140 + __msg("5: .12345.... (85) call pc+1") 141 + __msg("6: 0......... (95) exit") 142 + /* read_first_param() function */ 143 + __msg("7: .1........ (79) r0 = *(u64 *)(r1 +0)") 144 + __msg("8: 0......... (95) exit") 145 + /* update for callsite at (2) */ 146 + __msg("(2,7) frame 0 insn 7 +live -8") 147 + __msg("(2,7) live stack update done in 2 iterations") 148 + __msg("(0) frame 0 insn 2 +live -8") 149 + __msg("(0) live stack update done in 2 iterations") 150 + /* update for callsite at (5) */ 151 + __msg("(5,7) frame 0 insn 7 +live -16") 152 + __msg("(5,7) live stack update done in 2 iterations") 153 + __msg("(0) frame 0 insn 5 +live -16") 154 + __msg("(0) live stack update done in 2 iterations") 155 + __naked void caller_stack_read(void) 156 + { 157 + asm volatile ( 158 + "r1 = r10;" 159 + "r1 += -8;" 160 + "call read_first_param;" 161 + "r1 = r10;" 162 + "r1 += -16;" 163 + "call read_first_param;" 164 + "exit;" 165 + ::: __clobber_all); 166 + } 167 + 168 + static __used __naked void read_first_param(void) 169 + { 170 + asm volatile ( 171 + "r0 = *(u64 *)(r1 + 0);" 172 + "exit;" 173 + ::: __clobber_all); 174 + } 175 + 176 + SEC("socket") 177 + __flag(BPF_F_TEST_STATE_FREQ) 178 + __log_level(2) 179 + /* read_first_param2() function */ 180 + __msg(" 9: .1........ (79) r0 = *(u64 *)(r1 +0)") 181 + __msg("10: .......... (b7) r0 = 0") 182 + __msg("11: 0......... (05) goto pc+0") 183 + __msg("12: 0......... (95) exit") 184 + /* 185 + * The purpose of the test is to check that checkpoint in 186 + * read_first_param2() stops path traversal. This will only happen if 187 + * verifier understands that fp[0]-8 at insn (12) is not alive. 188 + */ 189 + __msg("12: safe") 190 + __msg("processed 20 insns") 191 + __naked void caller_stack_pruning(void) 192 + { 193 + asm volatile ( 194 + "call %[bpf_get_prandom_u32];" 195 + "if r0 == 42 goto 1f;" 196 + "r0 = %[map] ll;" 197 + "1:" 198 + "*(u64 *)(r10 - 8) = r0;" 199 + "r1 = r10;" 200 + "r1 += -8;" 201 + /* 202 + * fp[0]-8 is either pointer to map or a scalar, 203 + * preventing state pruning at checkpoint created for call. 204 + */ 205 + "call read_first_param2;" 206 + "exit;" 207 + : 208 + : __imm(bpf_get_prandom_u32), 209 + __imm_addr(map) 210 + : __clobber_all); 211 + } 212 + 213 + static __used __naked void read_first_param2(void) 214 + { 215 + asm volatile ( 216 + "r0 = *(u64 *)(r1 + 0);" 217 + "r0 = 0;" 218 + /* 219 + * Checkpoint at goto +0 should fire, 220 + * as caller stack fp[0]-8 is not alive at this point. 221 + */ 222 + "goto +0;" 223 + "exit;" 224 + ::: __clobber_all); 225 + } 226 + 227 + SEC("socket") 228 + __flag(BPF_F_TEST_STATE_FREQ) 229 + __failure 230 + __msg("R1 type=scalar expected=map_ptr") 231 + __naked void caller_stack_pruning_callback(void) 232 + { 233 + asm volatile ( 234 + "r0 = %[map] ll;" 235 + "*(u64 *)(r10 - 8) = r0;" 236 + "r1 = 2;" 237 + "r2 = loop_cb ll;" 238 + "r3 = r10;" 239 + "r3 += -8;" 240 + "r4 = 0;" 241 + /* 242 + * fp[0]-8 is either pointer to map or a scalar, 243 + * preventing state pruning at checkpoint created for call. 244 + */ 245 + "call %[bpf_loop];" 246 + "r0 = 42;" 247 + "exit;" 248 + : 249 + : __imm(bpf_get_prandom_u32), 250 + __imm(bpf_loop), 251 + __imm_addr(map) 252 + : __clobber_all); 253 + } 254 + 255 + static __used __naked void loop_cb(void) 256 + { 257 + asm volatile ( 258 + /* 259 + * Checkpoint at function entry should not fire, as caller 260 + * stack fp[0]-8 is alive at this point. 261 + */ 262 + "r6 = r2;" 263 + "r1 = *(u64 *)(r6 + 0);" 264 + "*(u64*)(r10 - 8) = 7;" 265 + "r2 = r10;" 266 + "r2 += -8;" 267 + "call %[bpf_map_lookup_elem];" 268 + /* 269 + * This should stop verifier on a second loop iteration, 270 + * but only if verifier correctly maintains that fp[0]-8 271 + * is still alive. 272 + */ 273 + "*(u64 *)(r6 + 0) = 0;" 274 + "r0 = 0;" 275 + "exit;" 276 + : 277 + : __imm(bpf_map_lookup_elem), 278 + __imm(bpf_get_prandom_u32) 279 + : __clobber_all); 280 + } 281 + 282 + /* 283 + * Because of a bug in verifier.c:compute_postorder() 284 + * the program below overflowed traversal queue in that function. 285 + */ 286 + SEC("socket") 287 + __naked void syzbot_postorder_bug1(void) 288 + { 289 + asm volatile ( 290 + "r0 = 0;" 291 + "if r0 != 0 goto -1;" 292 + "exit;" 293 + ::: __clobber_all); 294 + }
+8 -8
tools/testing/selftests/bpf/progs/verifier_precision.c
··· 144 144 __success __log_level(2) 145 145 /* 146 146 * Without the bug fix there will be no history between "last_idx 3 first_idx 3" 147 - * and "parent state regs=" lines. "R0_w=6" parts are here to help anchor 147 + * and "parent state regs=" lines. "R0=6" parts are here to help anchor 148 148 * expected log messages to the one specific mark_chain_precision operation. 149 149 * 150 150 * This is quite fragile: if verifier checkpointing heuristic changes, this 151 151 * might need adjusting. 152 152 */ 153 - __msg("2: (07) r0 += 1 ; R0_w=6") 153 + __msg("2: (07) r0 += 1 ; R0=6") 154 154 __msg("3: (35) if r0 >= 0xa goto pc+1") 155 155 __msg("mark_precise: frame0: last_idx 3 first_idx 3 subseq_idx -1") 156 156 __msg("mark_precise: frame0: regs=r0 stack= before 2: (07) r0 += 1") 157 157 __msg("mark_precise: frame0: regs=r0 stack= before 1: (07) r0 += 1") 158 158 __msg("mark_precise: frame0: regs=r0 stack= before 4: (05) goto pc-4") 159 159 __msg("mark_precise: frame0: regs=r0 stack= before 3: (35) if r0 >= 0xa goto pc+1") 160 - __msg("mark_precise: frame0: parent state regs= stack=: R0_rw=P4") 161 - __msg("3: R0_w=6") 160 + __msg("mark_precise: frame0: parent state regs= stack=: R0=P4") 161 + __msg("3: R0=6") 162 162 __naked int state_loop_first_last_equal(void) 163 163 { 164 164 asm volatile ( ··· 233 233 234 234 SEC("lsm.s/socket_connect") 235 235 __success __log_level(2) 236 - __msg("0: (b7) r0 = 1 ; R0_w=1") 237 - __msg("1: (84) w0 = -w0 ; R0_w=0xffffffff") 236 + __msg("0: (b7) r0 = 1 ; R0=1") 237 + __msg("1: (84) w0 = -w0 ; R0=0xffffffff") 238 238 __msg("mark_precise: frame0: last_idx 2 first_idx 0 subseq_idx -1") 239 239 __msg("mark_precise: frame0: regs=r0 stack= before 1: (84) w0 = -w0") 240 240 __msg("mark_precise: frame0: regs=r0 stack= before 0: (b7) r0 = 1") ··· 268 268 269 269 SEC("lsm.s/socket_connect") 270 270 __success __log_level(2) 271 - __msg("0: (b7) r0 = 1 ; R0_w=1") 272 - __msg("1: (87) r0 = -r0 ; R0_w=-1") 271 + __msg("0: (b7) r0 = 1 ; R0=1") 272 + __msg("1: (87) r0 = -r0 ; R0=-1") 273 273 __msg("mark_precise: frame0: last_idx 2 first_idx 0 subseq_idx -1") 274 274 __msg("mark_precise: frame0: regs=r0 stack= before 1: (87) r0 = -r0") 275 275 __msg("mark_precise: frame0: regs=r0 stack= before 0: (b7) r0 = 1")
+5 -5
tools/testing/selftests/bpf/progs/verifier_scalar_ids.c
··· 353 353 * collect_linked_regs() can't tie more than 6 registers for a single insn. 354 354 */ 355 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") 356 + __msg("9: (bf) r6 = r6 ; R6=scalar(id=2") 357 357 /* check that r{0-5} are marked precise after 'if' */ 358 358 __msg("frame0: regs=r0 stack= before 8: (25) if r0 > 0x7 goto pc+0") 359 359 __msg("frame0: parent state regs=r0,r1,r2,r3,r4,r5 stack=:") ··· 779 779 __retval(0) 780 780 /* Check that verifier believes r1/r0 are zero at exit */ 781 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") 782 + __msg("4: (77) r1 >>= 32 ; R1=0") 783 + __msg("5: (bf) r0 = r1 ; R0=0 R1=0") 784 784 __msg("6: (95) exit") 785 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") 786 + __msg("4: (77) r1 >>= 32 ; R1=0") 787 + __msg("5: (bf) r0 = r1 ; R0=0 R1=0") 788 788 __msg("6: (95) exit") 789 789 /* Verify that statements to randomize upper half of r1 had not been 790 790 * generated.
+20 -20
tools/testing/selftests/bpf/progs/verifier_spill_fill.c
··· 506 506 __log_level(2) 507 507 __success 508 508 /* fp-8 is spilled IMPRECISE value zero (represented by a zero value fake reg) */ 509 - __msg("2: (7a) *(u64 *)(r10 -8) = 0 ; R10=fp0 fp-8_w=0") 509 + __msg("2: (7a) *(u64 *)(r10 -8) = 0 ; R10=fp0 fp-8=0") 510 510 /* but fp-16 is spilled IMPRECISE zero const reg */ 511 - __msg("4: (7b) *(u64 *)(r10 -16) = r0 ; R0_w=0 R10=fp0 fp-16_w=0") 511 + __msg("4: (7b) *(u64 *)(r10 -16) = r0 ; R0=0 R10=fp0 fp-16=0") 512 512 /* validate that assigning R2 from STACK_SPILL with zero value doesn't mark register 513 513 * precise immediately; if necessary, it will be marked precise later 514 514 */ 515 - __msg("6: (71) r2 = *(u8 *)(r10 -1) ; R2_w=0 R10=fp0 fp-8_w=0") 515 + __msg("6: (71) r2 = *(u8 *)(r10 -1) ; R2=0 R10=fp0 fp-8=0") 516 516 /* similarly, when R2 is assigned from spilled register, it is initially 517 517 * imprecise, but will be marked precise later once it is used in precise context 518 518 */ 519 - __msg("10: (71) r2 = *(u8 *)(r10 -9) ; R2_w=0 R10=fp0 fp-16_w=0") 519 + __msg("10: (71) r2 = *(u8 *)(r10 -9) ; R2=0 R10=fp0 fp-16=0") 520 520 __msg("11: (0f) r1 += r2") 521 521 __msg("mark_precise: frame0: last_idx 11 first_idx 0 subseq_idx -1") 522 522 __msg("mark_precise: frame0: regs=r2 stack= before 10: (71) r2 = *(u8 *)(r10 -9)") ··· 598 598 __success 599 599 /* fp-4 is STACK_ZERO */ 600 600 __msg("2: (62) *(u32 *)(r10 -4) = 0 ; R10=fp0 fp-8=0000????") 601 - __msg("4: (71) r2 = *(u8 *)(r10 -1) ; R2_w=0 R10=fp0 fp-8=0000????") 601 + __msg("4: (71) r2 = *(u8 *)(r10 -1) ; R2=0 R10=fp0 fp-8=0000????") 602 602 __msg("5: (0f) r1 += r2") 603 603 __msg("mark_precise: frame0: last_idx 5 first_idx 0 subseq_idx -1") 604 604 __msg("mark_precise: frame0: regs=r2 stack= before 4: (71) r2 = *(u8 *)(r10 -1)") ··· 640 640 __log_level(2) __flag(BPF_F_TEST_STATE_FREQ) 641 641 __success 642 642 /* make sure fp-8 is IMPRECISE fake register spill */ 643 - __msg("3: (7a) *(u64 *)(r10 -8) = 1 ; R10=fp0 fp-8_w=1") 643 + __msg("3: (7a) *(u64 *)(r10 -8) = 1 ; R10=fp0 fp-8=1") 644 644 /* and fp-16 is spilled IMPRECISE const reg */ 645 - __msg("5: (7b) *(u64 *)(r10 -16) = r0 ; R0_w=1 R10=fp0 fp-16_w=1") 645 + __msg("5: (7b) *(u64 *)(r10 -16) = r0 ; R0=1 R10=fp0 fp-16=1") 646 646 /* validate load from fp-8, which was initialized using BPF_ST_MEM */ 647 - __msg("8: (79) r2 = *(u64 *)(r10 -8) ; R2_w=1 R10=fp0 fp-8=1") 647 + __msg("8: (79) r2 = *(u64 *)(r10 -8) ; R2=1 R10=fp0 fp-8=1") 648 648 __msg("9: (0f) r1 += r2") 649 649 __msg("mark_precise: frame0: last_idx 9 first_idx 7 subseq_idx -1") 650 650 __msg("mark_precise: frame0: regs=r2 stack= before 8: (79) r2 = *(u64 *)(r10 -8)") 651 651 __msg("mark_precise: frame0: regs= stack=-8 before 7: (bf) r1 = r6") 652 652 /* note, fp-8 is precise, fp-16 is not yet precise, we'll get there */ 653 - __msg("mark_precise: frame0: parent state regs= stack=-8: R0_w=1 R1=ctx() R6_r=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8_rw=P1 fp-16_w=1") 653 + __msg("mark_precise: frame0: parent state regs= stack=-8: R0=1 R1=ctx() R6=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8=P1 fp-16=1") 654 654 __msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7") 655 655 __msg("mark_precise: frame0: regs= stack=-8 before 6: (05) goto pc+0") 656 656 __msg("mark_precise: frame0: regs= stack=-8 before 5: (7b) *(u64 *)(r10 -16) = r0") 657 657 __msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r0 = 1") 658 658 __msg("mark_precise: frame0: regs= stack=-8 before 3: (7a) *(u64 *)(r10 -8) = 1") 659 - __msg("10: R1_w=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2_w=1") 659 + __msg("10: R1=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2=1") 660 660 /* validate load from fp-16, which was initialized using BPF_STX_MEM */ 661 - __msg("12: (79) r2 = *(u64 *)(r10 -16) ; R2_w=1 R10=fp0 fp-16=1") 661 + __msg("12: (79) r2 = *(u64 *)(r10 -16) ; R2=1 R10=fp0 fp-16=1") 662 662 __msg("13: (0f) r1 += r2") 663 663 __msg("mark_precise: frame0: last_idx 13 first_idx 7 subseq_idx -1") 664 664 __msg("mark_precise: frame0: regs=r2 stack= before 12: (79) r2 = *(u64 *)(r10 -16)") ··· 668 668 __msg("mark_precise: frame0: regs= stack=-16 before 8: (79) r2 = *(u64 *)(r10 -8)") 669 669 __msg("mark_precise: frame0: regs= stack=-16 before 7: (bf) r1 = r6") 670 670 /* now both fp-8 and fp-16 are precise, very good */ 671 - __msg("mark_precise: frame0: parent state regs= stack=-16: R0_w=1 R1=ctx() R6_r=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8_rw=P1 fp-16_rw=P1") 671 + __msg("mark_precise: frame0: parent state regs= stack=-16: R0=1 R1=ctx() R6=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8=P1 fp-16=P1") 672 672 __msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7") 673 673 __msg("mark_precise: frame0: regs= stack=-16 before 6: (05) goto pc+0") 674 674 __msg("mark_precise: frame0: regs= stack=-16 before 5: (7b) *(u64 *)(r10 -16) = r0") 675 675 __msg("mark_precise: frame0: regs=r0 stack= before 4: (b7) r0 = 1") 676 - __msg("14: R1_w=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2_w=1") 676 + __msg("14: R1=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2=1") 677 677 __naked void stack_load_preserves_const_precision(void) 678 678 { 679 679 asm volatile ( ··· 719 719 /* make sure fp-8 is 32-bit FAKE subregister spill */ 720 720 __msg("3: (62) *(u32 *)(r10 -8) = 1 ; R10=fp0 fp-8=????1") 721 721 /* but fp-16 is spilled IMPRECISE zero const reg */ 722 - __msg("5: (63) *(u32 *)(r10 -16) = r0 ; R0_w=1 R10=fp0 fp-16=????1") 722 + __msg("5: (63) *(u32 *)(r10 -16) = r0 ; R0=1 R10=fp0 fp-16=????1") 723 723 /* validate load from fp-8, which was initialized using BPF_ST_MEM */ 724 - __msg("8: (61) r2 = *(u32 *)(r10 -8) ; R2_w=1 R10=fp0 fp-8=????1") 724 + __msg("8: (61) r2 = *(u32 *)(r10 -8) ; R2=1 R10=fp0 fp-8=????1") 725 725 __msg("9: (0f) r1 += r2") 726 726 __msg("mark_precise: frame0: last_idx 9 first_idx 7 subseq_idx -1") 727 727 __msg("mark_precise: frame0: regs=r2 stack= before 8: (61) r2 = *(u32 *)(r10 -8)") 728 728 __msg("mark_precise: frame0: regs= stack=-8 before 7: (bf) r1 = r6") 729 - __msg("mark_precise: frame0: parent state regs= stack=-8: R0_w=1 R1=ctx() R6_r=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8_r=????P1 fp-16=????1") 729 + __msg("mark_precise: frame0: parent state regs= stack=-8: R0=1 R1=ctx() R6=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8=????P1 fp-16=????1") 730 730 __msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7") 731 731 __msg("mark_precise: frame0: regs= stack=-8 before 6: (05) goto pc+0") 732 732 __msg("mark_precise: frame0: regs= stack=-8 before 5: (63) *(u32 *)(r10 -16) = r0") 733 733 __msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r0 = 1") 734 734 __msg("mark_precise: frame0: regs= stack=-8 before 3: (62) *(u32 *)(r10 -8) = 1") 735 - __msg("10: R1_w=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2_w=1") 735 + __msg("10: R1=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2=1") 736 736 /* validate load from fp-16, which was initialized using BPF_STX_MEM */ 737 - __msg("12: (61) r2 = *(u32 *)(r10 -16) ; R2_w=1 R10=fp0 fp-16=????1") 737 + __msg("12: (61) r2 = *(u32 *)(r10 -16) ; R2=1 R10=fp0 fp-16=????1") 738 738 __msg("13: (0f) r1 += r2") 739 739 __msg("mark_precise: frame0: last_idx 13 first_idx 7 subseq_idx -1") 740 740 __msg("mark_precise: frame0: regs=r2 stack= before 12: (61) r2 = *(u32 *)(r10 -16)") ··· 743 743 __msg("mark_precise: frame0: regs= stack=-16 before 9: (0f) r1 += r2") 744 744 __msg("mark_precise: frame0: regs= stack=-16 before 8: (61) r2 = *(u32 *)(r10 -8)") 745 745 __msg("mark_precise: frame0: regs= stack=-16 before 7: (bf) r1 = r6") 746 - __msg("mark_precise: frame0: parent state regs= stack=-16: R0_w=1 R1=ctx() R6_r=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8_r=????P1 fp-16_r=????P1") 746 + __msg("mark_precise: frame0: parent state regs= stack=-16: R0=1 R1=ctx() R6=map_value(map=.data.two_byte_,ks=4,vs=2) R10=fp0 fp-8=????P1 fp-16=????P1") 747 747 __msg("mark_precise: frame0: last_idx 6 first_idx 3 subseq_idx 7") 748 748 __msg("mark_precise: frame0: regs= stack=-16 before 6: (05) goto pc+0") 749 749 __msg("mark_precise: frame0: regs= stack=-16 before 5: (63) *(u32 *)(r10 -16) = r0") 750 750 __msg("mark_precise: frame0: regs=r0 stack= before 4: (b7) r0 = 1") 751 - __msg("14: R1_w=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2_w=1") 751 + __msg("14: R1=map_value(map=.data.two_byte_,ks=4,vs=2,off=1) R2=1") 752 752 __naked void stack_load_preserves_const_precision_subreg(void) 753 753 { 754 754 asm volatile (
+3 -3
tools/testing/selftests/bpf/progs/verifier_subprog_precision.c
··· 105 105 __msg("mark_precise: frame0: regs=r0 stack= before 3: (57) r0 &= 3") 106 106 __msg("mark_precise: frame0: regs=r0 stack= before 10: (95) exit") 107 107 __msg("mark_precise: frame1: regs=r0 stack= before 9: (bf) r0 = (s8)r10") 108 - __msg("7: R0_w=scalar") 108 + __msg("7: R0=scalar") 109 109 __naked int fp_precise_subprog_result(void) 110 110 { 111 111 asm volatile ( ··· 141 141 * anyways, at which point we'll break precision chain 142 142 */ 143 143 __msg("mark_precise: frame1: regs=r1 stack= before 9: (bf) r1 = r10") 144 - __msg("7: R0_w=scalar") 144 + __msg("7: R0=scalar") 145 145 __naked int sneaky_fp_precise_subprog_result(void) 146 146 { 147 147 asm volatile ( ··· 681 681 __msg("mark_precise: frame0: regs=r7 stack= before 9: (bf) r1 = r8") 682 682 __msg("mark_precise: frame0: regs=r7 stack= before 8: (27) r7 *= 4") 683 683 __msg("mark_precise: frame0: regs=r7 stack= before 7: (79) r7 = *(u64 *)(r10 -8)") 684 - __msg("mark_precise: frame0: parent state regs= stack=-8: R0_w=2 R6_w=1 R8_rw=map_value(map=.data.vals,ks=4,vs=16) R10=fp0 fp-8_rw=P1") 684 + __msg("mark_precise: frame0: parent state regs= stack=-8: R0=2 R6=1 R8=map_value(map=.data.vals,ks=4,vs=16) R10=fp0 fp-8=P1") 685 685 __msg("mark_precise: frame0: last_idx 18 first_idx 0 subseq_idx 7") 686 686 __msg("mark_precise: frame0: regs= stack=-8 before 18: (95) exit") 687 687 __msg("mark_precise: frame1: regs= stack= before 17: (0f) r0 += r2")
+150 -49
tools/testing/selftests/bpf/test_loader.c
··· 2 2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ 3 3 #include <linux/capability.h> 4 4 #include <stdlib.h> 5 - #include <regex.h> 6 5 #include <test_progs.h> 7 6 #include <bpf/btf.h> 8 7 ··· 19 20 #define TEST_TAG_EXPECT_FAILURE "comment:test_expect_failure" 20 21 #define TEST_TAG_EXPECT_SUCCESS "comment:test_expect_success" 21 22 #define TEST_TAG_EXPECT_MSG_PFX "comment:test_expect_msg=" 23 + #define TEST_TAG_EXPECT_NOT_MSG_PFX "comment:test_expect_not_msg=" 22 24 #define TEST_TAG_EXPECT_XLATED_PFX "comment:test_expect_xlated=" 23 25 #define TEST_TAG_EXPECT_FAILURE_UNPRIV "comment:test_expect_failure_unpriv" 24 26 #define TEST_TAG_EXPECT_SUCCESS_UNPRIV "comment:test_expect_success_unpriv" 25 27 #define TEST_TAG_EXPECT_MSG_PFX_UNPRIV "comment:test_expect_msg_unpriv=" 28 + #define TEST_TAG_EXPECT_NOT_MSG_PFX_UNPRIV "comment:test_expect_not_msg_unpriv=" 26 29 #define TEST_TAG_EXPECT_XLATED_PFX_UNPRIV "comment:test_expect_xlated_unpriv=" 27 30 #define TEST_TAG_LOG_LEVEL_PFX "comment:test_log_level=" 28 31 #define TEST_TAG_PROG_FLAGS_PFX "comment:test_prog_flags=" ··· 64 63 enum load_mode { 65 64 JITED = 1 << 0, 66 65 NO_JITED = 1 << 1, 67 - }; 68 - 69 - struct expect_msg { 70 - const char *substr; /* substring match */ 71 - regex_t regex; 72 - bool is_regex; 73 - bool on_next_line; 74 - }; 75 - 76 - struct expected_msgs { 77 - struct expect_msg *patterns; 78 - size_t cnt; 79 66 }; 80 67 81 68 struct test_subspec { ··· 205 216 return 0; 206 217 } 207 218 208 - static int __push_msg(const char *pattern, bool on_next_line, struct expected_msgs *msgs) 219 + static int __push_msg(const char *pattern, bool on_next_line, bool negative, 220 + struct expected_msgs *msgs) 209 221 { 210 222 struct expect_msg *msg; 211 223 void *tmp; ··· 222 232 msg = &msgs->patterns[msgs->cnt]; 223 233 msg->on_next_line = on_next_line; 224 234 msg->substr = pattern; 235 + msg->negative = negative; 225 236 msg->is_regex = false; 226 237 if (strstr(pattern, "{{")) { 227 238 err = compile_regex(pattern, &msg->regex); ··· 241 250 242 251 for (i = 0; i < from->cnt; i++) { 243 252 msg = &from->patterns[i]; 244 - err = __push_msg(msg->substr, msg->on_next_line, to); 253 + err = __push_msg(msg->substr, msg->on_next_line, msg->negative, to); 245 254 if (err) 246 255 return err; 247 256 } 248 257 return 0; 249 258 } 250 259 251 - static int push_msg(const char *substr, struct expected_msgs *msgs) 260 + static int push_msg(const char *substr, bool negative, struct expected_msgs *msgs) 252 261 { 253 - return __push_msg(substr, false, msgs); 262 + return __push_msg(substr, false, negative, msgs); 254 263 } 255 264 256 265 static int push_disasm_msg(const char *regex_str, bool *on_next_line, struct expected_msgs *msgs) ··· 261 270 *on_next_line = false; 262 271 return 0; 263 272 } 264 - err = __push_msg(regex_str, *on_next_line, msgs); 273 + err = __push_msg(regex_str, *on_next_line, false, msgs); 265 274 if (err) 266 275 return err; 267 276 *on_next_line = true; ··· 473 482 spec->auxiliary = true; 474 483 spec->mode_mask |= UNPRIV; 475 484 } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_MSG_PFX))) { 476 - err = push_msg(msg, &spec->priv.expect_msgs); 485 + err = push_msg(msg, false, &spec->priv.expect_msgs); 486 + if (err) 487 + goto cleanup; 488 + spec->mode_mask |= PRIV; 489 + } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_NOT_MSG_PFX))) { 490 + err = push_msg(msg, true, &spec->priv.expect_msgs); 477 491 if (err) 478 492 goto cleanup; 479 493 spec->mode_mask |= PRIV; 480 494 } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_MSG_PFX_UNPRIV))) { 481 - err = push_msg(msg, &spec->unpriv.expect_msgs); 495 + err = push_msg(msg, false, &spec->unpriv.expect_msgs); 496 + if (err) 497 + goto cleanup; 498 + spec->mode_mask |= UNPRIV; 499 + } else if ((msg = skip_dynamic_pfx(s, TEST_TAG_EXPECT_NOT_MSG_PFX_UNPRIV))) { 500 + err = push_msg(msg, true, &spec->unpriv.expect_msgs); 482 501 if (err) 483 502 goto cleanup; 484 503 spec->mode_mask |= UNPRIV; ··· 765 764 fprintf(stdout, "STDOUT:\n=============\n%s=============\n", bpf_stdout); 766 765 } 767 766 768 - static void validate_msgs(char *log_buf, struct expected_msgs *msgs, 769 - void (*emit_fn)(const char *buf, bool force)) 767 + static const char *match_msg(struct expect_msg *msg, const char **log) 770 768 { 771 - const char *log = log_buf, *prev_match; 769 + const char *match = NULL; 772 770 regmatch_t reg_match[1]; 773 - int prev_match_line; 774 - int match_line; 775 - int i, j, err; 771 + int err; 776 772 777 - prev_match_line = -1; 778 - match_line = 0; 773 + if (!msg->is_regex) { 774 + match = strstr(*log, msg->substr); 775 + if (match) 776 + *log = match + strlen(msg->substr); 777 + } else { 778 + err = regexec(&msg->regex, *log, 1, reg_match, 0); 779 + if (err == 0) { 780 + match = *log + reg_match[0].rm_so; 781 + *log += reg_match[0].rm_eo; 782 + } 783 + } 784 + return match; 785 + } 786 + 787 + static int count_lines(const char *start, const char *end) 788 + { 789 + const char *tmp; 790 + int n = 0; 791 + 792 + for (tmp = start; tmp < end; ++tmp) 793 + if (*tmp == '\n') 794 + n++; 795 + return n; 796 + } 797 + 798 + struct match { 799 + const char *start; 800 + const char *end; 801 + int line; 802 + }; 803 + 804 + /* 805 + * Positive messages are matched sequentially, each next message 806 + * is looked for starting from the end of a previous matched one. 807 + */ 808 + static void match_positive_msgs(const char *log, struct expected_msgs *msgs, struct match *matches) 809 + { 810 + const char *prev_match; 811 + int i, line; 812 + 779 813 prev_match = log; 814 + line = 0; 780 815 for (i = 0; i < msgs->cnt; i++) { 781 816 struct expect_msg *msg = &msgs->patterns[i]; 782 - const char *match = NULL, *pat_status; 783 - bool wrong_line = false; 817 + const char *match = NULL; 784 818 785 - if (!msg->is_regex) { 786 - match = strstr(log, msg->substr); 787 - if (match) 788 - log = match + strlen(msg->substr); 789 - } else { 790 - err = regexec(&msg->regex, log, 1, reg_match, 0); 791 - if (err == 0) { 792 - match = log + reg_match[0].rm_so; 793 - log += reg_match[0].rm_eo; 819 + if (msg->negative) 820 + continue; 821 + 822 + match = match_msg(msg, &log); 823 + if (match) { 824 + line += count_lines(prev_match, match); 825 + matches[i].start = match; 826 + matches[i].end = log; 827 + matches[i].line = line; 828 + prev_match = match; 829 + } 830 + } 831 + } 832 + 833 + /* 834 + * Each negative messages N located between positive messages P1 and P2 835 + * is matched in the span P1.end .. P2.start. Consequently, negative messages 836 + * are unordered within the span. 837 + */ 838 + static void match_negative_msgs(const char *log, struct expected_msgs *msgs, struct match *matches) 839 + { 840 + const char *start = log, *end, *next, *match; 841 + const char *log_end = log + strlen(log); 842 + int i, j, next_positive; 843 + 844 + for (i = 0; i < msgs->cnt; i++) { 845 + struct expect_msg *msg = &msgs->patterns[i]; 846 + 847 + /* positive message bumps span start */ 848 + if (!msg->negative) { 849 + start = matches[i].end ?: start; 850 + continue; 851 + } 852 + 853 + /* count stride of negative patterns and adjust span end */ 854 + end = log_end; 855 + for (next_positive = i + 1; next_positive < msgs->cnt; next_positive++) { 856 + if (!msgs->patterns[next_positive].negative) { 857 + end = matches[next_positive].start; 858 + break; 794 859 } 795 860 } 796 861 797 - if (match) { 798 - for (; prev_match < match; ++prev_match) 799 - if (*prev_match == '\n') 800 - ++match_line; 801 - wrong_line = msg->on_next_line && prev_match_line >= 0 && 802 - prev_match_line + 1 != match_line; 862 + /* try matching negative messages within identified span */ 863 + for (j = i; j < next_positive; j++) { 864 + next = start; 865 + match = match_msg(msg, &next); 866 + if (match && next <= end) { 867 + matches[j].start = match; 868 + matches[j].end = next; 869 + } 803 870 } 804 871 805 - if (!match || wrong_line) { 872 + /* -1 to account for i++ */ 873 + i = next_positive - 1; 874 + } 875 + } 876 + 877 + void validate_msgs(const char *log_buf, struct expected_msgs *msgs, 878 + void (*emit_fn)(const char *buf, bool force)) 879 + { 880 + struct match matches[msgs->cnt]; 881 + struct match *prev_match = NULL; 882 + int i, j; 883 + 884 + memset(matches, 0, sizeof(*matches) * msgs->cnt); 885 + match_positive_msgs(log_buf, msgs, matches); 886 + match_negative_msgs(log_buf, msgs, matches); 887 + 888 + for (i = 0; i < msgs->cnt; i++) { 889 + struct expect_msg *msg = &msgs->patterns[i]; 890 + struct match *match = &matches[i]; 891 + const char *pat_status; 892 + bool unexpected; 893 + bool wrong_line; 894 + bool no_match; 895 + 896 + no_match = !msg->negative && !match->start; 897 + wrong_line = !msg->negative && 898 + msg->on_next_line && 899 + prev_match && prev_match->line + 1 != match->line; 900 + unexpected = msg->negative && match->start; 901 + if (no_match || wrong_line || unexpected) { 806 902 PRINT_FAIL("expect_msg\n"); 807 903 if (env.verbosity == VERBOSE_NONE) 808 904 emit_fn(log_buf, true /*force*/); ··· 909 811 pat_status = "MATCHED "; 910 812 else if (wrong_line) 911 813 pat_status = "WRONG LINE"; 912 - else 814 + else if (no_match) 913 815 pat_status = "EXPECTED "; 816 + else 817 + pat_status = "UNEXPECTED"; 914 818 msg = &msgs->patterns[j]; 915 819 fprintf(stderr, "%s %s: '%s'\n", 916 820 pat_status, ··· 922 822 if (wrong_line) { 923 823 fprintf(stderr, 924 824 "expecting match at line %d, actual match is at line %d\n", 925 - prev_match_line + 1, match_line); 825 + prev_match->line + 1, match->line); 926 826 } 927 827 break; 928 828 } 929 829 930 - prev_match_line = match_line; 830 + if (!msg->negative) 831 + prev_match = match; 931 832 } 932 833 } 933 834
+17
tools/testing/selftests/bpf/test_progs.h
··· 7 7 #include <errno.h> 8 8 #include <string.h> 9 9 #include <assert.h> 10 + #include <regex.h> 10 11 #include <stdlib.h> 11 12 #include <stdarg.h> 12 13 #include <time.h> ··· 546 545 test_loader__run_subtests(&tester, #skel, skel##__elf_bytes); \ 547 546 test_loader_fini(&tester); \ 548 547 }) 548 + 549 + struct expect_msg { 550 + const char *substr; /* substring match */ 551 + regex_t regex; 552 + bool is_regex; 553 + bool on_next_line; 554 + bool negative; 555 + }; 556 + 557 + struct expected_msgs { 558 + struct expect_msg *patterns; 559 + size_t cnt; 560 + }; 561 + 562 + void validate_msgs(const char *log_buf, struct expected_msgs *msgs, 563 + void (*emit_fn)(const char *buf, bool force)); 549 564 550 565 #endif /* __TEST_PROGS_H */
+2 -2
tools/testing/selftests/bpf/verifier/bpf_st_mem.c
··· 93 93 .expected_attach_type = BPF_SK_LOOKUP, 94 94 .result = VERBOSE_ACCEPT, 95 95 .runs = -1, 96 - .errstr = "0: (7a) *(u64 *)(r10 -8) = -44 ; R10=fp0 fp-8_w=-44\ 96 + .errstr = "0: (7a) *(u64 *)(r10 -8) = -44 ; R10=fp0 fp-8=-44\ 97 97 2: (c5) if r0 s< 0x0 goto pc+2\ 98 - R0_w=-44", 98 + R0=-44", 99 99 },