git: c85ff48a092e - stable/13 - nfscl: Fix handling of expired Kerberos credentials (NFSv4.1/4.2)

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Tue, 02 Jan 2024 01:44:47 UTC
The branch stable/13 has been updated by rmacklem:

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

commit c85ff48a092e4c5989f91a4a1ccf99441ffb3170
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2023-12-26 22:33:39 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2024-01-02 01:41:19 +0000

    nfscl: Fix handling of expired Kerberos credentials (NFSv4.1/4.2)
    
    If the NFS server detects that the Kerberos credentials provided
    by a NFSv4.1/4.2 mount using sec=krb5[ip] have expired, the NFS
    server replies with a krpc layer error of RPC_AUTHERROR.
    When this happened, the client erroneously left the NFSv4.1/4.2
    session slot busy, so that it could not be used by other RPCs.
    If this happened for all session slots, the mount point would
    hang.
    
    This patch fixes the problem by releasing the session slot
    and resetting its sequence# upon receiving a RPC_AUTHERROR
    reply.
    
    This bug only affects NFSv4.1/4.2 mounts using sec=krb5[ip],
    but has existed since NFSv4.1 client support was added to
    FreeBSD.
    
    So, why has the bug remained undetected for so long?
    I cannot be sure, but I suspect that, often, the client detected
    the Kerberos credential expiration before attempting the RPC.
    For this case, the client would not do the RPC and, as such,
    there would be no busy session slot.  Also, no hang would
    occur until all session slots are busied (64 for a FreeBSD
    client/server), so many cases of the bug probably went undetected?
    Also, use of sec=krb5[ip] mounts are not that common.
    
    PR:     275905
    
    (cherry picked from commit a558130881e9d574dc5f37827fe2284667d5aba8)
---
 sys/fs/nfs/nfs_commonkrpc.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/sys/fs/nfs/nfs_commonkrpc.c b/sys/fs/nfs/nfs_commonkrpc.c
index 29fbb8dc4351..3aa3129ad67f 100644
--- a/sys/fs/nfs/nfs_commonkrpc.c
+++ b/sys/fs/nfs/nfs_commonkrpc.c
@@ -1040,6 +1040,22 @@ tryagain:
 			NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
 			error = ENXIO;
 		}
+	} else if (stat == RPC_AUTHERROR) {
+		/* Check for a session slot that needs to be free'd. */
+		if ((nd->nd_flag & (ND_NFSV41 | ND_HASSLOTID)) ==
+		    (ND_NFSV41 | ND_HASSLOTID) && nmp != NULL &&
+		    nd->nd_procnum != NFSPROC_NULL) {
+			/*
+			 * This can occur when a Kerberos/RPCSEC_GSS session
+			 * expires, due to TGT expiration.
+			 * Free the slot, resetting the slot's sequence#.
+			 */
+			if (sep == NULL)
+				sep = nfsmnt_mdssession(nmp);
+			nfsv4_freeslot(sep, nd->nd_slotid, true);
+		}
+		NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
+		error = EACCES;
 	} else {
 		NFSINCRGLOBAL(nfsstatsv1.rpcinvalid);
 		error = EACCES;