[PATCH bpf-next v6 09/17] bpf: Track r11 registers in const_fold and liveness

Yonghong Song
2026-04-19T16:34:11Z

Since BPF_REG_PARAMS (r11) is beyond MAX_BPF_REG (r11), using it as an
array index into the register tracking arrays in const_fold.c and
liveness.c could cause out-of-bounds accesses.

When dst_reg is BPF_REG_PARAMS (BPF_ST/BPF_STX storing to the stack
arg area), no tracked register state changes, so an early return is
sufficient.

When src_reg is BPF_REG_PARAMS (BPF_LDX loading from the stack arg
area), dst_reg is a normal register that gets overwritten. Simply
returning early would leave dst_reg with stale state from a prior
path, which could cause incorrect constant folding or liveness
analysis. Mark dst_reg as unknown/none before returning to prevent
this.

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
kernel/bpf/const_fold.c | 14 ++++++++++++--
kernel/bpf/liveness.c | 14 ++++++++++++--
2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/kernel/bpf/const_fold.c b/kernel/bpf/const_fold.c
index db73c4740b1e..41e5a406432c 100644
--- a/kernel/bpf/const_fold.c
+++ b/kernel/bpf/const_fold.c
@@ -51,13 +51,23 @@ static void const_reg_xfer(struct bpf_verifier_env *env, struct const_arg_info *
struct bpf_insn *insn, struct bpf_insn *insns, int idx)
{
struct const_arg_info unknown = { .state = CONST_ARG_UNKNOWN, .val = 0 };
- struct const_arg_info *dst = &ci_out[insn->dst_reg];
- struct const_arg_info *src = &ci_out[insn->src_reg];
+ struct const_arg_info *dst, *src;
u8 class = BPF_CLASS(insn->code);
u8 mode = BPF_MODE(insn->code);
u8 opcode = BPF_OP(insn->code) | BPF_SRC(insn->code);
int r;

+ /* Stack arguments using BPF_REG_PARAMS are outside the tracked register set. */
+ if (insn->dst_reg >= MAX_BPF_REG)
+ return;
+ if (insn->src_reg >= MAX_BPF_REG) {
+ if (class == BPF_LDX)
+ ci_out[insn->dst_reg] = unknown;
+ return;
+ }
+
+ dst = &ci_out[insn->dst_reg];
+ src = &ci_out[insn->src_reg];
switch (class) {
case BPF_ALU:
case BPF_ALU64:
diff --git a/kernel/bpf/liveness.c b/kernel/bpf/liveness.c
index 332e6e003f27..87022da94f3a 100644
--- a/kernel/bpf/liveness.c
+++ b/kernel/bpf/liveness.c
@@ -1068,11 +1068,21 @@ static void arg_track_xfer(struct bpf_verifier_env *env, struct bpf_insn *insn,
int depth = instance->depth;
u8 class = BPF_CLASS(insn->code);
u8 code = BPF_OP(insn->code);
- struct arg_track *dst = &at_out[insn->dst_reg];
- struct arg_track *src = &at_out[insn->src_reg];
+ struct arg_track *dst, *src;
struct arg_track none = { .frame = ARG_NONE };
int r;

+ /* Stack arguments using BPF_REG_PARAMS are outside the tracked register set. */
+ if (insn->dst_reg >= MAX_BPF_REG)
+ return;
+ if (insn->src_reg >= MAX_BPF_REG) {
+ if (class == BPF_LDX)
+ at_out[insn->dst_reg] = none;
+ return;
+ }
+
+ dst = &at_out[insn->dst_reg];
+ src = &at_out[insn->src_reg];
if (class == BPF_ALU64 && BPF_SRC(insn->code) == BPF_K) {
if (code == BPF_MOV) {
*dst = none;
--
2.52.0