]> git.baikalelectronics.ru Git - kernel.git/commitdiff
netfilter: conntrack: fix boot failure with nf_conntrack.enable_hooks=1
authorFlorian Westphal <fw@strlen.de>
Thu, 23 Sep 2021 14:44:34 +0000 (16:44 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 28 Sep 2021 11:04:55 +0000 (13:04 +0200)
This is a revert of
995262f6a0 ("netfilter: nf_defrag_ipv4: use net_generic infra")
and a partial revert of
b0267976a7 ("netfilter: nf_defrag_ipv6: use net_generic infra").

If conntrack is builtin and kernel is booted with:
nf_conntrack.enable_hooks=1

.... kernel will fail to boot due to a NULL deref in
nf_defrag_ipv4_enable(): Its called before the ipv4 defrag initcall is
made, so net_generic() returns NULL.

To resolve this, move the user refcount back to struct net so calls
to those functions are possible even before their initcalls have run.

Fixes: 995262f6a025 ("netfilter: nf_defrag_ipv4: use net_generic infra")
Fixes: b0267976a72d ("netfilter: nf_defrag_ipv6: use net_generic infra").
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/net/netfilter/ipv6/nf_defrag_ipv6.h
include/net/netns/netfilter.h
net/ipv4/netfilter/nf_defrag_ipv4.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/netfilter/nf_defrag_ipv6_hooks.c

index 0fd8a4159662d094fd5f02c34c856a9bb08d2813..ceadf8ba25a446b648f21adb71361609ff58beee 100644 (file)
@@ -17,7 +17,6 @@ struct inet_frags_ctl;
 struct nft_ct_frag6_pernet {
        struct ctl_table_header *nf_frag_frags_hdr;
        struct fqdir    *fqdir;
-       unsigned int users;
 };
 
 #endif /* _NF_DEFRAG_IPV6_H */
index 986a2a9cfdfa444fe8c2087e1a72507baf469a81..b593f95e99913e9946da7bd2d3b28462350217ee 100644 (file)
@@ -27,5 +27,11 @@ struct netns_nf {
 #if IS_ENABLED(CONFIG_DECNET)
        struct nf_hook_entries __rcu *hooks_decnet[NF_DN_NUMHOOKS];
 #endif
+#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4)
+       unsigned int defrag_ipv4_users;
+#endif
+#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6)
+       unsigned int defrag_ipv6_users;
+#endif
 };
 #endif
index 613432a36f0a701afc993d23053bfc03c4a8ed0a..e61ea428ea1872077ec6c2917b8c511518a692d8 100644 (file)
 #endif
 #include <net/netfilter/nf_conntrack_zones.h>
 
-static unsigned int defrag4_pernet_id __read_mostly;
 static DEFINE_MUTEX(defrag4_mutex);
 
-struct defrag4_pernet {
-       unsigned int users;
-};
-
 static int nf_ct_ipv4_gather_frags(struct net *net, struct sk_buff *skb,
                                   u_int32_t user)
 {
@@ -111,19 +106,15 @@ static const struct nf_hook_ops ipv4_defrag_ops[] = {
 
 static void __net_exit defrag4_net_exit(struct net *net)
 {
-       struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id);
-
-       if (nf_defrag->users) {
+       if (net->nf.defrag_ipv4_users) {
                nf_unregister_net_hooks(net, ipv4_defrag_ops,
                                        ARRAY_SIZE(ipv4_defrag_ops));
-               nf_defrag->users = 0;
+               net->nf.defrag_ipv4_users = 0;
        }
 }
 
 static struct pernet_operations defrag4_net_ops = {
        .exit = defrag4_net_exit,
-       .id   = &defrag4_pernet_id,
-       .size = sizeof(struct defrag4_pernet),
 };
 
 static int __init nf_defrag_init(void)
@@ -138,24 +129,23 @@ static void __exit nf_defrag_fini(void)
 
 int nf_defrag_ipv4_enable(struct net *net)
 {
-       struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id);
        int err = 0;
 
        mutex_lock(&defrag4_mutex);
-       if (nf_defrag->users == UINT_MAX) {
+       if (net->nf.defrag_ipv4_users == UINT_MAX) {
                err = -EOVERFLOW;
                goto out_unlock;
        }
 
-       if (nf_defrag->users) {
-               nf_defrag->users++;
+       if (net->nf.defrag_ipv4_users) {
+               net->nf.defrag_ipv4_users++;
                goto out_unlock;
        }
 
        err = nf_register_net_hooks(net, ipv4_defrag_ops,
                                    ARRAY_SIZE(ipv4_defrag_ops));
        if (err == 0)
-               nf_defrag->users = 1;
+               net->nf.defrag_ipv4_users = 1;
 
  out_unlock:
        mutex_unlock(&defrag4_mutex);
@@ -165,12 +155,10 @@ EXPORT_SYMBOL_GPL(nf_defrag_ipv4_enable);
 
 void nf_defrag_ipv4_disable(struct net *net)
 {
-       struct defrag4_pernet *nf_defrag = net_generic(net, defrag4_pernet_id);
-
        mutex_lock(&defrag4_mutex);
-       if (nf_defrag->users) {
-               nf_defrag->users--;
-               if (nf_defrag->users == 0)
+       if (net->nf.defrag_ipv4_users) {
+               net->nf.defrag_ipv4_users--;
+               if (net->nf.defrag_ipv4_users == 0)
                        nf_unregister_net_hooks(net, ipv4_defrag_ops,
                                                ARRAY_SIZE(ipv4_defrag_ops));
        }
index a0108415275fe02a643efb307743b503985ae3f2..5c47be29b9ee9832069aa4b9e97852e22dd4278b 100644 (file)
@@ -33,7 +33,7 @@
 
 static const char nf_frags_cache_name[] = "nf-frags";
 
-unsigned int nf_frag_pernet_id __read_mostly;
+static unsigned int nf_frag_pernet_id __read_mostly;
 static struct inet_frags nf_frags;
 
 static struct nft_ct_frag6_pernet *nf_frag_pernet(struct net *net)
index e8a59d8bf2adf705824586f6f60b35b53d2be9e6..cb4eb1d2c620b96f23e516d17835a2aada6f0fa8 100644 (file)
@@ -25,8 +25,6 @@
 #include <net/netfilter/nf_conntrack_zones.h>
 #include <net/netfilter/ipv6/nf_defrag_ipv6.h>
 
-extern unsigned int nf_frag_pernet_id;
-
 static DEFINE_MUTEX(defrag6_mutex);
 
 static enum ip6_defrag_users nf_ct6_defrag_user(unsigned int hooknum,
@@ -91,12 +89,10 @@ static const struct nf_hook_ops ipv6_defrag_ops[] = {
 
 static void __net_exit defrag6_net_exit(struct net *net)
 {
-       struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id);
-
-       if (nf_frag->users) {
+       if (net->nf.defrag_ipv6_users) {
                nf_unregister_net_hooks(net, ipv6_defrag_ops,
                                        ARRAY_SIZE(ipv6_defrag_ops));
-               nf_frag->users = 0;
+               net->nf.defrag_ipv6_users = 0;
        }
 }
 
@@ -134,24 +130,23 @@ static void __exit nf_defrag_fini(void)
 
 int nf_defrag_ipv6_enable(struct net *net)
 {
-       struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id);
        int err = 0;
 
        mutex_lock(&defrag6_mutex);
-       if (nf_frag->users == UINT_MAX) {
+       if (net->nf.defrag_ipv6_users == UINT_MAX) {
                err = -EOVERFLOW;
                goto out_unlock;
        }
 
-       if (nf_frag->users) {
-               nf_frag->users++;
+       if (net->nf.defrag_ipv6_users) {
+               net->nf.defrag_ipv6_users++;
                goto out_unlock;
        }
 
        err = nf_register_net_hooks(net, ipv6_defrag_ops,
                                    ARRAY_SIZE(ipv6_defrag_ops));
        if (err == 0)
-               nf_frag->users = 1;
+               net->nf.defrag_ipv6_users = 1;
 
  out_unlock:
        mutex_unlock(&defrag6_mutex);
@@ -161,12 +156,10 @@ EXPORT_SYMBOL_GPL(nf_defrag_ipv6_enable);
 
 void nf_defrag_ipv6_disable(struct net *net)
 {
-       struct nft_ct_frag6_pernet *nf_frag = net_generic(net, nf_frag_pernet_id);
-
        mutex_lock(&defrag6_mutex);
-       if (nf_frag->users) {
-               nf_frag->users--;
-               if (nf_frag->users == 0)
+       if (net->nf.defrag_ipv6_users) {
+               net->nf.defrag_ipv6_users--;
+               if (net->nf.defrag_ipv6_users == 0)
                        nf_unregister_net_hooks(net, ipv6_defrag_ops,
                                                ARRAY_SIZE(ipv6_defrag_ops));
        }