[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