Commit d8e8fbec authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull nfsd fixes from Chuck Lever:

 - Address three recently introduced regressions

* tag 'nfsd-6.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux:
  NFSD: CREATE_SESSION must never cache NFS4ERR_DELAY replies
  SUNRPC: Revert 561141dd
  nfsd: Fix error cleanup path in nfsd_rename()
parents 50108c35 99dc2ef0
Loading
Loading
Loading
Loading
+25 −11
Original line number Diff line number Diff line
@@ -3831,15 +3831,20 @@ nfsd4_create_session(struct svc_rqst *rqstp,
	else
		cs_slot = &unconf->cl_cs_slot;
	status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
	if (status) {
		if (status == nfserr_replay_cache) {
	switch (status) {
	case nfs_ok:
		cs_slot->sl_seqid++;
		cr_ses->seqid = cs_slot->sl_seqid;
		break;
	case nfserr_replay_cache:
		status = nfsd4_replay_create_session(cr_ses, cs_slot);
		fallthrough;
	case nfserr_jukebox:
		/* The server MUST NOT cache NFS4ERR_DELAY */
		goto out_free_conn;
		}
	default:
		goto out_cache_error;
	}
	cs_slot->sl_seqid++;
	cr_ses->seqid = cs_slot->sl_seqid;

	/* RFC 8881 Section 18.36.4 Phase 3: Client ID confirmation. */
	if (conf) {
@@ -3859,10 +3864,8 @@ nfsd4_create_session(struct svc_rqst *rqstp,
		old = find_confirmed_client_by_name(&unconf->cl_name, nn);
		if (old) {
			status = mark_client_expired_locked(old);
			if (status) {
				old = NULL;
				goto out_cache_error;
			}
			if (status)
				goto out_expired_error;
			trace_nfsd_clid_replaced(&old->cl_clientid);
		}
		move_to_confirmed(unconf);
@@ -3894,6 +3897,17 @@ nfsd4_create_session(struct svc_rqst *rqstp,
		expire_client(old);
	return status;

out_expired_error:
	old = NULL;
	/*
	 * Revert the slot seq_nr change so the server will process
	 * the client's resend instead of returning a cached response.
	 */
	if (status == nfserr_jukebox) {
		cs_slot->sl_seqid--;
		cr_ses->seqid = cs_slot->sl_seqid;
		goto out_free_conn;
	}
out_cache_error:
	nfsd4_cache_create_session(cr_ses, cs_slot, status);
out_free_conn:
+2 −1
Original line number Diff line number Diff line
@@ -1852,7 +1852,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
	trap = lock_rename(tdentry, fdentry);
	if (IS_ERR(trap)) {
		err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev;
		goto out;
		goto out_want_write;
	}
	err = fh_fill_pre_attrs(ffhp);
	if (err != nfs_ok)
@@ -1922,6 +1922,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
	}
out_unlock:
	unlock_rename(tdentry, fdentry);
out_want_write:
	fh_drop_write(ffhp);

	/*
+8 −6
Original line number Diff line number Diff line
@@ -921,8 +921,6 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, u32 len,
 * Caller provides the truncation length of the output token (h) in
 * cksumout.len.
 *
 * Note that for RPCSEC, the "initial cipher state" is always all zeroes.
 *
 * Return values:
 *   %GSS_S_COMPLETE: Digest computed, @cksumout filled in
 *   %GSS_S_FAILURE: Call failed
@@ -933,19 +931,22 @@ u32 krb5_etm_checksum(struct crypto_sync_skcipher *cipher,
		      int body_offset, struct xdr_netobj *cksumout)
{
	unsigned int ivsize = crypto_sync_skcipher_ivsize(cipher);
	static const u8 iv[GSS_KRB5_MAX_BLOCKSIZE];
	struct ahash_request *req;
	struct scatterlist sg[1];
	u8 *iv, *checksumdata;
	int err = -ENOMEM;
	u8 *checksumdata;

	checksumdata = kmalloc(crypto_ahash_digestsize(tfm), GFP_KERNEL);
	if (!checksumdata)
		return GSS_S_FAILURE;
	/* For RPCSEC, the "initial cipher state" is always all zeroes. */
	iv = kzalloc(ivsize, GFP_KERNEL);
	if (!iv)
		goto out_free_mem;

	req = ahash_request_alloc(tfm, GFP_KERNEL);
	if (!req)
		goto out_free_cksumdata;
		goto out_free_mem;
	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
	err = crypto_ahash_init(req);
	if (err)
@@ -969,7 +970,8 @@ u32 krb5_etm_checksum(struct crypto_sync_skcipher *cipher,

out_free_ahash:
	ahash_request_free(req);
out_free_cksumdata:
out_free_mem:
	kfree(iv);
	kfree_sensitive(checksumdata);
	return err ? GSS_S_FAILURE : GSS_S_COMPLETE;
}