git: 3c6bc3e9664a - stable/13 - nfscl: Acquire a refcount on "cred" for mirrored pNFS RPCs

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Tue, 17 May 2022 20:42:12 UTC
The branch stable/13 has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=3c6bc3e9664a9ece9e92115aed5087dc1c25fc34

commit 3c6bc3e9664a9ece9e92115aed5087dc1c25fc34
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2022-05-03 14:22:15 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2022-05-17 20:39:49 +0000

    nfscl: Acquire a refcount on "cred" for mirrored pNFS RPCs
    
    When the NFSv4.1/4.2 client is doing a pnfs mount to
    mirrored DS(s), asynchronous threads are used to do the
    RPCs against the DS(s) concurrently.  If a DS is slow
    to reply, it is possible for the "cred" to be free'd
    before the asynchronous thread is done with it, causing
    a panic/crash.
    
    This patch fixes the problem by acquiring a refcount on
    the "cred" while it is being used by the asynchronous thread
    for a DS RPC.  This bug was found during a recent IETF
    NFSv4 testing event.
    
    This bug only affects "pnfs" mounts to mirrored pNFS
    servers.
    
    (cherry picked from commit 70910e4b55ca976ca0ad4aa3e34252ba148a6126)
---
 sys/fs/nfsclient/nfs_clrpcops.c | 23 ++++++++++++++++-------
 1 file changed, 16 insertions(+), 7 deletions(-)

diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 9922cf00d464..149b57e49fb7 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -6723,6 +6723,7 @@ start_writedsmir(void *arg, int pending)
 	    drpc->fhp, drpc->m, drpc->vers, drpc->minorvers, drpc->cred,
 	    drpc->p);
 	drpc->done = 1;
+	crfree(drpc->cred);
 	NFSCL_DEBUG(4, "start_writedsmir: err=%d\n", drpc->err);
 }
 
@@ -6750,7 +6751,7 @@ nfsio_writedsmir(vnode_t vp, int *iomode, int *must_commit,
 	drpc->m = m;
 	drpc->vers = vers;
 	drpc->minorvers = minorvers;
-	drpc->cred = cred;
+	drpc->cred = crhold(cred);
 	drpc->p = p;
 	drpc->inprog = 0;
 	ret = EIO;
@@ -6758,9 +6759,11 @@ nfsio_writedsmir(vnode_t vp, int *iomode, int *must_commit,
 		ret = nfs_pnfsio(start_writedsmir, drpc);
 		NFSCL_DEBUG(4, "nfsio_writedsmir: nfs_pnfsio=%d\n", ret);
 	}
-	if (ret != 0)
+	if (ret != 0) {
 		error = nfsrpc_writedsmir(vp, iomode, &drpc->must_commit,
 		    stateidp, dsp, off, len, fhp, m, vers, minorvers, cred, p);
+		crfree(drpc->cred);
+	}
 	NFSCL_DEBUG(4, "nfsio_writedsmir: error=%d\n", error);
 	return (error);
 }
@@ -6908,6 +6911,7 @@ start_commitds(void *arg, int pending)
 	    drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, drpc->cred,
 	    drpc->p);
 	drpc->done = 1;
+	crfree(drpc->cred);
 	NFSCL_DEBUG(4, "start_commitds: err=%d\n", drpc->err);
 }
 
@@ -6930,7 +6934,7 @@ nfsio_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
 	drpc->fhp = fhp;
 	drpc->vers = vers;
 	drpc->minorvers = minorvers;
-	drpc->cred = cred;
+	drpc->cred = crhold(cred);
 	drpc->p = p;
 	drpc->inprog = 0;
 	ret = EIO;
@@ -6938,9 +6942,11 @@ nfsio_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
 		ret = nfs_pnfsio(start_commitds, drpc);
 		NFSCL_DEBUG(4, "nfsio_commitds: nfs_pnfsio=%d\n", ret);
 	}
-	if (ret != 0)
+	if (ret != 0) {
 		error = nfsrpc_commitds(vp, offset, cnt, dsp, fhp, vers,
 		    minorvers, cred, p);
+		crfree(drpc->cred);
+	}
 	NFSCL_DEBUG(4, "nfsio_commitds: error=%d\n", error);
 	return (error);
 }
@@ -7047,11 +7053,12 @@ start_adviseds(void *arg, int pending)
 	    drpc->advise, drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers,
 	    drpc->cred, drpc->p);
 	drpc->done = 1;
+	crfree(drpc->cred);
 	NFSCL_DEBUG(4, "start_adviseds: err=%d\n", drpc->err);
 }
 
 /*
- * Set up the commit DS mirror call for the pNFS I/O thread.
+ * Set up the advise DS mirror call for the pNFS I/O thread.
  */
 static int
 nfsio_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise,
@@ -7070,7 +7077,7 @@ nfsio_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise,
 	drpc->fhp = fhp;
 	drpc->vers = vers;
 	drpc->minorvers = minorvers;
-	drpc->cred = cred;
+	drpc->cred = crhold(cred);
 	drpc->p = p;
 	drpc->inprog = 0;
 	ret = EIO;
@@ -7078,9 +7085,11 @@ nfsio_adviseds(vnode_t vp, uint64_t offset, int cnt, int advise,
 		ret = nfs_pnfsio(start_adviseds, drpc);
 		NFSCL_DEBUG(4, "nfsio_adviseds: nfs_pnfsio=%d\n", ret);
 	}
-	if (ret != 0)
+	if (ret != 0) {
 		error = nfsrpc_adviseds(vp, offset, cnt, advise, dsp, fhp, vers,
 		    minorvers, cred, p);
+		crfree(drpc->cred);
+	}
 	NFSCL_DEBUG(4, "nfsio_adviseds: error=%d\n", error);
 	return (error);
 }