]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bpf: split check_reg_sane_offset() in two parts
authorEduard Zingerman <eddyz87@gmail.com>
Thu, 12 Feb 2026 21:34:21 +0000 (13:34 -0800)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 13 Feb 2026 22:41:22 +0000 (14:41 -0800)
check_reg_sane_offset() is used when verifying operations like:

  dst_reg += src_reg
  ^          ^
  |          '-------- scalar
  '------------------- pointer

To verify range for both dst_reg and src_reg. Split it in two parts:
- one to check a pointer offset
- another to check scalar offset

This would be useful for further refactoring.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260212-ptrs-off-migration-v2-1-00820e4d3438@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/verifier.c

index edf5342b982f676567579ed6349ccd5391eee7c8..3bf72eacbec2407fc79e22f62098755415bdf61c 100644 (file)
@@ -14426,9 +14426,9 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
        return 0;
 }
 
-static bool check_reg_sane_offset(struct bpf_verifier_env *env,
-                                 const struct bpf_reg_state *reg,
-                                 enum bpf_reg_type type)
+static bool check_reg_sane_offset_scalar(struct bpf_verifier_env *env,
+                                        const struct bpf_reg_state *reg,
+                                        enum bpf_reg_type type)
 {
        bool known = tnum_is_const(reg->var_off);
        s64 val = reg->var_off.value;
@@ -14440,12 +14440,6 @@ static bool check_reg_sane_offset(struct bpf_verifier_env *env,
                return false;
        }
 
-       if (reg->off >= BPF_MAX_VAR_OFF || reg->off <= -BPF_MAX_VAR_OFF) {
-               verbose(env, "%s pointer offset %d is not allowed\n",
-                       reg_type_str(env, type), reg->off);
-               return false;
-       }
-
        if (smin == S64_MIN) {
                verbose(env, "math between %s pointer and register with unbounded min value is not allowed\n",
                        reg_type_str(env, type));
@@ -14461,6 +14455,27 @@ static bool check_reg_sane_offset(struct bpf_verifier_env *env,
        return true;
 }
 
+static bool check_reg_sane_offset_ptr(struct bpf_verifier_env *env,
+                                     const struct bpf_reg_state *reg,
+                                     enum bpf_reg_type type)
+{
+       s64 smin = reg->smin_value;
+
+       if (reg->off >= BPF_MAX_VAR_OFF || reg->off <= -BPF_MAX_VAR_OFF) {
+               verbose(env, "%s pointer offset %d is not allowed\n",
+                       reg_type_str(env, type), reg->off);
+               return false;
+       }
+
+       if (smin >= BPF_MAX_VAR_OFF || smin <= -BPF_MAX_VAR_OFF) {
+               verbose(env, "%s pointer offset %lld is not allowed\n",
+                       reg_type_str(env, type), smin);
+               return false;
+       }
+
+       return true;
+}
+
 enum {
        REASON_BOUNDS   = -1,
        REASON_TYPE     = -2,
@@ -14874,8 +14889,8 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
        dst_reg->type = ptr_reg->type;
        dst_reg->id = ptr_reg->id;
 
-       if (!check_reg_sane_offset(env, off_reg, ptr_reg->type) ||
-           !check_reg_sane_offset(env, ptr_reg, ptr_reg->type))
+       if (!check_reg_sane_offset_scalar(env, off_reg, ptr_reg->type) ||
+           !check_reg_sane_offset_ptr(env, ptr_reg, ptr_reg->type))
                return -EINVAL;
 
        /* pointer types do not carry 32-bit bounds at the moment. */
@@ -15004,7 +15019,7 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
                return -EACCES;
        }
 
-       if (!check_reg_sane_offset(env, dst_reg, ptr_reg->type))
+       if (!check_reg_sane_offset_ptr(env, dst_reg, ptr_reg->type))
                return -EINVAL;
        reg_bounds_sync(dst_reg);
        bounds_ret = sanitize_check_bounds(env, insn, dst_reg);