bpf_reg_state carries a single bool, ->precise. Other per-register boolean
properties exist (and more are coming), so convert the bool into a u8,
call it flags and give the property a name.

  -     bool precise;
  +#define BPF_FLAG_PRECISE     (1U << 7)
  +     u8 flags;

Both occupy 1 byte at the same offset, so the struct layout is unchanged.
->precise was the last field, after ->frameno, and ->flags takes exactly
that slot, so the memcmp()/offsetof() based comparisons are unaffected:
every one of them stops at offsetof(id), offsetof(var_off) or
offsetof(frameno), i.e. at or before the field either way.

That tail position is not an accident -- it is where fields live that are
compared semantically rather than byte-wise. ->precise is never memcmp()ed;
regsafe() tests it explicitly, and an imprecise old scalar is a wildcard:

        if (!reg_is_precise(rold) && exact == NOT_EXACT)
                return true;

PRECISE also takes bit 7 rather than bit 0, because it is the odd one out
among the flags that will share this byte: the others describe how a register
relates to its ->id set and are cleared as a group, while PRECISE belongs to
the register alone and must survive that clearing. Growing the rest up from
bit 0 keeps a clear-the-link-bits mask from reaching it by construction.

Reads go through a helper, since they are the common case and read better.
Set and clear stay open-coded as the usual reg->flags |= / &= ~ bit ops.

No functional change intended.

Suggested-by: Eduard Zingerman <[email protected]>
Signed-off-by: Vineet Gupta <[email protected]>
---
 include/linux/bpf_verifier.h | 18 ++++++++++++++++--
 kernel/bpf/backtrack.c       | 22 +++++++++++-----------
 kernel/bpf/log.c             |  2 +-
 kernel/bpf/states.c          | 10 +++++-----
 kernel/bpf/verifier.c        | 14 +++++++++-----
 5 files changed, 42 insertions(+), 24 deletions(-)

diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 27b43fda9b17..ebab483fc7f2 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -162,10 +162,24 @@ struct bpf_reg_state {
         * pointing to bpf_func_state.
         */
        u32 frameno;
-       /* if (!precise && SCALAR_VALUE) min/max/tnum don't affect safety */
-       bool precise;
+       /*
+        * Register state flags.
+        * BPF_FLAG_PRECISE: if unset, and this is a SCALAR_VALUE, then
+        * min/max/tnum don't affect safety.
+        *
+        * PRECISE is a property of this register alone, so it is placed at bit 
7,
+        * apart from the link flags, which grow up from bit 0 and are cleared 
as
+        * a group -- a clear-the-link-bits mask can then never reach it.
+        */
+#define BPF_FLAG_PRECISE       (1U << 7)
+       u8 flags;
 };
 
+static inline bool reg_is_precise(const struct bpf_reg_state *reg)
+{
+       return reg->flags & BPF_FLAG_PRECISE;
+}
+
 static inline s64 reg_smin(const struct bpf_reg_state *reg)
 {
        return cnum64_smin(reg->r64);
diff --git a/kernel/bpf/backtrack.c b/kernel/bpf/backtrack.c
index a2b18a9f1694..400c69152ed2 100644
--- a/kernel/bpf/backtrack.c
+++ b/kernel/bpf/backtrack.c
@@ -675,9 +675,9 @@ void bpf_mark_all_scalars_precise(struct bpf_verifier_env 
*env,
                        func = st->frame[i];
                        for (j = 0; j < BPF_REG_FP; j++) {
                                reg = &func->regs[j];
-                               if (reg->type != SCALAR_VALUE || reg->precise)
+                               if (reg->type != SCALAR_VALUE || 
reg_is_precise(reg))
                                        continue;
-                               reg->precise = true;
+                               reg->flags |= BPF_FLAG_PRECISE;
                                if (env->log.level & BPF_LOG_LEVEL2) {
                                        verbose(env, "force_precise: frame%d: 
forcing r%d to be precise\n",
                                                i, j);
@@ -687,9 +687,9 @@ void bpf_mark_all_scalars_precise(struct bpf_verifier_env 
*env,
                                if (!bpf_is_spilled_reg(&func->stack[j]))
                                        continue;
                                reg = &func->stack[j].spilled_ptr;
-                               if (reg->type != SCALAR_VALUE || reg->precise)
+                               if (reg->type != SCALAR_VALUE || 
reg_is_precise(reg))
                                        continue;
-                               reg->precise = true;
+                               reg->flags |= BPF_FLAG_PRECISE;
                                if (env->log.level & BPF_LOG_LEVEL2) {
                                        verbose(env, "force_precise: frame%d: 
forcing fp%d to be precise\n",
                                                i, -(j + 1) * 8);
@@ -851,7 +851,7 @@ int bpf_mark_chain_precision(struct bpf_verifier_env *env,
                                        reg = &st->frame[0]->regs[i];
                                        bt_clear_reg(bt, i);
                                        if (reg->type == SCALAR_VALUE) {
-                                               reg->precise = true;
+                                               reg->flags |= BPF_FLAG_PRECISE;
                                                *changed = true;
                                        }
                                }
@@ -912,10 +912,10 @@ int bpf_mark_chain_precision(struct bpf_verifier_env *env,
                                        bt_clear_frame_reg(bt, fr, i);
                                        continue;
                                }
-                               if (reg->precise) {
+                               if (reg_is_precise(reg)) {
                                        bt_clear_frame_reg(bt, fr, i);
                                } else {
-                                       reg->precise = true;
+                                       reg->flags |= BPF_FLAG_PRECISE;
                                        *changed = true;
                                }
                        }
@@ -932,10 +932,10 @@ int bpf_mark_chain_precision(struct bpf_verifier_env *env,
                                        continue;
                                }
                                reg = &func->stack[i].spilled_ptr;
-                               if (reg->precise) {
+                               if (reg_is_precise(reg)) {
                                        bt_clear_frame_slot(bt, fr, i);
                                } else {
-                                       reg->precise = true;
+                                       reg->flags |= BPF_FLAG_PRECISE;
                                        *changed = true;
                                }
                        }
@@ -943,10 +943,10 @@ int bpf_mark_chain_precision(struct bpf_verifier_env *env,
                                if (!bt_is_frame_stack_arg_slot_set(bt, fr, i))
                                        continue;
                                reg = &func->stack_arg_regs[i];
-                               if (reg->type != SCALAR_VALUE || reg->precise) {
+                               if (reg->type != SCALAR_VALUE || 
reg_is_precise(reg)) {
                                        bt_clear_frame_stack_arg_slot(bt, fr, 
i);
                                } else {
-                                       reg->precise = true;
+                                       reg->flags |= BPF_FLAG_PRECISE;
                                        *changed = true;
                                }
                        }
diff --git a/kernel/bpf/log.c b/kernel/bpf/log.c
index b740fa73ee26..9a4445d492c9 100644
--- a/kernel/bpf/log.c
+++ b/kernel/bpf/log.c
@@ -640,7 +640,7 @@ static void print_reg_state(struct bpf_verifier_env *env,
        const char *sep = "";
 
        t = reg->type;
-       if (t == SCALAR_VALUE && reg->precise)
+       if (t == SCALAR_VALUE && reg_is_precise(reg))
                verbose(env, "P");
        if (t == SCALAR_VALUE && tnum_is_const(reg->var_off)) {
                verbose_snum(env, reg->var_off.value);
diff --git a/kernel/bpf/states.c b/kernel/bpf/states.c
index 4e6aafad33bd..f7a0314fa106 100644
--- a/kernel/bpf/states.c
+++ b/kernel/bpf/states.c
@@ -548,7 +548,7 @@ static bool regsafe(struct bpf_verifier_env *env, struct 
bpf_reg_state *rold,
                        return memcmp(rold, rcur, offsetof(struct 
bpf_reg_state, id)) == 0 &&
                               check_scalar_ids(rold->id, rcur->id, idmap);
                }
-               if (!rold->precise && exact == NOT_EXACT)
+               if (!reg_is_precise(rold) && exact == NOT_EXACT)
                        return true;
                /*
                 * Linked register tracking uses rold->id to detect 
relationships.
@@ -1034,7 +1034,7 @@ static int propagate_precision(struct bpf_verifier_env 
*env,
                first = true;
                for (i = 0; i < BPF_REG_FP; i++, state_reg++) {
                        if (state_reg->type != SCALAR_VALUE ||
-                           !state_reg->precise)
+                           !reg_is_precise(state_reg))
                                continue;
                        if (env->log.level & BPF_LOG_LEVEL2) {
                                if (first)
@@ -1051,7 +1051,7 @@ static int propagate_precision(struct bpf_verifier_env 
*env,
                                continue;
                        state_reg = &state->stack[i].spilled_ptr;
                        if (state_reg->type != SCALAR_VALUE ||
-                           !state_reg->precise)
+                           !reg_is_precise(state_reg))
                                continue;
                        if (env->log.level & BPF_LOG_LEVEL2) {
                                if (first)
@@ -1223,7 +1223,7 @@ static void mark_all_scalars_imprecise(struct 
bpf_verifier_env *env, struct bpf_
                        reg = &func->regs[j];
                        if (reg->type != SCALAR_VALUE)
                                continue;
-                       reg->precise = false;
+                       reg->flags &= ~BPF_FLAG_PRECISE;
                }
                for (j = 0; j < func->allocated_stack / BPF_REG_SIZE; j++) {
                        if (!bpf_is_spilled_reg(&func->stack[j]))
@@ -1231,7 +1231,7 @@ static void mark_all_scalars_imprecise(struct 
bpf_verifier_env *env, struct bpf_
                        reg = &func->stack[j].spilled_ptr;
                        if (reg->type != SCALAR_VALUE)
                                continue;
-                       reg->precise = false;
+                       reg->flags &= ~BPF_FLAG_PRECISE;
                }
        }
 }
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 6ac1afced20b..8925749d636e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -1830,7 +1830,9 @@ static void __mark_reg_const_zero(const struct 
bpf_verifier_env *env, struct bpf
        /* all scalars are assumed imprecise initially (unless unprivileged,
         * in which case everything is forced to be precise)
         */
-       reg->precise = !env->bpf_capable;
+       reg->flags &= ~BPF_FLAG_PRECISE;
+       if (!env->bpf_capable)
+               reg->flags |= BPF_FLAG_PRECISE;
 }
 
 static void mark_reg_known_zero(struct bpf_verifier_env *env,
@@ -2139,13 +2141,14 @@ void bpf_mark_reg_unknown_imprecise(struct 
bpf_reg_state *reg)
 }
 
 /* Mark a register as having a completely unknown (scalar) value,
- * initialize .precise as true when not bpf capable.
+ * set BPF_FLAG_PRECISE when not bpf capable.
  */
 static void __mark_reg_unknown(const struct bpf_verifier_env *env,
                               struct bpf_reg_state *reg)
 {
        bpf_mark_reg_unknown_imprecise(reg);
-       reg->precise = !env->bpf_capable;
+       if (!env->bpf_capable)
+               reg->flags |= BPF_FLAG_PRECISE;
 }
 
 static void mark_reg_unknown(struct bpf_verifier_env *env,
@@ -7506,7 +7509,8 @@ static void maybe_widen_reg(struct bpf_verifier_env *env,
                return;
        if (rold->type != rcur->type)
                return;
-       if (rold->precise || rcur->precise || scalars_exact_for_widen(rold, 
rcur))
+       if (reg_is_precise(rold) || reg_is_precise(rcur) ||
+           scalars_exact_for_widen(rold, rcur))
                return;
        __mark_reg_unknown(env, rcur);
 }
@@ -14876,7 +14880,7 @@ static int adjust_reg_min_max_vals(struct 
bpf_verifier_env *env,
                                return err;
                        return adjust_ptr_min_max_vals(env, insn,
                                                       dst_reg, src_reg);
-               } else if (dst_reg->precise) {
+               } else if (reg_is_precise(dst_reg)) {
                        /* if dst_reg is precise, src_reg should be precise as 
well */
                        err = mark_chain_precision(env, insn->src_reg);
                        if (err)
-- 
2.53.0-Meta


Reply via email to