diff options
| author | Namjae Jeon <linkinjeon@kernel.org> | 2026-08-16 13:46:36 +0900 |
|---|---|---|
| committer | Namjae Jeon <linkinjeon@kernel.org> | 2026-08-17 22:38:25 +0900 |
| commit | d8fc4fc7e57fc2bfd45699a10ee0df8ab9dccfa5 (patch) | |
| tree | bf1e39d08362cfe8b78418e008c6f6b9d9f325ea | |
| parent | 12a6680ce59bcd431730c9f049caddb017964c64 (diff) | |
| download | linux-d8fc4fc7e57fc2bfd45699a10ee0df8ab9dccfa5.tar.gz linux-d8fc4fc7e57fc2bfd45699a10ee0df8ab9dccfa5.zip | |
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 <linkinjeon@kernel.org>
| -rw-r--r-- | fs/smb/server/auth.c | 12 | ||||
| -rw-r--r-- | 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; |
