netfilter: x_tables: close dangling table module init race

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: fdacd57c79 ("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>
This commit is contained in:
Florian Westphal 2026-05-06 12:07:20 +02:00 committed by Pablo Neira Ayuso
parent 92c603fa07
commit 16bc4b6686
9 changed files with 105 additions and 99 deletions

View 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;
}

View 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)

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}