[PATCH] ksmbd: decrypt requests from expired encrypted sessions

Namjae Jeon <[email protected]>
Newsgroups org.kernel.vger.linux-cifs
Message-ID <[email protected]>
Previous-session replacement marks the old session expired but retains its
SMB3 encryption key. An in-flight encrypted request can still arrive on
that connection. Rejecting the expired session before decryption made ksmbd
treat the request as a key failure and abort the transport, causing
reconnect failures.

Allow key lookup for expired sessions that have encryption enabled. Keep
the session reference during validation so the normal
STATUS_USER_SESSION_DELETED response is encrypted with the old key. The
session remains expired and no command is executed.

Fixes: fa9415d4024f ("ksmbd: mark SMB2_SESSION_EXPIRED to session when destroying previous session")
Signed-off-by: Namjae Jeon <[email protected]>
---
 fs/smb/server/auth.c    | 12 ++++++------
 fs/smb/server/smb2pdu.c |  8 ++++++++
 2 files changed, 14 insertions(+), 6 deletions(-)

diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index bcd371f5550d..78491b20897e 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -724,15 +724,15 @@ static int ksmbd_get_encryption_key(struct ksmbd_work *work, __u64 ses_id,
 		sess = work->sess;
 	else {
 		/*
-		 * An encrypted SESSION_SETUP request may reauthenticate an expired
-		 * Kerberos session.  Keep using the established decryption key so
-		 * that the command can reach the session setup handler. Other
-		 * commands are rejected there with STATUS_NETWORK_SESSION_EXPIRED.
+		 * A previous-session replacement leaves the old encryption key in
+		 * place.  Use it to authenticate an encrypted request, then let
+		 * session validation reject the expired session.  This preserves the
+		 * encrypted STATUS_USER_SESSION_DELETED response without reviving
+		 * the session.
 		 */
 		sess = ksmbd_session_lookup_all_states(work->conn, ses_id);
 		if (sess && sess->state != SMB2_SESSION_VALID &&
-		    (sess->state != SMB2_SESSION_EXPIRED ||
-		     !sess->kerberos_expiry)) {
+		    (sess->state != SMB2_SESSION_EXPIRED || !sess->enc)) {
 			ksmbd_user_session_put(sess);
 			sess = NULL;
 		}
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index ade16532a8c1..8d06c934f24f 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -1012,6 +1012,14 @@ int smb2_check_user_session(struct ksmbd_work *work)
 				1 : -EKEYEXPIRED;
 		}
 		if (work->sess->state != SMB2_SESSION_VALID) {
+			/*
+			 * Keep the reference for an encrypted request so the caller can
+			 * return STATUS_USER_SESSION_DELETED encrypted with the old key.
+			 */
+			if (work->encrypted &&
+			    work->sess->state == SMB2_SESSION_EXPIRED &&
+			    work->sess->enc)
+				return -ENOENT;
 			ksmbd_user_session_put(work->sess);
 			work->sess = NULL;
 			return -ENOENT;
-- 
2.25.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.