Commit ee177a54 authored by Florian Westphal's avatar Florian Westphal Committed by Pablo Neira Ayuso

netfilter: ip6_tables: pass table pointer via nf_hook_ops

Same patch as the ip_tables one: removal of all accesses to ip6_tables
xt_table pointers.  After this patch the struct net xt_table anchors
can be removed.
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent f9006acc
...@@ -26,9 +26,8 @@ extern void *ip6t_alloc_initial_table(const struct xt_table *); ...@@ -26,9 +26,8 @@ extern void *ip6t_alloc_initial_table(const struct xt_table *);
int ip6t_register_table(struct net *net, const struct xt_table *table, int ip6t_register_table(struct net *net, const struct xt_table *table,
const struct ip6t_replace *repl, const struct ip6t_replace *repl,
const struct nf_hook_ops *ops, struct xt_table **res); const struct nf_hook_ops *ops);
void ip6t_unregister_table_pre_exit(struct net *net, const char *name, void ip6t_unregister_table_pre_exit(struct net *net, const char *name);
const struct nf_hook_ops *ops);
void ip6t_unregister_table_exit(struct net *net, const char *name); void ip6t_unregister_table_exit(struct net *net, const char *name);
extern unsigned int ip6t_do_table(struct sk_buff *skb, extern unsigned int ip6t_do_table(struct sk_buff *skb,
const struct nf_hook_state *state, const struct nf_hook_state *state,
......
...@@ -1725,10 +1725,11 @@ static void __ip6t_unregister_table(struct net *net, struct xt_table *table) ...@@ -1725,10 +1725,11 @@ static void __ip6t_unregister_table(struct net *net, struct xt_table *table)
int ip6t_register_table(struct net *net, const struct xt_table *table, int ip6t_register_table(struct net *net, const struct xt_table *table,
const struct ip6t_replace *repl, const struct ip6t_replace *repl,
const struct nf_hook_ops *ops, const struct nf_hook_ops *template_ops)
struct xt_table **res)
{ {
int ret; struct nf_hook_ops *ops;
unsigned int num_ops;
int ret, i;
struct xt_table_info *newinfo; struct xt_table_info *newinfo;
struct xt_table_info bootstrap = {0}; struct xt_table_info bootstrap = {0};
void *loc_cpu_entry; void *loc_cpu_entry;
...@@ -1742,40 +1743,54 @@ int ip6t_register_table(struct net *net, const struct xt_table *table, ...@@ -1742,40 +1743,54 @@ int ip6t_register_table(struct net *net, const struct xt_table *table,
memcpy(loc_cpu_entry, repl->entries, repl->size); memcpy(loc_cpu_entry, repl->entries, repl->size);
ret = translate_table(net, newinfo, loc_cpu_entry, repl); ret = translate_table(net, newinfo, loc_cpu_entry, repl);
if (ret != 0) if (ret != 0) {
goto out_free; xt_free_table_info(newinfo);
return ret;
}
new_table = xt_register_table(net, table, &bootstrap, newinfo); new_table = xt_register_table(net, table, &bootstrap, newinfo);
if (IS_ERR(new_table)) { if (IS_ERR(new_table)) {
ret = PTR_ERR(new_table); xt_free_table_info(newinfo);
goto out_free; return PTR_ERR(new_table);
} }
/* set res now, will see skbs right after nf_register_net_hooks */ if (!template_ops)
WRITE_ONCE(*res, new_table);
if (!ops)
return 0; return 0;
ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks)); num_ops = hweight32(table->valid_hooks);
if (ret != 0) { if (num_ops == 0) {
__ip6t_unregister_table(net, new_table); ret = -EINVAL;
*res = NULL; goto out_free;
} }
ops = kmemdup(template_ops, sizeof(*ops) * num_ops, GFP_KERNEL);
if (!ops) {
ret = -ENOMEM;
goto out_free;
}
for (i = 0; i < num_ops; i++)
ops[i].priv = new_table;
new_table->ops = ops;
ret = nf_register_net_hooks(net, ops, num_ops);
if (ret != 0)
goto out_free;
return ret; return ret;
out_free: out_free:
xt_free_table_info(newinfo); __ip6t_unregister_table(net, new_table);
return ret; return ret;
} }
void ip6t_unregister_table_pre_exit(struct net *net, const char *name, void ip6t_unregister_table_pre_exit(struct net *net, const char *name)
const struct nf_hook_ops *ops)
{ {
struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name); struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name);
if (table) if (table)
nf_unregister_net_hooks(net, ops, hweight32(table->valid_hooks)); nf_unregister_net_hooks(net, table->ops, hweight32(table->valid_hooks));
} }
void ip6t_unregister_table_exit(struct net *net, const char *name) void ip6t_unregister_table_exit(struct net *net, const char *name)
......
...@@ -35,7 +35,7 @@ static unsigned int ...@@ -35,7 +35,7 @@ static unsigned int
ip6table_filter_hook(void *priv, struct sk_buff *skb, ip6table_filter_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_filter); return ip6t_do_table(skb, state, priv);
} }
static struct nf_hook_ops *filter_ops __read_mostly; static struct nf_hook_ops *filter_ops __read_mostly;
...@@ -56,8 +56,7 @@ static int __net_init ip6table_filter_table_init(struct net *net) ...@@ -56,8 +56,7 @@ static int __net_init ip6table_filter_table_init(struct net *net)
((struct ip6t_standard *)repl->entries)[1].target.verdict = ((struct ip6t_standard *)repl->entries)[1].target.verdict =
forward ? -NF_ACCEPT - 1 : -NF_DROP - 1; forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;
err = ip6t_register_table(net, &packet_filter, repl, filter_ops, err = ip6t_register_table(net, &packet_filter, repl, filter_ops);
&net->ipv6.ip6table_filter);
kfree(repl); kfree(repl);
return err; return err;
} }
...@@ -72,14 +71,12 @@ static int __net_init ip6table_filter_net_init(struct net *net) ...@@ -72,14 +71,12 @@ static int __net_init ip6table_filter_net_init(struct net *net)
static void __net_exit ip6table_filter_net_pre_exit(struct net *net) static void __net_exit ip6table_filter_net_pre_exit(struct net *net)
{ {
ip6t_unregister_table_pre_exit(net, "filter", ip6t_unregister_table_pre_exit(net, "filter");
filter_ops);
} }
static void __net_exit ip6table_filter_net_exit(struct net *net) static void __net_exit ip6table_filter_net_exit(struct net *net)
{ {
ip6t_unregister_table_exit(net, "filter"); ip6t_unregister_table_exit(net, "filter");
net->ipv6.ip6table_filter = NULL;
} }
static struct pernet_operations ip6table_filter_net_ops = { static struct pernet_operations ip6table_filter_net_ops = {
......
...@@ -32,7 +32,7 @@ static const struct xt_table packet_mangler = { ...@@ -32,7 +32,7 @@ static const struct xt_table packet_mangler = {
}; };
static unsigned int static unsigned int
ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state, void *priv)
{ {
unsigned int ret; unsigned int ret;
struct in6_addr saddr, daddr; struct in6_addr saddr, daddr;
...@@ -49,7 +49,7 @@ ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state) ...@@ -49,7 +49,7 @@ ip6t_mangle_out(struct sk_buff *skb, const struct nf_hook_state *state)
/* flowlabel and prio (includes version, which shouldn't change either */ /* flowlabel and prio (includes version, which shouldn't change either */
flowlabel = *((u_int32_t *)ipv6_hdr(skb)); flowlabel = *((u_int32_t *)ipv6_hdr(skb));
ret = ip6t_do_table(skb, state, state->net->ipv6.ip6table_mangle); ret = ip6t_do_table(skb, state, priv);
if (ret != NF_DROP && ret != NF_STOLEN && if (ret != NF_DROP && ret != NF_STOLEN &&
(!ipv6_addr_equal(&ipv6_hdr(skb)->saddr, &saddr) || (!ipv6_addr_equal(&ipv6_hdr(skb)->saddr, &saddr) ||
...@@ -71,8 +71,8 @@ ip6table_mangle_hook(void *priv, struct sk_buff *skb, ...@@ -71,8 +71,8 @@ ip6table_mangle_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
if (state->hook == NF_INET_LOCAL_OUT) if (state->hook == NF_INET_LOCAL_OUT)
return ip6t_mangle_out(skb, state); return ip6t_mangle_out(skb, state, priv);
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_mangle); return ip6t_do_table(skb, state, priv);
} }
static struct nf_hook_ops *mangle_ops __read_mostly; static struct nf_hook_ops *mangle_ops __read_mostly;
...@@ -84,21 +84,19 @@ static int __net_init ip6table_mangle_table_init(struct net *net) ...@@ -84,21 +84,19 @@ static int __net_init ip6table_mangle_table_init(struct net *net)
repl = ip6t_alloc_initial_table(&packet_mangler); repl = ip6t_alloc_initial_table(&packet_mangler);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops, ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops);
&net->ipv6.ip6table_mangle);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit ip6table_mangle_net_pre_exit(struct net *net) static void __net_exit ip6table_mangle_net_pre_exit(struct net *net)
{ {
ip6t_unregister_table_pre_exit(net, "mangle", mangle_ops); ip6t_unregister_table_pre_exit(net, "mangle");
} }
static void __net_exit ip6table_mangle_net_exit(struct net *net) static void __net_exit ip6table_mangle_net_exit(struct net *net)
{ {
ip6t_unregister_table_exit(net, "mangle"); ip6t_unregister_table_exit(net, "mangle");
net->ipv6.ip6table_mangle = NULL;
} }
static struct pernet_operations ip6table_mangle_net_ops = { static struct pernet_operations ip6table_mangle_net_ops = {
......
...@@ -68,12 +68,19 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = { ...@@ -68,12 +68,19 @@ static const struct nf_hook_ops nf_nat_ipv6_ops[] = {
}, },
}; };
static int ip6t_nat_register_lookups(struct net *net, struct xt_table *table) static int ip6t_nat_register_lookups(struct net *net)
{ {
struct nf_hook_ops *ops = kmemdup(nf_nat_ipv6_ops, sizeof(nf_nat_ipv6_ops), GFP_KERNEL); struct ip6table_nat_pernet *xt_nat_net;
struct ip6table_nat_pernet *xt_nat_net = net_generic(net, ip6table_nat_net_id); struct nf_hook_ops *ops;
struct xt_table *table;
int i, ret; int i, ret;
table = xt_find_table(net, NFPROTO_IPV6, "nat");
if (WARN_ON_ONCE(!table))
return -ENOENT;
xt_nat_net = net_generic(net, ip6table_nat_net_id);
ops = kmemdup(nf_nat_ipv6_ops, sizeof(nf_nat_ipv6_ops), GFP_KERNEL);
if (!ops) if (!ops)
return -ENOMEM; return -ENOMEM;
...@@ -111,25 +118,21 @@ static void ip6t_nat_unregister_lookups(struct net *net) ...@@ -111,25 +118,21 @@ static void ip6t_nat_unregister_lookups(struct net *net)
static int __net_init ip6table_nat_table_init(struct net *net) static int __net_init ip6table_nat_table_init(struct net *net)
{ {
struct ip6t_replace *repl; struct ip6t_replace *repl;
struct xt_table *table;
int ret; int ret;
repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table); repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl, ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl,
NULL, &table); NULL);
if (ret < 0) { if (ret < 0) {
kfree(repl); kfree(repl);
return ret; return ret;
} }
ret = ip6t_nat_register_lookups(net, table); ret = ip6t_nat_register_lookups(net);
if (ret < 0) { if (ret < 0)
ip6t_unregister_table_exit(net, "nat"); ip6t_unregister_table_exit(net, "nat");
} else {
net->ipv6.ip6table_nat = table;
}
kfree(repl); kfree(repl);
return ret; return ret;
...@@ -143,7 +146,6 @@ static void __net_exit ip6table_nat_net_pre_exit(struct net *net) ...@@ -143,7 +146,6 @@ static void __net_exit ip6table_nat_net_pre_exit(struct net *net)
static void __net_exit ip6table_nat_net_exit(struct net *net) static void __net_exit ip6table_nat_net_exit(struct net *net)
{ {
ip6t_unregister_table_exit(net, "nat"); ip6t_unregister_table_exit(net, "nat");
net->ipv6.ip6table_nat = NULL;
} }
static struct pernet_operations ip6table_nat_net_ops = { static struct pernet_operations ip6table_nat_net_ops = {
......
...@@ -40,7 +40,7 @@ static unsigned int ...@@ -40,7 +40,7 @@ static unsigned int
ip6table_raw_hook(void *priv, struct sk_buff *skb, ip6table_raw_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_raw); return ip6t_do_table(skb, state, priv);
} }
static struct nf_hook_ops *rawtable_ops __read_mostly; static struct nf_hook_ops *rawtable_ops __read_mostly;
...@@ -57,22 +57,19 @@ static int __net_init ip6table_raw_table_init(struct net *net) ...@@ -57,22 +57,19 @@ static int __net_init ip6table_raw_table_init(struct net *net)
repl = ip6t_alloc_initial_table(table); repl = ip6t_alloc_initial_table(table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ip6t_register_table(net, table, repl, rawtable_ops, ret = ip6t_register_table(net, table, repl, rawtable_ops);
&net->ipv6.ip6table_raw);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit ip6table_raw_net_pre_exit(struct net *net) static void __net_exit ip6table_raw_net_pre_exit(struct net *net)
{ {
ip6t_unregister_table_pre_exit(net, "raw", ip6t_unregister_table_pre_exit(net, "raw");
rawtable_ops);
} }
static void __net_exit ip6table_raw_net_exit(struct net *net) static void __net_exit ip6table_raw_net_exit(struct net *net)
{ {
ip6t_unregister_table_exit(net, "raw"); ip6t_unregister_table_exit(net, "raw");
net->ipv6.ip6table_raw = NULL;
} }
static struct pernet_operations ip6table_raw_net_ops = { static struct pernet_operations ip6table_raw_net_ops = {
......
...@@ -39,7 +39,7 @@ static unsigned int ...@@ -39,7 +39,7 @@ static unsigned int
ip6table_security_hook(void *priv, struct sk_buff *skb, ip6table_security_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_security); return ip6t_do_table(skb, state, priv);
} }
static struct nf_hook_ops *sectbl_ops __read_mostly; static struct nf_hook_ops *sectbl_ops __read_mostly;
...@@ -52,21 +52,19 @@ static int __net_init ip6table_security_table_init(struct net *net) ...@@ -52,21 +52,19 @@ static int __net_init ip6table_security_table_init(struct net *net)
repl = ip6t_alloc_initial_table(&security_table); repl = ip6t_alloc_initial_table(&security_table);
if (repl == NULL) if (repl == NULL)
return -ENOMEM; return -ENOMEM;
ret = ip6t_register_table(net, &security_table, repl, sectbl_ops, ret = ip6t_register_table(net, &security_table, repl, sectbl_ops);
&net->ipv6.ip6table_security);
kfree(repl); kfree(repl);
return ret; return ret;
} }
static void __net_exit ip6table_security_net_pre_exit(struct net *net) static void __net_exit ip6table_security_net_pre_exit(struct net *net)
{ {
ip6t_unregister_table_pre_exit(net, "security", sectbl_ops); ip6t_unregister_table_pre_exit(net, "security");
} }
static void __net_exit ip6table_security_net_exit(struct net *net) static void __net_exit ip6table_security_net_exit(struct net *net)
{ {
ip6t_unregister_table_exit(net, "security"); ip6t_unregister_table_exit(net, "security");
net->ipv6.ip6table_security = NULL;
} }
static struct pernet_operations ip6table_security_net_ops = { static struct pernet_operations ip6table_security_net_ops = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment