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 = ®s[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 */