On Wed, Jul 22, 2026 at 05:27:31AM +0000, Yiyang Chen wrote:
[...]
> --- a/kernel/bpf/verifier.c
> +++ b/kernel/bpf/verifier.c
> @@ -13726,11 +13726,14 @@ static int adjust_ptr_min_max_vals(struct 
> bpf_verifier_env *env,
>       s64 smin_val = reg_smin(off_reg), smax_val = reg_smax(off_reg);
>       u64 umin_val = reg_umin(off_reg), umax_val = reg_umax(off_reg);
>       struct bpf_sanitize_info info = {};
> +     const struct bpf_reg_state *orig_off_reg = off_reg;
> +     bool ptr_is_dst_reg;
> 
>       u8 opcode = BPF_OP(insn->code);
>       u32 dst = insn->dst_reg;
>       int ret, bounds_ret;
>  
>       dst_reg = &regs[dst];
> +     ptr_is_dst_reg = ptr_reg == dst_reg;
>  
>       if ((known && (smin_val != smax_val || umin_val != umax_val)) ||
>           smin_val > smax_val || umin_val > umax_val) {
[...]
> @@ -13813,7 +13820,7 @@ static int adjust_ptr_min_max_vals(struct 
> bpf_verifier_env *env,
>               ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg,
>                                      &info, false);
>               if (ret < 0)
> -                     return sanitize_err(env, insn, ret, off_reg, dst_reg);
> +                     return sanitize_err(env, insn, ret, orig_off_reg, 
> dst_reg);
>       }
>  
>       switch (opcode) {
[...]
> @@ -13906,7 +13913,7 @@ static int adjust_ptr_min_max_vals(struct 
> bpf_verifier_env *env,
>                       return -EFAULT;
>               }
>               if (ret < 0)
> -                     return sanitize_err(env, insn, ret, off_reg, dst_reg);
> +                     return sanitize_err(env, insn, ret, orig_off_reg, 
> dst_reg);
>       }
>  
>       return 0;

The sole purpose of having orig_off_reg seem to be for satisfying the
'off_reg == dst_reg' conditional in sanitize_err(). If that's the case,
maybe it is better to change sanitize_err to accept an ptr_is_dst_reg
argument too.

And given now that we are starting to make more use of scratch register
states, it seems better to get rid the likes of 'off_reg == dst_reg' all
together, and simply have ptr_is_dst_reg passed down by
adjust_scalar_min_max_vals().


diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 52be0a118cce..72d49f2a57a3 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -13505,13 +13505,13 @@ static int sanitize_ptr_alu(struct bpf_verifier_env 
*env,
                            const struct bpf_reg_state *off_reg,
                            struct bpf_reg_state *dst_reg,
                            struct bpf_sanitize_info *info,
-                           const bool commit_window)
+                           const bool commit_window,
+                           const bool ptr_is_dst_reg)
 {
        struct bpf_insn_aux_data *aux = commit_window ? cur_aux(env) : 
&info->aux;
        struct bpf_verifier_state *vstate = env->cur_state;
        bool off_is_imm = tnum_is_const(off_reg->var_off);
        bool off_is_neg = reg_smin(off_reg) < 0;
-       bool ptr_is_dst_reg = ptr_reg == dst_reg;
        u8 opcode = BPF_OP(insn->code);
        u32 alu_state, alu_limit;
        struct bpf_reg_state tmp;
@@ -13611,7 +13611,8 @@ static void sanitize_mark_insn_seen(struct 
bpf_verifier_env *env)
 static int sanitize_err(struct bpf_verifier_env *env,
                        const struct bpf_insn *insn, int reason,
                        const struct bpf_reg_state *off_reg,
-                       const struct bpf_reg_state *dst_reg)
+                       const struct bpf_reg_state *dst_reg,
+                       const bool ptr_is_dst_reg)
 {
        static const char *err = "pointer arithmetic with it prohibited for 
!root";
        const char *op = BPF_OP(insn->code) == BPF_ADD ? "add" : "sub";
@@ -13620,11 +13621,11 @@ static int sanitize_err(struct bpf_verifier_env *env,
        switch (reason) {
        case REASON_BOUNDS:
                verbose(env, "R%d has unknown scalar with mixed signed bounds, 
%s\n",
-                       off_reg == dst_reg ? dst : src, err);
+                       !ptr_is_dst_reg ? dst : src, err);
                break;
        case REASON_TYPE:
                verbose(env, "R%d has pointer with unsupported alu operation, 
%s\n",
-                       off_reg == dst_reg ? src : dst, err);
+                       !ptr_is_dst_reg ? src : dst, err);
                break;
        case REASON_PATHS:
                verbose(env, "R%d tried to %s from different maps, paths or 
scalars, %s\n",
@@ -13717,7 +13718,8 @@ static int sanitize_check_bounds(struct 
bpf_verifier_env *env,
 static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
                                   struct bpf_insn *insn,
                                   const struct bpf_reg_state *ptr_reg,
-                                  const struct bpf_reg_state *off_reg)
+                                  const struct bpf_reg_state *off_reg,
+                                  const bool ptr_is_dst_reg)
 {
        struct bpf_verifier_state *vstate = env->cur_state;
        struct bpf_func_state *state = vstate->frame[vstate->curframe];
@@ -13811,9 +13813,9 @@ static int adjust_ptr_min_max_vals(struct 
bpf_verifier_env *env,
 
        if (sanitize_needed(opcode)) {
                ret = sanitize_ptr_alu(env, insn, ptr_reg, off_reg, dst_reg,
-                                      &info, false);
+                                      &info, false, ptr_is_dst_reg);
                if (ret < 0)
-                       return sanitize_err(env, insn, ret, off_reg, dst_reg);
+                       return sanitize_err(env, insn, ret, off_reg, dst_reg, 
ptr_is_dst_reg);
        }
 
        switch (opcode) {
@@ -13843,7 +13845,7 @@ static int adjust_ptr_min_max_vals(struct 
bpf_verifier_env *env,
                }
                break;
        case BPF_SUB:
-               if (dst_reg == off_reg) {
+               if (!ptr_is_dst_reg) {
                        /* scalar -= pointer.  Creates an unknown scalar */
                        verbose(env, "R%d tried to subtract pointer from 
scalar\n",
                                dst);
@@ -13897,7 +13899,7 @@ static int adjust_ptr_min_max_vals(struct 
bpf_verifier_env *env,
                return bounds_ret;
        if (sanitize_needed(opcode)) {
                ret = sanitize_ptr_alu(env, insn, dst_reg, off_reg, dst_reg,
-                                      &info, true);
+                                      &info, true, ptr_is_dst_reg);
                if (verifier_bug_if(!can_skip_alu_sanitation(env, insn)
                                    && !env->cur_state->speculative
                                    && bounds_ret
@@ -13906,7 +13908,7 @@ static int adjust_ptr_min_max_vals(struct 
bpf_verifier_env *env,
                        return -EFAULT;
                }
                if (ret < 0)
-                       return sanitize_err(env, insn, ret, off_reg, dst_reg);
+                       return sanitize_err(env, insn, ret, off_reg, dst_reg, 
ptr_is_dst_reg);
        }
 
        return 0;
@@ -14658,7 +14660,7 @@ static int adjust_scalar_min_max_vals(struct 
bpf_verifier_env *env,
        if (sanitize_needed(opcode)) {
                ret = sanitize_val_alu(env, insn);
                if (ret < 0)
-                       return sanitize_err(env, insn, ret, NULL, NULL);
+                       return sanitize_err(env, insn, ret, NULL, NULL, true /* 
does it matter here? */);
        }
 
        /* Calculate sign/unsigned bounds and tnum for alu32 and alu64 bit ops.
@@ -14862,7 +14864,7 @@ static int adjust_reg_min_max_vals(struct 
bpf_verifier_env *env,
                                if (err)
                                        return err;
                                return adjust_ptr_min_max_vals(env, insn,
-                                                              src_reg, 
dst_reg);
+                                                              src_reg, 
dst_reg, false);
                        }
                } else if (ptr_reg) {
                        /* pointer += scalar */
@@ -14870,7 +14872,7 @@ static int adjust_reg_min_max_vals(struct 
bpf_verifier_env *env,
                        if (err)
                                return err;
                        return adjust_ptr_min_max_vals(env, insn,
-                                                      dst_reg, src_reg);
+                                                      dst_reg, src_reg, true);
                } else if (dst_reg->precise) {
                        /* if dst_reg is precise, src_reg should be precise as 
well */
                        err = mark_chain_precision(env, insn->src_reg);
@@ -14886,7 +14888,7 @@ static int adjust_reg_min_max_vals(struct 
bpf_verifier_env *env,
                src_reg = &off_reg;
                if (ptr_reg) /* pointer += K */
                        return adjust_ptr_min_max_vals(env, insn,
-                                                      ptr_reg, src_reg);
+                                                      ptr_reg, src_reg, true);
        }
 
        /* Got here implies adding two SCALAR_VALUEs */

Reply via email to