summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNamjae Jeon <linkinjeon@kernel.org>2026-07-02 21:16:50 +0900
committerSteve French <stfrench@microsoft.com>2026-07-06 07:55:41 -0500
commitf49bca41c12f9f79d39dbf0779d0c672d74b09fe (patch)
tree0060685838586ec07542ff0305f6df807ff7b07c
parent3e67423336f08a28e9efaac66e842210f9421484 (diff)
ksmbd: use the session dialect for rejected binding signatures
When an SMB3 session is referenced by a binding request on an SMB2.1 connection, the request is signed with the existing session's SMB3 signing algorithm. ksmbd instead verifies it with the new connection's SMB2.1 HMAC algorithm, so verification fails and the client receives STATUS_ACCESS_DENIED instead of STATUS_REQUEST_NOT_ACCEPTED. Select the signing verifier from the referenced session dialect. Permit a signed SESSION_SETUP without an established channel to use the SMB3 session signing key for verification. This is limited to SESSION_SETUP so other unbound requests remain rejected. The rejected response must use the same existing session algorithm. When an SMB3 session is referenced on an SMB2.1 connection, sign the SESSION_SETUP response with the SMB3 signing path rather than the connection's SMB2.1 path. This fixes smb2.session.bind_negative_smb3to2s. Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
-rw-r--r--fs/smb/server/server.c10
-rw-r--r--fs/smb/server/smb2pdu.c16
2 files changed, 21 insertions, 5 deletions
diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c
index bc861ca4f0cc..f5baba934840 100644
--- a/fs/smb/server/server.c
+++ b/fs/smb/server/server.c
@@ -243,8 +243,14 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
if (work->sess &&
(work->sess->sign || smb3_11_final_sess_setup_resp(work) ||
- conn->ops->is_sign_req(work, command)))
- conn->ops->set_sign_rsp(work);
+ conn->ops->is_sign_req(work, command))) {
+ if (command == SMB2_SESSION_SETUP_HE &&
+ work->sess->dialect >= SMB30_PROT_ID &&
+ conn->dialect < SMB30_PROT_ID)
+ smb3_set_sign_rsp(work);
+ else
+ conn->ops->set_sign_rsp(work);
+ }
} while (is_chained == true);
send:
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 123ba63b2410..b73167785e87 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -2015,10 +2015,16 @@ int smb2_sess_setup(struct ksmbd_work *work)
(req->Flags & SMB2_SESSION_REQ_FLAG_BINDING)) {
sess = ksmbd_session_lookup_slowpath(le64_to_cpu(req->hdr.SessionId));
if (sess) {
+ int sign_ret;
+
work->sess = sess;
+ if (sess->dialect >= SMB30_PROT_ID)
+ sign_ret = smb3_check_sign_req(work);
+ else
+ sign_ret = smb2_check_sign_req(work);
if (sess->state != SMB2_SESSION_VALID ||
!(req->hdr.Flags & SMB2_FLAGS_SIGNED) ||
- !conn->ops->check_sign_req(work)) {
+ !sign_ret) {
ksmbd_user_session_put(sess);
work->sess = NULL;
sess = NULL;
@@ -9681,9 +9687,13 @@ int smb3_check_sign_req(struct ksmbd_work *work)
} else {
chann = lookup_chann_list(work->sess, conn);
if (!chann) {
- return 0;
+ if (le16_to_cpu(hdr->Command) != SMB2_SESSION_SETUP_HE ||
+ !(hdr->Flags & SMB2_FLAGS_SIGNED))
+ return 0;
+ signing_key = work->sess->smb3signingkey;
+ } else {
+ signing_key = chann->smb3signingkey;
}
- signing_key = chann->smb3signingkey;
}
if (!signing_key) {