]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ksmbd: handle channel binding with a different user
authorNamjae Jeon <linkinjeon@kernel.org>
Thu, 2 Jul 2026 11:07:25 +0000 (20:07 +0900)
committerSteve French <stfrench@microsoft.com>
Mon, 6 Jul 2026 12:55:41 +0000 (07:55 -0500)
When an authenticated user tries to bind a channel to a session owned by a
different user, ksmbd returns STATUS_LOGON_FAILURE. Windows instead rejects
this attempt with STATUS_ACCESS_DENIED. The supplied credentials are valid
but cannot be used with the existing session.

Use a distinct internal error for a user mismatch in both NTLM and Kerberos
authentication and map it to STATUS_ACCESS_DENIED during SESSION_SETUP.
Keep ordinary authentication failures mapped to STATUS_LOGON_FAILURE.

A failed SMB 3.1.1 binding also leaves its preauthentication context on the
connection. A subsequent binding attempt for the same session reuses the
stale hash and derives an incorrect channel signing key. Remove the binding
preauthentication context on failure so a valid retry starts with a fresh
hash.

This fixes smb2.session.bind_different_user.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/auth.c
fs/smb/server/smb2pdu.c

index 2c7096a782daa358ed287daefc70391de9a3dc63..4e7b6f0e6b8cd88f67e1c41eda826dd3601a679c 100644 (file)
@@ -451,7 +451,7 @@ int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
        } else {
                if (!ksmbd_compare_user(sess->user, user)) {
                        ksmbd_debug(AUTH, "different user tried to reuse session\n");
-                       retval = -EPERM;
+                       retval = -EKEYREJECTED;
                        ksmbd_free_user(user);
                        goto out;
                }
index a8665054151e2f5a2bbaea4cd7748d44a43d9c02..1f51b7d68de166f60135fe2ff09247be87412dd6 100644 (file)
@@ -1734,7 +1734,7 @@ static int ntlm_authenticate(struct ksmbd_work *work,
 
                if (!ksmbd_compare_user(sess->user, user)) {
                        ksmbd_free_user(user);
-                       return -EPERM;
+                       return -EKEYREJECTED;
                }
                ksmbd_free_user(user);
        } else {
@@ -1845,7 +1845,8 @@ static int krb5_authenticate(struct ksmbd_work *work,
                                         out_blob, &out_len, auth_key);
        if (retval) {
                ksmbd_debug(SMB, "krb5 authentication failed\n");
-               retval = -EINVAL;
+               if (retval != -EKEYREJECTED)
+                       retval = -EINVAL;
                goto out;
        }
 
@@ -2139,6 +2140,8 @@ out_err:
                rsp->hdr.Status = STATUS_INSUFFICIENT_RESOURCES;
        else if (rc == -EOPNOTSUPP)
                rsp->hdr.Status = STATUS_NOT_SUPPORTED;
+       else if (rc == -EKEYREJECTED)
+               rsp->hdr.Status = STATUS_ACCESS_DENIED;
        else if (rc)
                rsp->hdr.Status = STATUS_LOGON_FAILURE;
 
@@ -2148,6 +2151,16 @@ out_err:
        }
 
        if (rc < 0) {
+               if (sess && (req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
+                       struct preauth_session *preauth_sess;
+
+                       preauth_sess = ksmbd_preauth_session_lookup(conn, sess->id);
+                       if (preauth_sess) {
+                               list_del(&preauth_sess->preauth_entry);
+                               kfree(preauth_sess);
+                       }
+               }
+
                /*
                 * SecurityBufferOffset should be set to zero
                 * in session setup error response.