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 --- 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