mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 17:12:50 -04:00
bpf: introduce forward arg-tracking dataflow analysis
The analysis is a basis for static liveness tracking mechanism
introduced by the next two commits.
A forward fixed-point analysis that tracks which frame's FP each
register value is derived from, and at what byte offset. This is
needed because a callee can receive a pointer to its caller's stack
frame (e.g. r1 = fp-16 at the call site), then do *(u64 *)(r1 + 0)
inside the callee — a cross-frame stack access that the callee's local
liveness must attribute to the caller's stack.
Each register holds an arg_track value from a three-level lattice:
- Precise {frame=N, off=[o1,o2,...]} — known frame index and
up to 4 concrete byte offsets
- Offset-imprecise {frame=N, off_cnt=0} — known frame, unknown offset
- Fully-imprecise {frame=ARG_IMPRECISE, mask=bitmask} — unknown frame,
mask says which frames might be involved
At CFG merge points the lattice moves toward imprecision (same
frame+offset stays precise, same frame different offsets merges offset
sets or becomes offset-imprecise, different frames become
fully-imprecise with OR'd bitmask).
The analysis also tracks spills/fills to the callee's own stack
(at_stack_in/out), so FP derived values spilled and reloaded.
This pass is run recursively per call site: when subprog A calls B
with specific FP-derived arguments, B is re-analyzed with those entry
args. The recursion follows analyze_subprog -> compute_subprog_args ->
(for each call insn) -> analyze_subprog. Subprogs that receive no
FP-derived args are skipped during recursion and analyzed
independently at depth 0.
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260410-patch-set-v4-7-5d4eecb343db@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
committed by
Alexei Starovoitov
parent
8d3219f64d
commit
bf0c571f7f
@@ -226,6 +226,7 @@ enum bpf_stack_slot_type {
|
|||||||
|
|
||||||
/* 4-byte stack slot granularity for liveness analysis */
|
/* 4-byte stack slot granularity for liveness analysis */
|
||||||
#define BPF_HALF_REG_SIZE 4
|
#define BPF_HALF_REG_SIZE 4
|
||||||
|
#define STACK_SLOT_SZ 4
|
||||||
#define STACK_SLOTS (MAX_BPF_STACK / BPF_HALF_REG_SIZE) /* 128 */
|
#define STACK_SLOTS (MAX_BPF_STACK / BPF_HALF_REG_SIZE) /* 128 */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -886,6 +887,8 @@ struct bpf_verifier_env {
|
|||||||
} cfg;
|
} cfg;
|
||||||
struct backtrack_state bt;
|
struct backtrack_state bt;
|
||||||
struct bpf_jmp_history_entry *cur_hist_ent;
|
struct bpf_jmp_history_entry *cur_hist_ent;
|
||||||
|
/* Per-callsite copy of parent's converged at_stack_in for cross-frame fills. */
|
||||||
|
struct arg_track **callsite_at_stack;
|
||||||
u32 pass_cnt; /* number of times do_check() was called */
|
u32 pass_cnt; /* number of times do_check() was called */
|
||||||
u32 subprog_cnt;
|
u32 subprog_cnt;
|
||||||
/* number of instructions analyzed by the verifier */
|
/* number of instructions analyzed by the verifier */
|
||||||
@@ -1213,6 +1216,7 @@ s64 bpf_helper_stack_access_bytes(struct bpf_verifier_env *env,
|
|||||||
s64 bpf_kfunc_stack_access_bytes(struct bpf_verifier_env *env,
|
s64 bpf_kfunc_stack_access_bytes(struct bpf_verifier_env *env,
|
||||||
struct bpf_insn *insn, int arg,
|
struct bpf_insn *insn, int arg,
|
||||||
int insn_idx);
|
int insn_idx);
|
||||||
|
int bpf_compute_subprog_arg_access(struct bpf_verifier_env *env);
|
||||||
|
|
||||||
int bpf_stack_liveness_init(struct bpf_verifier_env *env);
|
int bpf_stack_liveness_init(struct bpf_verifier_env *env);
|
||||||
void bpf_stack_liveness_free(struct bpf_verifier_env *env);
|
void bpf_stack_liveness_free(struct bpf_verifier_env *env);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -26414,6 +26414,11 @@ static int compute_live_registers(struct bpf_verifier_env *env)
|
|||||||
for (i = 0; i < insn_cnt; ++i)
|
for (i = 0; i < insn_cnt; ++i)
|
||||||
compute_insn_live_regs(env, &insns[i], &state[i]);
|
compute_insn_live_regs(env, &insns[i], &state[i]);
|
||||||
|
|
||||||
|
/* Forward pass: resolve stack access through FP-derived pointers */
|
||||||
|
err = bpf_compute_subprog_arg_access(env);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
changed = true;
|
changed = true;
|
||||||
while (changed) {
|
while (changed) {
|
||||||
changed = false;
|
changed = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user