[PATCH nf,v2 1/2] netfilter: ctnetlink: reject expectation deletions on unconfirmed conntrack

Pablo Neira Ayuso <[email protected]> Wed, 29 Jul 2026 13:35:47 +0200
Newsgroups gmane.comp.security.firewalls.netfilter.devel
Message-ID <[email protected]>
ctnetlink allows to reach expectations that refer to unconfirmed
conntrack. The ct extension area of unconfirmed conntrack could be
reallocated while the packet is in transit.

While holding the spinlock, check if the master conntrack is
unconfirmed. The existing expectation spinlock ensures that the master
conntrack is still alive because nf_ct_remove_expectations() tears down
all expectations on conntrack removal. So, while holding the spinlock,
the lifetime of the expectations is attached to the master conntrack.

Fixes: ecfab2c9fe55 [NETFILTER]: nf_conntrack: introduce extension infrastructure
Signed-off-by: Pablo Neira Ayuso <[email protected]>
---
v2: new in this series, to address sashiko report.

 net/netfilter/nf_conntrack_expect.c  | 3 +++
 net/netfilter/nf_conntrack_netlink.c | 6 ++++++
 2 files changed, 9 insertions(+)

diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index 8a3b9e33e94f..7694deaa5b12 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -620,6 +620,9 @@ void nf_ct_expect_iterate_net(struct net *net,
 			if (!net_eq(nf_ct_exp_net(exp), net))
 				continue;
 
+			if (!nf_ct_is_confirmed(exp->master))
+				continue;
+
 			if (iter(exp, data))
 				nf_ct_unlink_expect_report(exp, portid, report);
 		}
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 31cbb1b55b9e..b58f51372849 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -3442,6 +3442,12 @@ static int ctnetlink_del_expect(struct sk_buff *skb,
 			}
 		}
 
+		if (!nf_ct_is_confirmed(exp->master)) {
+			nf_ct_expect_put(exp);
+			spin_unlock_bh(&nf_conntrack_expect_lock);
+			return -EBUSY;
+		}
+
 		/* after list removal, usage count == 1 */
 		nf_ct_unlink_expect_report(exp, NETLINK_CB(skb).portid,
 					   nlmsg_report(info->nlh));
-- 
2.47.3