Proof/Linux kernel/ksmbd: enforce session signing
The packet decided whether the packet got checked.
KSMBD already stored “this session requires signing” in trusted state. Request processing then used the incoming request’s own SMB2_FLAGS_SIGNED bit to decide whether signature verification ran at all.
SMB2_FLAGS_SIGNEDSMB signing protects the integrity and authenticity of requests inside an established session. KSMBD already holds the required policy state in work->sess->sign, and the incoming SMB2 header carries SMB2_FLAGS_SIGNED. These answer different questions.
| Value | Question it answers | Trust |
|---|---|---|
sess->sign | Does this session require signing? | authenticated session state |
SMB2_FLAGS_SIGNED | Does this request claim to contain a signature? | attacker-controllable metadata |
Once an SMB session requires signing, the server must enforce that policy from authenticated session state. An incoming request may indicate that it carries a signature, but it may never decide whether signing is required.
A secure server consults the first value to decide whether an unsigned plaintext request is allowed at all, and the second to decide whether a present signature needs verification.
Before the accepted patch, __process_request() checked signatures only when the protocol helper reported the request as signed:
if (work->sess && conn->ops->is_sign_req(work, command)) {
ret = conn->ops->check_sign_req(work);
...
}For SMB2, is_sign_req() primarily reflected the packet’s SMB2_FLAGS_SIGNED bit. An attacker able to alter a live plaintext SMB request could clear the bit that would have sent the message through signature verification. Trusted session state said “signing required”; the untrusted message said “this request is not signed” — and thereby skipped the check.
An established session requires signing
Authentication has already happened; policy is set in trusted state.
An on-path actor alters a live plaintext request
Enough control over the SMB/TCP flow to preserve the authenticated session while replacing or modifying a request.
The signed flag is cleared
The request is sent without a valid signature.
Verification never runs
The vulnerable server used the request flag to decide whether to check.
The request reaches command dispatch
With the authority of the existing session — and no cryptographic authentication.
The demonstrated threat model is same-session and on-path, not off-path unauthenticated session takeover.
The original validation used an owned disposable KSMBD environment with signing required, comparing three message shapes inside the same session policy.
Correctly signed
Establishes that valid signed traffic continues to work.
Corrupt signature
Denied — confirming signature verification is active rather than absent.
Unsigned plaintext
Clearing the flag prevents the request from entering check_sign_req() at all.
| Boundary | Result |
|---|---|
| Trusted policy | work->sess->sign says signing is required |
| Attacker-controlled metadata | SMB2 Flags / SMB2_FLAGS_SIGNED |
| Vulnerable decision | Run verification only when the request marks itself signed |
| Consequence | Clearing the flag bypasses the mandatory verification branch |
Untrusted input can describe compliance. It cannot select whether enforcement occurs.
Find the value that should never have had a vote.
Mandatory controls fail quietly when the enforcement decision is wired to the wrong input. The question was not whether KSMBD verified signatures — it does — but what decided whether verification ran.
Source mapping
Trace every input to the branch that decides whether signature verification executes.
Trust-direction hypothesis
Look for a mandatory control gated on packet metadata instead of authenticated state.
Three-shape construction
Compare valid signed, corrupt signed and unsigned plaintext inside one signing-required session.
Skeptic gate
Keep the claim same-session and on-path; the corrupt-signature denial proves verification itself works.
Report and upstream review
Report to the KSMBD maintainers; preserve patch-authorship and review credit.
Mainline commit 2bebf2470af1 separates “signing is required” from “the request is signed.” It computes the request state once:
signed_req = conn->ops->is_sign_req &&
conn->ops->is_sign_req(work, command);Then enforces the session requirement before dispatch:
if (work->sess && work->sess->sign && !work->encrypted &&
!signed_req) {
conn->ops->set_rsp_status(work, STATUS_ACCESS_DENIED);
return SERVER_HANDLER_ABORT;
}Signed requests are still verified whether signing is mandatory or optional. The patch also stops excluding SMB2_OPLOCK_BREAK from signed-request detection:
if ((rcv_hdr2->Flags & SMB2_FLAGS_SIGNED) &&
- command != SMB2_NEGOTIATE_HE &&
- command != SMB2_OPLOCK_BREAK_HE)
+ command != SMB2_NEGOTIATE_HE)
return true;Encrypted requests are a separate case — they have already been authenticated during decryption — and the patch explicitly excludes them from the missing-signature rejection branch.
The accepted commit fixes pre-existing mainline behaviour but does not publish a complete affected-version range, and none is invented here.
| Tag | Fix present | Basis |
|---|---|---|
| Linux 7.1.3 | no | original validation reproduced the issue here |
| v7.2-rc4 | no | public tag containment check |
| v7.2-rc5 | yes | first verified mainline tag containing the fix |
The exact introducing commit was not independently identified during the bounded review. Consumers should verify their own vendor or stable branch directly rather than infer patch presence from this mainline boundary alone. The upstream commit assigns no CVE or CVSS score.
A useful signing regression suite should assert policy from session state, not from incoming message claims. At minimum:
- signing-required session + valid signed request → accepted;
- signing-required session + invalid signed request → rejected;
- signing-required session + unsigned plaintext request → rejected before dispatch;
- signing-optional session + valid signed request → signature still verified;
- signing-optional session + permitted unsigned request → behaviour matches negotiated policy;
- encrypted request → handled through the authenticated encryption path;
- signed
SMB2_OPLOCK_BREAKacknowledgement → normal signature handling applies.
A request can report whether it carries a signature, but the requirement to authenticate that request must come from trusted session policy.
Credit: Reported by Charles Vosburgh, credited upstream through the accepted commit’s Reported-by trailer. The accepted patch was authored by Namjae Jeon and signed into the SMB tree by Steve French. This page preserves that distinction rather than presenting reporting credit as patch authorship.