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

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
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -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,
			const struct ip6t_replace *repl,
			const struct nf_hook_ops *ops, struct xt_table **res);
void ip6t_unregister_table_pre_exit(struct net *net, const char *name,
			const struct nf_hook_ops *ops);
void ip6t_unregister_table_pre_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,
				  const struct nf_hook_state *state,
+33 −18
Original line number Diff line number Diff line
@@ -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,
			const struct ip6t_replace *repl,
			const struct nf_hook_ops *ops,
			struct xt_table **res)
			const struct nf_hook_ops *template_ops)
{
	int ret;
	struct nf_hook_ops *ops;
	unsigned int num_ops;
	int ret, i;
	struct xt_table_info *newinfo;
	struct xt_table_info bootstrap = {0};
	void *loc_cpu_entry;
@@ -1742,40 +1743,54 @@ int ip6t_register_table(struct net *net, const struct xt_table *table,
	memcpy(loc_cpu_entry, repl->entries, repl->size);

	ret = translate_table(net, newinfo, loc_cpu_entry, repl);
	if (ret != 0)
		goto out_free;
	if (ret != 0) {
		xt_free_table_info(newinfo);
		return ret;
	}

	new_table = xt_register_table(net, table, &bootstrap, newinfo);
	if (IS_ERR(new_table)) {
		ret = PTR_ERR(new_table);
		goto out_free;
		xt_free_table_info(newinfo);
		return PTR_ERR(new_table);
	}

	/* set res now, will see skbs right after nf_register_net_hooks */
	WRITE_ONCE(*res, new_table);
	if (!ops)
	if (!template_ops)
		return 0;

	ret = nf_register_net_hooks(net, ops, hweight32(table->valid_hooks));
	if (ret != 0) {
		__ip6t_unregister_table(net, new_table);
		*res = NULL;
	num_ops = hweight32(table->valid_hooks);
	if (num_ops == 0) {
		ret = -EINVAL;
		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;

out_free:
	xt_free_table_info(newinfo);
	__ip6t_unregister_table(net, new_table);
	return ret;
}

void ip6t_unregister_table_pre_exit(struct net *net, const char *name,
				    const struct nf_hook_ops *ops)
void ip6t_unregister_table_pre_exit(struct net *net, const char *name)
{
	struct xt_table *table = xt_find_table(net, NFPROTO_IPV6, name);

	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)
+3 −6
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ static unsigned int
ip6table_filter_hook(void *priv, struct sk_buff *skb,
		     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;
@@ -56,8 +56,7 @@ static int __net_init ip6table_filter_table_init(struct net *net)
	((struct ip6t_standard *)repl->entries)[1].target.verdict =
		forward ? -NF_ACCEPT - 1 : -NF_DROP - 1;

	err = ip6t_register_table(net, &packet_filter, repl, filter_ops,
				  &net->ipv6.ip6table_filter);
	err = ip6t_register_table(net, &packet_filter, repl, filter_ops);
	kfree(repl);
	return err;
}
@@ -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)
{
	ip6t_unregister_table_pre_exit(net, "filter",
				       filter_ops);
	ip6t_unregister_table_pre_exit(net, "filter");
}

static void __net_exit ip6table_filter_net_exit(struct net *net)
{
	ip6t_unregister_table_exit(net, "filter");
	net->ipv6.ip6table_filter = NULL;
}

static struct pernet_operations ip6table_filter_net_ops = {
+6 −8
Original line number Diff line number Diff line
@@ -32,7 +32,7 @@ static const struct xt_table packet_mangler = {
};

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;
	struct in6_addr saddr, daddr;
@@ -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 = *((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 &&
	    (!ipv6_addr_equal(&ipv6_hdr(skb)->saddr, &saddr) ||
@@ -71,8 +71,8 @@ ip6table_mangle_hook(void *priv, struct sk_buff *skb,
		     const struct nf_hook_state *state)
{
	if (state->hook == NF_INET_LOCAL_OUT)
		return ip6t_mangle_out(skb, state);
	return ip6t_do_table(skb, state, state->net->ipv6.ip6table_mangle);
		return ip6t_mangle_out(skb, state, priv);
	return ip6t_do_table(skb, state, priv);
}

static struct nf_hook_ops *mangle_ops __read_mostly;
@@ -84,21 +84,19 @@ static int __net_init ip6table_mangle_table_init(struct net *net)
	repl = ip6t_alloc_initial_table(&packet_mangler);
	if (repl == NULL)
		return -ENOMEM;
	ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops,
				  &net->ipv6.ip6table_mangle);
	ret = ip6t_register_table(net, &packet_mangler, repl, mangle_ops);
	kfree(repl);
	return ret;
}

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)
{
	ip6t_unregister_table_exit(net, "mangle");
	net->ipv6.ip6table_mangle = NULL;
}

static struct pernet_operations ip6table_mangle_net_ops = {
+13 −11
Original line number Diff line number Diff line
@@ -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 = net_generic(net, ip6table_nat_net_id);
	struct ip6table_nat_pernet *xt_nat_net;
	struct nf_hook_ops *ops;
	struct xt_table *table;
	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)
		return -ENOMEM;

@@ -111,25 +118,21 @@ static void ip6t_nat_unregister_lookups(struct net *net)
static int __net_init ip6table_nat_table_init(struct net *net)
{
	struct ip6t_replace *repl;
	struct xt_table *table;
	int ret;

	repl = ip6t_alloc_initial_table(&nf_nat_ipv6_table);
	if (repl == NULL)
		return -ENOMEM;
	ret = ip6t_register_table(net, &nf_nat_ipv6_table, repl,
				  NULL, &table);
				  NULL);
	if (ret < 0) {
		kfree(repl);
		return ret;
	}

	ret = ip6t_nat_register_lookups(net, table);
	if (ret < 0) {
	ret = ip6t_nat_register_lookups(net);
	if (ret < 0)
		ip6t_unregister_table_exit(net, "nat");
	} else {
		net->ipv6.ip6table_nat = table;
	}

	kfree(repl);
	return ret;
@@ -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)
{
	ip6t_unregister_table_exit(net, "nat");
	net->ipv6.ip6table_nat = NULL;
}

static struct pernet_operations ip6table_nat_net_ops = {
Loading