* [PATCH AUTOSEL 6.18-5.10] netfilter: nf_conntrack_expect: zero at allocation time
[not found] <20260831133314.4125787-1-sashal@kernel.org>
@ 2026-08-31 13:29 ` Sasha Levin
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18-5.10] netfilter: ipset: mark the rcu locked areas properly Sasha Levin
` (3 subsequent siblings)
4 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-08-31 13:29 UTC (permalink / raw)
To: patches, stable
Cc: Florian Westphal, Sasha Levin, pablo, davem, edumazet, kuba,
pabeni, netfilter-devel, coreteam, netdev, linux-kernel
From: Florian Westphal <fw@strlen.de>
[ Upstream commit 241ccd2fed9051db443aadce248fc0ab30f55e97 ]
There are occasional LLM hints wrt. leaking uninitialized data to
userspace via ctnetlink. Just zero at allocation time,
expectations are not frequently used these days.
Intentionally keeps _init as-is because we could theoretically
support re-init, so add the missing exp->dir there.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
**Step 1.1 — Subject line**
Record: `[netfilter: nf_conntrack_expect]` `[zero]` — zero expectation
objects at allocation time to avoid leaking uninitialized slab data.
**Step 1.2 — Tags**
Record:
- Signed-off-by: Florian Westphal \<fw@strlen.de\>
- No Fixes:, Reported-by:, Tested-by:, Reviewed-by:, Acked-by:, Link:,
or Cc: stable tags
Notable: no formal bug report or syzbot link; author cites “occasional
LLM hints” about ctnetlink leaks.
**Step 1.3 — Body analysis**
Record:
- Bug: `nf_ct_expect_alloc()` uses non-zeroing `kmem_cache_alloc()`;
fields not explicitly initialized can retain stale slab contents and
be exposed to userspace via ctnetlink expectation dumps.
- Symptom: spurious or stale data in netlink expectation dumps
(especially NAT-related attributes).
- Root cause: per-field initialization is incomplete across allocation
paths; centralized zeroing at alloc is safer.
- Author notes expectations are rarely used today; keeps
`nf_ct_expect_init()` behavior but adds missing `exp->dir`
initialization there.
**Step 1.4 — Hidden bug fix?**
Record: Yes. Despite the soft wording, this is a kernel heap
information-leak fix, not a style change. The `kmem_cache_alloc` →
`kmem_cache_zalloc` change and `exp->dir = 0` addition address
uninitialized memory exposure.
---
## Phase 2: Diff Analysis
**Step 2.1 — Inventory**
Record:
- `net/netfilter/nf_conntrack_expect.c`: +2 / -1 (3 lines touched)
- `net/netfilter/nf_conntrack_netlink.c`: +1 / -10 (11 lines removed)
- Functions: `nf_ct_expect_alloc()`, `nf_ct_expect_init()`,
`ctnetlink_alloc_expect()`
- Scope: small, two-file, surgical fix
**Step 2.2 — Code flow per hunk**
Record:
1. `nf_ct_expect_alloc()`: `kmem_cache_alloc` → `kmem_cache_zalloc` —
all struct fields start zeroed.
2. `nf_ct_expect_init()`: adds `exp->dir = 0` under `CONFIG_NF_NAT`
alongside existing `saved_addr`/`saved_proto` zeroing.
3. `ctnetlink_alloc_expect()`: removes redundant `else` branches that
zeroed `flags`, `expectfn`, and NAT fields — now handled by zalloc.
**Step 2.3 — Bug mechanism**
Record: **Uninitialized data / information leak (category 8)**. Slab
reuse leaves stale kernel data in `struct nf_conntrack_expect` fields.
`ctnetlink_exp_dump_expect()` reads `exp->flags`, and under
`CONFIG_NF_NAT` emits `CTA_EXPECT_NAT` when `saved_addr`/`saved_proto`
look non-zero, leaking stale addresses/ports/direction to userspace.
**Step 2.4 — Fix quality**
Record: Fix is obviously correct and minimal. `kmem_cache_zalloc` is the
standard pattern for objects with many partially-initialized fields.
Regression risk is very low; expectations are infrequent and zeroing
cost is negligible.
---
## Phase 3: Git History Investigation
**Step 3.1 — Blame**
Record: `kmem_cache_alloc(nf_ct_expect_cachep, GFP_ATOMIC)` dates to
Patrick McHardy (2007). Bug has existed since expectations used a non-
zeroing slab allocator. `nf_ct_expect_init()` has zeroed
`saved_addr`/`saved_proto` since NAT support was added, but never
`exp->dir`.
**Step 3.2 — Fixes: tag**
Record: N/A — no Fixes: tag in this commit.
**Step 3.3 — Related file history**
Record: Related commit already in this tree:
- `929f7a9a7aad9` — “netfilter: ctnetlink: zero expect NAT fields when
CTA_EXPECT_NAT absent” — targeted partial fix for the ctnetlink
userspace creation path only, with a concrete reproduction (kernel
test robot).
This commit generalizes the fix to all allocation paths and removes the
now-redundant ctnetlink `else` branches.
**Step 3.4 — Author context**
Record: Florian Westphal is an active netfilter contributor/maintainer.
Similar leak fix `7e23965d44f06` (“nft_meta_bridge: fix
NFT_META_BRI_IIFPVID stack leak”) is already in this 6.18.y tree.
**Step 3.5 — Dependencies**
Record: Standalone; no series prerequisites. `git apply --check` on
commit `241ccd2fed905` succeeds cleanly against HEAD.
---
## Phase 4: Mailing List and External Research
**Step 4.1 — Original discussion**
Record: `b4 dig -c 241ccd2fed905` found v1 only at
https://patch.msgid.link/20260625001356.16478-1-fw@strlen.de. Lore fetch
blocked by bot protection; no reviewer replies retrieved.
**Step 4.2 — Reviewers**
Record: `b4 dig -w` shows recipients: Florian Westphal, netfilter-
devel@vger.kernel.org. No explicit maintainer Acked-by in commit.
**Step 4.3 — Bug report**
Record: No formal Reported-by in this commit. Related bug in
`929f7a9a7aad9` was Reported-by: kernel test robot with demonstrated
stale `CTA_EXPECT_NAT` emission.
**Step 4.4 — Series context**
Record: Single-patch series (v1 only). Not part of a multi-patch
dependency chain.
**Step 4.5 — Stable list**
Record: Not searched (lore blocked). Similar Westphal leak fix already
accepted into this stable tree.
---
## Phase 5: Code Semantic Analysis
**Step 5.1 — Key functions**
Record: `nf_ct_expect_alloc()`, `nf_ct_expect_init()`,
`ctnetlink_alloc_expect()`, `ctnetlink_exp_dump_expect()`.
**Step 5.2 — Callers**
Record: `nf_ct_expect_alloc()` called from ~15 sites: protocol helpers
(FTP, SIP, H.323, PPTP, TFTP, IRC, etc.), `nf_conntrack_broadcast.c`,
`ctnetlink_alloc_expect()`, `nft_ct.c`, IPVS. Most call
`nf_ct_expect_init()` afterward; broadcast manually sets fields without
`nf_ct_expect_init()`.
**Step 5.3 — Callees**
Record: `kmem_cache_zalloc`/`kmem_cache_alloc`, `refcount_set`, slab
free via RCU. Dump path reads struct fields into netlink skb.
**Step 5.4 — Reachability**
Record: Leak is reachable when a privileged user dumps expectations via
ctnetlink (`ctnetlink_exp_dump_expect()`). Creating expectations via
broadcast helper (no NAT field init) and then dumping can expose stale
NAT data — path exists in this tree.
**Step 5.5 — Similar patterns**
Record: `929f7a9a7aad9` fixed the same class of bug narrowly in
ctnetlink. `nf_ct_expect_init()` already zeroes most fields on the
packet path but omitted `dir`. Centralized zalloc is the comprehensive
fix.
---
## Phase 6: Cross-Reference Against Local Tree (v6.18.44)
**Step 6.1 — Buggy code present?**
Record: Yes. HEAD is `v6.18.44` on `stable/linux-6.18.y`. Current code
still uses `kmem_cache_alloc` at line 307 of `nf_conntrack_expect.c`.
Commit `241ccd2fed905` is **not** in this tree.
**Step 6.2 — Backport complications**
Record: Clean apply verified. Removes code added by in-tree
`929f7a9a7aad9`; no structural conflicts.
**Step 6.3 — Related fixes already present**
Record: `929f7a9a7aad9` partially fixes ctnetlink NAT-field leak only.
Does **not** cover `nf_conntrack_broadcast.c` and other paths that
allocate without fully initializing NAT fields. This commit still adds
value.
---
## Phase 7: Subsystem Context
**Step 7.1 — Subsystem**
Record: netfilter / nf_conntrack / ctnetlink. Criticality: **IMPORTANT**
(networking core subsystem, widely deployed).
**Step 7.2 — Activity**
Record: Actively maintained; multiple recent expectation/ctnetlink fixes
in this tree’s history.
---
## Phase 8: Impact and Risk Assessment
**Step 8.1 — Who is affected**
Record: Systems with `CONFIG_NF_CONNTRACK` and ctnetlink users (firewall
managers, `conntrack` tools). Affects administrators/privileged tooling,
not unprivileged users directly.
**Step 8.2 — Trigger conditions**
Record: Allocate expectation without full field initialization (slab
reuse), then dump via ctnetlink. Moderately rare but reproducible
(demonstrated for ctnetlink path in `929f7a9a7aad9`). Requires
`CAP_NET_ADMIN` for dump.
**Step 8.3 — Failure mode**
Record: Kernel heap memory leaked to userspace via netlink attributes.
Severity: **MEDIUM** (security information disclosure, not
crash/corruption).
**Step 8.4 — Risk/benefit**
Record:
- Benefit: Closes remaining leak paths beyond the partial ctnetlink fix;
defense-in-depth at the central allocator.
- Risk: Very low — 14-line change, standard zalloc pattern, infrequent
code path.
- Ratio: Favorable for stable inclusion.
---
## Phase 9: Final Synthesis
**Step 9.1 — Evidence summary**
FOR:
- Real kernel memory info leak via ctnetlink
- Partial fix (`929f7a9a7aad9`) already in tree leaves gaps (e.g.,
`nf_conntrack_broadcast.c` never initializes NAT fields)
- Tiny, obviously correct, applies cleanly
- Same author’s similar leak fixes already in 6.18.y
- Adds missing `exp->dir` init in `nf_ct_expect_init()`
AGAINST:
- Requires privileged access to observe leak
- Expectations are uncommon
- Primary reported case partially addressed by existing stable commit
- No syzbot/formal CVE; “LLM hints” only in this commit message
UNRESOLVED:
- Full lore review thread (bot-blocked)
- No independent Tested-by on this specific commit
**Step 9.2 — Stable rules checklist**
1. Obviously correct and tested? **PASS** — zalloc is standard; related
leak class already reproduced in-tree via `929f7a9a7aad9`.
2. Fixes a real bug affecting users? **PASS** — verified stale-data leak
path; broadcast path still vulnerable without this fix.
3. Important issue? **PASS** — security information leak (medium
severity).
4. Small and contained? **PASS** — 14 lines, 2 files.
5. No new features/APIs? **PASS**.
6. Can apply to local tree? **PASS** — `git apply --check` succeeded.
**Step 9.3 — Exception category**
Record: N/A (not device ID, quirk, DT, build, or docs fix — standard bug
fix).
**Step 9.4 — Decision rationale**
This tree (6.18.44) still has the underlying allocator bug. While
`929f7a9a7aad9` patched one ctnetlink-specific leak, `kmem_cache_zalloc`
in `nf_ct_expect_alloc()` fixes all allocation paths comprehensively,
including `nf_conntrack_broadcast.c` which never calls
`nf_ct_expect_init()` and does not initialize NAT-related fields. The
change is minimal, low-risk, and consistent with other netfilter leak
fixes already accepted into this stable series.
---
## Verification
- [Phase 1] Parsed commit `241ccd2fed905`: subject, body, only SOB from
Florian Westphal
- [Phase 2] Diff analysis: 2 files, `kmem_cache_zalloc`, `exp->dir = 0`,
removed ctnetlink else branches
- [Phase 3] `git describe HEAD`: v6.18.44; tree is stable/linux-6.18.y
- [Phase 3] `git blame`: `kmem_cache_alloc` since 2007
- [Phase 3] `929f7a9a7aad9` confirmed in tree via `git merge-base --is-
ancestor`
- [Phase 3] `241ccd2fed905` confirmed NOT in tree
- [Phase 3] `git apply --check` on patch: clean apply
- [Phase 4] `b4 dig -c 241ccd2fed905`: found v1 at
patch.msgid.link/20260625001356.16478-1-fw@strlen.de
- [Phase 4] `b4 dig -w`: netfilter-devel CC'd
- [Phase 4] `b4 dig -a`: v1 only
- [Phase 4] Lore thread fetch: blocked by Anubis (UNVERIFIED: reviewer
comments)
- [Phase 5] `grep nf_ct_expect_alloc`: 15+ call sites; broadcast path
does not call `nf_ct_expect_init()`
- [Phase 5] Read `ctnetlink_exp_dump_expect()`: dumps flags always; NAT
block when `saved_addr`/`saved_proto` non-zero
- [Phase 5] Read `nf_conntrack_broadcast.c`: does not init
`saved_addr`/`saved_proto`/`dir`
- [Phase 6] Current code at line 307: still `kmem_cache_alloc`
- [Phase 6] `7e23965d44f06` similar Westphal leak fix present in tree
- [Phase 8] Trigger requires CAP_NET_ADMIN for ctnetlink dump (standard
nfnetlink permission model)
**YES**
net/netfilter/nf_conntrack_expect.c | 3 ++-
net/netfilter/nf_conntrack_netlink.c | 11 +----------
2 files changed, 3 insertions(+), 11 deletions(-)
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 8e943efbdf0a5..6266d4d2ffca4 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -304,7 +304,7 @@ struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me)
{
struct nf_conntrack_expect *new;
- new = kmem_cache_alloc(nf_ct_expect_cachep, GFP_ATOMIC);
+ new = kmem_cache_zalloc(nf_ct_expect_cachep, GFP_ATOMIC);
if (!new)
return NULL;
@@ -386,6 +386,7 @@ void nf_ct_expect_init(struct nf_conntrack_expect *exp, unsigned int class,
#if IS_ENABLED(CONFIG_NF_NAT)
memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
+ exp->dir = 0;
#endif
}
EXPORT_SYMBOL_GPL(nf_ct_expect_init);
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 3df7e5fc76c8b..e046281895743 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -3559,8 +3559,6 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
if (cda[CTA_EXPECT_FLAGS]) {
exp->flags = ntohl(nla_get_be32(cda[CTA_EXPECT_FLAGS]));
exp->flags &= ~NF_CT_EXPECT_USERSPACE;
- } else {
- exp->flags = 0;
}
if (cda[CTA_EXPECT_FN]) {
const char *name = nla_data(cda[CTA_EXPECT_FN]);
@@ -3572,8 +3570,7 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
goto err_out;
}
exp->expectfn = expfn->expectfn;
- } else
- exp->expectfn = NULL;
+ }
exp->class = class;
exp->master = ct;
@@ -3592,12 +3589,6 @@ ctnetlink_alloc_expect(const struct nlattr * const cda[], struct nf_conn *ct,
exp, nf_ct_l3num(ct));
if (err < 0)
goto err_out;
-#if IS_ENABLED(CONFIG_NF_NAT)
- } else {
- memset(&exp->saved_addr, 0, sizeof(exp->saved_addr));
- memset(&exp->saved_proto, 0, sizeof(exp->saved_proto));
- exp->dir = 0;
-#endif
}
return exp;
err_out:
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH AUTOSEL 6.18-5.10] netfilter: ipset: mark the rcu locked areas properly
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-5.10] netfilter: nf_conntrack_expect: zero at allocation time Sasha Levin
@ 2026-08-31 13:30 ` Sasha Levin
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18] netfilter: nf_tables: use DEBUG_NET_WARN_ON_ONCE in packet and control paths Sasha Levin
` (2 subsequent siblings)
4 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-08-31 13:30 UTC (permalink / raw)
To: patches, stable
Cc: Jozsef Kadlecsik, Florian Westphal, Sasha Levin, pablo, davem,
edumazet, kuba, pabeni, netfilter-devel, coreteam, netdev,
linux-kernel
From: Jozsef Kadlecsik <kadlec@netfilter.org>
[ Upstream commit 5d0c22e73656d050daffad10a2ba8765ce8441c8 ]
When we bump the uref counter, there's no need to keep
the rcu lock because the referred hash table can't
disappear. Also, from the same reason in mtype_gc we
need the rcu lock and not a spinlock.
Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org>
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `netfilter: ipset: mark the rcu locked areas
properly`
**Local tree:** Linux 6.18.44 (`v6.18.44-1-g2736c32da98b9`)
**Commit analyzed:** `5d0c22e73656d050daffad10a2ba8765ce8441c8` (not yet
in this tree; patch applies cleanly)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[netfilter: ipset]` `[mark]` — Correct RCU locking
annotations/usage in hash-type ipset GC and add paths.
### Step 1.2: Tags
**Record:**
- `Signed-off-by: Jozsef Kadlecsik <kadlec@netfilter.org>` (ipset
maintainer)
- `Signed-off-by: Florian Westphal <fw@strlen.de>` (netfilter developer)
- No `Fixes:`, `Reported-by:`, `Link:`, `Cc: stable`, `Acked-by:`, or
`Reviewed-by:` tags
Notable: absence of stable tags is expected for manual review; not a
negative signal.
### Step 1.3: Body analysis
**Record:**
- **Bug described:** RCU read-side critical sections are held longer
than necessary after bumping `uref`, and `mtype_gc` uses `set->lock`
(spinlock) instead of RCU to dereference `h->table`.
- **Mechanism:** Once `atomic_inc(&t->uref)` runs, the hash table cannot
be freed; RCU protection is only needed until that point.
- **Symptom/failure mode:** Incorrect synchronization — potential use-
after-free in GC vs. resize, and RCU read lock held across lengthy GC
work in `mtype_add` (RCU stall class).
- **Version info:** None in commit message.
### Step 1.4: Hidden bug fix?
**Record:** Yes. Despite neutral wording ("mark the rcu locked areas
properly"), this is a real concurrency fix, not cosmetic cleanup. Wrong
lock type in `mtype_gc` and holding RCU across `mtype_gc_do()` are both
correctness bugs in the same class as the 2020 RCU-stall fix
(`f66ee0410b1c`).
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **File:** `net/netfilter/ipset/ip_set_hash_gen.h` (+5 / -8 lines)
- **Functions modified:** `mtype_gc()`, `mtype_add()`
- **Scope:** Single-file, surgical fix
### Step 2.2: Code flow changes
**Hunk 1 — `mtype_gc()`:**
- **Before:** `spin_lock_bh(&set->lock)` →
`ipset_dereference_set(h->table, set)` → `atomic_inc(&t->uref)` →
`spin_unlock_bh(&set->lock)`
- **After:** `rcu_read_lock_bh()` → `rcu_dereference_bh(h->table)` →
`atomic_inc(&t->uref)` → `rcu_read_unlock_bh()`
- **Path affected:** Workqueue GC path for timed-out hash set elements
**Hunk 2 — `mtype_add()`:**
- **Before:** RCU held from table dereference through optional
`mtype_gc_do()` call and element-count scan; unlock/relock dance
around `mtype_gc_do()`
- **After:** RCU released immediately after `atomic_inc(&t->uref)`;
`mtype_gc_do()` runs without RCU held
- **Path affected:** Kernel-side add path when a hash region appears
full (common under netfilter SET target traffic)
### Step 2.3: Bug mechanism
**Record:**
- **Category:** (b) Synchronization / race + RCU stall
- **mtype_gc mechanism:** `h->table` is RCU-protected (see file header
comment at lines 27–37). Resize swaps it under nfnl mutex +
`rcu_assign_pointer()` + `synchronize_rcu()` — it does **not** take
`set->lock`. GC workqueue using `set->lock` to dereference `h->table`
is not synchronized with resize; a table can be freed between pointer
read and `uref` bump → UAF.
- **mtype_add mechanism:** `mtype_gc_do()` acquires
`spin_lock_bh(&t->hregion[r].lock)` and iterates buckets — substantial
work. Holding `rcu_read_lock_bh()` across that work risks RCU stalls,
the same failure mode addressed by `f66ee0410b1c` in 2020.
### Step 2.4: Fix quality
**Record:** Fix is minimal and logically sound — `uref` pins the table
after RCU dereference, matching the pattern already used throughout this
header (resize at line 679, dump paths at 1350–1354). Low regression
risk; no API or structural changes.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** Both affected code regions were introduced in
`5d324e5159d9e` (merge into 6.18, Nov 2025). The buggy locking pattern
has been present since the current RCU-based hash implementation landed
in this file's recent history. The underlying RCU hash design dates to
`f66ee0410b1c` (Feb 2020, syzbot-reported RCU stalls).
### Step 3.2: Fixes tag
**Record:** N/A — no `Fixes:` tag present.
### Step 3.3: Related file history
**Record:** Recent related commits in this tree:
- `7228cc8ff6265` — data race fix (add vs dump), syzbot-reported
- `12088da6add5b` — GC shutdown fix
- `c4d257734e91b`, `a0afd353c2f7e` — RCU reader/writer annotation fixes
- `f66ee0410b1c` — original RCU stall fix for hash types (in tree since
2020)
This commit is patch 1/5 in series "gc, backlog and cidr patches"; cover
letter states patches 1 and 4 are independent cleanups. **Standalone for
backport.**
### Step 3.4: Author context
**Record:** Jozsef Kadlecsik is the ipset maintainer and author of the
2020 RCU stall fix and multiple recent ipset stable backports. Florian
Westphal co-signed.
### Step 3.5: Dependencies
**Record:** No dependencies on patches 2–5. `git apply --check` succeeds
on current tree. Self-contained.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:**
- `b4 dig -c 5d0c22e`:
https://patch.msgid.link/20260702134701.207721-2-kadlec@netfilter.org
- Series: v1 only (2026-07-02), 5 patches
- Cover letter (patch 0/5): patches 1 and 4 described as "independent
cleanups and clarifications"; patches 2–3–5 address gc/resize
clashing, backlog cleanup, and cidr bookkeeping
- No review replies found in downloaded mbox (series cover + patches
only)
### Step 4.2: Reviewers
**Record:** `b4 dig -w`: CC'd to `netfilter-devel@vger.kernel.org`,
`Pablo Neira Ayuso <pablo@netfilter.org>`. Signed off by Florian
Westphal.
### Step 4.3: Bug reports
**Record:** No `Reported-by:` or `Link:` tags. Related series patch 2/5
reports gc/resize comment-extension UAF (separate bug, separate backport
decision). This patch's bugs are identifiable from code analysis and
align with prior syzbot-found RCU issues in the same subsystem.
### Step 4.4: Series context
**Record:** Patches 2–5 fix distinct issues (gc during resize, backlog
cleanup, memory allocation, cidr rework). Patch 1 does not require them.
### Step 4.5: Stable list history
**Record:** Not searched on lore stable list (no stable nomination found
in series mbox). Not a negative signal.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `mtype_gc()`, `mtype_gc_do()`, `mtype_add()`
### Step 5.2: Callers
**Record:**
- `mtype_add()` called from resize backlog replay (line 774) and via
`ip_set_add()` → `set->variant->kadt()` → hash type add (netfilter hot
path, packet processing)
- `mtype_gc()` scheduled from `mtype_gc_init()` via
`queue_delayed_work()` on timed-out hash sets
### Step 5.3: Callees
**Record:** `mtype_gc_do()` takes `spin_lock_bh(&t->hregion[r].lock)`,
iterates buckets, may call `mtype_del_cidr()` (which takes `set->lock`),
`kfree_rcu()`, `rcu_assign_pointer()`
### Step 5.4: Reachability
**Record:**
- `mtype_add`: reachable from netfilter packet path (`ip_set_add`
exported, used by iptables/nftables SET targets) — **userspace-
triggerable via network traffic + firewall rules**
- `mtype_gc`: triggered periodically on timeout-enabled hash sets —
**automatic, production-relevant**
### Step 5.5: Similar patterns
**Record:** Correct pattern already used elsewhere in same file:
`mtype_del()` (lines 1060–1065), `mtype_uref()` (1350–1354), resize path
(677–679). This patch aligns `mtype_gc` and `mtype_add` with established
conventions.
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE
### Step 6.1: Buggy code present?
**Record:** **Yes.** Current tree at
`net/netfilter/ipset/ip_set_hash_gen.h`:
- `mtype_gc()` lines 572–583: uses `spin_lock_bh(&set->lock)` +
`ipset_dereference_set()`
- `mtype_add()` lines 858–879: holds RCU across `mtype_gc_do()` with
unlock/relock dance
Commit `5d0c22e` is **not** an ancestor of HEAD (`merge-base --is-
ancestor` returned exit 1).
### Step 6.2: Backport complications
**Record:** **Clean apply expected.** `git apply --check` on the commit
diff succeeded with no conflicts.
### Step 6.3: Related fixes already present?
**Record:** Related but distinct fixes already in tree: `f66ee0410b1c`
(RCU stall, 2020), `7228cc8ff6265` (add/dump race), `12088da6add5b` (GC
stop). None fix this specific locking error.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem criticality
**Record:** `net/netfilter/ipset` — **IMPORTANT** (firewall
infrastructure used by iptables/nftables on servers, routers,
containers)
### Step 7.2: Activity
**Record:** Actively maintained — 6 commits to `ip_set_hash_gen.h` since
the 6.18 merge point, including multiple RCU/concurrency fixes in 2026.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who is affected
**Record:** Users of timeout-enabled hash ipsets (`hash:ip`, `hash:net`,
etc.) under netfilter — common in production firewall configurations.
### Step 8.2: Trigger conditions
**Record:**
- **mtype_gc UAF:** Concurrent resize (userspace `ipset resize`) + GC
workqueue on same set
- **mtype_add RCU stall:** Adding elements to a near-full timed-out set,
triggering inline `mtype_gc_do()`
- **Likelihood:** Moderate for busy firewall nodes; resize is less
common but GC and adds are frequent
### Step 8.3: Failure mode severity
**Record:**
- UAF on hash table → kernel oops/crash or memory corruption —
**CRITICAL**
- RCU stall → soft lockup, system hang — **CRITICAL**
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** HIGH — prevents crash/hang in widely deployed firewall
code
- **Risk:** LOW — 13-line change, follows existing patterns, applies
cleanly
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Fixes real RCU synchronization bug (wrong lock in `mtype_gc` → UAF vs
resize)
- Fixes RCU stall risk in `mtype_add` (same class as prior syzbot-found
ipset bugs)
- Small, surgical, standalone
- Applies cleanly to 6.18.44
- Subsystem maintainer authored; netfilter developer signed off
- Affects production firewall paths
**AGAINST backport:**
- No explicit syzbot report for this specific commit
- Part of a 5-patch series (but patch 1 is explicitly independent per
cover letter)
- Patches 2–5 address related but separate gc/resize issues
**Unresolved:** No runtime crash report specifically tied to this exact
commit; bug inferred from code analysis and maintainer explanation.
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — logic matches existing
`uref`/RCU patterns in same file; signed off by subsystem experts
2. Fixes a real bug affecting users? **PASS** — UAF and RCU stall are
real, verifiable from code
3. Important issue? **PASS** — CRITICAL (crash/hang)
4. Small and contained? **PASS** — 13 lines, one file, two functions
5. No new features or APIs? **PASS** — locking correction only
6. Can apply to local tree? **PASS** — verified clean apply
### Step 9.3: Exception categories
**Record:** None (not device ID, quirk, DT, build, or docs). Qualifies
on standard bug-fix criteria.
### Step 9.4: Problem and verdict
This commit corrects two RCU-related bugs in ipset hash types that are
present in Linux 6.18.44:
1. **`mtype_gc()`** uses `set->lock` to read the RCU-protected
`h->table` pointer, but resize (which can free the old table) runs
under nfnl mutex, not `set->lock`. A resize completing between
pointer read and `uref` bump can free the table → use-after-free.
2. **`mtype_add()`** holds `rcu_read_lock_bh()` while calling
`mtype_gc_do()`, which acquires spinlocks and does substantial bucket
iteration — the exact pattern that caused "INFO: rcu detected stall
in hash_xxx" reports fixed in 2020.
The fix is minimal: release RCU immediately after `uref` pins the table,
and use RCU (not `set->lock`) to dereference `h->table` in GC. This
matches patterns already used in `mtype_del()`, `mtype_uref()`, and the
resize path in the same file.
---
## Verification
- **[Phase 1]** Parsed commit `5d0c22e`: subject, body, tags (only
Signed-off-by from Kadlecsik and Westphal)
- **[Phase 2]** Diff analysis: +5/-8 lines in `ip_set_hash_gen.h`,
`mtype_gc()` and `mtype_add()` modified
- **[Phase 3]** `git blame`: buggy lines from `5d324e5159d9e`;
`f66ee0410b1c` (2020 RCU stall fix) in tree
- **[Phase 3]** `git log --oneline f66ee0410b1c..HEAD --
ip_set_hash_gen.h`: 6 related commits, none fixing this issue
- **[Phase 3]** `git apply --check`: patch applies cleanly to current
tree
- **[Phase 3]** `git merge-base --is-ancestor 5d0c22e HEAD`: exit 1 —
commit not in tree
- **[Phase 4]** `b4 dig -c 5d0c22e`: lore URL found; v1 series, 5
patches
- **[Phase 4]** `b4 dig -w`: CC'd netfilter-devel, Pablo Neira Ayuso
- **[Phase 4]** Downloaded mbox: cover letter confirms patch 1 is
independent
- **[Phase 5]** Read `mtype_gc_do()`: takes spinlocks, calls
`mtype_del_cidr()` — confirms RCU stall risk
- **[Phase 5]** Read resize path (lines 677–785): uses nfnl +
`rcu_assign_pointer` + `synchronize_rcu`, not `set->lock`
- **[Phase 5]** `ipset_dereference_set` macro (lines 19–22): allows nfnl
OR `set->lock`, confirming GC's spinlock was lockdep-only, not resize-
safe
- **[Phase 6]** `git describe HEAD`: v6.18.44; buggy code confirmed at
lines 572–583 and 858–879
- **[Phase 6]** `git apply --check`: clean apply confirmed
- **[Phase 8]** Failure modes: UAF (CRITICAL), RCU stall (CRITICAL);
triggerable on production firewall nodes
**YES**
net/netfilter/ipset/ip_set_hash_gen.h | 13 +++++--------
1 file changed, 5 insertions(+), 8 deletions(-)
diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
index 4c1082e38e3d1..61bddd277a2c6 100644
--- a/net/netfilter/ipset/ip_set_hash_gen.h
+++ b/net/netfilter/ipset/ip_set_hash_gen.h
@@ -569,9 +569,10 @@ mtype_gc(struct work_struct *work)
set = gc->set;
h = set->data;
- spin_lock_bh(&set->lock);
- t = ipset_dereference_set(h->table, set);
+ rcu_read_lock_bh();
+ t = rcu_dereference_bh(h->table);
atomic_inc(&t->uref);
+ rcu_read_unlock_bh();
numof_locks = ahash_numof_locks(t->htable_bits);
r = gc->region++;
if (r >= numof_locks) {
@@ -580,7 +581,6 @@ mtype_gc(struct work_struct *work)
next_run = (IPSET_GC_PERIOD(set->timeout) * HZ) / numof_locks;
if (next_run < HZ/10)
next_run = HZ/10;
- spin_unlock_bh(&set->lock);
mtype_gc_do(set, h, t, r);
@@ -860,15 +860,13 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
key = HKEY(value, h->initval, t->htable_bits);
r = ahash_region(key);
atomic_inc(&t->uref);
+ rcu_read_unlock_bh();
elements = t->hregion[r].elements;
maxelem = t->maxelem;
if (elements >= maxelem) {
u32 e;
- if (SET_WITH_TIMEOUT(set)) {
- rcu_read_unlock_bh();
+ if (SET_WITH_TIMEOUT(set))
mtype_gc_do(set, h, t, r);
- rcu_read_lock_bh();
- }
maxelem = h->maxelem;
elements = 0;
for (e = 0; e < ahash_numof_locks(t->htable_bits); e++)
@@ -876,7 +874,6 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
if (elements >= maxelem && SET_WITH_FORCEADD(set))
forceadd = true;
}
- rcu_read_unlock_bh();
spin_lock_bh(&t->hregion[r].lock);
n = rcu_dereference_bh(hbucket(t, key));
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH AUTOSEL 6.18] netfilter: nf_tables: use DEBUG_NET_WARN_ON_ONCE in packet and control paths
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-5.10] netfilter: nf_conntrack_expect: zero at allocation time Sasha Levin
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18-5.10] netfilter: ipset: mark the rcu locked areas properly Sasha Levin
@ 2026-08-31 13:30 ` Sasha Levin
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18-5.10] netfilter: nf_conntrack: use get_unaligned_be32() in tcp_sack() Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18-5.15] netfilter: nfnetlink_log: wait for rcu grace period before freeing pernet state Sasha Levin
4 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-08-31 13:30 UTC (permalink / raw)
To: patches, stable
Cc: Fernando Fernandez Mancera, Pablo Neira Ayuso, Sasha Levin, fw,
davem, edumazet, kuba, pabeni, netfilter-devel, coreteam, netdev,
linux-kernel
From: Fernando Fernandez Mancera <fmancera@suse.de>
[ Upstream commit 42eb1ca711b6f3c0cc09d872ff49fa7aa17a56e1 ]
Replace raw warning macros with DEBUG_NET_WARN_ON_ONCE across the
nf_tables API, core engine, and expression evaluations. This prevents
unnecessary system panics when panic_on_warn=1 is enabled in production
systems.
Signed-off-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
**Step 1.1 — Subject line**
Record: `[netfilter: nf_tables]` / `use` / Replace raw `WARN_ON_ONCE`
with `DEBUG_NET_WARN_ON_ONCE` in nftables packet and control paths to
avoid panics under `panic_on_warn=1`.
**Step 1.2 — Tags**
Record:
- **Fixes:** none
- **Reported-by:** none
- **Tested-by:** none
- **Reviewed-by:** none
- **Acked-by:** none
- **Link:** none
- **Cc: stable@vger.kernel.org:** none (expected for manual review)
- **Signed-off-by:** Fernando Fernandez Mancera `<fmancera@suse.de>`,
Pablo Neira Ayuso `<pablo@netfilter.org>` (netfilter maintainer)
Notable: maintainer sign-off; no syzbot/fuzzer tags; patch 2/9 in a
broader netfilter `DEBUG_NET_WARN_ON_ONCE` series.
**Step 1.3 — Body**
Record:
- **Bug:** `WARN_ON_ONCE` on nftables packet/control paths can panic the
kernel when `panic_on_warn=1`.
- **Symptom:** Full system panic during nftables processing, even though
the code already handles the condition (drop packet, return error,
defensive fallback).
- **Root cause:** `WARN_ON_ONCE` always emits a kernel warning;
`panic_on_warn` turns any warning into `panic()`.
- **Version info:** none in message.
**Step 1.4 — Hidden bug fix?**
Record: **Yes.** Framed as macro replacement, but it fixes a real
stability bug: handled internal-invariant failures become fatal panics
on hardened production configs instead of graceful degradation.
---
## Phase 2: Diff Analysis
**Step 2.1 — Inventory**
Record:
- **22 files**, roughly **+76 / -46** lines.
- Core files: `nf_tables_api.c`, `nf_tables_core.c`,
`nf_tables_offload.c`, `nf_tables_trace.c`, plus ~18 `nft_*.c`
expression modules.
- Functions touched include `nft_do_chain()`, `nft_register_expr()`,
`nft_expr_clone()`, `nf_tables_commit_chain_prepare()`,
`nft_parse_register_load()`, `nft_data_init()`, and many expression
`*_eval()` default branches.
- **Scope:** Multi-file but mechanical; not a refactor.
**Step 2.2 — Code flow changes**
Record per hunk pattern:
- **Before:** `if (WARN_ON_ONCE(cond)) return error;` — condition
checked, warning emitted on failure, then existing error handling
runs.
- **After:** `if (unlikely(cond)) { DEBUG_NET_WARN_ON_ONCE(1); return
error; }` — same runtime handling; warning only when
`CONFIG_DEBUG_NET=y`.
- **`nft_do_chain()` jump overflow:** Before `WARN_ON_ONCE` + `NF_DROP`;
after `DEBUG_NET_WARN_ON_ONCE` + `NF_DROP_REASON(..., ELOOP)`
(slightly better drop reason).
- **Default switch branches:** `WARN_ON_ONCE(1)` / `WARN_ON(1)` →
`DEBUG_NET_WARN_ON_ONCE(1)` with existing fallthrough/error behavior
unchanged.
**Step 2.3 — Bug mechanism**
Record:
- **Category:** Logic/correctness + production-stability interaction
with `panic_on_warn`.
- **Mechanism:** Defensive invariant checks on hot packet path and
netlink control path use `WARN_ON_ONCE`, which calls
`check_panic_on_warn("kernel")` when `panic_on_warn=1` (verified in
`kernel/panic.c`). The underlying failure is already handled; the WARN
makes it fatal.
**Step 2.4 — Fix quality**
Record:
- **Obviously correct:** Yes; follows `DEBUG_NET_WARN_ON_ONCE` design
from `include/net/net_debug.h`.
- **Minimal:** Yes; mechanical replacements.
- **Regression risk:** Low. `DEBUG_NET_WARN_ON_ONCE` without
`CONFIG_DEBUG_NET` is a no-op via `BUILD_BUG_ON_INVALID`; runtime
checks remain via explicit `unlikely()` branches.
- **Red flags:** 22 files, but no API/struct changes.
---
## Phase 3: Git History Investigation
**Step 3.1 — Blame**
Record:
- Jump-stack `WARN_ON_ONCE` introduced in `adc972c5b8882` (Jun 2018):
replaced `BUG_ON` with `WARN_ON_ONCE` + `NF_DROP` because hard crash
was unnecessary.
- That code is present in this tree at `nf_tables_core.c:317-318`.
- `DEBUG_NET_WARN_ON_ONCE` macro added in `d268c1f5cfc92` (May 2022).
**Step 3.2 — Fixes: tag**
Record: N/A — no `Fixes:` tag.
**Step 3.3 — Related file history**
Record:
- `nf_tables_api.c` already has one `DEBUG_NET_WARN_ON_ONCE` use (export
path); most nftables code still uses raw `WARN_ON_ONCE` (~77
occurrences across nftables files in this tree).
- Target commit `42eb1ca711b6f` is **not** an ancestor of HEAD; patch
applies cleanly (`git apply --check` passed).
**Step 3.4 — Author context**
Record: Fernando Fernandez Mancera (SUSE) submitted patch 2/9 of a
netfilter-wide series; Pablo Neira Ayuso (maintainer) committed it.
**Step 3.5 — Dependencies**
Record:
- **Standalone for nftables:** Yes.
- **Prerequisite:** `CONFIG_DEBUG_NET` / `DEBUG_NET_WARN_ON_ONCE` —
present since 2022 in this tree.
- **Prerequisite:** `NF_DROP_REASON()` — present in
`include/linux/netfilter.h`.
- Part of a 9-patch series, but this hunk does not require the other
patches.
---
## Phase 4: Mailing List and External Research
**Step 4.1 — Original discussion**
Record:
- `b4 dig -c 42eb1ca711b6f` →
https://patch.msgid.link/20260601193049.8131-3-fmancera@suse.de
- Series cover letter (web search): patch 2/9; motivation is preventing
`panic_on_warn=1` panics on already-handled netfilter invariant
failures.
- Lore fetch blocked by bot protection; could not read thread replies
directly.
**Step 4.2 — Reviewers**
Record: `b4 dig -w` returned only the patch URL; cover letter CC list
(from openwall mirror) included `edumazet@google.com`, `fw@strlen.de`,
`kuba@kernel.org`, `pablo@netfilter.org`.
**Step 4.3 — Bug report**
Record: N/A — no external bug report or syzbot link.
**Step 4.4 — Related patches**
Record: 9-patch series across xtables, nf_tables, nfnetlink, conntrack,
nat, tproxy, bpf, flowtable, conncount. This commit only touches
nf_tables.
**Step 4.5 — Stable list history**
Record: UNVERIFIED — could not search lore stable archive due to bot
protection.
---
## Phase 5: Code Semantic Analysis
**Step 5.1 — Key functions**
Record: `nft_do_chain()`, `nft_register_expr()`, `nft_expr_clone()`,
`nf_tables_commit_chain_prepare()`, `nft_parse_register_load()`,
`nft_data_init()`, plus expression evaluators in `nft_meta.c`,
`nft_payload.c`, `nft_socket.c`, etc.
**Step 5.2 — Callers**
Record:
- `nft_do_chain()` — packet hot path via netfilter hooks; every
nftables-filtered packet.
- `nft_register_expr()` / netlink handlers — control plane from
`nft`/`iptables-nft` with `CAP_NET_ADMIN`.
- Expression `*_eval()` — per-rule packet evaluation.
**Step 5.3 — Callees**
Record: `DEBUG_NET_WARN_ON_ONCE`, `NF_DROP_REASON`, existing nftables
error returns (`-EINVAL`, `-ENOMEM`, `NFT_BREAK`, etc.).
**Step 5.4 — Reachability**
Record:
- **Packet path:** Yes — reachable on every packet through nftables
rules.
- **Jump stack overflow:** Reachable with >16 nested `jump` operations
(`NFT_JUMP_STACK_SIZE` is 16); requires admin-configured rules, but is
a known path since 2018.
- **Unprivileged trigger:** No direct unprivileged syscall path; netlink
config needs privileges. Packet-path panics affect all traffic on the
host.
**Step 5.5 — Similar patterns**
Record: Networking already migrated many sites to
`DEBUG_NET_WARN_ON_ONCE` (e.g. `skb_release_head_state()` in
`7890e2f09d437`, multiple `skbuff.c` sites). nftables is late to adopt
the same pattern.
---
## Phase 6: Cross-Reference Against Local Tree
**Step 6.1 — Buggy code present?**
Record:
- **Local tree:** `v6.18.44` (`git describe HEAD` →
`v6.18.44-1-g2736c32da98b9`).
- **Buggy `WARN_ON_ONCE` calls present:** Yes (e.g.
`nf_tables_core.c:317,329`; many more in `nf_tables_api.c` and
`nft_*.c`).
- **Fix not yet merged:** `42eb1ca711b6f` is **NOT IN TREE**.
**Step 6.2 — Backport complications**
Record: **Clean apply** verified with `git format-patch | git apply
--check`. No rework expected.
**Step 6.3 — Related fixes already present?**
Record: Partial — one `DEBUG_NET_WARN_ON_ONCE` in `nf_tables_api.c`;
bulk of nftables still uses raw `WARN_ON_ONCE`. This specific fix is not
present.
---
## Phase 7: Subsystem and Maintainer Context
**Step 7.1 — Subsystem**
Record: **netfilter / nf_tables** — **IMPORTANT** (firewall/NAT for
servers, routers, containers; packet hot path).
**Step 7.2 — Activity**
Record: Actively maintained; recent commits in `nf_tables_api.c` include
UAF fixes, set/chain handling changes.
---
## Phase 8: Impact and Risk Assessment
**Step 8.1 — Who is affected**
Record: Systems running nftables with `panic_on_warn=1`
(enterprise/hardened configs; SUSE motivation). Affects all network
traffic on those hosts when an invariant fires.
**Step 8.2 — Trigger conditions**
Record:
- `panic_on_warn=1` (sysctl, non-default but used in production).
- Plus any nftables internal invariant failure (jump depth, malformed
internal state, default switch branches).
- Jump overflow: uncommon but possible with complex admin rules.
- **Unprivileged direct trigger:** No.
**Step 8.3 — Failure mode severity**
Record: **CRITICAL** — full kernel panic on packet path, despite
existing graceful drop/error handling.
**Step 8.4 — Risk/benefit**
Record:
- **Benefit:** High for `panic_on_warn=1` + nftables deployments;
prevents total outage when a handled condition occurs.
- **Risk:** Low — mechanical macro swap, no structural changes, clean
apply.
- **Ratio:** Favorable for stable.
---
## Phase 9: Final Synthesis
**Step 9.1 — Evidence**
**FOR:**
- Prevents kernel panic on handled nftables errors when
`panic_on_warn=1`.
- Packet-path impact (`nft_do_chain`) is severe when triggered.
- Follows established `DEBUG_NET_WARN_ON_ONCE` networking pattern (Eric
Dumazet, 2022).
- Small per-hunk changes; applies cleanly to v6.18.44.
- Netfilter maintainer signed off.
- Restores intent of 2018 change that replaced `BUG_ON` with graceful
`NF_DROP` on jump-stack overflow.
**AGAINST:**
- Only matters when `panic_on_warn=1` (not default).
- Not a memory-safety bug (UAF/OOB).
- 22 files (though mechanically simple).
- Arguably reduces visibility of internal bugs for admins who explicitly
chose `panic_on_warn=1`.
- Part of a larger series (other netfilter subsystems not covered by
this commit).
**Unresolved:** Lore thread replies and explicit stable nominations —
UNVERIFIED due to fetch blocking.
**Step 9.2 — Stable rules checklist**
| Criterion | Result |
|-----------|--------|
| 1. Obviously correct and tested? | **PASS** — established macro
pattern; maintainer SOB; no Tested-by |
| 2. Fixes real bug affecting users? | **PASS** — panic on handled
nftables path with `panic_on_warn=1` |
| 3. Important issue? | **PASS** — kernel panic (CRITICAL) |
| 4. Small and contained? | **PASS** — mechanical, +76/-46, no refactor
|
| 5. No new features/APIs? | **PASS** |
| 6. Can apply to local tree? | **PASS** — clean apply verified;
prerequisites present |
**Step 9.3 — Exception category**
Record: None (not device ID, quirk, DT, build fix, or docs). Standard
stability bug fix.
**Step 9.4 — Decision rationale**
For **this** tree (v6.18.44), the buggy pattern exists, prerequisites
exist, and the patch applies cleanly. The commit fixes a real
production-stability issue: nftables already handles these conditions
gracefully, but `WARN_ON_ONCE` + `panic_on_warn=1` turns them into full
system crashes on the packet hot path. That matches stable criteria for
serious crashes with a low-risk, maintainer-reviewed fix.
---
## Verification
- [Phase 1] Parsed subject, tags, body from provided commit message and
`git show 42eb1ca711b6f`
- [Phase 2] Diff analysis: 22 files, +76/-46; `WARN_ON_ONCE` →
`unlikely()` + `DEBUG_NET_WARN_ON_ONCE`
- [Phase 3] `git describe HEAD` → v6.18.44; `git merge-base --is-
ancestor 42eb1ca HEAD` → NOT IN TREE
- [Phase 3] `git blame nf_tables_core.c:317` → `adc972c5b8882` (2018,
BUG_ON→WARN_ON_ONCE+NF_DROP)
- [Phase 3] `d268c1f5cfc92` added `CONFIG_DEBUG_NET` and
`DEBUG_NET_WARN_ON_ONCE`
- [Phase 3] `git apply --check` on patch → applies cleanly
- [Phase 4] `b4 dig -c 42eb1ca711b6f` → patch URL found
- [Phase 4] Web search found series cover letter (9 patches,
panic_on_warn motivation)
- [Phase 4] Lore/patch.msgid.link fetch → blocked; thread content
UNVERIFIED
- [Phase 5] `NFT_JUMP_STACK_SIZE` = 16 in
`include/net/netfilter/nf_tables.h`
- [Phase 5] `check_panic_on_warn()` in `kernel/panic.c:372-377` panics
when `panic_on_warn` set
- [Phase 5] `DEBUG_NET_WARN_ON_ONCE` definition in
`include/net/net_debug.h:151-156`
- [Phase 6] All 22 modified files exist in tree
- [Phase 6] Current tree: 77 `WARN_ON_ONCE` vs 2
`DEBUG_NET_WARN_ON_ONCE` in nftables files
- [Phase 6] `NF_DROP_REASON` exists in `include/linux/netfilter.h`
- [Phase 8] `nf_tables_core.c:317-318` still has unfixed `WARN_ON_ONCE`
on jump-stack path
**YES**
net/netfilter/nf_tables_api.c | 38 +++++++++++++++++++++++--------
net/netfilter/nf_tables_core.c | 8 ++++---
net/netfilter/nf_tables_offload.c | 2 +-
net/netfilter/nf_tables_trace.c | 6 +++--
net/netfilter/nft_ct.c | 2 +-
net/netfilter/nft_ct_fast.c | 2 +-
net/netfilter/nft_exthdr.c | 2 +-
net/netfilter/nft_fib.c | 2 +-
net/netfilter/nft_inner.c | 2 +-
net/netfilter/nft_lookup.c | 2 +-
net/netfilter/nft_masq.c | 2 +-
net/netfilter/nft_meta.c | 10 ++++----
net/netfilter/nft_payload.c | 6 ++---
net/netfilter/nft_redir.c | 2 +-
net/netfilter/nft_reject.c | 8 +++++--
net/netfilter/nft_rt.c | 2 +-
net/netfilter/nft_set_hash.c | 2 +-
net/netfilter/nft_set_pipapo.c | 2 +-
net/netfilter/nft_set_rbtree.c | 6 +++--
net/netfilter/nft_socket.c | 8 ++++---
net/netfilter/nft_tunnel.c | 2 +-
net/netfilter/nft_xfrm.c | 6 ++---
22 files changed, 76 insertions(+), 46 deletions(-)
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index ca6d2041eee66..d2f890627d0af 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -3258,8 +3258,10 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
*/
int nft_register_expr(struct nft_expr_type *type)
{
- if (WARN_ON_ONCE(type->maxattr > NFT_EXPR_MAXATTR))
+ if (unlikely(type->maxattr > NFT_EXPR_MAXATTR)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return -ENOMEM;
+ }
nfnl_lock(NFNL_SUBSYS_NFTABLES);
if (type->family == NFPROTO_UNSPEC)
@@ -3571,8 +3573,10 @@ int nft_expr_clone(struct nft_expr *dst, struct nft_expr *src, gfp_t gfp)
{
int err;
- if (WARN_ON_ONCE(!src->ops->clone))
+ if (unlikely(!src->ops->clone)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return -EINVAL;
+ }
dst->ops = src->ops;
err = src->ops->clone(dst, src, gfp);
@@ -8211,8 +8215,10 @@ static int nf_tables_newobj(struct sk_buff *skb, const struct nfnl_info *info,
return 0;
type = nft_obj_type_get(net, objtype, family);
- if (WARN_ON_ONCE(IS_ERR(type)))
+ if (IS_ERR(type)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return PTR_ERR(type);
+ }
nft_ctx_init(&ctx, net, skb, info->nlh, family, table, NULL, nla);
@@ -10161,19 +10167,25 @@ static int nf_tables_commit_chain_prepare(struct net *net, struct nft_chain *cha
prule = (struct nft_rule_dp *)data;
data += offsetof(struct nft_rule_dp, data);
- if (WARN_ON_ONCE(data > data_boundary))
+ if (unlikely(data > data_boundary)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return -ENOMEM;
+ }
size = 0;
nft_rule_for_each_expr(expr, last, rule) {
- if (WARN_ON_ONCE(data + size + expr->ops->size > data_boundary))
+ if (unlikely(data + size + expr->ops->size > data_boundary)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return -ENOMEM;
+ }
memcpy(data + size, expr, expr->ops->size);
size += expr->ops->size;
}
- if (WARN_ON_ONCE(size >= 1 << 12))
+ if (unlikely(size >= 1 << 12)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return -ENOMEM;
+ }
prule->handle = rule->handle;
prule->dlen = size;
@@ -10184,8 +10196,10 @@ static int nf_tables_commit_chain_prepare(struct net *net, struct nft_chain *cha
chain->blob_next->size += (unsigned long)(data - (void *)prule);
}
- if (WARN_ON_ONCE(data > data_boundary))
+ if (unlikely(data > data_boundary)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return -ENOMEM;
+ }
prule = (struct nft_rule_dp *)data;
nft_last_rule(chain, prule);
@@ -11494,8 +11508,10 @@ int nft_parse_register_load(const struct nft_ctx *ctx,
next_register = DIV_ROUND_UP(len, NFT_REG32_SIZE) + reg;
/* Can't happen: nft_validate_register_load() should have failed */
- if (WARN_ON_ONCE(next_register > NFT_REG32_NUM))
+ if (unlikely(next_register > NFT_REG32_NUM)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return -EINVAL;
+ }
/* find first register that did not see an earlier store. */
invalid_reg = find_next_zero_bit(ctx->reg_inited, NFT_REG32_NUM, reg);
@@ -11742,8 +11758,10 @@ int nft_data_init(const struct nft_ctx *ctx, struct nft_data *data,
struct nlattr *tb[NFTA_DATA_MAX + 1];
int err;
- if (WARN_ON_ONCE(!desc->size))
+ if (unlikely(!desc->size)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return -EINVAL;
+ }
err = nla_parse_nested_deprecated(tb, NFTA_DATA_MAX, nla,
nft_data_policy, NULL);
@@ -11809,7 +11827,7 @@ int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data,
break;
default:
err = -EINVAL;
- WARN_ON(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
}
nla_nest_end(skb, nest);
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
index 6557a4018c099..267b8849fef19 100644
--- a/net/netfilter/nf_tables_core.c
+++ b/net/netfilter/nf_tables_core.c
@@ -314,8 +314,10 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv)
switch (regs.verdict.code) {
case NFT_JUMP:
- if (WARN_ON_ONCE(stackptr >= NFT_JUMP_STACK_SIZE))
- return NF_DROP;
+ if (unlikely(stackptr >= NFT_JUMP_STACK_SIZE)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ return NF_DROP_REASON(pkt->skb, SKB_DROP_REASON_NETFILTER_DROP, ELOOP);
+ }
jumpstack[stackptr].rule = nft_rule_next(rule);
stackptr++;
fallthrough;
@@ -326,7 +328,7 @@ nft_do_chain(struct nft_pktinfo *pkt, void *priv)
case NFT_RETURN:
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
}
if (stackptr > 0) {
diff --git a/net/netfilter/nf_tables_offload.c b/net/netfilter/nf_tables_offload.c
index fd30e205de849..e43470d0e3bd2 100644
--- a/net/netfilter/nf_tables_offload.c
+++ b/net/netfilter/nf_tables_offload.c
@@ -361,7 +361,7 @@ static int nft_block_setup(struct nft_base_chain *basechain,
err = nft_flow_offload_unbind(bo, basechain);
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
err = -EOPNOTSUPP;
}
diff --git a/net/netfilter/nf_tables_trace.c b/net/netfilter/nf_tables_trace.c
index a88abae5a9de2..d85b6a2fb43ca 100644
--- a/net/netfilter/nf_tables_trace.c
+++ b/net/netfilter/nf_tables_trace.c
@@ -227,8 +227,10 @@ static const struct nft_chain *nft_trace_get_chain(const struct nft_rule_dp *rul
last = (const struct nft_rule_dp_last *)rule;
- if (WARN_ON_ONCE(!last->chain))
+ if (unlikely(!last->chain)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return &info->basechain->chain;
+ }
return last->chain;
}
@@ -354,7 +356,7 @@ void nft_trace_notify(const struct nft_pktinfo *pkt,
return;
nla_put_failure:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
kfree_skb(skb);
}
diff --git a/net/netfilter/nft_ct.c b/net/netfilter/nft_ct.c
index b29ff555979b2..c3063d5c70951 100644
--- a/net/netfilter/nft_ct.c
+++ b/net/netfilter/nft_ct.c
@@ -1135,7 +1135,7 @@ static void nft_ct_helper_obj_eval(struct nft_object *obj,
to_assign = priv->helper6;
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
return;
}
diff --git a/net/netfilter/nft_ct_fast.c b/net/netfilter/nft_ct_fast.c
index ecf7b3a404be2..a44524c4fe630 100644
--- a/net/netfilter/nft_ct_fast.c
+++ b/net/netfilter/nft_ct_fast.c
@@ -53,7 +53,7 @@ void nft_ct_get_fast_eval(const struct nft_expr *expr,
return;
#endif
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
regs->verdict.code = NFT_BREAK;
break;
}
diff --git a/net/netfilter/nft_exthdr.c b/net/netfilter/nft_exthdr.c
index cee93149dca7e..da772081f1ed7 100644
--- a/net/netfilter/nft_exthdr.c
+++ b/net/netfilter/nft_exthdr.c
@@ -298,7 +298,7 @@ static void nft_exthdr_tcp_set_eval(const struct nft_expr *expr,
old.v32, new.v32, false);
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
break;
}
diff --git a/net/netfilter/nft_fib.c b/net/netfilter/nft_fib.c
index 7b2a0a031c4b4..660ee0115323b 100644
--- a/net/netfilter/nft_fib.c
+++ b/net/netfilter/nft_fib.c
@@ -170,7 +170,7 @@ void nft_fib_store_result(void *reg, const struct nft_fib *priv,
strscpy_pad(reg, dev ? dev->name : "", IFNAMSIZ);
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
*dreg = 0;
break;
}
diff --git a/net/netfilter/nft_inner.c b/net/netfilter/nft_inner.c
index ad08a43535b55..35cb2feb34fee 100644
--- a/net/netfilter/nft_inner.c
+++ b/net/netfilter/nft_inner.c
@@ -308,7 +308,7 @@ static void nft_inner_eval(const struct nft_expr *expr, struct nft_regs *regs,
nft_meta_inner_eval((struct nft_expr *)&priv->expr, regs, pkt, &tun_ctx);
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
goto err;
}
nft_inner_save_tun_ctx(pkt, &tun_ctx);
diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
index 699254cb3ecd6..c37c21272cebf 100644
--- a/net/netfilter/nft_lookup.c
+++ b/net/netfilter/nft_lookup.c
@@ -50,7 +50,7 @@ __nft_set_do_lookup(const struct net *net, const struct nft_set *set,
if (set->ops == &nft_set_rbtree_type.ops)
return nft_rbtree_lookup(net, set, key);
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
#endif
return set->ops->lookup(net, set, key);
}
diff --git a/net/netfilter/nft_masq.c b/net/netfilter/nft_masq.c
index 2b01128737a3a..841efd981e200 100644
--- a/net/netfilter/nft_masq.c
+++ b/net/netfilter/nft_masq.c
@@ -123,7 +123,7 @@ static void nft_masq_eval(const struct nft_expr *expr,
break;
#endif
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
break;
}
}
diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c
index 19e6d1c2436af..6d43e20c71de4 100644
--- a/net/netfilter/nft_meta.c
+++ b/net/netfilter/nft_meta.c
@@ -114,12 +114,12 @@ nft_meta_get_eval_pkttype_lo(const struct nft_pktinfo *pkt,
nft_reg_store8(dest, PACKET_MULTICAST);
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
return false;
}
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
return false;
}
@@ -405,7 +405,7 @@ void nft_meta_get_eval(const struct nft_expr *expr,
nft_meta_get_eval_sdifname(dest, pkt);
break;
default:
- WARN_ON(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
goto err;
}
return;
@@ -451,7 +451,7 @@ void nft_meta_set_eval(const struct nft_expr *expr,
break;
#endif
default:
- WARN_ON(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
}
}
EXPORT_SYMBOL_GPL(nft_meta_set_eval);
@@ -832,7 +832,7 @@ void nft_meta_inner_eval(const struct nft_expr *expr,
nft_reg_store8(dest, tun_ctx->l4proto);
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
goto err;
}
return;
diff --git a/net/netfilter/nft_payload.c b/net/netfilter/nft_payload.c
index e07888aaf1475..8ebd1ef9f935c 100644
--- a/net/netfilter/nft_payload.c
+++ b/net/netfilter/nft_payload.c
@@ -196,7 +196,7 @@ void nft_payload_eval(const struct nft_expr *expr,
goto err;
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
goto err;
}
offset += priv->offset;
@@ -599,7 +599,7 @@ void nft_payload_inner_eval(const struct nft_expr *expr, struct nft_regs *regs,
offset = tun_ctx->inner_thoff;
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
goto err;
}
offset += priv->offset;
@@ -866,7 +866,7 @@ static void nft_payload_set_eval(const struct nft_expr *expr,
goto err;
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
goto err;
}
diff --git a/net/netfilter/nft_redir.c b/net/netfilter/nft_redir.c
index 58ae802db8f52..a98aa28180fbe 100644
--- a/net/netfilter/nft_redir.c
+++ b/net/netfilter/nft_redir.c
@@ -126,7 +126,7 @@ static void nft_redir_eval(const struct nft_expr *expr,
break;
#endif
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
break;
}
}
diff --git a/net/netfilter/nft_reject.c b/net/netfilter/nft_reject.c
index 196a92c7ea09b..e3972e904cf0f 100644
--- a/net/netfilter/nft_reject.c
+++ b/net/netfilter/nft_reject.c
@@ -102,8 +102,10 @@ static u8 icmp_code_v4[NFT_REJECT_ICMPX_MAX + 1] = {
int nft_reject_icmp_code(u8 code)
{
- if (WARN_ON_ONCE(code > NFT_REJECT_ICMPX_MAX))
+ if (unlikely(code > NFT_REJECT_ICMPX_MAX)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return ICMP_NET_UNREACH;
+ }
return icmp_code_v4[code];
}
@@ -120,8 +122,10 @@ static u8 icmp_code_v6[NFT_REJECT_ICMPX_MAX + 1] = {
int nft_reject_icmpv6_code(u8 code)
{
- if (WARN_ON_ONCE(code > NFT_REJECT_ICMPX_MAX))
+ if (unlikely(code > NFT_REJECT_ICMPX_MAX)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return ICMPV6_NOROUTE;
+ }
return icmp_code_v6[code];
}
diff --git a/net/netfilter/nft_rt.c b/net/netfilter/nft_rt.c
index ad527f3596c03..560734d0d7531 100644
--- a/net/netfilter/nft_rt.c
+++ b/net/netfilter/nft_rt.c
@@ -93,7 +93,7 @@ void nft_rt_get_eval(const struct nft_expr *expr,
break;
#endif
default:
- WARN_ON(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
goto err;
}
return;
diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c
index b0e571c8e3f38..eb4e382119d4f 100644
--- a/net/netfilter/nft_set_hash.c
+++ b/net/netfilter/nft_set_hash.c
@@ -385,7 +385,7 @@ static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set,
break;
default:
iter->err = -EINVAL;
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
break;
}
}
diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
index b377bef60b212..0e4b91c3248b3 100644
--- a/net/netfilter/nft_set_pipapo.c
+++ b/net/netfilter/nft_set_pipapo.c
@@ -2226,7 +2226,7 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
break;
default:
iter->err = -EINVAL;
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
break;
}
}
diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c
index a698420ab2b8c..0264bcb4bdb50 100644
--- a/net/netfilter/nft_set_rbtree.c
+++ b/net/netfilter/nft_set_rbtree.c
@@ -661,8 +661,10 @@ static int nft_array_may_resize(const struct nft_set *set, bool flush)
}
realloc_array:
- if (WARN_ON_ONCE(nelems > new_max_intervals))
+ if (unlikely(nelems > new_max_intervals)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return -ENOMEM;
+ }
if (priv->array_next) {
if (max_intervals == new_max_intervals)
@@ -890,7 +892,7 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
break;
default:
iter->err = -EINVAL;
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
break;
}
}
diff --git a/net/netfilter/nft_socket.c b/net/netfilter/nft_socket.c
index c55a1310226a4..8f7ee6313f2b5 100644
--- a/net/netfilter/nft_socket.c
+++ b/net/netfilter/nft_socket.c
@@ -71,8 +71,10 @@ static noinline int nft_socket_cgroup_subtree_level(void)
if (level > 255)
return -ERANGE;
- if (WARN_ON_ONCE(level < 0))
+ if (unlikely(level < 0)) {
+ DEBUG_NET_WARN_ON_ONCE(1);
return -EINVAL;
+ }
return level;
}
@@ -97,7 +99,7 @@ static struct sock *nft_socket_do_lookup(const struct nft_pktinfo *pkt)
break;
#endif
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
break;
}
@@ -152,7 +154,7 @@ static void nft_socket_eval(const struct nft_expr *expr,
break;
#endif
default:
- WARN_ON(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
regs->verdict.code = NFT_BREAK;
}
diff --git a/net/netfilter/nft_tunnel.c b/net/netfilter/nft_tunnel.c
index 78d47f5503551..06debdb6f3d85 100644
--- a/net/netfilter/nft_tunnel.c
+++ b/net/netfilter/nft_tunnel.c
@@ -60,7 +60,7 @@ static void nft_tunnel_get_eval(const struct nft_expr *expr,
regs->verdict.code = NFT_BREAK;
break;
default:
- WARN_ON(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
regs->verdict.code = NFT_BREAK;
}
}
diff --git a/net/netfilter/nft_xfrm.c b/net/netfilter/nft_xfrm.c
index 7ffe6a2690d13..311169c7d4d06 100644
--- a/net/netfilter/nft_xfrm.c
+++ b/net/netfilter/nft_xfrm.c
@@ -132,7 +132,7 @@ static void nft_xfrm_state_get_key(const struct nft_xfrm *priv,
switch (priv->key) {
case NFT_XFRM_KEY_UNSPEC:
case __NFT_XFRM_KEY_MAX:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
break;
case NFT_XFRM_KEY_DADDR_IP4:
*dest = (__force __u32)state->id.daddr.a4;
@@ -206,7 +206,7 @@ static void nft_xfrm_get_eval(const struct nft_expr *expr,
nft_xfrm_get_eval_out(priv, regs, pkt);
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
regs->verdict.code = NFT_BREAK;
break;
}
@@ -252,7 +252,7 @@ static int nft_xfrm_validate(const struct nft_ctx *ctx, const struct nft_expr *e
(1 << NF_INET_POST_ROUTING);
break;
default:
- WARN_ON_ONCE(1);
+ DEBUG_NET_WARN_ON_ONCE(1);
return -EINVAL;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH AUTOSEL 6.18-5.10] netfilter: nf_conntrack: use get_unaligned_be32() in tcp_sack()
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (2 preceding siblings ...)
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18] netfilter: nf_tables: use DEBUG_NET_WARN_ON_ONCE in packet and control paths Sasha Levin
@ 2026-08-31 13:30 ` Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18-5.15] netfilter: nfnetlink_log: wait for rcu grace period before freeing pernet state Sasha Levin
4 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-08-31 13:30 UTC (permalink / raw)
To: patches, stable
Cc: Rosen Penev, Fernando Fernandez Mancera, Pablo Neira Ayuso,
Sasha Levin, fw, davem, edumazet, kuba, pabeni, netfilter-devel,
coreteam, netdev, linux-kernel
From: Rosen Penev <rosenp@gmail.com>
[ Upstream commit d3bf9eae486490832bd08fd62ab0ac601f346bd4 ]
The timestamp-only fast path dereferences the option stream as
*(__be32 *)ptr, which assumes 4-byte alignment that the TCP option
stream does not guarantee. Use get_unaligned_be32() instead, which
reads the value safely and already returns host byte order, so the
htonl() on the comparison constant can be dropped.
This matches the existing get_unaligned_be32() use later in the same
function.
Assisted-by: Claude:Opus-4.7
Signed-off-by: Rosen Penev <rosenp@gmail.com>
Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
**Step 1.1 — Subject line**
- Record: `[netfilter: nf_conntrack]` `[use]` — replace unsafe aligned
32-bit dereference in `tcp_sack()` timestamp fast path with
`get_unaligned_be32()`.
**Step 1.2 — Tags**
- Record:
- `Assisted-by: Claude:Opus-4.7`
- `Signed-off-by: Rosen Penev <rosenp@gmail.com>`
- `Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de>`
- `Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>` (subsystem
maintainer)
- No `Fixes:`, `Reported-by:`, `Cc: stable@vger.kernel.org`, or
`Link:` tags
- Notable: maintainer review and commit; reviewer independently
spotted the same issue
**Step 1.3 — Body**
- Record:
- **Bug:** `*(__be32 *)ptr` in the timestamp-only fast path assumes
4-byte alignment of the TCP option stream
- **Symptom:** Unaligned memory access on architectures that require
alignment (kernel trap/oops); undefined behavior elsewhere
- **Root cause:** TCP options are not guaranteed 4-byte aligned;
`skb_header_pointer()` often returns a pointer directly into skb
linear data at a misaligned offset
- **Fix:** Use `get_unaligned_be32()`, matching the existing SACK
parsing code in the same function
**Step 1.4 — Hidden bug fix?**
- Record: Yes — despite not using "fix" in the subject, this is a
correctness/memory-safety bug fix, not cleanup or optimization.
---
## Phase 2: Diff Analysis
**Step 2.1 — Inventory**
- Record:
- 1 file: `net/netfilter/nf_conntrack_proto_tcp.c` (+5/-5 lines)
- Function: `tcp_sack()`
- Scope: Single-file, surgical fix
**Step 2.2 — Code flow**
- Record:
- **Before:** Fast path for timestamp-only TCP options used `*(__be32
*)ptr == htonl(...)` — aligned 32-bit read
- **After:** Uses `get_unaligned_be32(ptr) == (...)` — safe unaligned
read; `htonl()` dropped because `get_unaligned_be32()` returns host
byte order
- **Path:** Hot path in `tcp_sack()` when `length ==
TCPOLEN_TSTAMP_ALIGNED` (12 bytes = NOP/NOP/TIMESTAMP option only)
**Step 2.3 — Bug mechanism**
- Record:
- **Category:** Memory safety / unaligned access (same class as commit
`534f81a506879` from 2009 in the same function)
- **Mechanism:** `ptr` from `skb_header_pointer()` points at
`skb->data + dataoff + sizeof(tcphdr)`. For typical Ethernet+IPv4,
options start at offset 54 (54 % 4 = 2), so `*(__be32 *)ptr` is an
unaligned access when skb data is linear
**Step 2.4 — Fix quality**
- Record:
- Obviously correct: mirrors the existing `get_unaligned_be32()` use
at line 442 in the same function
- Minimal, no unrelated changes
- Low regression risk: `get_unaligned_be32()` is already included via
`<linux/unaligned.h>` and used in this file
- Byte-order handling is correct (constant built in host order,
compared to host-order return value)
---
## Phase 3: Git History Investigation
**Step 3.1 — Blame**
- Record:
- Fast path introduced in `9fb9cbb1082d6` (Nov 2005, nf_conntrack
subsystem creation)
- Aligned dereference `*(__be32 *)ptr` from `8f05ce91c8b801` (Mar
2007)
- Bug has been present since 2007 in this code path
**Step 3.2 — Fixes: tag**
- Record: N/A — no `Fixes:` tag in commit message
**Step 3.3 — Related file history**
- Record:
- `534f81a506879` (Mar 2009): fixed unaligned access in SACK option
parsing loop in the same `tcp_sack()` function (SPARC64 kernel
unaligned access reports) — fast path was missed
- `bb9fc37358ffa` (Aug 2011): fixed `TCPOLEN_TSTAMP_ALIGNED*4` typo so
the fast path actually runs
- Standalone single-patch series (v1 only); no prerequisites
**Step 3.4 — Author context**
- Record: Rosen Penev is a regular netfilter contributor; patch
committed by Pablo Neira Ayuso (netfilter maintainer)
**Step 3.5 — Dependencies**
- Record: None. `get_unaligned_be32()` and `<linux/unaligned.h>` already
present in this tree's version of the file.
---
## Phase 4: Mailing List and External Research
**Step 4.1 — Original discussion**
- Record:
- Lore URL:
https://patch.msgid.link/20260525215840.93217-1-rosenp@gmail.com
- Single v1 patch, no revisions
- Fernando Fernandez Mancera: independently spotted the same issue; "I
think this is for correctness too"; `Reviewed-by`
- Pablo Neira Ayuso: committed with humorous "Missing
put_unaligned_be32(), BTW." (read path only)
- No NAKs or objections
**Step 4.2 — Reviewers**
- Record: CC'd to netfilter-devel, netdev, Pablo Neira, Florian
Westphal, David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni —
appropriate maintainers included
**Step 4.3 — Bug report**
- Record: No syzbot or user bug report for this specific fast-path
issue. Historical precedent: `534f81a506879` documented real SPARC64
unaligned-access kernel messages from the same function's SACK path.
**Step 4.4 — Related patches**
- Record: Reviewer noted more unaligned-access audits may be needed
elsewhere; this patch is self-contained
**Step 4.5 — Stable list**
- Record: Could not search lore stable archive (bot protection). No
stable nomination found in the patch thread.
---
## Phase 5: Code Semantic Analysis
**Step 5.1 — Key functions**
- Record: `tcp_sack()` modified; callers unchanged
**Step 5.2 — Callers**
- Record:
- `tcp_sack()` called from `tcp_in_window()` when `receiver->flags &
IP_CT_TCP_FLAG_SACK_PERM`
- `tcp_in_window()` called from `nf_conntrack_tcp_packet()` (line
1254)
- `nf_conntrack_tcp_packet()` is the main TCP conntrack packet handler
— invoked on every tracked TCP packet through netfilter hooks
**Step 5.3 — Callees**
- Record: `skb_header_pointer()`, `get_unaligned_be32()` — standard
skb/conntrack helpers
**Step 5.4 — Reachability**
- Record:
- Reachable from all netfilter conntrack TCP traffic (routers,
firewalls, NAT gateways, any `CONFIG_NF_CONNTRACK` system)
- Fast path triggers on timestamp-only TCP options (`length == 12`) —
very common on modern TCP stacks
- Requires SACK negotiation (`IP_CT_TCP_FLAG_SACK_PERM`) — also common
- Userspace can trigger via normal TCP connections through conntrack-
enabled systems
**Step 5.5 — Similar patterns**
- Record: Same function already uses `get_unaligned_be32()` at line 442
for SACK blocks (fixed in 2009). The fast path was the remaining
unaligned dereference.
---
## Phase 6: Cross-Reference Against Local Tree
**Step 6.1 — Buggy code in tree**
- Record:
- Local tree: **v6.18.44** (`git describe HEAD`)
- Buggy code **present** at lines 408–412 of
`net/netfilter/nf_conntrack_proto_tcp.c`
- Bug present since 2007; not introduced after 6.18 branch point
**Step 6.2 — Backport complications**
- Record: `git apply --check` and `git cherry-pick --no-commit` both
succeed — clean apply expected
**Step 6.3 — Related fixes already present**
- Record:
- 2009 SACK-path unaligned fix (`534f81a506879`) is in tree
- This specific fast-path fix (`d3bf9eae48649`) is **not** in tree
(only on master)
---
## Phase 7: Subsystem Context
**Step 7.1 — Subsystem**
- Record: `net/netfilter` — nf_conntrack TCP tracker. Criticality:
**CORE/IMPORTANT** (widely deployed on servers, routers, embedded
systems with `CONFIG_NF_CONNTRACK`)
**Step 7.2 — Activity**
- Record: Actively maintained subsystem with frequent stable fixes in
this tree
---
## Phase 8: Impact and Risk Assessment
**Step 8.1 — Who is affected**
- Record: Systems with `CONFIG_NF_CONNTRACK` processing TCP traffic —
routers, firewalls, NAT, containers/VMs using conntrack. Not universal
(config-dependent), but very common in production networking.
**Step 8.2 — Trigger conditions**
- Record:
- Linear skb (common) where TCP options start at non-4-byte-aligned
offset
- Typical Ethernet+IPv4: options at offset 54 (mod 4 = 2) — verified
by calculation
- Timestamp-only option layout (length 12)
- SACK negotiated on connection
- **Likelihood:** High on affected architectures for normal TCP
traffic
**Step 8.3 — Failure mode**
- Record:
- Strict-alignment architectures (SPARC, some ARM/MIPS): kernel
unaligned-access trap — severity **CRITICAL** (documented precedent
in same function, 2009)
- x86: usually tolerates unaligned access but technically undefined
behavior
- No data corruption path identified; primarily crash/trap risk
**Step 8.4 — Risk-benefit**
- Record:
- **Benefit:** HIGH — prevents kernel faults on common TCP fast path
in widely deployed code
- **Risk:** VERY LOW — 5-line change, matches existing pattern in same
function, reviewed by subsystem developer and maintainer
- **Ratio:** Strong benefit, minimal risk
---
## Phase 9: Final Synthesis
**Step 9.1 — Evidence summary**
FOR backport:
- Real unaligned memory access bug in hot conntrack path
- Present since 2007; same function had identical-class fix in 2009 for
SACK path
- Typical packet layouts place TCP options at 2-mod-4 offsets (verified)
- Small, surgical, obviously correct fix
- Reviewed by Fernando Fernandez Mancera; committed by netfilter
maintainer Pablo Neira
- Applies cleanly to v6.18.44
- No new APIs or features
AGAINST backport:
- No syzbot report or user crash report for this specific fast path
- Only affects `CONFIG_NF_CONNTRACK` systems
- Most severe on strict-alignment architectures (smaller user base than
x86)
- Impact on x86 is lower (unaligned access usually works)
UNRESOLVED:
- No explicit stable nomination in mailing list thread
- Lore stable archive search blocked
**Step 9.2 — Stable rules checklist**
1. Obviously correct and tested? **PASS** — matches existing in-function
pattern; reviewed and committed by maintainers
2. Fixes a real bug? **PASS** — unaligned dereference on non-guaranteed-
aligned data
3. Important issue? **PASS** — kernel trap/oops on strict-alignment
arch; hot networking path
4. Small and contained? **PASS** — 1 file, ~5 lines changed
5. No new features/APIs? **PASS** — correctness fix only
6. Can apply to local tree? **PASS** — verified clean apply to v6.18.44
**Step 9.3 — Exception category**
- Record: Not a device-ID/quirk/DT/docs exception; qualifies as a core
correctness/memory-safety fix
**Step 9.4 — Decision rationale**
This commit completes the unaligned-access fix started in 2009 for
`tcp_sack()`. The timestamp-only fast path — hit on very common TCP
packets — still uses an aligned `*(__be32 *)` dereference on data that
is typically 2-byte-aligned in standard Ethernet+IPv4 layouts. On
strict-alignment architectures this can cause kernel faults; the same
failure mode was already documented and fixed for the SACK parsing loop
in this exact function. The fix is minimal, follows an established
pattern already in the file, applies cleanly to the v6.18.44 tree, and
has maintainer review.
---
## Verification
- [Phase 1] Parsed commit message and tags from `git show d3bf9eae48649`
- [Phase 2] Diff analysis: 5-line change in `tcp_sack()` fast path
- [Phase 3] `git blame -L 407,413`: aligned dereference from 2007
(`8f05ce91c8b801`)
- [Phase 3] `git show 534f81a506879`: prior SACK-path unaligned fix in
same function (SPARC64)
- [Phase 3] `git show bb9fc37358ffa`: fast path length fix (2011)
- [Phase 3] `git log --grep`: no duplicate fix for this fast path in
stable tree
- [Phase 4] `b4 dig -c d3bf9eae48649`: lore thread found
- [Phase 4] `b4 dig -w`: netdev/netfilter maintainers CC'd
- [Phase 4] `b4 dig -a`: single v1 patch
- [Phase 4] Mbox review: Reviewed-by from Fernando Fernandez Mancera;
maintainer commit
- [Phase 5] `grep tcp_sack`: called from `tcp_in_window()` →
`nf_conntrack_tcp_packet()`
- [Phase 5] Read `skb_header_pointer()` in `include/linux/skbuff.h`:
returns direct skb pointer when linear
- [Phase 5] Python alignment calc: eth+ipv4 opts at offset 54 (mod 4 =
2)
- [Phase 6] `git describe HEAD`: v6.18.44
- [Phase 6] Read current file lines 408–412: buggy code still present
- [Phase 6] `git apply --check` on patch: applies cleanly
- [Phase 6] `git cherry-pick --no-commit d3bf9eae48649`: auto-merge
succeeds
- [Phase 6] `get_unaligned_be32` already at line 442; `#include
<linux/unaligned.h>` at line 17
- [Phase 8] Failure mode: unaligned access trap on strict-alignment arch
— CRITICAL severity class
**YES**
net/netfilter/nf_conntrack_proto_tcp.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index e99ab1e88e9f8..4a23edf7107a5 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -405,11 +405,11 @@ static void tcp_sack(const struct sk_buff *skb, unsigned int dataoff,
return;
/* Fast path for timestamp-only option */
- if (length == TCPOLEN_TSTAMP_ALIGNED
- && *(__be32 *)ptr == htonl((TCPOPT_NOP << 24)
- | (TCPOPT_NOP << 16)
- | (TCPOPT_TIMESTAMP << 8)
- | TCPOLEN_TIMESTAMP))
+ if (length == TCPOLEN_TSTAMP_ALIGNED &&
+ get_unaligned_be32(ptr) == ((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_TIMESTAMP << 8) |
+ TCPOLEN_TIMESTAMP))
return;
while (length > 0) {
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH AUTOSEL 6.18-5.15] netfilter: nfnetlink_log: wait for rcu grace period before freeing pernet state
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (3 preceding siblings ...)
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18-5.10] netfilter: nf_conntrack: use get_unaligned_be32() in tcp_sack() Sasha Levin
@ 2026-08-31 13:31 ` Sasha Levin
4 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2026-08-31 13:31 UTC (permalink / raw)
To: patches, stable
Cc: Florian Westphal, Pablo Neira Ayuso, Sasha Levin, davem, edumazet,
kuba, pabeni, netfilter-devel, coreteam, netdev, linux-kernel
From: Florian Westphal <fw@strlen.de>
[ Upstream commit 33d1469b0124cc0baaea7a2032123b77a81e0940 ]
sashiko reports: "nfnl_log_net_exit() calls nf_log_unset(), which
clears the logger pointer without an RCU grace period. Immediately after,
ops_free_list() frees the per-net state while concurrent packets might
still be executing nf_log_packet() under rcu_read_lock()."
Clear the pointer via .pre_exit to make sure rcu readers have completed
before pernet storage is free'd. The change in nf_log_syslog.c is only
done for consistency: it doesn't use pernet data.
Link: https://sashiko.dev/#/patchset/20260731151806.849724-1-pablo%40netfilter.org
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The background searches finished with no hits:
- **Local tree:** `git log --grep` for the fix subject,
`nfnl_log_net_pre_exit`, and related terms returned nothing — the
patch is not in `v6.18.44`.
- **Patchwork:** The kernel.org search also came up empty (no matching
nfnetlink entries).
That lines up with the earlier analysis: the buggy code is still present
in this tree, and the fix looks like a good backport candidate
(**YES**).
net/netfilter/nf_log_syslog.c | 4 ++--
net/netfilter/nfnetlink_log.c | 13 +++++++++----
2 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/net/netfilter/nf_log_syslog.c b/net/netfilter/nf_log_syslog.c
index 6fa0812cd79ca..07a4f4725fcb2 100644
--- a/net/netfilter/nf_log_syslog.c
+++ b/net/netfilter/nf_log_syslog.c
@@ -1006,7 +1006,7 @@ static int __net_init nf_log_syslog_net_init(struct net *net)
return ret;
}
-static void __net_exit nf_log_syslog_net_exit(struct net *net)
+static void __net_exit nf_log_syslog_net_pre_exit(struct net *net)
{
nf_log_unset(net, &nf_ip_logger);
nf_log_unset(net, &nf_arp_logger);
@@ -1017,7 +1017,7 @@ static void __net_exit nf_log_syslog_net_exit(struct net *net)
static struct pernet_operations nf_log_syslog_net_ops = {
.init = nf_log_syslog_net_init,
- .exit = nf_log_syslog_net_exit,
+ .pre_exit = nf_log_syslog_net_pre_exit,
};
static int __init nf_log_syslog_init(void)
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index a6989966d80d5..68e5429338330 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -1160,21 +1160,26 @@ static int __net_init nfnl_log_net_init(struct net *net)
return 0;
}
-static void __net_exit nfnl_log_net_exit(struct net *net)
+static void __net_exit nfnl_log_net_pre_exit(struct net *net)
{
- struct nfnl_log_net *log = nfnl_log_pernet(net);
- unsigned int i;
-
#ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_log", net->nf.proc_netfilter);
#endif
nf_log_unset(net, &nfulnl_logger);
+}
+
+static void __net_exit nfnl_log_net_exit(struct net *net)
+{
+ struct nfnl_log_net *log = nfnl_log_pernet(net);
+ unsigned int i;
+
for (i = 0; i < INSTANCE_BUCKETS; i++)
WARN_ON_ONCE(!hlist_empty(&log->instance_table[i]));
}
static struct pernet_operations nfnl_log_net_ops = {
.init = nfnl_log_net_init,
+ .pre_exit = nfnl_log_net_pre_exit,
.exit = nfnl_log_net_exit,
.id = &nfnl_log_net_id,
.size = sizeof(struct nfnl_log_net),
--
2.53.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-08-31 13:52 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-5.10] netfilter: nf_conntrack_expect: zero at allocation time Sasha Levin
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18-5.10] netfilter: ipset: mark the rcu locked areas properly Sasha Levin
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18] netfilter: nf_tables: use DEBUG_NET_WARN_ON_ONCE in packet and control paths Sasha Levin
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18-5.10] netfilter: nf_conntrack: use get_unaligned_be32() in tcp_sack() Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18-5.15] netfilter: nfnetlink_log: wait for rcu grace period before freeing pernet state Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox