From: Pablo Neira Ayuso <pablo@netfilter.org> Date: 2021-03-06 12:13:21
Hi,
The following patchset contains Netfilter fixes for net:
1) Fix incorrect enum type definition in nfnetlink_cthelper UAPI,
from Dmitry V. Levin.
2) Remove extra space in deprecated automatic helper assignment
notice, from Klemen Košir.
3) Drop early socket demux socket after NAT mangling, from
Florian Westphal. Add a test to exercise this bug.
4) Fix bogus invalid packet report in the conntrack TCP tracker,
also from Florian.
5) Fix access to xt[NFPROTO_UNSPEC] list with no mutex
in target/match_revfn(), from Vasily Averin.
6) Disallow updates on the table ownership flag.
7) Fix double hook unregistration of tables with owner.
8) Remove bogus check on the table owner in __nft_release_tables().
Please, pull these changes from:
git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git
Thanks!
----------------------------------------------------------------
The following changes since commit eee7ede695cfbb19fefdeb14992535b605448f35:
Merge branch 'bnxt_en-error-recovery-bug-fixes' (2021-02-26 15:50:25 -0800)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf.git HEAD
for you to fetch changes up to bd1777b3a88f98e223392221b330668458aac7f1:
netfilter: nftables: bogus check for netlink portID with table owner (2021-03-04 04:02:54 +0100)
----------------------------------------------------------------
Dmitry V. Levin (1):
uapi: nfnetlink_cthelper.h: fix userspace compilation error
Florian Westphal (3):
netfilter: nf_nat: undo erroneous tcp edemux lookup
netfilter: conntrack: avoid misleading 'invalid' in log message
selftests: netfilter: test nat port clash resolution interaction with tcp early demux
Klemen Košir (1):
netfilter: conntrack: Remove a double space in a log message
Pablo Neira Ayuso (3):
netfilter: nftables: disallow updates on table ownership
netfilter: nftables: fix possible double hook unregistration with table owner
netfilter: nftables: bogus check for netlink portID with table owner
Vasily Averin (1):
netfilter: x_tables: gpf inside xt_find_revision()
include/uapi/linux/netfilter/nfnetlink_cthelper.h | 2 +-
net/netfilter/nf_conntrack_helper.c | 3 +-
net/netfilter/nf_conntrack_proto_tcp.c | 6 +-
net/netfilter/nf_nat_proto.c | 25 +++++-
net/netfilter/nf_tables_api.c | 19 +++--
net/netfilter/x_tables.c | 6 +-
tools/testing/selftests/netfilter/Makefile | 2 +-
tools/testing/selftests/netfilter/nf_nat_edemux.sh | 99 ++++++++++++++++++++++
8 files changed, 145 insertions(+), 17 deletions(-)
create mode 100755 tools/testing/selftests/netfilter/nf_nat_edemux.sh
From: Pablo Neira Ayuso <pablo@netfilter.org> Date: 2021-03-06 12:13:21
From: Klemen Košir <redacted>
Removed an extra space in a log message and an extra blank line in code.
Signed-off-by: Klemen Košir <redacted>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_conntrack_helper.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
@@ -219,7 +219,7 @@ nf_ct_lookup_helper(struct nf_conn *ct, struct net *net)returnNULL;pr_info("nf_conntrack: default automatic helper assignment ""has been turned off for security reasons and CT-based "-" firewall rule not found. Use the iptables CT target "+"firewall rule not found. Use the iptables CT target ""to attach helpers instead.\n");net->ct.auto_assign_helper_warned=1;returnNULL;
@@ -228,7 +228,6 @@ nf_ct_lookup_helper(struct nf_conn *ct, struct net *net)return__nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);}-int__nf_ct_try_assign_helper(structnf_conn*ct,structnf_conn*tmpl,gfp_tflags){
From: Pablo Neira Ayuso <pablo@netfilter.org> Date: 2021-03-06 12:13:22
From: Florian Westphal <fw@strlen.de>
Under extremely rare conditions TCP early demux will retrieve the wrong
socket.
1. local machine establishes a connection to a remote server, S, on port
p.
This gives:
laddr:lport -> S:p
... both in tcp and conntrack.
2. local machine establishes a connection to host H, on port p2.
2a. TCP stack choses same laddr:lport, so we have
laddr:lport -> H:p2 from TCP point of view.
2b). There is a destination NAT rewrite in place, translating
H:p2 to S:p. This results in following conntrack entries:
I) laddr:lport -> S:p (origin) S:p -> laddr:lport (reply)
II) laddr:lport -> H:p2 (origin) S:p -> laddr:lport2 (reply)
NAT engine has rewritten laddr:lport to laddr:lport2 to map
the reply packet to the correct origin.
When server sends SYN/ACK to laddr:lport2, the PREROUTING hook
will undo-the SNAT transformation, rewriting IP header to
S:p -> laddr:lport
This causes TCP early demux to associate the skb with the TCP socket
of the first connection.
The INPUT hook will then reverse the DNAT transformation, rewriting
the IP header to H:p2 -> laddr:lport.
Because packet ends up with the wrong socket, the new connection
never completes: originator stays in SYN_SENT and conntrack entry
remains in SYN_RECV until timeout, and responder retransmits SYN/ACK
until it gives up.
To resolve this, orphan the skb after the input rewrite:
Because the source IP address changed, the socket must be incorrect.
We can't move the DNAT undo to prerouting due to backwards
compatibility, doing so will make iptables/nftables rules to no longer
match the way they did.
After orphan, the packet will be handed to the next protocol layer
(tcp, udp, ...) and that will repeat the socket lookup just like as if
early demux was disabled.
Fixes: 41063e9dd1195 ("ipv4: Early TCP socket demux.")
Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1427
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_nat_proto.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
@@ -330,6 +330,7 @@ static int match_revfn(u8 af, const char *name, u8 revision, int *bestp)conststructxt_match*m;inthave_rev=0;+mutex_lock(&xt[af].mutex);list_for_each_entry(m,&xt[af].match,list){if(strcmp(m->name,name)==0){if(m->revision>*bestp)
@@ -338,6 +339,7 @@ static int match_revfn(u8 af, const char *name, u8 revision, int *bestp)have_rev=1;}}+mutex_unlock(&xt[af].mutex);if(af!=NFPROTO_UNSPEC&&!have_rev)returnmatch_revfn(NFPROTO_UNSPEC,name,revision,bestp);
@@ -350,6 +352,7 @@ static int target_revfn(u8 af, const char *name, u8 revision, int *bestp)conststructxt_target*t;inthave_rev=0;+mutex_lock(&xt[af].mutex);list_for_each_entry(t,&xt[af].target,list){if(strcmp(t->name,name)==0){if(t->revision>*bestp)
@@ -358,6 +361,7 @@ static int target_revfn(u8 af, const char *name, u8 revision, int *bestp)have_rev=1;}}+mutex_unlock(&xt[af].mutex);if(af!=NFPROTO_UNSPEC&&!have_rev)returntarget_revfn(NFPROTO_UNSPEC,name,revision,bestp);
@@ -371,12 +375,10 @@ int xt_find_revision(u8 af, const char *name, u8 revision, int target,{inthave_rev,best=-1;-mutex_lock(&xt[af].mutex);if(target==1)have_rev=target_revfn(af,name,revision,&best);elsehave_rev=match_revfn(af,name,revision,&best);-mutex_unlock(&xt[af].mutex);/* Nothing at all? Return 0 to try loading module. */if(best==-1){
@@ -0,0 +1,99 @@+#!/bin/bash+# SPDX-License-Identifier: GPL-2.0+#+# Test NAT source port clash resolution+#++# Kselftest framework requirement - SKIP code is 4.+ksft_skip=4+ret=0++sfx=$(mktemp-u"XXXXXXXX")+ns1="ns1-$sfx"+ns2="ns2-$sfx"++cleanup()+{+ipnetnsdel$ns1+ipnetnsdel$ns2+}++iperf3-v>/dev/null2>&1+if[$?-ne0];then+echo"SKIP: Could not run test without iperf3"+exit$ksft_skip+fi++iptables--version>/dev/null2>&1+if[$?-ne0];then+echo"SKIP: Could not run test without iptables"+exit$ksft_skip+fi++ip-Version>/dev/null2>&1+if[$?-ne0];then+echo"SKIP: Could not run test without ip tool"+exit$ksft_skip+fi++ipnetnsadd"$ns1"+if[$?-ne0];then+echo"SKIP: Could not create net namespace $ns1"+exit$ksft_skip+fi++trapcleanupEXIT++ipnetnsadd$ns2++# Connect the namespaces using a veth pair+iplinkaddnameveth2typevethpeernameveth1+iplinksetnetns$ns1devveth1+iplinksetnetns$ns2devveth2++ipnetnsexec$ns1iplinksetupdevlo+ipnetnsexec$ns1iplinksetupdevveth1+ipnetnsexec$ns1ipaddradd192.168.1.1/24devveth1++ipnetnsexec$ns2iplinksetupdevlo+ipnetnsexec$ns2iplinksetupdevveth2+ipnetnsexec$ns2ipaddradd192.168.1.2/24devveth2++# Create a server in one namespace+ipnetnsexec$ns1iperf3-s>/dev/null2>&1&+iperfs=$!++# Restrict source port to just one so we don't have to exhaust+# all others.+ipnetnsexec$ns2sysctl-qnet.ipv4.ip_local_port_range="10000 10000"++# add a virtual IP using DNAT+ipnetnsexec$ns2iptables-tnat-AOUTPUT-d10.96.0.1/32-ptcp--dport443-jDNAT--to-destination192.168.1.1:5201++# ... and route it to the other namespace+ipnetnsexec$ns2iprouteadd10.96.0.1via192.168.1.1++sleep1++# add a persistent connection from the other namespace+ipnetnsexec$ns2nc-q10-w10192.168.1.15201>/dev/null&++sleep1++# ip daddr:dport will be rewritten to 192.168.1.1 5201+# NAT must reallocate source port 10000 because+# 192.168.1.2:10000 -> 192.168.1.1:5201 is already in use+echotest|ipnetnsexec$ns2nc-w3-q310.96.0.1443>/dev/null+ret=$?++kill$iperfs++# Check nc can connect to 10.96.0.1:443 (aka 192.168.1.1:5201).+if[$ret-eq0];then+echo"PASS: nc can connect via NAT'd address"+else+echo"FAIL: nc cannot connect via NAT'd address"+exit1+fi++exit0
From: Pablo Neira Ayuso <pablo@netfilter.org> Date: 2021-03-06 12:13:23
From: "Dmitry V. Levin" <redacted>
Apparently, <linux/netfilter/nfnetlink_cthelper.h> and
<linux/netfilter/nfnetlink_acct.h> could not be included into the same
compilation unit because of a cut-and-paste typo in the former header.
Fixes: 12f7a505331e6 ("netfilter: add user-space connection tracking helper infrastructure")
Cc: <redacted> # v3.6
Signed-off-by: Dmitry V. Levin <redacted>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
include/uapi/linux/netfilter/nfnetlink_cthelper.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
From: Pablo Neira Ayuso <pablo@netfilter.org> Date: 2021-03-06 12:13:23
Disallow updating the ownership bit on an existing table: Do not allow
to grab ownership on an existing table. Do not allow to drop ownership
on an existing table.
Fixes: 6001a930ce03 ("netfilter: nftables: introduce table ownership")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_tables_api.c | 6 ++++++
1 file changed, 6 insertions(+)
From: Pablo Neira Ayuso <pablo@netfilter.org> Date: 2021-03-06 12:13:23
From: Florian Westphal <fw@strlen.de>
The packet is not flagged as invalid: conntrack will accept it and
its associated with the conntrack entry.
This happens e.g. when receiving a retransmitted SYN in SYN_RECV state.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_conntrack_proto_tcp.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
@@ -982,8 +982,10 @@ int nf_conntrack_tcp_packet(struct nf_conn *ct,IP_CT_EXP_CHALLENGE_ACK;}spin_unlock_bh(&ct->lock);-nf_ct_l4proto_log_invalid(skb,ct,"invalid packet ignored in "-"state %s ",tcp_conntrack_names[old_state]);+nf_ct_l4proto_log_invalid(skb,ct,+"packet (index %d) in dir %d ignored, state %s",+index,dir,+tcp_conntrack_names[old_state]);returnNF_ACCEPT;caseTCP_CONNTRACK_MAX:/* Special case for SYN proxy: when the SYN to the server or
From: Mika Penttilä <hidden> Date: 2021-03-06 14:50:00
On 6.3.2021 14.12, Pablo Neira Ayuso wrote:
From: Florian Westphal <fw@strlen.de>
Under extremely rare conditions TCP early demux will retrieve the wrong
socket.
1. local machine establishes a connection to a remote server, S, on port
p.
This gives:
laddr:lport -> S:p
... both in tcp and conntrack.
2. local machine establishes a connection to host H, on port p2.
2a. TCP stack choses same laddr:lport, so we have
laddr:lport -> H:p2 from TCP point of view.
2b). There is a destination NAT rewrite in place, translating
H:p2 to S:p. This results in following conntrack entries:
I) laddr:lport -> S:p (origin) S:p -> laddr:lport (reply)
II) laddr:lport -> H:p2 (origin) S:p -> laddr:lport2 (reply)
NAT engine has rewritten laddr:lport to laddr:lport2 to map
the reply packet to the correct origin.
Could you eloborate where and how linux nat engine is doing the
laddr:lport to laddr:lport2
rewrite? There's only DST nat and there should be conflict (for reply)
in tuple establishment afaik....
quoted hunk
When server sends SYN/ACK to laddr:lport2, the PREROUTING hook
will undo-the SNAT transformation, rewriting IP header to
S:p -> laddr:lport
This causes TCP early demux to associate the skb with the TCP socket
of the first connection.
The INPUT hook will then reverse the DNAT transformation, rewriting
the IP header to H:p2 -> laddr:lport.
Because packet ends up with the wrong socket, the new connection
never completes: originator stays in SYN_SENT and conntrack entry
remains in SYN_RECV until timeout, and responder retransmits SYN/ACK
until it gives up.
To resolve this, orphan the skb after the input rewrite:
Because the source IP address changed, the socket must be incorrect.
We can't move the DNAT undo to prerouting due to backwards
compatibility, doing so will make iptables/nftables rules to no longer
match the way they did.
After orphan, the packet will be handed to the next protocol layer
(tcp, udp, ...) and that will repeat the socket lookup just like as if
early demux was disabled.
Fixes: 41063e9dd1195 ("ipv4: Early TCP socket demux.")
Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1427
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_nat_proto.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
From: Mika Penttilä <hidden> Date: 2021-03-06 16:11:07
On 6.3.2021 16.49, Mika Penttilä wrote:
On 6.3.2021 14.12, Pablo Neira Ayuso wrote:
quoted
From: Florian Westphal <fw@strlen.de>
Under extremely rare conditions TCP early demux will retrieve the wrong
socket.
1. local machine establishes a connection to a remote server, S, on port
p.
This gives:
laddr:lport -> S:p
... both in tcp and conntrack.
2. local machine establishes a connection to host H, on port p2.
2a. TCP stack choses same laddr:lport, so we have
laddr:lport -> H:p2 from TCP point of view.
2b). There is a destination NAT rewrite in place, translating
H:p2 to S:p. This results in following conntrack entries:
I) laddr:lport -> S:p (origin) S:p -> laddr:lport (reply)
II) laddr:lport -> H:p2 (origin) S:p -> laddr:lport2 (reply)
NAT engine has rewritten laddr:lport to laddr:lport2 to map
the reply packet to the correct origin.
Could you eloborate where and how linux nat engine is doing the
laddr:lport to laddr:lport2
rewrite? There's only DST nat and there should be conflict (for reply)
in tuple establishment afaik....
Ah I see it is the nat null binding for src to make it unique
quoted
When server sends SYN/ACK to laddr:lport2, the PREROUTING hook
will undo-the SNAT transformation, rewriting IP header to
S:p -> laddr:lport
This causes TCP early demux to associate the skb with the TCP socket
of the first connection.
The INPUT hook will then reverse the DNAT transformation, rewriting
the IP header to H:p2 -> laddr:lport.
Because packet ends up with the wrong socket, the new connection
never completes: originator stays in SYN_SENT and conntrack entry
remains in SYN_RECV until timeout, and responder retransmits SYN/ACK
until it gives up.
To resolve this, orphan the skb after the input rewrite:
Because the source IP address changed, the socket must be incorrect.
We can't move the DNAT undo to prerouting due to backwards
compatibility, doing so will make iptables/nftables rules to no longer
match the way they did.
After orphan, the packet will be handed to the next protocol layer
(tcp, udp, ...) and that will repeat the socket lookup just like as if
early demux was disabled.
Fixes: 41063e9dd1195 ("ipv4: Early TCP socket demux.")
Closes: https://bugzilla.netfilter.org/show_bug.cgi?id=1427
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
net/netfilter/nf_nat_proto.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
Hello:
This series was applied to netdev/net.git (refs/heads/master):
On Sat, 6 Mar 2021 13:12:15 +0100 you wrote:
From: "Dmitry V. Levin" <redacted>
Apparently, <linux/netfilter/nfnetlink_cthelper.h> and
<linux/netfilter/nfnetlink_acct.h> could not be included into the same
compilation unit because of a cut-and-paste typo in the former header.
Fixes: 12f7a505331e6 ("netfilter: add user-space connection tracking helper infrastructure")
Cc: <redacted> # v3.6
Signed-off-by: Dmitry V. Levin <redacted>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
[...]