From d8fc4fc7e57fc2bfd45699a10ee0df8ab9dccfa5 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 16 Aug 2026 13:46:36 +0900 Subject: [PATCH] ksmbd: decrypt requests from expired encrypted sessions 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 --- 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;