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: fa9415d402 ("ksmbd: mark SMB2_SESSION_EXPIRED to session when destroying previous session")
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
Namjae Jeon 2026-08-16 13:46:36 +09:00
parent 12a6680ce5
commit d8fc4fc7e5
2 changed files with 14 additions and 6 deletions

View File

@ -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;
}

View File

@ -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;