remarkable-linux/net/netfilter/nf_tables_inet.c
Pablo Neira Ayuso df05ef874b netfilter: nf_tables: release objects on netns destruction
We have to release the existing objects on netns removal otherwise we
leak them. Chains are unregistered in first place to make sure no
packets are walking on our rules and sets anymore.

The object release happens by when we unregister the family via
nft_release_afinfo() which is called from nft_unregister_afinfo() from
the corresponding __net_exit path in every family.

Reported-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
2015-12-28 18:34:35 +01:00

105 lines
2.4 KiB
C

/*
* Copyright (c) 2012-2014 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ip.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <net/netfilter/nf_tables.h>
#include <net/netfilter/nf_tables_ipv4.h>
#include <net/netfilter/nf_tables_ipv6.h>
#include <net/ip.h>
static void nft_inet_hook_ops_init(struct nf_hook_ops *ops, unsigned int n)
{
struct nft_af_info *afi;
if (n == 1)
afi = &nft_af_ipv4;
else
afi = &nft_af_ipv6;
ops->pf = afi->family;
if (afi->hooks[ops->hooknum])
ops->hook = afi->hooks[ops->hooknum];
}
static struct nft_af_info nft_af_inet __read_mostly = {
.family = NFPROTO_INET,
.nhooks = NF_INET_NUMHOOKS,
.owner = THIS_MODULE,
.nops = 2,
.hook_ops_init = nft_inet_hook_ops_init,
};
static int __net_init nf_tables_inet_init_net(struct net *net)
{
net->nft.inet = kmalloc(sizeof(struct nft_af_info), GFP_KERNEL);
if (net->nft.inet == NULL)
return -ENOMEM;
memcpy(net->nft.inet, &nft_af_inet, sizeof(nft_af_inet));
if (nft_register_afinfo(net, net->nft.inet) < 0)
goto err;
return 0;
err:
kfree(net->nft.inet);
return -ENOMEM;
}
static void __net_exit nf_tables_inet_exit_net(struct net *net)
{
nft_unregister_afinfo(net, net->nft.inet);
kfree(net->nft.inet);
}
static struct pernet_operations nf_tables_inet_net_ops = {
.init = nf_tables_inet_init_net,
.exit = nf_tables_inet_exit_net,
};
static const struct nf_chain_type filter_inet = {
.name = "filter",
.type = NFT_CHAIN_T_DEFAULT,
.family = NFPROTO_INET,
.owner = THIS_MODULE,
.hook_mask = (1 << NF_INET_LOCAL_IN) |
(1 << NF_INET_LOCAL_OUT) |
(1 << NF_INET_FORWARD) |
(1 << NF_INET_PRE_ROUTING) |
(1 << NF_INET_POST_ROUTING),
};
static int __init nf_tables_inet_init(void)
{
int ret;
nft_register_chain_type(&filter_inet);
ret = register_pernet_subsys(&nf_tables_inet_net_ops);
if (ret < 0)
nft_unregister_chain_type(&filter_inet);
return ret;
}
static void __exit nf_tables_inet_exit(void)
{
unregister_pernet_subsys(&nf_tables_inet_net_ops);
nft_unregister_chain_type(&filter_inet);
}
module_init(nf_tables_inet_init);
module_exit(nf_tables_inet_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_ALIAS_NFT_FAMILY(1);