Commit 1aee5513 authored by Trond Myklebust's avatar Trond Myklebust Committed by Anna Schumaker
Browse files

NFSv4: Clean up initialisation of uniquified client id strings



When the user sets a uniquifier, then ensure we copy the string
so that calls to strlen() etc are atomic with calls to snprintf().

Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent bff049a3
Loading
Loading
Loading
Loading
+34 −41
Original line number Diff line number Diff line
@@ -6093,9 +6093,22 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp,
	memcpy(bootverf->data, verf, sizeof(bootverf->data));
}

static size_t
nfs4_get_uniquifier(char *buf, size_t buflen)
{
	buf[0] = '\0';

	if (nfs4_client_id_uniquifier[0] != '\0')
		strscpy(buf, nfs4_client_id_uniquifier, buflen);

	return strlen(buf);
}

static int
nfs4_init_nonuniform_client_string(struct nfs_client *clp)
{
	char buf[NFS4_CLIENT_ID_UNIQ_LEN];
	size_t buflen;
	size_t len;
	char *str;

@@ -6109,8 +6122,11 @@ nfs4_init_nonuniform_client_string(struct nfs_client *clp)
		strlen(rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)) +
		1;
	rcu_read_unlock();
	if (nfs4_client_id_uniquifier[0] != '\0')
		len += strlen(nfs4_client_id_uniquifier) + 1;

	buflen = nfs4_get_uniquifier(buf, sizeof(buf));
	if (buflen)
		len += buflen + 1;

	if (len > NFS4_OPAQUE_LIMIT + 1)
		return -EINVAL;

@@ -6124,10 +6140,9 @@ nfs4_init_nonuniform_client_string(struct nfs_client *clp)
		return -ENOMEM;

	rcu_read_lock();
	if (nfs4_client_id_uniquifier[0] != '\0')
	if (buflen)
		scnprintf(str, len, "Linux NFSv4.0 %s/%s/%s",
			  clp->cl_rpcclient->cl_nodename,
			  nfs4_client_id_uniquifier,
			  clp->cl_rpcclient->cl_nodename, buf,
			  rpc_peeraddr2str(clp->cl_rpcclient,
					   RPC_DISPLAY_ADDR));
	else
@@ -6141,51 +6156,24 @@ nfs4_init_nonuniform_client_string(struct nfs_client *clp)
	return 0;
}

static int
nfs4_init_uniquifier_client_string(struct nfs_client *clp)
{
	size_t len;
	char *str;

	len = 10 + 10 + 1 + 10 + 1 +
		strlen(nfs4_client_id_uniquifier) + 1 +
		strlen(clp->cl_rpcclient->cl_nodename) + 1;

	if (len > NFS4_OPAQUE_LIMIT + 1)
		return -EINVAL;

	/*
	 * Since this string is allocated at mount time, and held until the
	 * nfs_client is destroyed, we can use GFP_KERNEL here w/o worrying
	 * about a memory-reclaim deadlock.
	 */
	str = kmalloc(len, GFP_KERNEL);
	if (!str)
		return -ENOMEM;

	scnprintf(str, len, "Linux NFSv%u.%u %s/%s",
			clp->rpc_ops->version, clp->cl_minorversion,
			nfs4_client_id_uniquifier,
			clp->cl_rpcclient->cl_nodename);
	clp->cl_owner_id = str;
	return 0;
}

static int
nfs4_init_uniform_client_string(struct nfs_client *clp)
{
	char buf[NFS4_CLIENT_ID_UNIQ_LEN];
	size_t buflen;
	size_t len;
	char *str;

	if (clp->cl_owner_id != NULL)
		return 0;

	if (nfs4_client_id_uniquifier[0] != '\0')
		return nfs4_init_uniquifier_client_string(clp);

	len = 10 + 10 + 1 + 10 + 1 +
		strlen(clp->cl_rpcclient->cl_nodename) + 1;

	buflen = nfs4_get_uniquifier(buf, sizeof(buf));
	if (buflen)
		len += buflen + 1;

	if (len > NFS4_OPAQUE_LIMIT + 1)
		return -EINVAL;

@@ -6198,6 +6186,11 @@ nfs4_init_uniform_client_string(struct nfs_client *clp)
	if (!str)
		return -ENOMEM;

	if (buflen)
		scnprintf(str, len, "Linux NFSv%u.%u %s/%s",
			  clp->rpc_ops->version, clp->cl_minorversion,
			  buf, clp->cl_rpcclient->cl_nodename);
	else
		scnprintf(str, len, "Linux NFSv%u.%u %s",
			  clp->rpc_ops->version, clp->cl_minorversion,
			  clp->cl_rpcclient->cl_nodename);