aboutsummaryrefslogtreecommitdiffstats
path: root/queue-5.10/revert-bpf-stop-setting-precise-in-current-state.patch
diff options
Diffstat (limited to 'queue-5.10/revert-bpf-stop-setting-precise-in-current-state.patch')
-rw-r--r--queue-5.10/revert-bpf-stop-setting-precise-in-current-state.patch174
1 files changed, 174 insertions, 0 deletions
diff --git a/queue-5.10/revert-bpf-stop-setting-precise-in-current-state.patch b/queue-5.10/revert-bpf-stop-setting-precise-in-current-state.patch
new file mode 100644
index 0000000000..ee18aa54d1
--- /dev/null
+++ b/queue-5.10/revert-bpf-stop-setting-precise-in-current-state.patch
@@ -0,0 +1,174 @@
+From stable+bounces-155354-greg=kroah.com@vger.kernel.org Mon Jun 23 13:55:13 2025
+From: Aaron Lu <ziqianlu@bytedance.com>
+Date: Mon, 23 Jun 2025 19:54:02 +0800
+Subject: Revert "bpf: stop setting precise in current state"
+To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Cc: stable@vger.kernel.org, Andrii Nakryiko <andrii@kernel.org>, Alexei Starovoitov <ast@kernel.org>, Pu Lehui <pulehui@huawei.com>, Luiz Capitulino <luizcap@amazon.com>, Wei Wei <weiwei.danny@bytedance.com>, Yuchen Zhang <zhangyuchen.lcr@bytedance.com>
+Message-ID: <20250623115403.299-4-ziqianlu@bytedance.com>
+
+From: Aaron Lu <ziqianlu@bytedance.com>
+
+This reverts commit 7ca3e7459f4a5795e78b14390635879f534d9741 which is
+commit f63181b6ae79fd3b034cde641db774268c2c3acf upstream.
+
+The backport of bpf precision tracking related changes has caused bpf
+verifier to panic while loading some certain bpf prog so revert them.
+
+Link: https://lkml.kernel.org/r/20250605070921.GA3795@bytedance/
+Reported-by: Wei Wei <weiwei.danny@bytedance.com>
+Signed-off-by: Aaron Lu <ziqianlu@bytedance.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ kernel/bpf/verifier.c | 103 +++++---------------------------------------------
+ 1 file changed, 12 insertions(+), 91 deletions(-)
+
+--- a/kernel/bpf/verifier.c
++++ b/kernel/bpf/verifier.c
+@@ -2028,11 +2028,8 @@ static void mark_all_scalars_precise(str
+
+ /* big hammer: mark all scalars precise in this path.
+ * pop_stack may still get !precise scalars.
+- * We also skip current state and go straight to first parent state,
+- * because precision markings in current non-checkpointed state are
+- * not needed. See why in the comment in __mark_chain_precision below.
+ */
+- for (st = st->parent; st; st = st->parent) {
++ for (; st; st = st->parent)
+ for (i = 0; i <= st->curframe; i++) {
+ func = st->frame[i];
+ for (j = 0; j < BPF_REG_FP; j++) {
+@@ -2050,88 +2047,8 @@ static void mark_all_scalars_precise(str
+ reg->precise = true;
+ }
+ }
+- }
+ }
+
+-/*
+- * __mark_chain_precision() backtracks BPF program instruction sequence and
+- * chain of verifier states making sure that register *regno* (if regno >= 0)
+- * and/or stack slot *spi* (if spi >= 0) are marked as precisely tracked
+- * SCALARS, as well as any other registers and slots that contribute to
+- * a tracked state of given registers/stack slots, depending on specific BPF
+- * assembly instructions (see backtrack_insns() for exact instruction handling
+- * logic). This backtracking relies on recorded jmp_history and is able to
+- * traverse entire chain of parent states. This process ends only when all the
+- * necessary registers/slots and their transitive dependencies are marked as
+- * precise.
+- *
+- * One important and subtle aspect is that precise marks *do not matter* in
+- * the currently verified state (current state). It is important to understand
+- * why this is the case.
+- *
+- * First, note that current state is the state that is not yet "checkpointed",
+- * i.e., it is not yet put into env->explored_states, and it has no children
+- * states as well. It's ephemeral, and can end up either a) being discarded if
+- * compatible explored state is found at some point or BPF_EXIT instruction is
+- * reached or b) checkpointed and put into env->explored_states, branching out
+- * into one or more children states.
+- *
+- * In the former case, precise markings in current state are completely
+- * ignored by state comparison code (see regsafe() for details). Only
+- * checkpointed ("old") state precise markings are important, and if old
+- * state's register/slot is precise, regsafe() assumes current state's
+- * register/slot as precise and checks value ranges exactly and precisely. If
+- * states turn out to be compatible, current state's necessary precise
+- * markings and any required parent states' precise markings are enforced
+- * after the fact with propagate_precision() logic, after the fact. But it's
+- * important to realize that in this case, even after marking current state
+- * registers/slots as precise, we immediately discard current state. So what
+- * actually matters is any of the precise markings propagated into current
+- * state's parent states, which are always checkpointed (due to b) case above).
+- * As such, for scenario a) it doesn't matter if current state has precise
+- * markings set or not.
+- *
+- * Now, for the scenario b), checkpointing and forking into child(ren)
+- * state(s). Note that before current state gets to checkpointing step, any
+- * processed instruction always assumes precise SCALAR register/slot
+- * knowledge: if precise value or range is useful to prune jump branch, BPF
+- * verifier takes this opportunity enthusiastically. Similarly, when
+- * register's value is used to calculate offset or memory address, exact
+- * knowledge of SCALAR range is assumed, checked, and enforced. So, similar to
+- * what we mentioned above about state comparison ignoring precise markings
+- * during state comparison, BPF verifier ignores and also assumes precise
+- * markings *at will* during instruction verification process. But as verifier
+- * assumes precision, it also propagates any precision dependencies across
+- * parent states, which are not yet finalized, so can be further restricted
+- * based on new knowledge gained from restrictions enforced by their children
+- * states. This is so that once those parent states are finalized, i.e., when
+- * they have no more active children state, state comparison logic in
+- * is_state_visited() would enforce strict and precise SCALAR ranges, if
+- * required for correctness.
+- *
+- * To build a bit more intuition, note also that once a state is checkpointed,
+- * the path we took to get to that state is not important. This is crucial
+- * property for state pruning. When state is checkpointed and finalized at
+- * some instruction index, it can be correctly and safely used to "short
+- * circuit" any *compatible* state that reaches exactly the same instruction
+- * index. I.e., if we jumped to that instruction from a completely different
+- * code path than original finalized state was derived from, it doesn't
+- * matter, current state can be discarded because from that instruction
+- * forward having a compatible state will ensure we will safely reach the
+- * exit. States describe preconditions for further exploration, but completely
+- * forget the history of how we got here.
+- *
+- * This also means that even if we needed precise SCALAR range to get to
+- * finalized state, but from that point forward *that same* SCALAR register is
+- * never used in a precise context (i.e., it's precise value is not needed for
+- * correctness), it's correct and safe to mark such register as "imprecise"
+- * (i.e., precise marking set to false). This is what we rely on when we do
+- * not set precise marking in current state. If no child state requires
+- * precision for any given SCALAR register, it's safe to dictate that it can
+- * be imprecise. If any child state does require this register to be precise,
+- * we'll mark it precise later retroactively during precise markings
+- * propagation from child state to parent states.
+- */
+ static int __mark_chain_precision(struct bpf_verifier_env *env, int frame, int regno,
+ int spi)
+ {
+@@ -2149,10 +2066,6 @@ static int __mark_chain_precision(struct
+ if (!env->bpf_capable)
+ return 0;
+
+- /* Do sanity checks against current state of register and/or stack
+- * slot, but don't set precise flag in current state, as precision
+- * tracking in the current state is unnecessary.
+- */
+ func = st->frame[frame];
+ if (regno >= 0) {
+ reg = &func->regs[regno];
+@@ -2160,7 +2073,11 @@ static int __mark_chain_precision(struct
+ WARN_ONCE(1, "backtracing misuse");
+ return -EFAULT;
+ }
+- new_marks = true;
++ if (!reg->precise)
++ new_marks = true;
++ else
++ reg_mask = 0;
++ reg->precise = true;
+ }
+
+ while (spi >= 0) {
+@@ -2173,7 +2090,11 @@ static int __mark_chain_precision(struct
+ stack_mask = 0;
+ break;
+ }
+- new_marks = true;
++ if (!reg->precise)
++ new_marks = true;
++ else
++ stack_mask = 0;
++ reg->precise = true;
+ break;
+ }
+
+@@ -9358,7 +9279,7 @@ static bool regsafe(struct bpf_verifier_
+ if (env->explore_alu_limits)
+ return false;
+ if (rcur->type == SCALAR_VALUE) {
+- if (!rold->precise)
++ if (!rold->precise && !rcur->precise)
+ return true;
+ /* new val must satisfy old val knowledge */
+ return range_within(rold, rcur) &&