From e105008c7dec13ce8a037141a8506916ef6b1689 Mon Sep 17 00:00:00 2001 From: lean Date: Sun, 2 Jan 2022 21:39:26 +0800 Subject: [PATCH] fw3: add a hack to revert register tables implementation by torvalds in 5.15 --- .../generic/hack-5.15/670-fixup-fw3.patch | 936 ++++++++++++++++++ 1 file changed, 936 insertions(+) create mode 100644 target/linux/generic/hack-5.15/670-fixup-fw3.patch diff --git a/target/linux/generic/hack-5.15/670-fixup-fw3.patch b/target/linux/generic/hack-5.15/670-fixup-fw3.patch new file mode 100644 index 000000000..3ad9498a9 --- /dev/null +++ b/target/linux/generic/hack-5.15/670-fixup-fw3.patch @@ -0,0 +1,936 @@ +From cd8c0fb90885e3733d0502375873a74e35eed2ec Mon Sep 17 00:00:00 2001 +From: Marty Jones +Date: Mon, 29 Nov 2021 13:30:11 -0500 +Subject: [PATCH] fixup fw3 + +Signed-off-by: Marty Jones +--- + include/linux/netfilter/x_tables.h | 6 +- + net/ipv4/netfilter/arptable_filter.c | 23 +++--- + net/ipv4/netfilter/iptable_filter.c | 24 +++---- + net/ipv4/netfilter/iptable_mangle.c | 11 ++- + net/ipv4/netfilter/iptable_nat.c | 20 +++--- + net/ipv4/netfilter/iptable_raw.c | 21 +++--- + net/ipv4/netfilter/iptable_security.c | 23 +++--- + net/ipv6/netfilter/ip6table_filter.c | 23 +++--- + net/ipv6/netfilter/ip6table_mangle.c | 22 +++--- + net/ipv6/netfilter/ip6table_nat.c | 16 ++--- + net/ipv6/netfilter/ip6table_raw.c | 24 ++++--- + net/ipv6/netfilter/ip6table_security.c | 22 +++--- + net/netfilter/x_tables.c | 98 +++++--------------------- + 13 files changed, 129 insertions(+), 204 deletions(-) + +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -238,6 +238,9 @@ struct xt_table { + u_int8_t af; /* address/protocol family */ + int priority; /* hook order */ + ++ /* called when table is needed in the given netns */ ++ int (*table_init)(struct net *net); ++ + /* A unique name... */ + const char name[XT_TABLE_MAXNAMELEN]; + }; +@@ -449,9 +452,6 @@ xt_get_per_cpu_counter(struct xt_counter + + struct nf_hook_ops *xt_hook_ops_alloc(const struct xt_table *, nf_hookfn *); + +-int xt_register_template(const struct xt_table *t, int(*table_init)(struct net *net)); +-void xt_unregister_template(const struct xt_table *t); +- + #ifdef CONFIG_NETFILTER_XTABLES_COMPAT + #include + +--- a/net/ipv4/netfilter/arptable_filter.c ++++ b/net/ipv4/netfilter/arptable_filter.c +@@ -18,12 +18,15 @@ MODULE_DESCRIPTION("arptables filter tab + #define FILTER_VALID_HOOKS ((1 << NF_ARP_IN) | (1 << NF_ARP_OUT) | \ + (1 << NF_ARP_FORWARD)) + ++static int __net_init arptable_filter_table_init(struct net *net); ++ + static const struct xt_table packet_filter = { + .name = "filter", + .valid_hooks = FILTER_VALID_HOOKS, + .me = THIS_MODULE, + .af = NFPROTO_ARP, + .priority = NF_IP_PRI_FILTER, ++ .table_init = arptable_filter_table_init, + }; + + /* The work comes in here from netfilter.c */ +@@ -36,7 +39,7 @@ arptable_filter_hook(void *priv, struct + + static struct nf_hook_ops *arpfilter_ops __read_mostly; + +-static int arptable_filter_table_init(struct net *net) ++static int __net_init arptable_filter_table_init(struct net *net) + { + struct arpt_replace *repl; + int err; +@@ -66,32 +69,30 @@ static struct pernet_operations arptable + + 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, arptable_filter_hook); +- 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) { +- xt_unregister_template(&packet_filter); + kfree(arpfilter_ops); + return ret; + } + ++ ret = arptable_filter_table_init(&init_net); ++ if (ret) { ++ unregister_pernet_subsys(&arptable_filter_net_ops); ++ kfree(arpfilter_ops); ++ } ++ + return ret; + } + + static void __exit arptable_filter_fini(void) + { + unregister_pernet_subsys(&arptable_filter_net_ops); +- xt_unregister_template(&packet_filter); + kfree(arpfilter_ops); + } + +--- a/net/ipv4/netfilter/iptable_filter.c ++++ b/net/ipv4/netfilter/iptable_filter.c +@@ -19,6 +19,7 @@ MODULE_DESCRIPTION("iptables filter tabl + #define FILTER_VALID_HOOKS ((1 << NF_INET_LOCAL_IN) | \ + (1 << NF_INET_FORWARD) | \ + (1 << NF_INET_LOCAL_OUT)) ++static int __net_init iptable_filter_table_init(struct net *net); + + static const struct xt_table packet_filter = { + .name = "filter", +@@ -26,6 +27,7 @@ static const struct xt_table packet_filt + .me = THIS_MODULE, + .af = NFPROTO_IPV4, + .priority = NF_IP_PRI_FILTER, ++ .table_init = iptable_filter_table_init, + }; + + static unsigned int +@@ -41,7 +43,7 @@ static struct nf_hook_ops *filter_ops __ + static bool forward __read_mostly = true; + module_param(forward, bool, 0000); + +-static int iptable_filter_table_init(struct net *net) ++static int __net_init iptable_filter_table_init(struct net *net) + { + struct ipt_replace *repl; + int err; +@@ -60,7 +62,7 @@ static int iptable_filter_table_init(str + + static int __net_init iptable_filter_net_init(struct net *net) + { +- if (!forward) ++ if (net == &init_net || !forward) + return iptable_filter_table_init(net); + + return 0; +@@ -84,32 +86,22 @@ static struct pernet_operations iptable_ + + 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, iptable_filter_hook); +- 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) { +- xt_unregister_template(&packet_filter); ++ if (ret < 0) + kfree(filter_ops); +- return ret; +- } + +- return 0; ++ return ret; + } + + static void __exit iptable_filter_fini(void) + { + unregister_pernet_subsys(&iptable_filter_net_ops); +- xt_unregister_template(&packet_filter); + kfree(filter_ops); + } + +--- a/net/ipv4/netfilter/iptable_mangle.c ++++ b/net/ipv4/netfilter/iptable_mangle.c +@@ -25,12 +25,15 @@ MODULE_DESCRIPTION("iptables mangle tabl + (1 << NF_INET_LOCAL_OUT) | \ + (1 << NF_INET_POST_ROUTING)) + ++static int __net_init iptable_mangle_table_init(struct net *net); ++ + static const struct xt_table packet_mangler = { + .name = "mangle", + .valid_hooks = MANGLE_VALID_HOOKS, + .me = THIS_MODULE, + .af = NFPROTO_IPV4, + .priority = NF_IP_PRI_MANGLE, ++ .table_init = iptable_mangle_table_init + }; + + static unsigned int +@@ -80,7 +83,7 @@ iptable_mangle_hook(void *priv, + } + + static struct nf_hook_ops *mangle_ops __read_mostly; +-static int iptable_mangle_table_init(struct net *net) ++static int __net_init iptable_mangle_table_init(struct net *net) + { + struct ipt_replace *repl; + int ret; +@@ -110,21 +113,18 @@ static struct pernet_operations iptable_ + + static int __init iptable_mangle_init(void) + { +- int ret = xt_register_template(&packet_mangler, +- iptable_mangle_table_init); ++ int ret; + if (ret < 0) + return 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; + } + + ret = register_pernet_subsys(&iptable_mangle_net_ops); + if (ret < 0) { +- xt_unregister_template(&packet_mangler); + kfree(mangle_ops); + return ret; + } +@@ -135,7 +135,6 @@ static int __init iptable_mangle_init(vo + static void __exit iptable_mangle_fini(void) + { + unregister_pernet_subsys(&iptable_mangle_net_ops); +- xt_unregister_template(&packet_mangler); + kfree(mangle_ops); + } + +--- a/net/ipv4/netfilter/iptable_nat.c ++++ b/net/ipv4/netfilter/iptable_nat.c +@@ -17,6 +17,8 @@ struct iptable_nat_pernet { + struct nf_hook_ops *nf_nat_ops; + }; + ++static int __net_init iptable_nat_table_init(struct net *net); ++ + static unsigned int iptable_nat_net_id __read_mostly; + + static const struct xt_table nf_nat_ipv4_table = { +@@ -27,6 +29,7 @@ static const struct xt_table nf_nat_ipv4 + (1 << NF_INET_LOCAL_IN), + .me = THIS_MODULE, + .af = NFPROTO_IPV4, ++ .table_init = iptable_nat_table_init, + }; + + static unsigned int iptable_nat_do_chain(void *priv, +@@ -110,7 +113,7 @@ static void ipt_nat_unregister_lookups(s + kfree(ops); + } + +-static int iptable_nat_table_init(struct net *net) ++static int __net_init iptable_nat_table_init(struct net *net) + { + struct ipt_replace *repl; + int ret; +@@ -152,25 +155,20 @@ static struct pernet_operations iptable_ + + static int __init iptable_nat_init(void) + { +- int ret = xt_register_template(&nf_nat_ipv4_table, +- iptable_nat_table_init); +- +- if (ret < 0) +- return ret; ++ int ret = register_pernet_subsys(&iptable_nat_net_ops); + +- ret = register_pernet_subsys(&iptable_nat_net_ops); +- if (ret < 0) { +- xt_unregister_template(&nf_nat_ipv4_table); ++ if (ret) + return ret; +- } + ++ ret = iptable_nat_table_init(&init_net); ++ if (ret) ++ unregister_pernet_subsys(&iptable_nat_net_ops); + return ret; + } + + static void __exit iptable_nat_exit(void) + { + unregister_pernet_subsys(&iptable_nat_net_ops); +- xt_unregister_template(&nf_nat_ipv4_table); + } + + module_init(iptable_nat_init); +--- a/net/ipv4/netfilter/iptable_raw.c ++++ b/net/ipv4/netfilter/iptable_raw.c +@@ -12,6 +12,8 @@ + + #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT)) + ++static int __net_init iptable_raw_table_init(struct net *net); ++ + static bool raw_before_defrag __read_mostly; + MODULE_PARM_DESC(raw_before_defrag, "Enable raw table before defrag"); + module_param(raw_before_defrag, bool, 0000); +@@ -22,6 +24,7 @@ static const struct xt_table packet_raw + .me = THIS_MODULE, + .af = NFPROTO_IPV4, + .priority = NF_IP_PRI_RAW, ++ .table_init = iptable_raw_table_init, + }; + + static const struct xt_table packet_raw_before_defrag = { +@@ -30,6 +33,7 @@ static const struct xt_table packet_raw_ + .me = THIS_MODULE, + .af = NFPROTO_IPV4, + .priority = NF_IP_PRI_RAW_BEFORE_DEFRAG, ++ .table_init = iptable_raw_table_init, + }; + + /* The work comes in here from netfilter.c. */ +@@ -85,24 +89,22 @@ 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, iptable_raw_hook); +- 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) { +- xt_unregister_template(table); + kfree(rawtable_ops); + return ret; + } + ++ ret = iptable_raw_table_init(&init_net); ++ if (ret) { ++ unregister_pernet_subsys(&iptable_raw_net_ops); ++ kfree(rawtable_ops); ++ } ++ + return ret; + } + +@@ -110,7 +112,6 @@ static void __exit iptable_raw_fini(void + { + unregister_pernet_subsys(&iptable_raw_net_ops); + kfree(rawtable_ops); +- xt_unregister_template(&packet_raw); + } + + module_init(iptable_raw_init); +--- a/net/ipv4/netfilter/iptable_security.c ++++ b/net/ipv4/netfilter/iptable_security.c +@@ -25,12 +25,15 @@ MODULE_DESCRIPTION("iptables security ta + (1 << NF_INET_FORWARD) | \ + (1 << NF_INET_LOCAL_OUT) + ++static int __net_init iptable_security_table_init(struct net *net); ++ + static const struct xt_table security_table = { + .name = "security", + .valid_hooks = SECURITY_VALID_HOOKS, + .me = THIS_MODULE, + .af = NFPROTO_IPV4, + .priority = NF_IP_PRI_SECURITY, ++ .table_init = iptable_security_table_init, + }; + + static unsigned int +@@ -42,7 +45,7 @@ iptable_security_hook(void *priv, struct + + static struct nf_hook_ops *sectbl_ops __read_mostly; + +-static int iptable_security_table_init(struct net *net) ++static int __net_init iptable_security_table_init(struct net *net) + { + struct ipt_replace *repl; + int ret; +@@ -72,25 +75,24 @@ static struct pernet_operations iptable_ + + 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, iptable_security_hook); +- 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) { +- xt_unregister_template(&security_table); + kfree(sectbl_ops); + return ret; + } + ++ ret = iptable_security_table_init(&init_net); ++ if (ret) { ++ unregister_pernet_subsys(&iptable_security_net_ops); ++ kfree(sectbl_ops); ++ } ++ + return ret; + } + +@@ -98,7 +100,6 @@ static void __exit iptable_security_fini + { + unregister_pernet_subsys(&iptable_security_net_ops); + kfree(sectbl_ops); +- xt_unregister_template(&security_table); + } + + module_init(iptable_security_init); +--- a/net/ipv6/netfilter/ip6table_filter.c ++++ b/net/ipv6/netfilter/ip6table_filter.c +@@ -19,12 +19,15 @@ MODULE_DESCRIPTION("ip6tables filter tab + (1 << NF_INET_FORWARD) | \ + (1 << NF_INET_LOCAL_OUT)) + ++static int __net_init ip6table_filter_table_init(struct net *net); ++ + static const struct xt_table packet_filter = { + .name = "filter", + .valid_hooks = FILTER_VALID_HOOKS, + .me = THIS_MODULE, + .af = NFPROTO_IPV6, + .priority = NF_IP6_PRI_FILTER, ++ .table_init = ip6table_filter_table_init, + }; + + /* The work comes in here from netfilter.c. */ +@@ -41,7 +44,7 @@ static struct nf_hook_ops *filter_ops __ + static bool forward = true; + module_param(forward, bool, 0000); + +-static int ip6table_filter_table_init(struct net *net) ++static int __net_init ip6table_filter_table_init(struct net *net) + { + struct ip6t_replace *repl; + int err; +@@ -60,7 +63,7 @@ static int ip6table_filter_table_init(st + + static int __net_init ip6table_filter_net_init(struct net *net) + { +- if (!forward) ++ if (net == &init_net || !forward) + return ip6table_filter_table_init(net); + + return 0; +@@ -84,24 +87,15 @@ static struct pernet_operations ip6table + + 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, ip6table_filter_hook); +- 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) { +- xt_unregister_template(&packet_filter); ++ if (ret < 0) + kfree(filter_ops); +- return ret; +- } + + return ret; + } +@@ -109,7 +103,6 @@ static int __init ip6table_filter_init(v + static void __exit ip6table_filter_fini(void) + { + unregister_pernet_subsys(&ip6table_filter_net_ops); +- xt_unregister_template(&packet_filter); + kfree(filter_ops); + } + +--- a/net/ipv6/netfilter/ip6table_mangle.c ++++ b/net/ipv6/netfilter/ip6table_mangle.c +@@ -20,12 +20,15 @@ MODULE_DESCRIPTION("ip6tables mangle tab + (1 << NF_INET_LOCAL_OUT) | \ + (1 << NF_INET_POST_ROUTING)) + ++static int __net_init ip6table_mangle_table_init(struct net *net); ++ + static const struct xt_table packet_mangler = { + .name = "mangle", + .valid_hooks = MANGLE_VALID_HOOKS, + .me = THIS_MODULE, + .af = NFPROTO_IPV6, + .priority = NF_IP6_PRI_MANGLE, ++ .table_init = ip6table_mangle_table_init, + }; + + static unsigned int +@@ -73,7 +76,7 @@ ip6table_mangle_hook(void *priv, struct + } + + static struct nf_hook_ops *mangle_ops __read_mostly; +-static int ip6table_mangle_table_init(struct net *net) ++static int __net_init ip6table_mangle_table_init(struct net *net) + { + struct ip6t_replace *repl; + int ret; +@@ -103,32 +106,29 @@ static struct pernet_operations ip6table + + 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) { +- xt_unregister_template(&packet_mangler); + kfree(mangle_ops); + return ret; + } + ++ ret = ip6table_mangle_table_init(&init_net); ++ if (ret) { ++ unregister_pernet_subsys(&ip6table_mangle_net_ops); ++ kfree(mangle_ops); ++ } + return ret; + } + + static void __exit ip6table_mangle_fini(void) + { + unregister_pernet_subsys(&ip6table_mangle_net_ops); +- xt_unregister_template(&packet_mangler); + kfree(mangle_ops); + } + +--- a/net/ipv6/netfilter/ip6table_nat.c ++++ b/net/ipv6/netfilter/ip6table_nat.c +@@ -19,6 +19,8 @@ struct ip6table_nat_pernet { + struct nf_hook_ops *nf_nat_ops; + }; + ++static int __net_init ip6table_nat_table_init(struct net *net); ++ + static unsigned int ip6table_nat_net_id __read_mostly; + + static const struct xt_table nf_nat_ipv6_table = { +@@ -29,6 +31,7 @@ static const struct xt_table nf_nat_ipv6 + (1 << NF_INET_LOCAL_IN), + .me = THIS_MODULE, + .af = NFPROTO_IPV6, ++ .table_init = ip6table_nat_table_init, + }; + + static unsigned int ip6table_nat_do_chain(void *priv, +@@ -112,7 +115,7 @@ static void ip6t_nat_unregister_lookups( + kfree(ops); + } + +-static int ip6table_nat_table_init(struct net *net) ++static int __net_init ip6table_nat_table_init(struct net *net) + { + struct ip6t_replace *repl; + int ret; +@@ -154,23 +157,20 @@ static struct pernet_operations ip6table + + static int __init ip6table_nat_init(void) + { +- int ret = xt_register_template(&nf_nat_ipv6_table, +- ip6table_nat_table_init); ++ int ret = register_pernet_subsys(&ip6table_nat_net_ops); + +- if (ret < 0) ++ if (ret) + return ret; + +- ret = register_pernet_subsys(&ip6table_nat_net_ops); ++ ret = ip6table_nat_table_init(&init_net); + if (ret) +- xt_unregister_template(&nf_nat_ipv6_table); +- ++ unregister_pernet_subsys(&ip6table_nat_net_ops); + return ret; + } + + static void __exit ip6table_nat_exit(void) + { + unregister_pernet_subsys(&ip6table_nat_net_ops); +- xt_unregister_template(&nf_nat_ipv6_table); + } + + module_init(ip6table_nat_init); +--- a/net/ipv6/netfilter/ip6table_raw.c ++++ b/net/ipv6/netfilter/ip6table_raw.c +@@ -11,6 +11,8 @@ + + #define RAW_VALID_HOOKS ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_OUT)) + ++static int __net_init ip6table_raw_table_init(struct net *net); ++ + static bool raw_before_defrag __read_mostly; + MODULE_PARM_DESC(raw_before_defrag, "Enable raw table before defrag"); + module_param(raw_before_defrag, bool, 0000); +@@ -21,6 +23,7 @@ static const struct xt_table packet_raw + .me = THIS_MODULE, + .af = NFPROTO_IPV6, + .priority = NF_IP6_PRI_RAW, ++ .table_init = ip6table_raw_table_init, + }; + + static const struct xt_table packet_raw_before_defrag = { +@@ -29,6 +32,7 @@ static const struct xt_table packet_raw_ + .me = THIS_MODULE, + .af = NFPROTO_IPV6, + .priority = NF_IP6_PRI_RAW_BEFORE_DEFRAG, ++ .table_init = ip6table_raw_table_init, + }; + + /* The work comes in here from netfilter.c. */ +@@ -41,7 +45,7 @@ ip6table_raw_hook(void *priv, struct sk_ + + static struct nf_hook_ops *rawtable_ops __read_mostly; + +-static int ip6table_raw_table_init(struct net *net) ++static int __net_init ip6table_raw_table_init(struct net *net) + { + struct ip6t_replace *repl; + const struct xt_table *table = &packet_raw; +@@ -75,39 +79,37 @@ static struct pernet_operations ip6table + + static int __init ip6table_raw_init(void) + { +- const struct xt_table *table = &packet_raw; + int ret; ++ const struct xt_table *table = &packet_raw; + + if (raw_before_defrag) { + table = &packet_raw_before_defrag; ++ + 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, ip6table_raw_hook); +- 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) { + kfree(rawtable_ops); +- xt_unregister_template(table); + return ret; + } + ++ ret = ip6table_raw_table_init(&init_net); ++ if (ret) { ++ unregister_pernet_subsys(&ip6table_raw_net_ops); ++ kfree(rawtable_ops); ++ } + return ret; + } + + static void __exit ip6table_raw_fini(void) + { + unregister_pernet_subsys(&ip6table_raw_net_ops); +- xt_unregister_template(&packet_raw); + kfree(rawtable_ops); + } + +--- a/net/ipv6/netfilter/ip6table_security.c ++++ b/net/ipv6/netfilter/ip6table_security.c +@@ -24,12 +24,15 @@ MODULE_DESCRIPTION("ip6tables security t + (1 << NF_INET_FORWARD) | \ + (1 << NF_INET_LOCAL_OUT) + ++static int __net_init ip6table_security_table_init(struct net *net); ++ + static const struct xt_table security_table = { + .name = "security", + .valid_hooks = SECURITY_VALID_HOOKS, + .me = THIS_MODULE, + .af = NFPROTO_IPV6, + .priority = NF_IP6_PRI_SECURITY, ++ .table_init = ip6table_security_table_init, + }; + + static unsigned int +@@ -41,7 +44,7 @@ ip6table_security_hook(void *priv, struc + + static struct nf_hook_ops *sectbl_ops __read_mostly; + +-static int ip6table_security_table_init(struct net *net) ++static int __net_init ip6table_security_table_init(struct net *net) + { + struct ip6t_replace *repl; + int ret; +@@ -71,32 +74,29 @@ static struct pernet_operations ip6table + + 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, ip6table_security_hook); +- 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) { + kfree(sectbl_ops); +- xt_unregister_template(&security_table); + return ret; + } + ++ ret = ip6table_security_table_init(&init_net); ++ if (ret) { ++ unregister_pernet_subsys(&ip6table_security_net_ops); ++ kfree(sectbl_ops); ++ } + return ret; + } + + static void __exit ip6table_security_fini(void) + { + unregister_pernet_subsys(&ip6table_security_net_ops); +- xt_unregister_template(&security_table); + kfree(sectbl_ops); + } + +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -39,20 +39,6 @@ MODULE_DESCRIPTION("{ip,ip6,arp,eb}_tabl + #define XT_PCPU_BLOCK_SIZE 4096 + #define XT_MAX_TABLE_SIZE (512 * 1024 * 1024) + +-struct xt_template { +- struct list_head list; +- +- /* called when table is needed in the given netns */ +- int (*table_init)(struct net *net); +- +- struct module *me; +- +- /* A unique name... */ +- char name[XT_TABLE_MAXNAMELEN]; +-}; +- +-static struct list_head xt_templates[NFPROTO_NUMPROTO]; +- + struct xt_pernet { + struct list_head tables[NFPROTO_NUMPROTO]; + }; +@@ -1235,43 +1221,48 @@ struct xt_table *xt_find_table_lock(stru + const char *name) + { + struct xt_pernet *xt_net = net_generic(net, xt_pernet_id); +- struct module *owner = NULL; +- struct xt_template *tmpl; +- struct xt_table *t; ++ struct xt_table *t, *found = NULL; + + mutex_lock(&xt[af].mutex); + list_for_each_entry(t, &xt_net->tables[af], list) + if (strcmp(t->name, name) == 0 && try_module_get(t->me)) + return t; + +- /* Table doesn't exist in this netns, check larval list */ +- list_for_each_entry(tmpl, &xt_templates[af], list) { ++ if (net == &init_net) ++ goto out; ++ ++ /* Table doesn't exist in this netns, re-try init */ ++ xt_net = net_generic(&init_net, xt_pernet_id); ++ list_for_each_entry(t, &xt_net->tables[af], list) { + int err; + +- if (strcmp(tmpl->name, name)) ++ if (strcmp(t->name, name)) + continue; +- if (!try_module_get(tmpl->me)) ++ if (!try_module_get(t->me)) + goto out; +- +- owner = tmpl->me; +- + mutex_unlock(&xt[af].mutex); +- err = tmpl->table_init(net); ++ err = t->table_init(net); + if (err < 0) { +- module_put(owner); ++ module_put(t->me); + return ERR_PTR(err); + } + ++ found = t; ++ + mutex_lock(&xt[af].mutex); + break; + } + ++ if (!found) ++ goto out; ++ ++ xt_net = net_generic(net, xt_pernet_id); + /* and once again: */ + list_for_each_entry(t, &xt_net->tables[af], list) + if (strcmp(t->name, name) == 0) + return t; + +- module_put(owner); ++ module_put(found->me); + out: + mutex_unlock(&xt[af].mutex); + return ERR_PTR(-ENOENT); +@@ -1758,58 +1749,6 @@ xt_hook_ops_alloc(const struct xt_table + } + EXPORT_SYMBOL_GPL(xt_hook_ops_alloc); + +-int xt_register_template(const struct xt_table *table, +- int (*table_init)(struct net *net)) +-{ +- int ret = -EEXIST, af = table->af; +- struct xt_template *t; +- +- mutex_lock(&xt[af].mutex); +- +- list_for_each_entry(t, &xt_templates[af], list) { +- if (WARN_ON_ONCE(strcmp(table->name, t->name) == 0)) +- goto out_unlock; +- } +- +- ret = -ENOMEM; +- t = kzalloc(sizeof(*t), GFP_KERNEL); +- if (!t) +- goto out_unlock; +- +- BUILD_BUG_ON(sizeof(t->name) != sizeof(table->name)); +- +- strscpy(t->name, table->name, sizeof(t->name)); +- t->table_init = table_init; +- t->me = table->me; +- list_add(&t->list, &xt_templates[af]); +- ret = 0; +-out_unlock: +- mutex_unlock(&xt[af].mutex); +- return ret; +-} +-EXPORT_SYMBOL_GPL(xt_register_template); +- +-void xt_unregister_template(const struct xt_table *table) +-{ +- struct xt_template *t; +- int af = table->af; +- +- mutex_lock(&xt[af].mutex); +- list_for_each_entry(t, &xt_templates[af], list) { +- if (strcmp(table->name, t->name)) +- continue; +- +- list_del(&t->list); +- mutex_unlock(&xt[af].mutex); +- kfree(t); +- return; +- } +- +- mutex_unlock(&xt[af].mutex); +- WARN_ON_ONCE(1); +-} +-EXPORT_SYMBOL_GPL(xt_unregister_template); +- + int xt_proto_init(struct net *net, u_int8_t af) + { + #ifdef CONFIG_PROC_FS +@@ -1998,7 +1937,6 @@ static int __init xt_init(void) + #endif + INIT_LIST_HEAD(&xt[i].target); + INIT_LIST_HEAD(&xt[i].match); +- INIT_LIST_HEAD(&xt_templates[i]); + } + rv = register_pernet_subsys(&xt_net_ops); + if (rv < 0)