[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