Commit 2fcba19c authored by Fernando Fernandez Mancera's avatar Fernando Fernandez Mancera Committed by Pablo Neira Ayuso
Browse files

netfilter: synproxy: add mutex to guard hook reference counting



As the synproxy infrastructure register netfilter hooks on-demand when a
user adds the first iptables target or nftables expression, if done
concurrently they can race each other.

Introduce a mutex to serialize the refcount control blocks access from
both frontends. While a per namespace mutex might be more efficient, it
is not needed for target/expression like SYNPROXY.

Fixes: ad49d86e ("netfilter: nf_tables: Add synproxy support")
Signed-off-by: default avatarFernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 36d29cee
Loading
Loading
Loading
Loading
+18 −6
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@
#include <net/netfilter/nf_conntrack_zones.h>
#include <net/netfilter/nf_synproxy.h>

static DEFINE_MUTEX(synproxy_mutex);

unsigned int synproxy_net_id;
EXPORT_SYMBOL_GPL(synproxy_net_id);

@@ -769,26 +771,31 @@ static const struct nf_hook_ops ipv4_synproxy_ops[] = {

int nf_synproxy_ipv4_init(struct synproxy_net *snet, struct net *net)
{
	int err;
	int err = 0;

	mutex_lock(&synproxy_mutex);
	if (snet->hook_ref4 == 0) {
		err = nf_register_net_hooks(net, ipv4_synproxy_ops,
					    ARRAY_SIZE(ipv4_synproxy_ops));
		if (err)
			return err;
			goto out;
	}

	snet->hook_ref4++;
	return 0;
out:
	mutex_unlock(&synproxy_mutex);
	return err;
}
EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_init);

void nf_synproxy_ipv4_fini(struct synproxy_net *snet, struct net *net)
{
	mutex_lock(&synproxy_mutex);
	snet->hook_ref4--;
	if (snet->hook_ref4 == 0)
		nf_unregister_net_hooks(net, ipv4_synproxy_ops,
					ARRAY_SIZE(ipv4_synproxy_ops));
	mutex_unlock(&synproxy_mutex);
}
EXPORT_SYMBOL_GPL(nf_synproxy_ipv4_fini);

@@ -1193,27 +1200,32 @@ static const struct nf_hook_ops ipv6_synproxy_ops[] = {
int
nf_synproxy_ipv6_init(struct synproxy_net *snet, struct net *net)
{
	int err;
	int err = 0;

	mutex_lock(&synproxy_mutex);
	if (snet->hook_ref6 == 0) {
		err = nf_register_net_hooks(net, ipv6_synproxy_ops,
					    ARRAY_SIZE(ipv6_synproxy_ops));
		if (err)
			return err;
			goto out;
	}

	snet->hook_ref6++;
	return 0;
out:
	mutex_unlock(&synproxy_mutex);
	return err;
}
EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_init);

void
nf_synproxy_ipv6_fini(struct synproxy_net *snet, struct net *net)
{
	mutex_lock(&synproxy_mutex);
	snet->hook_ref6--;
	if (snet->hook_ref6 == 0)
		nf_unregister_net_hooks(net, ipv6_synproxy_ops,
					ARRAY_SIZE(ipv6_synproxy_ops));
	mutex_unlock(&synproxy_mutex);
}
EXPORT_SYMBOL_GPL(nf_synproxy_ipv6_fini);
#endif /* CONFIG_IPV6 */