Commit 960f0716 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull NFS client bugfixes from Trond Myklebust:
 "Highlights include:

  Stable fixes:

   - Fix use-after-free in nfs4_init_client()

  Bugfixes:

   - Fix deadlock between nfs4_evict_inode() and nfs4_opendata_get_inode()

   - Fix second deadlock in nfs4_evict_inode()

   - nfs4_proc_set_acl should not change the value of NFS_CAP_UIDGID_NOMAP

   - Fix setting of the NFS_CAP_SECURITY_LABEL capability"

* tag 'nfs-for-5.13-3' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFSv4: Fix second deadlock in nfs4_evict_inode()
  NFSv4: Fix deadlock between nfs4_evict_inode() and nfs4_opendata_get_inode()
  NFS: FMODE_READ and friends are C macros, not enum types
  NFS: Fix a potential NULL dereference in nfs_get_client()
  NFS: Fix use-after-free in nfs4_init_client()
  NFS: Ensure the NFS_CAP_SECURITY_LABEL capability is set when appropriate
  NFSv4: nfs4_proc_set_acl needs to restore NFS_CAP_UIDGID_NOMAP on error.
parents 331a6edb c3aba897
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -406,7 +406,7 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *cl_init)

	if (cl_init->hostname == NULL) {
		WARN_ON(1);
		return NULL;
		return ERR_PTR(-EINVAL);
	}

	/* see if the client already exists */
+1 −0
Original line number Diff line number Diff line
@@ -205,6 +205,7 @@ struct nfs4_exception {
	struct inode *inode;
	nfs4_stateid *stateid;
	long timeout;
	unsigned char task_is_privileged : 1;
	unsigned char delay : 1,
		      recovering : 1,
		      retry : 1;
+1 −1
Original line number Diff line number Diff line
@@ -435,8 +435,8 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
		 */
		nfs_mark_client_ready(clp, -EPERM);
	}
	nfs_put_client(clp);
	clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags);
	nfs_put_client(clp);
	return old;

error:
+30 −7
Original line number Diff line number Diff line
@@ -589,6 +589,8 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_
		goto out_retry;
	}
	if (exception->recovering) {
		if (exception->task_is_privileged)
			return -EDEADLOCK;
		ret = nfs4_wait_clnt_recover(clp);
		if (test_bit(NFS_MIG_FAILED, &server->mig_status))
			return -EIO;
@@ -614,6 +616,8 @@ nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server,
		goto out_retry;
	}
	if (exception->recovering) {
		if (exception->task_is_privileged)
			return -EDEADLOCK;
		rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
		if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
			rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
@@ -3878,6 +3882,10 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
			server->caps |= NFS_CAP_HARDLINKS;
		if (res.has_symlinks != 0)
			server->caps |= NFS_CAP_SYMLINKS;
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
		if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL)
			server->caps |= NFS_CAP_SECURITY_LABEL;
#endif
		if (!(res.attr_bitmask[0] & FATTR4_WORD0_FILEID))
			server->fattr_valid &= ~NFS_ATTR_FATTR_FILEID;
		if (!(res.attr_bitmask[1] & FATTR4_WORD1_MODE))
@@ -3898,10 +3906,6 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
			server->fattr_valid &= ~NFS_ATTR_FATTR_CTIME;
		if (!(res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY))
			server->fattr_valid &= ~NFS_ATTR_FATTR_MTIME;
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
		if (!(res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL))
			server->fattr_valid &= ~NFS_ATTR_FATTR_V4_SECURITY_LABEL;
#endif
		memcpy(server->attr_bitmask_nl, res.attr_bitmask,
				sizeof(server->attr_bitmask));
		server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
@@ -5968,6 +5972,14 @@ static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen
	do {
		err = __nfs4_proc_set_acl(inode, buf, buflen);
		trace_nfs4_set_acl(inode, err);
		if (err == -NFS4ERR_BADOWNER || err == -NFS4ERR_BADNAME) {
			/*
			 * no need to retry since the kernel
			 * isn't involved in encoding the ACEs.
			 */
			err = -EINVAL;
			break;
		}
		err = nfs4_handle_exception(NFS_SERVER(inode), err,
				&exception);
	} while (exception.retry);
@@ -6409,6 +6421,7 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
	struct nfs4_exception exception = {
		.inode = data->inode,
		.stateid = &data->stateid,
		.task_is_privileged = data->args.seq_args.sa_privileged,
	};

	if (!nfs4_sequence_done(task, &data->res.seq_res))
@@ -6532,7 +6545,6 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred,
	data = kzalloc(sizeof(*data), GFP_NOFS);
	if (data == NULL)
		return -ENOMEM;
	nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1, 0);

	nfs4_state_protect(server->nfs_client,
			NFS_SP4_MACH_CRED_CLEANUP,
@@ -6563,6 +6575,12 @@ static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred,
		}
	}

	if (!data->inode)
		nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1,
				   1);
	else
		nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1,
				   0);
	task_setup_data.callback_data = data;
	msg.rpc_argp = &data->args;
	msg.rpc_resp = &data->res;
@@ -9640,15 +9658,20 @@ int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync)
			&task_setup_data.rpc_client, &msg);

	dprintk("--> %s\n", __func__);
	if (!sync) {
	lrp->inode = nfs_igrab_and_active(lrp->args.inode);
	if (!sync) {
		if (!lrp->inode) {
			nfs4_layoutreturn_release(lrp);
			return -EAGAIN;
		}
		task_setup_data.flags |= RPC_TASK_ASYNC;
	}
	nfs4_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1, 0);
	if (!lrp->inode)
		nfs4_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1,
				   1);
	else
		nfs4_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1,
				   0);
	task = rpc_run_task(&task_setup_data);
	if (IS_ERR(task))
		return PTR_ERR(task);
+0 −4
Original line number Diff line number Diff line
@@ -430,10 +430,6 @@ TRACE_DEFINE_ENUM(O_CLOEXEC);
		{ O_NOATIME, "O_NOATIME" }, \
		{ O_CLOEXEC, "O_CLOEXEC" })

TRACE_DEFINE_ENUM(FMODE_READ);
TRACE_DEFINE_ENUM(FMODE_WRITE);
TRACE_DEFINE_ENUM(FMODE_EXEC);

#define show_fmode_flags(mode) \
	__print_flags(mode, "|", \
		{ ((__force unsigned long)FMODE_READ), "READ" }, \