]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpf: Relax fixed offset check for PTR_TO_CTX
authorKumar Kartikeya Dwivedi <memxor@gmail.com>
Fri, 27 Feb 2026 00:57:24 +0000 (16:57 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 3 Mar 2026 16:45:16 +0000 (08:45 -0800)
The limitation on fixed offsets stems from the fact that certain program
types rewrite the accesses to the context structure and translate them
to accesses to the real underlying type. Technically, in the past, we
could have stashed the register offset in insn_aux and made rewrites
work, but we've never needed it in the past since the offset for such
context structures easily fit in the s16 signed instruction offset.

Regardless, the consequence is that for program types where the program
type's verifier ops doesn't supply a convert_ctx_access callback, we
unnecessarily reject accesses with a modified ctx pointer (i.e., one
whose offset has been shifted) in check_ptr_off_reg. Make an exception
for such program types (like syscall, tracepoint, raw_tp, etc.).

Pass in fixed_off_ok as true to __check_ptr_off_reg for such cases, and
accumulate the register offset into insn->off passed to check_ctx_access.
In particular, the accumulation is critical since we need to correctly
track the max_ctx_offset which is used for bounds checking the buffer
for syscall programs at runtime.

Reported-by: Tejun Heo <tj@kernel.org>
Reported-by: Dan Schatzberg <dschatzberg@meta.com>
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Link: https://lore.kernel.org/r/20260227005725.1247305-2-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index fc4ccd1de569ceb6ce9d6adf7505f6af4eb62b0c..34f89ed29c47a982e42f74cf34249b5e4ddc02a7 100644 (file)
@@ -7752,6 +7752,11 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
                if (!err && value_regno >= 0 && (t == BPF_READ || rdonly_mem))
                        mark_reg_unknown(env, regs, value_regno);
        } else if (reg->type == PTR_TO_CTX) {
+               /*
+                * Program types that don't rewrite ctx accesses can safely
+                * dereference ctx pointers with fixed offsets.
+                */
+               bool fixed_off_ok = !env->ops->convert_ctx_access;
                struct bpf_retval_range range;
                struct bpf_insn_access_aux info = {
                        .reg_type = SCALAR_VALUE,
@@ -7765,10 +7770,16 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
                        return -EACCES;
                }
 
-               err = check_ptr_off_reg(env, reg, regno);
+               err = __check_ptr_off_reg(env, reg, regno, fixed_off_ok);
                if (err < 0)
                        return err;
 
+               /*
+                * Fold the register's constant offset into the insn offset so
+                * that is_valid_access() sees the true effective offset.
+                */
+               if (fixed_off_ok)
+                       off += reg->var_off.value;
                err = check_ctx_access(env, insn_idx, off, size, t, &info);
                if (err)
                        verbose_linfo(env, insn_idx, "; ");