Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4ee8d97 authored by Trond Myklebust's avatar Trond Myklebust
Browse files

LOCKD: fix races in nsm_client_get



Commit e9406db2 (lockd: per-net
NSM client creation and destruction helpers introduced) contains
a nasty race on initialisation of the per-net NSM client because
it doesn't check whether or not the client is set after grabbing
the nsm_create_mutex.

Reported-by: default avatarNix <nix@esperi.org.uk>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
Cc: stable@vger.kernel.org
parent f878b657
Loading
Loading
Loading
Loading
+26 −17
Original line number Diff line number Diff line
@@ -85,29 +85,38 @@ static struct rpc_clnt *nsm_create(struct net *net)
	return rpc_create(&args);
}

static struct rpc_clnt *nsm_client_get(struct net *net)
static struct rpc_clnt *nsm_client_set(struct lockd_net *ln,
		struct rpc_clnt *clnt)
{
	static DEFINE_MUTEX(nsm_create_mutex);
	struct rpc_clnt	*clnt;
	struct lockd_net *ln = net_generic(net, lockd_net_id);

	spin_lock(&ln->nsm_clnt_lock);
	if (ln->nsm_users) {
		ln->nsm_users++;
		clnt = ln->nsm_clnt;
		spin_unlock(&ln->nsm_clnt_lock);
	if (ln->nsm_users == 0) {
		if (clnt == NULL)
			goto out;
		ln->nsm_clnt = clnt;
	}
	clnt = ln->nsm_clnt;
	ln->nsm_users++;
out:
	spin_unlock(&ln->nsm_clnt_lock);

	mutex_lock(&nsm_create_mutex);
	clnt = nsm_create(net);
	if (!IS_ERR(clnt)) {
		ln->nsm_clnt = clnt;
		smp_wmb();
		ln->nsm_users = 1;
	return clnt;
}
	mutex_unlock(&nsm_create_mutex);

static struct rpc_clnt *nsm_client_get(struct net *net)
{
	struct rpc_clnt	*clnt, *new;
	struct lockd_net *ln = net_generic(net, lockd_net_id);

	clnt = nsm_client_set(ln, NULL);
	if (clnt != NULL)
		goto out;

	clnt = new = nsm_create(net);
	if (IS_ERR(clnt))
		goto out;

	clnt = nsm_client_set(ln, new);
	if (clnt != new)
		rpc_shutdown_client(new);
out:
	return clnt;
}