[PATCH nf v2 2/2] netfilter: nf_conntrack_expect: reject reinsertion of DEAD expectations
Jaeyeong Lee <[email protected]>
| Newsgroups | gmane.comp.security.firewalls.netfilter.devel |
|---|---|
| Message-ID | <[email protected]> |
Since commit b8b09dc2bf35 ("netfilter: nf_conntrack_expect: use
conntrack GC to reap expectations"), nf_ct_unexpect_related() marks an
expectation as NF_CT_EXPECT_DEAD but leaves it linked until a GC or list
walker unlinks it.
Passing the same object to nf_ct_expect_related() again violates this
terminal-state invariant. If its tuple was changed and hashes to a
different bucket, __nf_ct_expect_check() does not encounter and unlink
the old DEAD entry. The still-linked object can then reach
nf_ct_expect_insert(), which links its hnode and lnode again and takes
another insertion reference, corrupting the expectation hash and the
per-master expectation list.
Reject DEAD expectations immediately after taking the expectation lock,
before the insertion checks can alter any expectation lists. Return
-EINVAL without warning or modifying the object or the lists, so an
invalid reinsertion cannot panic a kernel with panic_on_warn enabled.
Fixes: b8b09dc2bf35 ("netfilter: nf_conntrack_expect: use conntrack GC to reap expectations")
Link: https://lore.kernel.org/netfilter-devel/2026071235-geometric-snowdrift-bb4c@gregkh/
Suggested-by: Florian Westphal <[email protected]>
Signed-off-by: Jaeyeong Lee <[email protected]>
---
Changes in v2:
- New patch, based on a suggestion from Florian Westphal.
- Return -EINVAL without WARN_ON_ONCE to avoid panic_on_warn, as pointed
out by Greg Kroah-Hartman.
net/netfilter/nf_conntrack_expect.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 7ae68d60586a..f02f9ecdb08f 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -524,6 +524,11 @@ int nf_ct_expect_related_report(struct nf_conntrack_expect *expect,
int ret;
spin_lock_bh(&nf_conntrack_expect_lock);
+ if (expect->flags & NF_CT_EXPECT_DEAD) {
+ ret = -EINVAL;
+ goto out;
+ }
+
master_help = nfct_help(expect->master);
if (!master_help) {
ret = -ESHUTDOWN;
--
2.43.0