Commit 6fa9041b authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull nfsd fixes from Chuck Lever:
 "Address recently reported issues or issues found at the recent NFS
  bake-a-thon held in Raleigh, NC.

  Issues reported with v6.18-rc:
   - Address a kernel build issue
   - Reorder SEQUENCE processing to avoid spurious NFS4ERR_SEQ_MISORDERED

  Issues that need expedient stable backports:
   - Close a refcount leak exposure
   - Report support for NFSv4.2 CLONE correctly
   - Fix oops during COPY_NOTIFY processing
   - Prevent rare crash after XDR encoding failure
   - Prevent crash due to confused or malicious NFSv4.1 client"

* tag 'nfsd-6.18-3' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux:
  Revert "SUNRPC: Make RPCSEC_GSS_KRB5 select CRYPTO instead of depending on it"
  nfsd: ensure SEQUENCE replay sends a valid reply.
  NFSD: Never cache a COMPOUND when the SEQUENCE operation fails
  NFSD: Skip close replay processing if XDR encoding fails
  NFSD: free copynotify stateid in nfs4_free_ol_stateid()
  nfsd: add missing FATTR4_WORD2_CLONE_BLKSIZE from supported attributes
  nfsd: fix refcount leak in nfsd_set_fh_dentry()
parents 92385a07 324be6dc
Loading
Loading
Loading
Loading
+49 −19
Original line number Diff line number Diff line
@@ -1542,7 +1542,8 @@ static void nfs4_free_ol_stateid(struct nfs4_stid *stid)
	release_all_access(stp);
	if (stp->st_stateowner)
		nfs4_put_stateowner(stp->st_stateowner);
	WARN_ON(!list_empty(&stid->sc_cp_list));
	if (!list_empty(&stid->sc_cp_list))
		nfs4_free_cpntf_statelist(stid->sc_client->net, stid);
	kmem_cache_free(stateid_slab, stid);
}

@@ -3486,7 +3487,20 @@ nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
	struct nfsd4_slot *slot = resp->cstate.slot;
	unsigned int base;

	dprintk("--> %s slot %p\n", __func__, slot);
	/*
	 * RFC 5661 Section 2.10.6.1.2:
	 *
	 * Any time SEQUENCE ... returns an error ... [t]he replier MUST NOT
	 * modify the reply cache entry for the slot whenever an error is
	 * returned from SEQUENCE ...
	 *
	 * Because nfsd4_store_cache_entry is called only by
	 * nfsd4_sequence_done(), nfsd4_store_cache_entry() is called only
	 * when a SEQUENCE operation was part of the COMPOUND.
	 * nfs41_check_op_ordering() ensures SEQUENCE is the first op.
	 */
	if (resp->opcnt == 1 && resp->cstate.status != nfs_ok)
		return;

	slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
	slot->sl_opcnt = resp->opcnt;
@@ -4349,6 +4363,36 @@ static bool replay_matches_cache(struct svc_rqst *rqstp,
	return true;
}

/*
 * Note that the response is constructed here both for the case
 * of a new SEQUENCE request and for a replayed SEQUENCE request.
 * We do not cache SEQUENCE responses as SEQUENCE is idempotent.
 */
static void nfsd4_construct_sequence_response(struct nfsd4_session *session,
					      struct nfsd4_sequence *seq)
{
	struct nfs4_client *clp = session->se_client;

	seq->maxslots_response = max(session->se_target_maxslots,
				     seq->maxslots);
	seq->target_maxslots = session->se_target_maxslots;

	switch (clp->cl_cb_state) {
	case NFSD4_CB_DOWN:
		seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN;
		break;
	case NFSD4_CB_FAULT:
		seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT;
		break;
	default:
		seq->status_flags = 0;
	}
	if (!list_empty(&clp->cl_revoked))
		seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
	if (atomic_read(&clp->cl_admin_revoked))
		seq->status_flags |= SEQ4_STATUS_ADMIN_STATE_REVOKED;
}

__be32
nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		union nfsd4_op_u *u)
@@ -4398,6 +4442,9 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	dprintk("%s: slotid %d\n", __func__, seq->slotid);

	trace_nfsd_slot_seqid_sequence(clp, seq, slot);

	nfsd4_construct_sequence_response(session, seq);

	status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_flags);
	if (status == nfserr_replay_cache) {
		status = nfserr_seq_misordered;
@@ -4495,23 +4542,6 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	}

out:
	seq->maxslots = max(session->se_target_maxslots, seq->maxslots);
	seq->target_maxslots = session->se_target_maxslots;

	switch (clp->cl_cb_state) {
	case NFSD4_CB_DOWN:
		seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN;
		break;
	case NFSD4_CB_FAULT:
		seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT;
		break;
	default:
		seq->status_flags = 0;
	}
	if (!list_empty(&clp->cl_revoked))
		seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
	if (atomic_read(&clp->cl_admin_revoked))
		seq->status_flags |= SEQ4_STATUS_ADMIN_STATE_REVOKED;
	trace_nfsd_seq4_status(rqstp, seq);
out_no_session:
	if (conn)
+2 −3
Original line number Diff line number Diff line
@@ -5073,7 +5073,7 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
		return nfserr;
	/* Note slotid's are numbered from zero: */
	/* sr_highest_slotid */
	nfserr = nfsd4_encode_slotid4(xdr, seq->maxslots - 1);
	nfserr = nfsd4_encode_slotid4(xdr, seq->maxslots_response - 1);
	if (nfserr != nfs_ok)
		return nfserr;
	/* sr_target_highest_slotid */
@@ -5925,8 +5925,7 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
		 */
		warn_on_nonidempotent_op(op);
		xdr_truncate_encode(xdr, op_status_offset + XDR_UNIT);
	}
	if (so) {
	} else if (so) {
		int len = xdr->buf->len - (op_status_offset + XDR_UNIT);

		so->so_replay.rp_status = op->status;
+1 −0
Original line number Diff line number Diff line
@@ -458,6 +458,7 @@ enum {
#define NFSD4_2_SUPPORTED_ATTRS_WORD2 \
	(NFSD4_1_SUPPORTED_ATTRS_WORD2 | \
	FATTR4_WORD2_MODE_UMASK | \
	FATTR4_WORD2_CLONE_BLKSIZE | \
	NFSD4_2_SECURITY_ATTRS | \
	FATTR4_WORD2_XATTR_SUPPORT | \
	FATTR4_WORD2_TIME_DELEG_ACCESS | \
+3 −3
Original line number Diff line number Diff line
@@ -269,9 +269,6 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct net *net,
				dentry);
	}

	fhp->fh_dentry = dentry;
	fhp->fh_export = exp;

	switch (fhp->fh_maxsize) {
	case NFS4_FHSIZE:
		if (dentry->d_sb->s_export_op->flags & EXPORT_OP_NOATOMIC_ATTR)
@@ -293,6 +290,9 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct net *net,
			goto out;
	}

	fhp->fh_dentry = dentry;
	fhp->fh_export = exp;

	return 0;
out:
	exp_put(exp);
+2 −1
Original line number Diff line number Diff line
@@ -574,8 +574,9 @@ struct nfsd4_sequence {
	struct nfs4_sessionid	sessionid;		/* request/response */
	u32			seqid;			/* request/response */
	u32			slotid;			/* request/response */
	u32			maxslots;		/* request/response */
	u32			maxslots;		/* request */
	u32			cachethis;		/* request */
	u32			maxslots_response;	/* response */
	u32			target_maxslots;	/* response */
	u32			status_flags;		/* response */
};
Loading