mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
bpf: propagate read/precision marks over state graph backedges
Current loop_entry-based exact states comparison logic does not handle
the following case:
.-> A --. Assume the states are visited in the order A, B, C.
| | | Assume that state B reaches a state equivalent to state A.
| v v At this point, state C is not processed yet, so state A
'-- B C has not received any read or precision marks from C.
As a result, these marks won't be propagated to B.
If B has incomplete marks, it is unsafe to use it in states_equal()
checks.
This commit replaces the existing logic with the following:
- Strongly connected components (SCCs) are computed over the program's
control flow graph (intraprocedurally).
- When a verifier state enters an SCC, that state is recorded as the
SCC entry point.
- When a verifier state is found equivalent to another (e.g., B to A
in the example), it is recorded as a states graph backedge.
Backedges are accumulated per SCC.
- When an SCC entry state reaches `branches == 0`, read and precision
marks are propagated through the backedges (e.g., from A to B, from
C to A, and then again from A to B).
To support nested subprogram calls, the entry state and backedge list
are associated not with the SCC itself but with an object called
`bpf_scc_callchain`. A callchain is a tuple `(callsite*, scc_id)`,
where `callsite` is the index of a call instruction for each frame
except the last.
See the comments added in `is_state_visited()` and
`compute_scc_callchain()` for more details.
Fixes: 2a0992829e ("bpf: correct loop detection for iterators convergence")
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20250611200836.4135542-8-eddyz87@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
1 parent
b5c677d8d9
commit
c9e31900b5
2 files changed
+422
-68
No files matched your search
@@ -459,6 +459,10 @@ struct bpf_verifier_state {
|
||||
* See get_loop_entry() for more information.
|
||||
*/
|
||||
struct bpf_verifier_state *loop_entry;
|
||||
/* if this state is a backedge state then equal_state
|
||||
* records cached state to which this state is equal.
|
||||
*/
|
||||
struct bpf_verifier_state *equal_state;
|
||||
/* jmp history recorded from first to last.
|
||||
* backtracking is using it to go from last to first.
|
||||
* For most states jmp_history_cnt is [0-3].
|
||||
@@ -723,6 +727,37 @@ struct bpf_idset {
|
||||
u32 ids[BPF_ID_MAP_SIZE];
|
||||
};
|
||||
|
||||
/* see verifier.c:compute_scc_callchain() */
|
||||
struct bpf_scc_callchain {
|
||||
/* call sites from bpf_verifier_state->frame[*]->callsite leading to this SCC */
|
||||
u32 callsites[MAX_CALL_FRAMES - 1];
|
||||
/* last frame in a chain is identified by SCC id */
|
||||
u32 scc;
|
||||
};
|
||||
|
||||
/* verifier state waiting for propagate_backedges() */
|
||||
struct bpf_scc_backedge {
|
||||
struct bpf_scc_backedge *next;
|
||||
struct bpf_verifier_state state;
|
||||
};
|
||||
|
||||
struct bpf_scc_visit {
|
||||
struct bpf_scc_callchain callchain;
|
||||
/* first state in current verification path that entered SCC
|
||||
* identified by the callchain
|
||||
*/
|
||||
struct bpf_verifier_state *entry_state;
|
||||
struct bpf_scc_backedge *backedges; /* list of backedges */
|
||||
};
|
||||
|
||||
/* An array of bpf_scc_visit structs sharing tht same bpf_scc_callchain->scc
|
||||
* but having different bpf_scc_callchain->callsites.
|
||||
*/
|
||||
struct bpf_scc_info {
|
||||
u32 num_visits;
|
||||
struct bpf_scc_visit visits[];
|
||||
};
|
||||
|
||||
/* single container for all structs
|
||||
* one verifier_env per bpf_check() call
|
||||
*/
|
||||
@@ -819,6 +854,9 @@ struct bpf_verifier_env {
|
||||
char tmp_str_buf[TMP_STR_BUF_LEN];
|
||||
struct bpf_insn insn_buf[INSN_BUF_SIZE];
|
||||
struct bpf_insn epilogue_buf[INSN_BUF_SIZE];
|
||||
/* array of pointers to bpf_scc_info indexed by SCC id */
|
||||
struct bpf_scc_info **scc_info;
|
||||
u32 scc_cnt;
|
||||
};
|
||||
|
||||
static inline struct bpf_func_info_aux *subprog_aux(struct bpf_verifier_env *env, int subprog)
|
||||
|
||||
+384
-68
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user