[Devel] [PATCH RHEL7 COMMIT] net/netfilter: do not pretend nf_hook_ops->priv is always valid

Konstantin Khorenko khorenko at virtuozzo.com
Sun May 3 10:56:53 MSK 2020


The commit is pushed to "branch-rh7-3.10.0-1127.vz7.150.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1127.vz7.150.6
------>
commit 078421bbd20ada20c1f140f8ab0592cd6faa3f9e
Author: Konstantin Khorenko <khorenko at virtuozzo.com>
Date:   Sun May 3 10:50:25 2020 +0300

    net/netfilter: do not pretend nf_hook_ops->priv is always valid
    
    1) it's unsafe to consider nf_hook_ops->priv always filled in
       nf_nat_ipv{4,6}_fn() until we do all checks
    
    2) we better don't add extra checks for net correctness in every
       call of nf_nat_ipv{4,6}_fn() - we need them only on conntrack
       configuration stage.
    
    => move check for proper netns under IP_CT_NEW case.
    
    Fixes: 5ff26bf49074a net/netfilter: make nft NAT working in different
    netns simultaneously
    
    https://jira.sw.ru/browse/PSBM-103718
    https://jira.sw.ru/browse/PSBM-102728
    
    Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
 net/ipv4/netfilter/nf_nat_l3proto_ipv4.c | 21 +++++++++++----------
 net/ipv6/netfilter/nf_nat_l3proto_ipv6.c | 21 +++++++++++----------
 2 files changed, 22 insertions(+), 20 deletions(-)

diff --git a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
index fa880d189bed3..de977be995f5e 100644
--- a/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_nat_l3proto_ipv4.c
@@ -252,11 +252,6 @@ nf_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb,
 	/* maniptype == SRC for postrouting. */
 	enum nf_nat_manip_type maniptype = HOOK2MANIP(ops->hooknum);
 
-	const struct nft_chain *chain = ops->priv;
-	const struct net *chain_net =
-		read_pnet(&nft_base_chain(chain)->pnet);
-	const struct net *net;
-
 	/* We never see fragments: conntrack defrags on pre-routing
 	 * and local-out, and nf_nat_out protects post-routing.
 	 */
@@ -271,11 +266,6 @@ nf_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb,
 	if (!ct)
 		return NF_ACCEPT;
 
-	/* Ignore chains that are not for the current network namespace */
-	net = nf_ct_net(ct);
-	if (!net_eq(net, chain_net))
-		return NF_ACCEPT;
-
 	/* Don't try to NAT if this packet is not conntracked */
 	if (nf_ct_is_untracked(ct))
 		return NF_ACCEPT;
@@ -300,8 +290,19 @@ nf_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb,
 		 * or local packets.
 		 */
 		if (!nf_nat_initialized(ct, maniptype)) {
+			const struct nft_chain *chain = ops->priv;
+			const struct net *chain_net =
+				read_pnet(&nft_base_chain(chain)->pnet);
+			const struct net *net;
 			unsigned int ret;
 
+			/* Ignore chains that are not for the current network
+			 * namespace
+			 */
+			net = nf_ct_net(ct);
+			if (!net_eq(net, chain_net))
+				return NF_ACCEPT;
+
 			ret = do_chain(ops, skb, state, ct);
 			if (ret != NF_ACCEPT)
 				return ret;
diff --git a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
index f369123f89246..a0804157e12b2 100644
--- a/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_nat_l3proto_ipv6.c
@@ -265,11 +265,6 @@ nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb,
 	int hdrlen;
 	u8 nexthdr;
 
-	const struct nft_chain *chain = ops->priv;
-	const struct net *chain_net =
-		read_pnet(&nft_base_chain(chain)->pnet);
-	const struct net *net;
-
 	ct = nf_ct_get(skb, &ctinfo);
 	/* Can't track?  It's not due to stress, or conntrack would
 	 * have dropped it.  Hence it's the user's responsibilty to
@@ -279,11 +274,6 @@ nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb,
 	if (!ct)
 		return NF_ACCEPT;
 
-	/* Ignore chains that are not for the current network namespace */
-	net = nf_ct_net(ct);
-	if (!net_eq(net, chain_net))
-		return NF_ACCEPT;
-
 	/* Don't try to NAT if this packet is not conntracked */
 	if (nf_ct_is_untracked(ct))
 		return NF_ACCEPT;
@@ -313,8 +303,19 @@ nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb,
 		 * or local packets.
 		 */
 		if (!nf_nat_initialized(ct, maniptype)) {
+			const struct nft_chain *chain = ops->priv;
+			const struct net *chain_net =
+				read_pnet(&nft_base_chain(chain)->pnet);
+			const struct net *net;
 			unsigned int ret;
 
+			/* Ignore chains that are not for the current network
+			 * namespace
+			 */
+			net = nf_ct_net(ct);
+			if (!net_eq(net, chain_net))
+				return NF_ACCEPT;
+
 			ret = do_chain(ops, skb, state, ct);
 			if (ret != NF_ACCEPT)
 				return ret;


More information about the Devel mailing list