Re: [PATCH RFC bpf-next 2/8] bpf: mark instructions accessing program stack

sashiko-bot
2026-04-25T05:05:57Z

Sashiko AI review found 4 potential issue(s):
- [High] An instruction aliasing PTR_TO_STACK and other pointer types (e.g., PTR_TO_MAP_VALUE) will permanently be marked with accesses_stack = true, improperly bypassing KASAN monitoring for the non-stack access.
- [High] Instruction patching drops the accesses_stack flag from memory access instructions, causing unintended KASAN checks on stack accesses.
- [High] bpf_insn_accesses_stack() unconditionally returns false when env == NULL, breaking KASAN suppression for classic BPF (cBPF) programs.
- [Medium] Stack accesses inside global subprograms lack the accesses_stack flag, leading to unintended KASAN checks when stack pointers are passed to them.
--

commit 58c92691d6de0f6cbdbd48cc21d31e0a14a4fffa
Author: Alexis Lothoré (eBPF Foundation) <alexis.lothore@bootlin.com>

bpf: mark instructions accessing program stack

In order to prepare to emit KASAN checks in JITed programs, JIT
compilers need to be aware about whether some load/store instructions
are targeting the bpf program stack. Make the BPF verifier mark the
instructions that access program stack.

> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index 8b018ff488750..340abfdadbedb 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
[ ... ]
> @@ -1582,6 +1582,16 @@ bool bpf_insn_is_indirect_target(const struct bpf_verifier_env *env, const struc
> insn_idx += prog->aux->subprog_start;
> return env->insn_aux_data[insn_idx].indirect_target;
> }
> +
> +bool bpf_insn_accesses_stack(const struct bpf_verifier_env *env,
> + const struct bpf_prog *prog, int insn_idx)
> +{
> + if (!env)
> + return false;

Classic BPF (cBPF) programs are converted to eBPF and JIT-compiled directly,
bypassing the eBPF verifier, so env is NULL. The converted eBPF instructions
heavily use BPF_REG_FP for scratch memory accesses.

Because this returns false when env is NULL, will JIT compilers incorrectly
emit KASAN checks for all cBPF stack memory accesses?

Could this inspect the instruction directly when env == NULL (e.g., checking
if insn->dst_reg == BPF_REG_FP or insn->src_reg == BPF_REG_FP) to prevent
false positive KASAN splats for valid cBPF programs?

> + insn_idx += prog->aux->subprog_start;
> + return env->insn_aux_data[insn_idx].accesses_stack;
> +}
> +
> #endif /* CONFIG_BPF_JIT */
> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
> index 69d75515ed3f7..1ce0388847b2b 100644
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -3502,6 +3502,11 @@ static void mark_indirect_target(struct bpf_verifier_env *env, int idx)
> env->insn_aux_data[idx].indirect_target = true;
> }
>
> +static void mark_insn_accesses_stack(struct bpf_verifier_env *env, int idx)
> +{
> + env->insn_aux_data[idx].accesses_stack = true;
> +}
> +

If an instruction aliases PTR_TO_STACK and other pointer types (e.g.,
PTR_TO_MAP_VALUE) across different execution paths, check_mem_access() will
call this and permanently set accesses_stack = true when evaluating the stack
path.

When the PTR_TO_MAP_VALUE path is evaluated, the accesses_stack flag remains
true. Will this cause the map value access to completely bypass KASAN
monitoring during JIT compilation?

Additionally, when the verifier patches an instruction (e.g., for
zero-extension via bpf_patch_insn_data()), adjust_insn_aux_data() shifts the
original auxiliary data to the last instruction of the newly inserted patch
sequence.

For patches like zero-extension, a BPF_MOV is inserted after the original
BPF_LDX_MEM instruction. Does the accesses_stack flag thus move to the MOV
instruction, while the actual memory load receives zeroed auxiliary data?

Could this result in the JIT compiler erroneously emitting KASAN
instrumentation for these verified stack accesses?

> #define LR_FRAMENO_BITS 3
> #define LR_SPI_BITS 6
[ ... ]
> @@ -6493,6 +6498,8 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
> else
> err = check_stack_write(env, regno, off, size,
> value_regno, insn_idx);
> +
> + mark_insn_accesses_stack(env, insn_idx);

Global subprograms are verified independently of their call sites, and pointer
arguments are tracked as PTR_TO_MEM rather than PTR_TO_STACK. Inside the
subprogram, check_mem_access() evaluates loads and stores under the
PTR_TO_MEM branch, which does not invoke mark_insn_accesses_stack().

If a BPF caller dynamically passes a pointer to its stack as an argument to
the global subprogram, will the JIT-compiled global subprogram execute with
KASAN checks enabled for those accesses?

Does this erroneously monitor the BPF stack, bypassing the intended
suppression mechanism?

> } else if (reg_is_pkt_pointer(reg)) {
> if (t == BPF_WRITE && !may_access_direct_pkt_data(env, NULL, t)) {
> verbose(env, "cannot write into packet\n");

--
Sashiko AI review · https://sashiko.dev/#/patchset/20260413-kasan-v1-0-1a5831230821@bootlin.com?part=2