]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
netfilter: x_tables: close dangling table module init race
authorFlorian Westphal <fw@strlen.de>
Wed, 6 May 2026 10:07:20 +0000 (12:07 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 7 May 2026 23:30:17 +0000 (01:30 +0200)
Similar to the previous ebtables patch:
template add exposes the table to userspace, we must do this last to
rnsure the pernet ops are set up (contain the destructors).

Fixes: fdacd57c79b7 ("netfilter: x_tables: never register tables by default")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/ipv4/netfilter/arptable_filter.c
net/ipv4/netfilter/iptable_filter.c
net/ipv4/netfilter/iptable_mangle.c
net/ipv4/netfilter/iptable_raw.c
net/ipv4/netfilter/iptable_security.c
net/ipv6/netfilter/ip6table_filter.c
net/ipv6/netfilter/ip6table_mangle.c
net/ipv6/netfilter/ip6table_raw.c
net/ipv6/netfilter/ip6table_security.c

index 382345567a600aad00f687a6cce83cc338120ca2..370b635e3523b9f9ddbe0921a055fe38f9a0c681 100644 (file)
@@ -58,25 +58,26 @@ static struct pernet_operations arptable_filter_net_ops = {
 
 static int __init arptable_filter_init(void)
 {
-       int ret = xt_register_template(&packet_filter,
-                                      arptable_filter_table_init);
-
-       if (ret < 0)
-               return ret;
+       int ret;
 
        arpfilter_ops = xt_hook_ops_alloc(&packet_filter, arpt_do_table);
-       if (IS_ERR(arpfilter_ops)) {
-               xt_unregister_template(&packet_filter);
+       if (IS_ERR(arpfilter_ops))
                return PTR_ERR(arpfilter_ops);
-       }
 
        ret = register_pernet_subsys(&arptable_filter_net_ops);
+       if (ret < 0)
+               goto err_free;
+
+       ret = xt_register_template(&packet_filter,
+                                  arptable_filter_table_init);
        if (ret < 0) {
-               xt_unregister_template(&packet_filter);
-               kfree(arpfilter_ops);
-               return ret;
+               unregister_pernet_subsys(&arptable_filter_net_ops);
+               goto err_free;
        }
 
+       return 0;
+err_free:
+       kfree(arpfilter_ops);
        return ret;
 }
 
index 0dea754a91209a83f8522aa06fb7b5d43dafa228..672d7da1071d316f77e871c41847d8425555ce88 100644 (file)
@@ -77,26 +77,27 @@ static struct pernet_operations iptable_filter_net_ops = {
 
 static int __init iptable_filter_init(void)
 {
-       int ret = xt_register_template(&packet_filter,
-                                      iptable_filter_table_init);
-
-       if (ret < 0)
-               return ret;
+       int ret;
 
        filter_ops = xt_hook_ops_alloc(&packet_filter, ipt_do_table);
-       if (IS_ERR(filter_ops)) {
-               xt_unregister_template(&packet_filter);
+       if (IS_ERR(filter_ops))
                return PTR_ERR(filter_ops);
-       }
 
        ret = register_pernet_subsys(&iptable_filter_net_ops);
+       if (ret < 0)
+               goto err_free;
+
+       ret = xt_register_template(&packet_filter,
+                                  iptable_filter_table_init);
        if (ret < 0) {
-               xt_unregister_template(&packet_filter);
-               kfree(filter_ops);
-               return ret;
+               unregister_pernet_subsys(&iptable_filter_net_ops);
+               goto err_free;
        }
 
        return 0;
+err_free:
+       kfree(filter_ops);
+       return ret;
 }
 
 static void __exit iptable_filter_fini(void)
index 4d3b124923080ba4e63d55f1eaa9294cfbb9d067..13d25d9a4610e3f00dfbe892474e21396cf5781a 100644 (file)
@@ -111,25 +111,26 @@ static struct pernet_operations iptable_mangle_net_ops = {
 
 static int __init iptable_mangle_init(void)
 {
-       int ret = xt_register_template(&packet_mangler,
-                                      iptable_mangle_table_init);
-       if (ret < 0)
-               return ret;
+       int ret;
 
        mangle_ops = xt_hook_ops_alloc(&packet_mangler, iptable_mangle_hook);
-       if (IS_ERR(mangle_ops)) {
-               xt_unregister_template(&packet_mangler);
-               ret = PTR_ERR(mangle_ops);
-               return ret;
-       }
+       if (IS_ERR(mangle_ops))
+               return PTR_ERR(mangle_ops);
 
        ret = register_pernet_subsys(&iptable_mangle_net_ops);
+       if (ret < 0)
+               goto err_free;
+
+       ret = xt_register_template(&packet_mangler,
+                                  iptable_mangle_table_init);
        if (ret < 0) {
-               xt_unregister_template(&packet_mangler);
-               kfree(mangle_ops);
-               return ret;
+               unregister_pernet_subsys(&iptable_mangle_net_ops);
+               goto err_free;
        }
 
+       return 0;
+err_free:
+       kfree(mangle_ops);
        return ret;
 }
 
index 6f7afec7954bd4e87ae051a91ca779f41dea78b4..2745c22f4034d8793c8fb1ac674831950baaa77c 100644 (file)
@@ -77,24 +77,24 @@ static int __init iptable_raw_init(void)
                pr_info("Enabling raw table before defrag\n");
        }
 
-       ret = xt_register_template(table,
-                                  iptable_raw_table_init);
-       if (ret < 0)
-               return ret;
-
        rawtable_ops = xt_hook_ops_alloc(table, ipt_do_table);
-       if (IS_ERR(rawtable_ops)) {
-               xt_unregister_template(table);
+       if (IS_ERR(rawtable_ops))
                return PTR_ERR(rawtable_ops);
-       }
 
        ret = register_pernet_subsys(&iptable_raw_net_ops);
+       if (ret < 0)
+               goto err_free;
+
+       ret = xt_register_template(table,
+                                  iptable_raw_table_init);
        if (ret < 0) {
-               xt_unregister_template(table);
-               kfree(rawtable_ops);
-               return ret;
+               unregister_pernet_subsys(&iptable_raw_net_ops);
+               goto err_free;
        }
 
+       return 0;
+err_free:
+       kfree(rawtable_ops);
        return ret;
 }
 
index 81175c20ccbe8dc3087c73e93eacef03ea07d603..491894511c5441330e61de2e71f475fb1c2d93d0 100644 (file)
@@ -65,25 +65,26 @@ static struct pernet_operations iptable_security_net_ops = {
 
 static int __init iptable_security_init(void)
 {
-       int ret = xt_register_template(&security_table,
-                                      iptable_security_table_init);
-
-       if (ret < 0)
-               return ret;
+       int ret;
 
        sectbl_ops = xt_hook_ops_alloc(&security_table, ipt_do_table);
-       if (IS_ERR(sectbl_ops)) {
-               xt_unregister_template(&security_table);
+       if (IS_ERR(sectbl_ops))
                return PTR_ERR(sectbl_ops);
-       }
 
        ret = register_pernet_subsys(&iptable_security_net_ops);
+       if (ret < 0)
+               goto err_free;
+
+       ret = xt_register_template(&security_table,
+                                  iptable_security_table_init);
        if (ret < 0) {
-               xt_unregister_template(&security_table);
-               kfree(sectbl_ops);
-               return ret;
+               unregister_pernet_subsys(&iptable_security_net_ops);
+               goto err_free;
        }
 
+       return 0;
+err_free:
+       kfree(sectbl_ops);
        return ret;
 }
 
index cf561919bde84c285c9a9f6e7dba76f66ed89ca9..b074fc4776764ccfa2556cb56f60d138b19a132d 100644 (file)
@@ -76,25 +76,25 @@ static struct pernet_operations ip6table_filter_net_ops = {
 
 static int __init ip6table_filter_init(void)
 {
-       int ret = xt_register_template(&packet_filter,
-                                       ip6table_filter_table_init);
-
-       if (ret < 0)
-               return ret;
+       int ret;
 
        filter_ops = xt_hook_ops_alloc(&packet_filter, ip6t_do_table);
-       if (IS_ERR(filter_ops)) {
-               xt_unregister_template(&packet_filter);
+       if (IS_ERR(filter_ops))
                return PTR_ERR(filter_ops);
-       }
 
        ret = register_pernet_subsys(&ip6table_filter_net_ops);
+       if (ret < 0)
+               goto err_free;
+
+       ret = xt_register_template(&packet_filter, ip6table_filter_table_init);
        if (ret < 0) {
-               xt_unregister_template(&packet_filter);
-               kfree(filter_ops);
-               return ret;
+               unregister_pernet_subsys(&ip6table_filter_net_ops);
+               goto err_free;
        }
 
+       return 0;
+err_free:
+       kfree(filter_ops);
        return ret;
 }
 
index 1a758f2bc5379c4bed20825ebabcd6538851e7d1..e6ee036a9b2c5891b680f63bd7f1262c6577caee 100644 (file)
@@ -104,25 +104,26 @@ static struct pernet_operations ip6table_mangle_net_ops = {
 
 static int __init ip6table_mangle_init(void)
 {
-       int ret = xt_register_template(&packet_mangler,
-                                      ip6table_mangle_table_init);
-
-       if (ret < 0)
-               return ret;
+       int ret;
 
        mangle_ops = xt_hook_ops_alloc(&packet_mangler, ip6table_mangle_hook);
-       if (IS_ERR(mangle_ops)) {
-               xt_unregister_template(&packet_mangler);
+       if (IS_ERR(mangle_ops))
                return PTR_ERR(mangle_ops);
-       }
 
        ret = register_pernet_subsys(&ip6table_mangle_net_ops);
+       if (ret < 0)
+               goto err_free;
+
+       ret = xt_register_template(&packet_mangler,
+                                  ip6table_mangle_table_init);
        if (ret < 0) {
-               xt_unregister_template(&packet_mangler);
-               kfree(mangle_ops);
-               return ret;
+               unregister_pernet_subsys(&ip6table_mangle_net_ops);
+               goto err_free;
        }
 
+       return 0;
+err_free:
+       kfree(mangle_ops);
        return ret;
 }
 
index 923455921c1ddf2858869ae7a7ef3b02595de4fc..3b161ee875bcc1e52a893e57a003bae4f8040225 100644 (file)
@@ -75,24 +75,24 @@ static int __init ip6table_raw_init(void)
                pr_info("Enabling raw table before defrag\n");
        }
 
-       ret = xt_register_template(table, ip6table_raw_table_init);
-       if (ret < 0)
-               return ret;
-
        /* Register hooks */
        rawtable_ops = xt_hook_ops_alloc(table, ip6t_do_table);
-       if (IS_ERR(rawtable_ops)) {
-               xt_unregister_template(table);
+       if (IS_ERR(rawtable_ops))
                return PTR_ERR(rawtable_ops);
-       }
 
        ret = register_pernet_subsys(&ip6table_raw_net_ops);
+       if (ret < 0)
+               goto err_free;
+
+       ret = xt_register_template(table, ip6table_raw_table_init);
        if (ret < 0) {
-               kfree(rawtable_ops);
-               xt_unregister_template(table);
-               return ret;
+               unregister_pernet_subsys(&ip6table_raw_net_ops);
+               goto err_free;
        }
 
+       return 0;
+err_free:
+       kfree(rawtable_ops);
        return ret;
 }
 
index c44834d93fc792c51b95ad1f62d12ffce686e5fe..4bd5d97b8ab65d54c286cdee55cdf2c5782b1f33 100644 (file)
@@ -64,25 +64,26 @@ static struct pernet_operations ip6table_security_net_ops = {
 
 static int __init ip6table_security_init(void)
 {
-       int ret = xt_register_template(&security_table,
-                                      ip6table_security_table_init);
-
-       if (ret < 0)
-               return ret;
+       int ret;
 
        sectbl_ops = xt_hook_ops_alloc(&security_table, ip6t_do_table);
-       if (IS_ERR(sectbl_ops)) {
-               xt_unregister_template(&security_table);
+       if (IS_ERR(sectbl_ops))
                return PTR_ERR(sectbl_ops);
-       }
 
        ret = register_pernet_subsys(&ip6table_security_net_ops);
+       if (ret < 0)
+               goto err_free;
+
+       ret = xt_register_template(&security_table,
+                                  ip6table_security_table_init);
        if (ret < 0) {
-               kfree(sectbl_ops);
-               xt_unregister_template(&security_table);
-               return ret;
+               unregister_pernet_subsys(&ip6table_security_net_ops);
+               goto err_free;
        }
 
+       return 0;
+err_free:
+       kfree(sectbl_ops);
        return ret;
 }