[PATCH nf v2 1/2] netfilter: nf_nat: stop reusing DEAD RTP expectations

Jaeyeong Lee <[email protected]>
Newsgroups gmane.comp.security.firewalls.netfilter.devel
Message-ID <[email protected]>
Commit b8b09dc2bf35 ("netfilter: nf_conntrack_expect: use conntrack
GC to reap expectations") changed nf_ct_unexpect_related() to mark an
expectation NF_CT_EXPECT_DEAD and leave it linked until an expectation
walker unlinks it. The insertion reference is retained until that
unlink.

The SIP and H.323 NAT RTP/RTCP port searches still continue after
marking rtp_exp DEAD when insertion of rtcp_exp fails with -EBUSY. The
next iteration mutates rtp_exp and passes the same object to
nf_ct_expect_related() again.

If the new RTP tuple hashes to a different expectation bucket, the hash
walk in __nf_ct_expect_check() does not encounter the old DEAD link.
While the master is below its policy limit, no master-list eviction walk
runs either. nf_ct_expect_insert() can then add the already-linked hnode
and lnode again and take a second insertion reference, corrupting the
expectation lists. A later unlink or GC walk can revisit stale linkage
and cause a use-after-free.

Treat a DEAD expectation as terminal. On any RTCP insertion error, mark
rtp_exp DEAD and stop the port search instead of mutating and reinserting
it. The callers still drop both allocation references; the linked RTP
insertion reference is released when a walker or master teardown unlinks
it.

For SIP this follows the existing port == 0 path and drops the packet.
H.323 follows its existing no-port path without completing a usable
RTP/RTCP expectation pair or rewriting the signalling address.

This gives up retrying the next RTP/RTCP port pair after RTP insertion
succeeds but RTCP insertion fails. That search is best effort and is not
required for correctness.

Fixes: b8b09dc2bf35 ("netfilter: nf_conntrack_expect: use conntrack GC to reap expectations")
Signed-off-by: Jaeyeong Lee <[email protected]>
---
Changes in v2:
- Stop the port search on RTCP -EBUSY and merge the now-identical error
  paths.
- Clarify when a DEAD expectation can reach insertion while still linked.
- Add the core DEAD-reinsertion check as a separate patch, as suggested
  by Florian Westphal.

v1: https://lore.kernel.org/netfilter-devel/[email protected]/

 net/ipv4/netfilter/nf_nat_h323.c | 5 +----
 net/netfilter/nf_nat_sip.c       | 5 +----
 2 files changed, 2 insertions(+), 8 deletions(-)

diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index 183e8a3ff2ba..f09fa7704b90 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -234,10 +234,7 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
 			ret = nf_ct_expect_related(rtcp_exp, 0);
 			if (ret == 0)
 				break;
-			else if (ret == -EBUSY) {
-				nf_ct_unexpect_related(rtp_exp);
-				continue;
-			} else if (ret < 0) {
+			else if (ret < 0) {
 				nf_ct_unexpect_related(rtp_exp);
 				nated_port = 0;
 				break;
diff --git a/net/netfilter/nf_nat_sip.c b/net/netfilter/nf_nat_sip.c
index aea02f6aff09..5878b4a6a438 100644
--- a/net/netfilter/nf_nat_sip.c
+++ b/net/netfilter/nf_nat_sip.c
@@ -635,10 +635,7 @@ static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
 					   NF_CT_EXP_F_SKIP_MASTER);
 		if (ret == 0)
 			break;
-		else if (ret == -EBUSY) {
-			nf_ct_unexpect_related(rtp_exp);
-			continue;
-		} else if (ret < 0) {
+		else if (ret < 0) {
 			nf_ct_unexpect_related(rtp_exp);
 			port = 0;
 			break;
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.