* [PATCH AUTOSEL 6.18-5.15] ksmbd: skip fallocate for SMB2_CREATE_ALLOCATION_SIZE on a stream handle
[not found] <20261019135441.1420968-1-sashal@kernel.org>
@ 2026-10-19 13:45 ` Sasha Levin
2026-10-19 13:45 ` [PATCH AUTOSEL 6.18-6.12] ksmbd: fix off-by-one rejecting minimal COPYCHUNK query-limits request Sasha Levin
` (21 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:45 UTC (permalink / raw)
To: patches, stable
Cc: Gael Blivet, Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Gael Blivet <gael.blivet@gmail.com>
[ Upstream commit bfdf81c62f4f52a3626ea62db0744def6778e83f ]
smb2_open() calls vfs_fallocate(fp->filp, ...) unconditionally when a
client's CREATE request includes an AllocationSize create context.
For a stream handle, fp->filp refers to the base file's data fork
(streams are xattr-backed on the same underlying file, not separate
files), so this pre-allocates storage on the base file's actual data
instead of doing anything meaningful for the stream -- fallocate has
no applicability to an xattr-backed stream at all.
Skip the fallocate call for stream handles.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Gael Blivet <gael.blivet@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.12.111**. The buggy `vfs_fallocate()` on stream
CREATEs is present here, and the skip is a small, self-contained
correctness fix that applies to this checkout.
## Phase 1: Commit message forensics
**Step 1.1: Subject line**
- Record: **[ksmbd] [skip] skip fallocate for
SMB2_CREATE_ALLOCATION_SIZE on a stream handle**
- Subsystem: ksmbd (in-kernel SMB3 server). Verb “skip” here means “do
not run a VFS operation that does not apply.”
**Step 1.2: Tags**
- Record:
- `Assisted-by: Claude:claude-sonnet-5`
- `Signed-off-by: Gael Blivet <gael.blivet@gmail.com>`
- `Acked-by: Namjae Jeon <linkinjeon@kernel.org>` (on `e360be3d03f77`;
the candidate copy uses `Signed-off-by: Namjae Jeon`)
- `Signed-off-by: Steve French` (on the smb.git copy)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Cc: stable`, or `Link:`
- Absence of `Fixes:`/`Cc: stable` is expected for this review
pipeline
**Step 1.3: Body**
- Record:
- **Bug:** `smb2_open()` always calls `vfs_fallocate(fp->filp,
FALLOC_FL_KEEP_SIZE, …)` when CREATE has an AllocationSize context.
- **Root cause:** For a named-stream handle, `fp->filp` is the **base
file**. Streams are xattr-backed, not separate files.
- **Symptom:** Preallocation (and a level-II oplock break) hits the
base file’s data fork instead of the stream.
- **Failure mode:** Wrong-file disk preallocation; unexpected oplock
break on the base file.
- No stack trace, no version list, no user report.
**Step 1.4: Hidden bug fix?**
- Record: **Yes, this is an explicit bug fix**, not cleanup. Cover
letter for series 8/8: opening a stream with AllocationSize
“fallocates storage on the underlying base file’s actual data.”
## Phase 2: Diff analysis
**Step 2.1: Inventory**
- Record:
- File: `fs/smb/server/smb2pdu.c` only
- Scope: **+16 / −7** (net +9), one function: `smb2_open()`
- Classification: **single-file surgical fix**
**Step 2.2: Code-flow change**
- Record:
- **Before:** If CREATE has `SMB2_CREATE_ALLOCATION_SIZE`, always
`smb_break_all_levII_oplock(work, fp, 1)` then
`vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0, alloc_size)`.
Failures are only debug-logged.
- **After:** Same path, but only when `!ksmbd_stream_fd(fp)`. Stream
handles skip both the oplock break and fallocate.
- Affected path: SMB2 CREATE with AllocationSize on a stream, after
the file is already opened.
**Step 2.3: Bug mechanism**
- Record:
- **Category:** logic / correctness (wrong object for a VFS call),
with resource side effects
- **Mechanism:** Stream fds share the base `struct file`.
`ksmbd_stream_fd()` is `fp->stream.name != NULL`. Stream I/O already
goes through xattrs (`ksmbd_vfs_stream_read`/`_write`); fallocate
has no stream equivalent.
- `FALLOC_FL_KEEP_SIZE` does not change `i_size`, but it **does**
allocate blocks on the base inode and can fill the filesystem.
`vfs_fallocate()` also takes `file_start_write()` and may run for a
long time on a large client-supplied size (bounded by `s_maxbytes`).
**Step 2.4: Fix quality**
- Record:
- Obviously correct: skip a VFS op that cannot apply to an xattr
stream.
- Matches existing stream guards (read/write/copy-chunk).
- Regression risk is **very low**: regular-file CREATE is unchanged;
stream CREATE only stops a harmful no-op-for-the-stream.
- Incomplete vs SET_INFO: `set_file_allocation_info()` in this tree
still fallocates `fp->filp` with no stream check. That does not make
this CREATE skip wrong.
## Phase 3: Git history
**Step 3.1: Blame**
- Record:
- Unconditional fallocate in `smb2_open()` comes from `e8c061917133dd`
(“ksmbd: opencode to avoid trivial wrappers”, 2021-06-22), replacing
`ksmbd_vfs_alloc_size()`.
- That commit **is an ancestor of this HEAD**.
- `ksmbd_stream_fd()` is from `f44158485826c0` (2021-03-16) and is
also an ancestor.
- Bug has been in ksmbd for the lifetime of this 6.12 line.
**Step 3.2: Fixes: tag**
- Record: **N/A** (no `Fixes:`). Introducer is the original CREATE
AllocationSize handling, present since cifsd/`e8c0619`.
**Step 3.3: Related file history**
- Record:
- `a9f106c765c12` — “fix wrong allocation size update in smb2_open()”
(response timing, not this bug).
- `2a4179c99bc6b` — overflow in `set_file_allocation_info()` (already
in this tree).
- `3b41d8b05dc89` — “return requested create allocation size” is
**not** in this tree (`merge-base --is-ancestor` failed). Candidate
parent uses outer-scope `alloc_size`; 6.12 still has a local `loff_t
alloc_size`. Functional hunk still matches.
**Step 3.4: Author**
- Record: Gael Blivet, stream/AAPL/Time Machine work; maintainer Namjae
Jeon acked and applied this patch. Not a drive-by.
**Step 3.5: Dependencies**
- Record:
- Cover: **“None of this depends on or touches the AAPL/Time Machine
feature series.”**
- Needs only `ksmbd_stream_fd()`, which exists here.
- Series is **[PATCH 8/8]**; this hunk does not need patches 1–7.
- `git apply --check` of `e360be3d03f77` on this tree: **Hunk #1
succeeded at 3593 (offset -504 lines).**
## Phase 4: Mailing list / external
**Step 4.1: Original discussion**
- Record:
- `b4 dig -c e360be3d03f77` →
https://patch.msgid.link/20260709000548.66445-9-g.blivet@me.com
- Series: **[PATCH 0/8] ksmbd: follow-up fixes to previously-merged
patches** (2026-07-09)
- Only **v1** found (`b4 dig -a`).
- Namjae Jeon: **“Applied them except 0002, 0005 patch”** — this is
patch 8, so it was applied. No NAK on patch 8. No `Cc: stable` in
review.
**Step 4.2: Recipients (`b4 dig -w`)**
- Record: Gaël Blivet-Bailly, Namjae Jeon, `linux-cifs@vger.kernel.org`.
Maintainer was on To/Cc and acked.
**Step 4.3: Bug report**
- Record: No syzbot/bugzilla. Found by **Sashiko (LLM review)** of
stream-handling code. Related real-world class: namjaejeon/ksmbd#507
(SetInfo/EOF on a stream truncated the **base** file because
`fp->filp` is the base file). Same object-confusion pattern.
**Step 4.4: Series context**
- Record: Eight independent follow-ups. Patch 8 is standalone. Also
listed in the 7.3-rc1 ksmbd pull under alternate-data-stream handling
(`e360be3d03f77`).
**Step 4.5: Stable list**
- Record: lore.kernel.org/stable returned **403**. **UNVERIFIED**
whether stable@ already discussed this; that does not change the
technical verdict.
## Phase 5: Semantic / call-graph
**Step 5.1: Functions**
- Record: `smb2_open()` only. Helper used: `ksmbd_stream_fd()`.
**Step 5.2: Callers**
- Record: `fs/smb/server/smb2ops.c` maps `SMB2_CREATE_HE` → `smb2_open`.
Reachable from any authenticated SMB2 CREATE.
**Step 5.3: Callees**
- Record: `smb2_find_context_vals()`, `smb_break_all_levII_oplock()`,
`vfs_fallocate()`. Stream CREATE still sets `fp->stream.name` via
`smb2_set_stream_name_xattr()` **before** this block (around line
3485).
**Step 5.4: Reachability**
- Record: **Yes, from the network.** Requires:
1. `CONFIG_SMB_SERVER`
2. Share with `KSMBD_SHARE_FLAG_STREAMS`
3. CREATE of `name:stream` plus AllocationSize create context (`AlSi`)
- Windows ADS and macOS resource-fork/Finder streams are the usual
clients. Unprivileged local syscall is not the path; an authenticated
SMB client is.
**Step 5.5: Similar patterns**
- Record: `ksmbd_vfs_read`/`write` already branch on
`ksmbd_stream_fd()`. `ksmbd_vfs_copy_file_ranges()` returns `-EBADF`
for streams. This CREATE fallocate path was the missing guard.
`set_file_allocation_info()` still unguarded in **this** tree.
## Phase 6: This tree (6.12.111)
**Step 6.1: Buggy code present?**
- Record: **Yes.** `fs/smb/server/smb2pdu.c` ~3596–3602:
```3592:3602:fs/smb/server/smb2pdu.c
alloc_size =
le64_to_cpu(az_req->AllocationSize);
ksmbd_debug(SMB,
"request smb2 create allocate size :
%llu\n",
alloc_size);
smb_break_all_levII_oplock(work, fp, 1);
err = vfs_fallocate(fp->filp,
FALLOC_FL_KEEP_SIZE, 0,
alloc_size);
if (err < 0)
ksmbd_debug(SMB,
"vfs_fallocate is failed :
%d\n",
err);
```
- `ksmbd_stream_fd()` is in `fs/smb/server/vfs_cache.h`.
- Candidate SHAs `e360be3d03f77` / `bfdf81c62f4f` are **not** ancestors
of HEAD.
**Step 6.2: Backport difficulty**
- Record: **Clean apply with offset** (`git apply --check` succeeded at
line 3593). Local `loff_t alloc_size` vs later outer-scope
`alloc_size` does not conflict with the wrapped lines.
**Step 6.3: Related fixes already here?**
- Record: No skip of CREATE fallocate for streams. Overflow check in
SET_INFO allocation is a different bug.
## Phase 7: Subsystem context
**Step 7.1**
- Record: **ksmbd (`fs/smb/server`)**, **IMPORTANT** (in-kernel SMB3
server for NAS/shares). Not mm/core, but network-facing and used in
production.
**Step 7.2**
- Record: Actively backported on this branch (many ksmbd fixes in recent
`git log -- fs/smb/server`).
## Phase 8: Impact and risk
**Step 8.1: Who is affected**
- Record: ksmbd users with **streams enabled**, when a client CREATEs a
named stream with AllocationSize. Typical Windows/macOS
interoperability.
**Step 8.2: Trigger**
- Record: Authenticated SMB CREATE of `file:stream` + AllocationSize.
Not every open; common enough for ADS-aware clients. Same client could
already write the file; unique harm is **wrong object** (base file)
and a large fallocate without intending to preallocate the data fork.
**Step 8.3: Failure mode**
- Record:
- Preallocates blocks on the **base file** (`FALLOC_FL_KEEP_SIZE` → no
size change, but real space use).
- Breaks level-II oplocks on the base file (other clients can lose
caching).
- Large `AllocationSize` can run a long `fallocate` under
`file_start_write()` (filesystem write exclusion).
- **Severity: HIGH** for disk/oplock side effects on a NAS; not a
panic/UAF. Not content corruption of existing data.
**Step 8.4: Risk–benefit**
- Record:
- **Benefit:** Stops wrong-file preallocation and spurious oplock
breaks; one `if` around existing code.
- **Risk:** Very low. Stream CREATE AllocationSize currently does the
wrong thing; skipping is the correct xattr-stream behavior.
- **Ratio:** Favorable.
## Phase 9: Synthesis
**Step 9.1: Evidence**
**For:**
- Real wrong-file VFS operation, present since 2021, present in 6.12.111
- User-visible: disk on the base file, oplock disruption
- Small, obviously correct, applies with offset
- `ksmbd_stream_fd()` already here; no AAPL/Time Machine dependency
- Maintainer applied it (patch 8 of 8)
- Same stream/`fp->filp` confusion class as documented user bugs
**Against:**
- No crash/UAF/CVE; found by automated review, not a reporter
- SET_INFO allocation path still unfixed here
- Needs streams share flag
- lore stable search unverified (HTTP 403)
**Step 9.2: Stable rules**
1. Obviously correct and tested? **PASS** — skip is correct; maintainer
applied it.
2. Real bug affecting users? **PASS** — wrong-file fallocate on stream
CREATE.
3. Important (crash/security/corruption/deadlock/etc.)? **PASS** —
unexpected allocation and oplock break on the base file of a network
file server; can consume substantial disk.
4. Small and contained? **PASS** — ~9 lines, one function.
5. No new features/APIs? **PASS**
6. Applies to this tree? **PASS** — `git apply --check` succeeded.
**Step 9.3: Exceptions**
- Record: Not a device-ID/quirk/DT/build/doc exception. Qualifies as a
normal small bugfix.
**Step 9.4: Decision**
Backport to **this** 6.12.111 tree. The bug is here, the helper is here,
the patch applies, and the change only disables a harmful path.
---
### What this solves for 6.12 users
On ksmbd shares with named streams, an SMB2 CREATE of an alternate data
stream that includes AllocationSize currently calls `vfs_fallocate()` on
the **base file**. That can allocate disk and break oplocks on the wrong
object. Streams are xattr-backed; fallocate cannot apply to them.
Skipping it is the correct, minimal fix.
### Verification
- **[Phase 1]** Parsed tags on `e360be3d03f77` / `bfdf81c62f4f` (same
patch-id `8e46981f5116…`); no Fixes/Reported-by/Cc:stable
- **[Phase 2]** Diff: wrap fallocate + oplock break in `if
(!ksmbd_stream_fd(fp))` in `smb2_open()`
- **[Phase 3]** `git blame`: fallocate from `e8c061917133dd` (ancestor);
`ksmbd_stream_fd` from `f44158485826c0` (ancestor)
- **[Phase 3]** `git merge-base --is-ancestor e360be3d03f77 HEAD` → not
in this tree
- **[Phase 3]** `git merge-base --is-ancestor 3b41d8b05dc89 HEAD` →
later alloc_size-field commit not here
- **[Phase 4]** `b4 dig -c e360be3d03f77` → lore msgid
`20260709000548.66445-9-g.blivet@me.com`; series 8/8
- **[Phase 4]** `b4 dig -a`: v1 only; `b4 dig -w`: linux-cifs + Namjae
Jeon
- **[Phase 4]** mbox: Namjae “Applied them except 0002, 0005”; patch 8
applied; no NAK
- **[Phase 4]** Cover: independent of Time Machine/AAPL
- **[Phase 5]** `SMB2_CREATE_HE` → `smb2_open`; streams gated by
`KSMBD_SHARE_FLAG_STREAMS`
- **[Phase 6]** `git describe HEAD` → `p-6.12-3-gc504cf0baa3d8`; `make
kernelversion` → **6.12.111**
- **[Phase 6]** Buggy lines at `smb2pdu.c:3596–3602`; `git apply
--check` succeeded at 3593
- **[Phase 8]** Failure mode: wrong-file preallocation + oplock break;
severity HIGH for ksmbd/NAS, not a panic
- **UNVERIFIED:** stable@ lore search (HTTP 403); whether Windows always
sends AllocationSize on ADS CREATE (bug is still real when it does)
**YES**
fs/smb/server/smb2pdu.c | 23 ++++++++++++++++-------
1 file changed, 16 insertions(+), 7 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index f383d1e5e5cb7..9c5275d3640cc 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -3633,13 +3633,22 @@ int smb2_open(struct ksmbd_work *work)
ksmbd_debug(SMB,
"request smb2 create allocate size : %llu\n",
alloc_size);
- smb_break_all_levII_oplock(work, fp, 1);
- err = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0,
- alloc_size);
- if (err < 0)
- ksmbd_debug(SMB,
- "vfs_fallocate is failed : %d\n",
- err);
+ /*
+ * fp->filp is the base file's data fork for a stream
+ * handle (streams are xattr-backed on the same
+ * underlying file) -- fallocate has no meaning for a
+ * stream and would otherwise pre-allocate storage on
+ * the base file's data instead.
+ */
+ if (!ksmbd_stream_fd(fp)) {
+ smb_break_all_levII_oplock(work, fp, 1);
+ err = vfs_fallocate(fp->filp, FALLOC_FL_KEEP_SIZE, 0,
+ alloc_size);
+ if (err < 0)
+ ksmbd_debug(SMB,
+ "vfs_fallocate is failed : %d\n",
+ err);
+ }
}
context = smb2_find_context_vals(req, SMB2_CREATE_QUERY_ON_DISK_ID, 4);
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-6.12] ksmbd: fix off-by-one rejecting minimal COPYCHUNK query-limits request
[not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:45 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: skip fallocate for SMB2_CREATE_ALLOCATION_SIZE on a stream handle Sasha Levin
@ 2026-10-19 13:45 ` Sasha Levin
2026-10-19 13:46 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: handle empty QUERY_ALLOCATED_RANGES output Sasha Levin
` (20 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:45 UTC (permalink / raw)
To: patches, stable
Cc: Gael Blivet, Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Gael Blivet <gael.blivet@gmail.com>
[ Upstream commit d68d4b3293034f549d55f407a23b4c0a6c90e50a ]
The FSCTL_COPYCHUNK/FSCTL_COPYCHUNK_WRITE input length check uses
in_buf_len <= sizeof(struct copychunk_ioctl_req), which rejects a
buffer that is exactly sizeof(struct copychunk_ioctl_req) bytes -- the
minimal, valid request containing only the fixed header with
ChunkCount=0 and no chunk entries, used by clients to query the
server's copy limits before issuing a real copychunk.
Since copychunk_ioctl_req ends in a flexible array member, the correct
minimum is that the buffer covers the fixed header, so use
offsetof(..., Chunks) with '<' instead of '<=' against sizeof(): same
value, but the boundary case is now correctly accepted.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Gael Blivet <gael.blivet@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
I have enough to judge this as a one-line protocol check against the
6.12 tree: the buggy `<= sizeof` test is present, the handler already
implements ChunkCount=0, and the patch applies cleanly.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[ksmbd]** **[fix]** off-by-one that rejects a minimal
COPYCHUNK query-limits request (ChunkCount=0, header-only).
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- **Signed-off-by:** Gael Blivet `<gael.blivet@gmail.com>` (author)
- **Signed-off-by:** Namjae Jeon `<linkinjeon@kernel.org>` (ksmbd
maintainer)
- **Assisted-by:** Claude:claude-sonnet-5
- **No Fixes:** tag (expected for this review pipeline)
- **No Cc: stable** (expected)
- **No Reported-by / Tested-by / Reviewed-by / Acked-by / Link:** in the
committed message
- Ignore any pipeline “Upstream commit” / Sasha Levin SOB (none in the
provided message)
Notable: maintainer SOB is a quality signal. No syzbot/KASAN tags.
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** `in_buf_len <= sizeof(struct copychunk_ioctl_req)` rejects a
buffer that is **exactly** the fixed header size.
- **Symptom:** clients sending FSCTL_COPYCHUNK / FSCTL_COPYCHUNK_WRITE
with ChunkCount=0 and no chunk entries (the standard “query server
copy limits” request) get `-EINVAL` / `STATUS_INVALID_PARAMETER`.
- **Root cause:** the struct ends in a flexible array; the minimum valid
length is the fixed header. `sizeof` and `offsetof(..., Chunks)` are
the same numeric value (32); the real change is `<=` → `<` so equality
is accepted.
- **Version info:** none in the message. The FAM conversion that made
`sizeof` equal the header size is in this tree.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: **Not hidden.** Subject/body explicitly describe a protocol off-
by-one. Not cleanup/refactor.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- **File:** `fs/smb/server/smb2pdu.c` — 1 line changed (`<= sizeof(...)`
→ `< offsetof(..., Chunks)`).
- **Function:** `smb2_ioctl()` (`FSCTL_SRV_COPYCHUNK` /
`FSCTL_SRV_COPYCHUNK_WRITE` cases).
- **Scope:** single-file surgical fix, ~1 line.
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- **Before:** reject when `in_buf_len <= 32` → a valid 32-byte header-
only request is rejected; `goto out` with `ret = -EINVAL` **before**
`nbytes` is set, so the client gets an error response **without** the
copychunk limits body.
- **After:** reject only when `in_buf_len < 32` → 32-byte request
proceeds into `fsctl_copychunk()`.
- **Path:** ioctl input-length check (not a crash path). Downstream
`fsctl_copychunk()` already does `if (chunk_count == 0) goto out;`
after filling max chunk count/size/total in the response.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record:
- **Category:** logic / correctness (off-by-one bounds check), protocol
interoperability.
- **Mechanism:** `<=` vs `<` on a FAM struct whose `sizeof` is the
header size. Valid minimum request was treated as too small.
- **Not:** UAF, leak, race, overflow, deadlock.
Verified safety after the change: if a 32-byte buffer lies with
ChunkCount ≠ 0, `fsctl_copychunk()` still rejects via `input_count <
struct_size(ci_req, Chunks, chunk_count)` before touching `Chunks[]`.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- **Obviously correct.** `offsetof` on a FAM is the idiomatic minimum;
verified `sizeof == offsetof == 32` with a packed layout compile.
- **Minimal.** No unrelated changes, no API/struct changes.
- **Regression risk: very low.** Only newly accepted case is `in_buf_len
== 32`, which is the documented header-only request. Inner
ChunkCount=0 path already exists in this tree.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- Current check is from **8bb04fb2b7e34** (“ksmbd: Replace one-element
arrays with flexible-array members”, Thorsten Blum, 2024-08-20; in
v6.12).
- That commit changed `< sizeof` to `<= sizeof` when converting `__u8
Chunks[1]` (sizeof **33**) to a FAM (sizeof **32**), preserving “need
33+ bytes” and thus still rejecting the 32-byte query.
- Original ioctl length check: **f7db8fd03a4bc5** (“ksmbd: add
validation in smb2_ioctl”, 2021-10-08), `in_buf_len < sizeof` with the
1-byte dummy array — also rejected 32-byte requests.
- **Bug has been present since ioctl validation was added (5.16-era
ksmbd), still present in this 6.12 tree.**
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: **No Fixes: tag.** Buggy behavior traces to f7db8fd / 8bb04fb as
above. Both are ancestors of HEAD.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record:
- **0801c1374ab15** — `__counted_by_le` on `copychunk_ioctl_req` (in
this tree); inner `struct_size` check is already correct.
- **8a84ffa455462** — moved copychunk structs to
`fs/smb/common/smb2pdu.h` (in this tree).
- No other local commit already applies this `<=` → `< offsetof` change
(`git log --grep` on the path found nothing).
- **Standalone.** Cover letter: “These 7 fixes are independent of each
other.”
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record:
- Author Gael Blivet has **no** prior commits in this tree’s `fs/smb/`.
- Series: macOS/Time Machine work; this patch is explicitly **not**
Apple-specific.
- **Namjae Jeon** (maintainer) applied the series (except patch 7,
replaced by other ADS copychunk commits).
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record:
- Needs FAM `Chunks[]` so `offsetof(..., Chunks)` is valid — **present**
(8bb04fb).
- Does **not** need later AAPL full-file-copy (`529d203daa00b`, not in
this tree). In 6.12, ChunkCount=0 already means “return limits and
succeed.”
- **Can apply standalone.** `git apply --check` succeeded at offset −857
lines.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- **b4 dig -c fdf17b206bdc8:** match at
https://patch.msgid.link/20260707100033.47512-2-g.blivet@me.com
- **b4 dig -a:** only **v1**; committed version is that v1 (plus later
Assisted-by in the git message).
- Cover: `[PATCH 0/7] ksmbd: assorted fixes found while adding
macOS/Time Machine support` (2026-07-07).
- Author: independent of Apple-specific behavior; this one “affects any
client probing server copy limits with a minimal FSCTL_SRV_COPYCHUNK
request (ChunkCount=0).” Found and verified in live Time
Machine/Finder testing.
- **Namjae Jeon (2026-07-08):** “Applied them to #ksmbd-for-next-next
except 0007 patch.” **No NAK.** No reviewer asked for Cc: stable.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record (**b4 dig -w**): To/Cc were Gaël Blivet-Bailly, **Namjae Jeon**,
**linux-cifs@vger.kernel.org**. Maintainer was the recipient and applied
it. No other Named Reviewed-by.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: no bugzilla/syzbot. Evidence is live macOS Finder/Time Machine
testing described in the cover letter. Linux CIFS client
(`__smb2_copychunk_range`) does **not** send ChunkCount=0; it sends real
chunks and learns limits from `STATUS_INVALID_PARAMETER` + response
body. This bug hits clients that probe with a header-only request (macOS
Finder, and any similar SMB2 client).
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: 7 independent patches. This is 1/7. Patch 7 (ADS copychunk) was
**not** taken; maintainer used other commits. Later AAPL ChunkCount=0
full-file copy is a **feature**, not required here.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable search did not turn up discussion of this
specific fix (WebSearch results were unrelated). No evidence it was
previously rejected for stable.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: IDENTIFY KEY FUNCTIONS**
Record: `smb2_ioctl()` (length check). Downstream: `fsctl_copychunk()`.
**Step 5.2: TRACE CALLERS**
Record: `smb2_ioctl` is `SMB2_IOCTL_HE` in `fs/smb/server/smb2ops.c`.
Reachable from authenticated SMB2/SMB3 clients over the network (not a
local syscall). Interrupt/hot-path: no; file-server request path.
**Step 5.3: TRACE CALLEES**
Record: on success, `fsctl_copychunk()` fills `copychunk_ioctl_rsp` with
`ksmbd_server_side_copy_max_{chunk_count,chunk_size,total_size}()` (256
chunks, ~2GiB), then if ChunkCount==0 returns 0 without copy I/O.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: SMB client → SMB2 IOCTL → `smb2_ioctl` → (currently rejected) /
(after fix) `fsctl_copychunk`. **Reachable from userspace/network** with
a writable share. Unprivileged local users cannot hit it unless they are
SMB clients of ksmbd.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: same FAM conversion also used `<= sizeof` for `smb2_ea_info_req`
(line 4779). That is a **different** request and not this patch. Other
ioctl checks already use `in_buf_len < sizeof` or `offsetof`
(validate_negotiate, sparse, zero-data, etc.).
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: **Yes.** Local tree is **6.12.111** (`pending-6.12`, `git
describe` p-6.12-3-gc504cf0baa3d8). Buggy check is at
`fs/smb/server/smb2pdu.c:8475`. Inner ChunkCount=0 limits path is at
7925–7934. Candidate commit **fdf17b206bdc8 is not** an ancestor of
HEAD.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: **Clean apply** with line-number offset (`git apply --check`:
hunk succeeded at 8472). Context around the COPYCHUNK cases matches. No
conflicting local refactor of this check.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: **No.** `git log --grep='off-by-one rejecting minimal
COPYCHUNK'` on `fs/smb/server/` is empty. No alternate fix of this
comparison.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: **ksmbd** (`fs/smb/server/`), in-kernel SMB3 server.
**IMPORTANT** (not core mm/VFS; not staging). `CONFIG_SMB_SERVER`.
Network-facing; protocol mistakes affect all clients of that server.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: **Active.** Recent 6.12.y ksmbd work is mostly
protocol/security/response-size fixes. Mature enough that this ioctl
check dates to 2021; still getting interoperability fixes.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: **Config-specific + client-specific:** ksmbd servers whose
clients send a 32-byte COPYCHUNK query-limits request. Linux CIFS does
not. macOS Finder does (author’s live testing). Any other SMB2 client
using that probe is affected.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record: Authenticated client, writable share,
FSCTL_SRV_COPYCHUNK(_WRITE) with InputCount=32 and ChunkCount=0.
**Common for macOS file copy / Time Machine-style copychunk probing.**
Not a race. Not triggerable by a random unprivileged local process
unless it is an SMB client.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record:
- **Failure:** `STATUS_INVALID_PARAMETER` and **no** limits payload
(`smb2_set_err_rsp` after `-EINVAL` with nbytes still 0).
- Server-side copy probe fails; clients that require this query cannot
offload copy (fail or fall back to read/write).
- **Not** a panic, UAF, deadlock, or corruption.
- **Severity: MEDIUM** (functional/interop), important for
ksmbd+macOS/Finder, not a kernel crash.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- **Benefit: medium-high for ksmbd users** — restores a path the inner
handler already implements; 1-line; live-tested against real clients.
- **Risk: very low** — equality case only; ChunkCount≠0 still size-
checked; no locking/API change.
- **Ratio:** strongly favors backport.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
**FOR:**
- Real protocol bug: valid header-only COPYCHUNK is rejected; inner
handler already supports ChunkCount=0 query-limits.
- User-visible: macOS Finder/Time Machine testing; any client using that
probe.
- 1-line, obviously correct; sizeof/offsetof verified equal to 32.
- Standalone; maintainer applied it; applies cleanly here.
- Buggy code is in 6.12; candidate is not.
- Downstream access of `Chunks[]` remains guarded.
**AGAINST:**
- Not a crash/security/corruption/deadlock.
- Linux CIFS does not use this probe (Windows often uses oversized-chunk
+ EINVAL).
- Full Time Machine still needs later AAPL work not in 6.12 — but Finder
copychunk probing does not.
- No Fixes:/Cc: stable (expected; not a negative).
**UNRESOLVED:**
- Exact share of Windows versions that send ChunkCount=0 was not
verified against MS-SMB2 traces (author’s claim is “any client” using
that probe; macOS was live-tested).
- lore.kernel.org HTTP fetch returned 403; discussion recovered via `b4
dig -m`.
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — 1-line; maintainer applied;
live Finder/TM testing.
2. Fixes a real bug that affects users? **PASS** — valid SMB2 request
rejected.
3. Important issue? **PASS** — interoperability for server-side copy
(MEDIUM, not panic). For ksmbd this is a real service bug, not
cosmetic.
4. Small and contained? **PASS** — 1 line, one function.
5. No new features or APIs? **PASS** — enables an already-implemented
handler path.
6. Can apply to the local tree? **PASS** — `git apply --check` clean.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: None (not a device ID, quirk, DT, build, or docs fix). Qualifies
as a normal small bugfix.
**Step 9.4: MAKE YOUR DECISION**
This is a surgical protocol off-by-one in ksmbd’s COPYCHUNK ioctl check.
The 6.12 tree still has `in_buf_len <= sizeof(...)`, which rejects the
32-byte query-limits request that `fsctl_copychunk()` already handles.
Benefit is real for ksmbd users with clients that probe that way; risk
is negligible. It meets stable rules for this tree.
### What the commit solves and why it matters here
ksmbd currently turns a spec-valid FSCTL_COPYCHUNK with only the 32-byte
header (ChunkCount=0) into `STATUS_INVALID_PARAMETER` and drops the
limits body. After the fix, that request reaches the existing
ChunkCount=0 path and returns max chunk count/size/total. That is
required for server-side copy probing used by macOS Finder (and similar
clients). On **this** 6.12 tree the bug is present and the later AAPL
full-file-copy feature is not required.
### Risk vs benefit
Benefit: restore working COPYCHUNK limit queries. Risk: one comparison
change; non-zero ChunkCount still validated with `struct_size`. Applies
with a line offset only.
Verification:
- [Phase 1] Parsed tags: SOB Gael Blivet + Namjae Jeon; Assisted-by
Claude; no Fixes/Cc stable/Reported-by
- [Phase 2] Diff: 1 line in `smb2_ioctl` COPYCHUNK cases; `<= sizeof` →
`< offsetof(..., Chunks)`
- [Phase 2] Compile check: packed `sizeof=32` and `offsetof(Chunks)=32`
- [Phase 2] Read `fsctl_copychunk`: ChunkCount==0 already fills limits
and returns 0; non-zero uses `struct_size` before `Chunks[]`
- [Phase 2] Read `smb2_ioctl` `out:`: `-EINVAL` →
`STATUS_INVALID_PARAMETER` via `smb2_set_err_rsp` (no limits body)
- [Phase 3] `git blame`: check from 8bb04fb2b7e34 (FAM); originally
f7db8fd03a4bc5
- [Phase 3] `git merge-base --is-ancestor` 8bb04fb, f7db8fd, 0801c137:
all in HEAD; fdf17b206bdc8 not in HEAD
- [Phase 3] `git log --grep='off-by-one rejecting minimal COPYCHUNK' --
fs/smb/server/`: empty
- [Phase 4] `b4 dig -c fdf17b206bdc8`: lore match
20260707100033.47512-2; cover 0/7; Namjae applied except 0007
- [Phase 4] `b4 dig -a`: v1 only; `b4 dig -w`: maintainer + linux-cifs
- [Phase 4] Cover letter: independent of Apple-specific patches; live
TM/Finder testing
- [Phase 4] stable@ lore search: no hit for this subject
- [Phase 5] Caller: `smb2ops.c` SMB2_IOCTL_HE → `smb2_ioctl`; network
SMB path
- [Phase 5] Linux client `__smb2_copychunk_range` does not send
ChunkCount=0
- [Phase 6] `git describe HEAD`: p-6.12-3-gc504cf0baa3d8; `make
kernelversion`: 6.12.111
- [Phase 6] Buggy line at smb2pdu.c:8475; `git apply --check` succeeded
at 8472
- [Phase 8] Failure: protocol reject of valid COPYCHUNK query, severity
MEDIUM; not a crash
- UNVERIFIED: whether every Windows build sends ChunkCount=0 (not used
to drive the verdict)
**YES**
fs/smb/server/smb2pdu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index d64753124dd9a..9bb885fa1ac66 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -8576,7 +8576,7 @@ int smb2_ioctl(struct ksmbd_work *work)
goto out;
}
- if (in_buf_len <= sizeof(struct copychunk_ioctl_req)) {
+ if (in_buf_len < offsetof(struct copychunk_ioctl_req, Chunks)) {
ret = -EINVAL;
goto out;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: handle empty QUERY_ALLOCATED_RANGES output
[not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:45 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: skip fallocate for SMB2_CREATE_ALLOCATION_SIZE on a stream handle Sasha Levin
2026-10-19 13:45 ` [PATCH AUTOSEL 6.18-6.12] ksmbd: fix off-by-one rejecting minimal COPYCHUNK query-limits request Sasha Levin
@ 2026-10-19 13:46 ` Sasha Levin
2026-10-19 13:46 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: notify parent directory leases on child create Sasha Levin
` (19 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:46 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 7f07791522a251e2be087d11ae9cd51eb3408f1d ]
FSCTL_QUERY_ALLOCATED_RANGES can be issued with a valid input buffer but
without room for an output range. Do not reject the request before
looking at the file layout. If the query would produce a range, return
STATUS_BUFFER_TOO_SMALL. If it produces no ranges, return success with an
empty output.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.12.111** (`pending-6.12`). The buggy `in_count ==
0` path is present here; the upstream fix is not. This is a small, spec-
driven ksmbd protocol fix that applies cleanly.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[ksmbd] [handle] empty QUERY_ALLOCATED_RANGES output** —
“handle” here means correct SMB2 status/output when the client supplies
a valid input buffer but no room for an output range.
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record: Tags on upstream `7f07791522a251e2be087d11ae9cd51eb3408f1d`:
- Signed-off-by: Namjae Jeon `<linkinjeon@kernel.org>` (ksmbd
maintainer; also committer)
- No Fixes:, Reported-by:, Tested-by:, Reviewed-by:, Acked-by:, Link:,
or Cc: stable
- The candidate copy’s `[Upstream commit …]` and `Signed-off-by: Sasha
Levin` were ignored as pipeline markers
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** `FSCTL_QUERY_ALLOCATED_RANGES` is rejected when the output
buffer cannot hold one `FILE_ALLOCATED_RANGE_BUFFER` (16 bytes),
before the file layout is inspected.
- **Symptom:** Client gets a hard `STATUS_INVALID_PARAMETER` instead of
`STATUS_BUFFER_TOO_SMALL` (ranges exist) or success with empty output
(no ranges).
- **Root cause:** Early `if (in_count == 0) return -EINVAL` in
`fsctl_query_allocated_ranges()`.
- **No version range** in the message. Function dates to 2021
(`e2f34481b24db2`).
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not a disguised cleanup. It is an explicit protocol-correctness
fix: wrong NTSTATUS for a documented FSCTL.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `fs/smb/server/smb2pdu.c` — **+12 / −4** (16 lines)
- Function: `fsctl_query_allocated_ranges()` only
- Scope: **single-file surgical fix**
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- **Before:** `in_count == 0` (i.e. `out_buf_len < sizeof(struct
file_allocated_range_buffer)`) returns `-EINVAL` immediately, mapped
in `smb2_ioctl()` to `STATUS_INVALID_PARAMETER`. File is never looked
at.
- **After:** Validate offset/length and look up the file. If `in_count
== 0`, probe with a **stack** dummy range and `in_count=1`. If that
probe fills a range, return `-ENOSPC` (`STATUS_BUFFER_TOO_SMALL` at
line 8701–8702). If it fills nothing, return 0 with `*out_count = 0`.
Non-zero `in_count` is unchanged.
- Path: normal FSCTL handling, not an init/error-only cleanup.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **Logic / protocol correctness**, matching [MS-FSA]
FSCTL_QUERY_ALLOCATED_RANGES:
- `OutputBufferSize < sizeof(FILE_ALLOCATED_RANGE_BUFFER)` **MUST** fail
with `STATUS_BUFFER_TOO_SMALL`
- No allocated ranges → `STATUS_SUCCESS`, `BytesReturned = 0`
- Input `Length == 0` → success with empty output
Using a stack dummy is required: calling `ksmbd_vfs_fqar_lseek()` with
`qar_rsp` and `in_count=1` when the real output buffer is shorter than
16 bytes would write past the ioctl response buffer.
**Step 2.4: ASSESS THE FIX QUALITY**
Record: Obviously correct against MS-FSA and the existing `-ENOSPC` →
`STATUS_BUFFER_TOO_SMALL` mapping. Minimal. Regression risk is low: fd
get/put stay balanced; dummy is on-stack; `*out_count` is forced to 0 on
the empty-output path. Slight error-code change for “bad fid **and**
tiny output buffer” (`-EINVAL` → `-ENOENT`) is more correct.
Verified `git apply --check` on this tree: **hunks apply cleanly**
(offset −891 lines only).
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1: BLAME THE CHANGED LINES**
Record: The `if (in_count == 0) return -EINVAL` lines were introduced in
**`e2f34481b24db2`** (“cifsd: add server-side procedures for SMB3”,
2021-05-10). Present for the entire ksmbd lifetime in this tree.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No Fixes: tag. Introducing commit **is** an ancestor of HEAD
(`git merge-base --is-ancestor e2f34481b24db2 HEAD` succeeded).
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record: Related later mainline work (not in this tree):
- `350684e049851` — dense-file SEEK_DATA handling (`vfs.c`)
- `25e414db70333` — holes / `-E2BIG` overflow (`vfs.c` + `smb2pdu.c`,
larger)
- `3c707d4b3f926` — READ_DATA permission on this FSCTL
Those are **independent** bugs. This patch only changes the zero-output-
buffer gate and does not need them.
Recent 6.12 ksmbd work on the same file includes other buffer-size
protocol fixes already in this tree (`fix partial file information
responses`, `return buffer overflow for partial filesystem info`, `fix
partial normalized name responses`). Same class of bug.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Namjae Jeon is listed in MAINTAINERS as **KERNEL SMB3 SERVER
(KSMBD)** maintainer. This landed in his 7.3-rc1 ksmbd pull (protocol-
compat / smbtorture).
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: Standalone. Calls existing `ksmbd_vfs_fqar_lseek()`. In this
tree that helper still has `if (!in_count) return 0`, which is why the
probe must pass `in_count=1`. No new helpers or struct fields. **Applies
standalone.**
`git merge-base --is-ancestor 7f07791522a251e2be087d11ae9cd51eb3408f1d
HEAD` → not in this tree.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c 7f07791522a251e2be087d11ae9cd51eb3408f1d` failed:
lore.kernel.org returned an error
- WebFetch of lore search URLs returned **403**
- **UNVERIFIED:** v1/v2 revisions, NAKs, reviewer-requested Cc: stable
- Verified via LKML: commit is in **[GIT PULL] ksmbd server update for
7.3-rc1** (Namjae Jeon, 2026-08-23), grouped with protocol-
compatibility fixes “validated with smbtorture” and “allocated-range
queries”
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: **UNVERIFIED** (b4 -w failed with lore). Commit is authored
**and** committed by the ksmbd maintainer.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No syzbot/bugzilla tag. Behavior is specified in [MS-FSA]
2.1.5.10.22: too-small output **MUST** be `STATUS_BUFFER_TOO_SMALL`;
empty result is success. Samba/Windows discussions distinguish that
status from `STATUS_BUFFER_OVERFLOW` (partial fill) and from
`STATUS_INVALID_PARAMETER` (hard fail).
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Sequential maintainer commits around 2026-07-09; next ones
change `vfs.c` for dense files/holes. Not a numbered `N/M` series. This
hunk is self-contained.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: **UNVERIFIED** (lore 403). Absence of Cc: stable is expected for
this pipeline.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1: KEY FUNCTIONS**
Record: `fsctl_query_allocated_ranges()`; helper
`ksmbd_vfs_fqar_lseek()`; dispatcher `smb2_ioctl()`.
**Step 5.2: TRACE CALLERS**
Record:
- Sole caller: `smb2_ioctl()` `case FSCTL_QUERY_ALLOCATED_RANGES`
(`fs/smb/server/smb2pdu.c`)
- `smb2_ioctl` is `SMB2_IOCTL_HE` in `fs/smb/server/smb2ops.c`
- Reachable from authenticated SMB2 clients over the network (not
interrupt context)
**Step 5.3: TRACE CALLEES**
Record: `ksmbd_lookup_fd_fast` / `ksmbd_fd_put`; `ksmbd_vfs_fqar_lseek`
→ `vfs_llseek(SEEK_DATA/SEEK_HOLE)`. Probe uses a stack buffer, not the
response buffer.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Userspace/network client → SMB2 IOCTL →
FSCTL_QUERY_ALLOCATED_RANGES. **Yes, user-triggerable.** `in_count == 0`
when `smb2_calc_max_out_buf_len()` yields `out_buf_len < 16`
(`MaxOutputResponse` 0..15). Linux CIFS often asks for ≥16 bytes
(`smb2ops.c`); Windows/smbtorture can send a smaller max output. That is
a real client pattern for this FSCTL.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Same file already special-cases `-E2BIG` →
`STATUS_BUFFER_OVERFLOW` and `-ENOSPC` → `STATUS_BUFFER_TOO_SMALL`. This
patch is the missing `in_count==0` case of that protocol. Other ksmbd
“too-small output buffer” fixes are already in this 6.12 tree.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: **Yes.** `fs/smb/server/smb2pdu.c` lines 8196–8198:
```8196:8211:fs/smb/server/smb2pdu.c
*out_count = 0;
if (in_count == 0)
return -EINVAL;
...
ret = ksmbd_vfs_fqar_lseek(fp, start, length,
qar_rsp, in_count, out_count);
```
Local version: **6.12.111**. Bug introduced **v5.15-era ksmbd (2021)**.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: **Clean apply** (`git apply --check` succeeded). Surrounding
function matches the upstream pre-image besides line numbers.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No other commit in this tree greps to this subject/behavior.
Dense-file / holes / extra permission commits are **not** ancestors of
HEAD. Not required for this gate-fix.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1: IDENTIFY THE SUBSYSTEM**
Record: **ksmbd** (`fs/smb/server/`). **IMPORTANT** (in-kernel SMB3
server: NAS, OpenWrt, appliances). Not core mm/VFS for all boots;
network-facing for every ksmbd user. `CONFIG_SMB_SERVER` default n.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Actively maintained; many ksmbd protocol fixes already on this
branch.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1: WHO IS AFFECTED**
Record: **Driver/config-specific:** ksmbd (`CONFIG_SMB_SERVER`) serving
`FSCTL_QUERY_ALLOCATED_RANGES` (sparse-file tools, backup, smbtorture,
some Windows APIs).
**Step 8.2: TRIGGER CONDITIONS**
Record: Valid QUERY_ALLOCATED_RANGES input **and** `MaxOutputResponse <
16`. Not every IOCTL; not unprivileged local syscalls except via an SMB
session. Timing-independent.
**Step 8.3: FAILURE MODE SEVERITY**
Record: Wrong NTSTATUS → client treats a sizing/empty query as a **hard
parameter error** instead of retry (`BUFFER_TOO_SMALL`) or empty
success. Can fail sparse-file / backup / torture paths. **MEDIUM**
(functional interoperability, not oops/UAF/corruption).
**Step 8.4: RISK-BENEFIT RATIO**
Record:
- **Benefit:** Medium — restores documented SMB status for a long-
standing ksmbd FSCTL; clients can retry or accept empty results.
- **Risk:** Very low — 16 lines, existing error mapping, stack dummy,
clean apply, no API/locking change.
- **Ratio:** Favorable.
---
## PHASE 9: FINAL SYNTHESIS
**Step 9.1: COMPILE THE EVIDENCE**
**FOR:**
- Real MS-FSA MUST violation: tiny output buffer returns
`STATUS_INVALID_PARAMETER` instead of `STATUS_BUFFER_TOO_SMALL` /
empty success
- User-visible: SMB clients abort instead of retrying or treating the
file as having no ranges
- Present in this 6.12 tree since ksmbd was added
- 16-line surgical change; applies cleanly; no prerequisites
- Maintainer-authored; in 7.3 ksmbd pull as smbtorture protocol-compat
- Dummy buffer avoids a would-be response-buffer overflow
- Same class as buffer-size ksmbd fixes already on this branch
**AGAINST:**
- Not a crash, UAF, security hole, deadlock, or data corruption
- No syzbot/CVE/Reported-by
- Trigger is a small `MaxOutputResponse`, not the Linux CIFS client’s
usual 16+-byte buffer
- Sibling dense-file/holes fixes remain separate (they do not block this
one)
**UNRESOLVED:** lore/b4 review thread (403/server error); no explicit
stable mailing-list discussion.
**Step 9.2: STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — matches MS-FSA; maintainer
commit; smbtorture-oriented 7.3 pull. Direct lore Tested-by
unverified.
2. Fixes a real bug that affects users? **PASS** — wrong NTSTATUS on a
reachable FSCTL.
3. Important issue? **PASS** (MEDIUM-HIGH for a network file server) —
hard client failure vs retryable/empty result; not a panic.
4. Small and contained? **PASS** — one function, +12/−4.
5. No new features or APIs? **PASS**.
6. Can apply to the local tree? **PASS** — buggy code present; `git
apply --check` clean.
**Step 9.3: EXCEPTION CATEGORIES**
Record: None (not a device ID / quirk / DT / build / docs patch).
Qualifies as a normal contained bugfix.
**Step 9.4: DECISION**
Backport to **this** 6.12 tree. The bug exists here, the fix is
standalone and low-risk, and returning the wrong SMB status on
QUERY_ALLOCATED_RANGES is a real interoperability failure for ksmbd
users.
---
### What the commit solves for stable users
On 6.12 ksmbd, a legal `FSCTL_QUERY_ALLOCATED_RANGES` with
`MaxOutputResponse` smaller than one range is failed as
`STATUS_INVALID_PARAMETER` before the file is examined.
Windows/smbtorture expect `STATUS_BUFFER_TOO_SMALL` if ranges exist, or
success with zero output if they do not. That mismatch can abort sparse-
file queries instead of allowing a retry.
### Stable rules / risk
The change is obviously correct, small, and already wired to this tree’s
`-ENOSPC` mapping. It does not need the later dense-file or holes vfs
work. Risk is a slightly different (more accurate) status on a rare
combined bad-fid + tiny-buffer case.
### Verification
- **[Phase 1]** Parsed upstream
`7f07791522a251e2be087d11ae9cd51eb3408f1d`: maintainer SOB only; no
Fixes/Reported-by/Cc stable
- **[Phase 2]** Diff: +12/−4 in `fsctl_query_allocated_ranges()`; dummy
stack probe; `-ENOSPC` when probe fills a range
- **[Phase 2]** Confirmed `smb2_ioctl()` maps `-ENOSPC` →
`STATUS_BUFFER_TOO_SMALL` (lines 8701–8702)
- **[Phase 3]** `git blame`: `in_count == 0` from `e2f34481b24db2`
(2021); ancestor of HEAD
- **[Phase 3]** `git merge-base --is-ancestor 7f077915… HEAD` → not in
this tree
- **[Phase 3]** `git apply --check` of the upstream diff → clean (offset
−891)
- **[Phase 3]** Sibling dense/holes/perms commits exist as objects,
**not** ancestors of HEAD; vfs probe still works with 6.12
`ksmbd_vfs_fqar_lseek`
- **[Phase 4]** `b4 dig` lore error; lore WebFetch 403; LKML 7.3-rc1
ksmbd pull lists this subject
- **[Phase 4]** MS-FSA: too-small output MUST be
`STATUS_BUFFER_TOO_SMALL`
- **[Phase 5]** Only caller is `smb2_ioctl`
FSCTL_QUERY_ALLOCATED_RANGES; dispatched as `SMB2_IOCTL_HE`
- **[Phase 6]** `git describe HEAD` → `p-6.12-3-gc504cf0baa3d8`; `make
kernelversion` → 6.12.111; buggy early `-EINVAL` still present
- **[Phase 7]** MAINTAINERS: Namjae Jeon is ksmbd maintainer
- **[Phase 8]** Failure mode: wrong NTSTATUS / client abort, not oops
- **UNVERIFIED:** lore reviewer comments, Tested-by, explicit stable
nomination
**YES**
fs/smb/server/smb2pdu.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 0fbbb47f94644..c18590d8ee2b9 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -8302,8 +8302,6 @@ static int fsctl_query_allocated_ranges(struct ksmbd_work *work, u64 id,
int ret = 0;
*out_count = 0;
- if (in_count == 0)
- return -EINVAL;
start = le64_to_cpu(qar_req->file_offset);
length = le64_to_cpu(qar_req->length);
@@ -8315,8 +8313,18 @@ static int fsctl_query_allocated_ranges(struct ksmbd_work *work, u64 id,
if (!fp)
return -ENOENT;
- ret = ksmbd_vfs_fqar_lseek(fp, start, length,
- qar_rsp, in_count, out_count);
+ if (!in_count) {
+ struct file_allocated_range_buffer range;
+
+ ret = ksmbd_vfs_fqar_lseek(fp, start, length, &range, 1,
+ out_count);
+ if (!ret && *out_count)
+ ret = -ENOSPC;
+ *out_count = 0;
+ } else {
+ ret = ksmbd_vfs_fqar_lseek(fp, start, length,
+ qar_rsp, in_count, out_count);
+ }
if (ret && ret != -E2BIG)
*out_count = 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: notify parent directory leases on child create
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (2 preceding siblings ...)
2026-10-19 13:46 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: handle empty QUERY_ALLOCATED_RANGES output Sasha Levin
@ 2026-10-19 13:46 ` Sasha Levin
2026-10-19 13:46 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: handle allocated range queries on dense files Sasha Levin
` (18 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:46 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit abe5acb34282206c2a6303d0e09b3165b1addf0e ]
BVT_DirectoryLeasing_ReadWriteHandleCaching requires a parent directory
lease break notification when another client creates a child in the
leased directory. A child CREATE without a lease context did not notify
the parent lease holders because the notification path expected a
non-NULL lease context.
Allow the parent lease notification helper to handle a NULL child lease
context and notify matching parent leases. Invoke it after a child is
created without a lease context while preserving the existing lease-key
filtering for requests that provide one.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.12.111** (`pending-6.12`). Directory leasing is
already advertised here, and this patch fills a hole in that existing
notification path.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[ksmbd] [notify] parent directory leases on child create**
- Subsystem: `ksmbd` (kernel SMB3 server)
- Verb: “notify” — protocol-correctness / missing-event fix, not a
feature add
- Claimed intent: send a parent directory lease break when a child is
created
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Verified from `git log -1 --format='%B' abe5acb342822`:
- **Signed-off-by: Namjae Jeon** `<linkinjeon@kernel.org>` (author and
committer; ksmbd maintainer)
- **No Fixes:** tag (expected for this review pipeline)
- **No Cc: stable** (expected)
- **No Reported-by / Tested-by / Reviewed-by / Acked-by / Link**
- Ignore pipeline-added Sasha Levin SOB / `[Upstream commit …]` if
present on a candidate copy
Notable: maintainer-authored, no external review tags. The body cites
Microsoft BVT `BVT_DirectoryLeasing_ReadWriteHandleCaching`.
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** A child CREATE with no lease context never notifies holders
of a parent directory lease, because
`smb_send_parent_lease_break_noti()` assumed `lctx` was non-NULL.
- **Symptom:** Windows BVT `BVT_DirectoryLeasing_ReadWriteHandleCaching`
fails; SMB3 clients with a directory lease keep a stale directory
cache after another client creates a child.
- **Version info:** None in the message. Introducing code is from
v6.7-rc6 (`d47d9886aeef7`).
- **Root cause:** Notification only ran on CREATE-with-lease-context;
the helper immediately used `lctx->version`.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: **Not a disguised cleanup.** This is an explicit protocol bug
fix: missing lease-break on a common CREATE path. Not a refactor or new
API.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1: INVENTORY THE CHANGES**
Record:
- `fs/smb/server/oplock.c`: +5/−4 in
`smb_send_parent_lease_break_noti()`
- `fs/smb/server/smb2pdu.c`: +3 in `smb2_open()`
- **Scope:** 8 insertions, 4 deletions; single-subsystem surgical fix
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Verified against local `smb_send_parent_lease_break_noti()`
(`fs/smb/server/oplock.c` ~1214) and `smb2_open()` (~3521):
Hunk 1 (helper guard):
- **Before:** `if (lctx->version != 2) return;` — NULL `lctx` would
crash; callers never passed NULL.
- **After:** `if (lctx && lctx->version != 2) return;` — NULL means
“notify matching parent leases”.
Hunk 2 (filter condition):
- **Before:** Always used `lctx->flags` / `lctx->parent_lease_key` to
skip the same parent lease.
- **After:** `!lctx || (existing parent-key filter)` — NULL child
context breaks all active parent directory leases; lease-key filtering
is unchanged when `lctx` is present.
Hunk 3 (`smb2_open`):
- **Before:** Parent notify only inside `if (req_op_level ==
SMB2_OPLOCK_LEVEL_LEASE && lc)`.
- **After:** Also `if (created && !lc)
smb_send_parent_lease_break_noti(fp, NULL);` in the oplocks-enabled
branch.
`created` is set when `smb2_creat()` succeeds (`smb2pdu.c` ~3301–3313).
`lc` is only set when a lease create context is parsed (~3017, ~3061).
The two notify sites are mutually exclusive (`!lc` vs `lc`).
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **[Logic / protocol correctness]** Directory leasing is
advertised (`SMB2_GLOBAL_CAP_DIRECTORY_LEASING` in `smb2ops.c`; docs say
“Directory leases(v2 lease) Supported”). CREATE without a lease context
never broke the parent directory lease. The helper change is a NULL-safe
call convention so that path can notify. Not UAF/leak/race/overflow by
itself; the failure mode is stale client directory cache.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- Obviously correct: short-circuit `!lctx` avoids `lctx->flags` deref;
reuses the existing break helper.
- Minimal; no unrelated edits.
- Regression risk **low**: extra breaks only on real child create with
no lease context, which MS-SMB2 requires. Locking matches the existing
`smb_send_parent_lease_break_noti(fp, lc)` call a few lines later
(`p_ci->m_lock` then `oplock_break_drain_none()`).
- No public API / data-structure change.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- Buggy helper and the lease-context-only call site: **`d47d9886aeef7`**
(“ksmbd: send v2 lease break notification for directory”, Namjae Jeon,
2023-12-08).
- First contained in **`v6.7-rc6`**. Present in this 6.12 tree (`git
merge-base --is-ancestor d47d9886aeef7 HEAD` → yes).
- Directory leasing capability: **`18dd1c367c31d`** (“ksmbd: set v2
lease capability”), also in this tree.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: **No Fixes: tag.** The incomplete behavior was introduced by
`d47d9886aeef7`, which is in this tree.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record:
- Same class already in this tree: `3fc74c65b3674` “send lease break
notification on FILE_RENAME_INFORMATION” (smb2.lease.v2_epoch2);
`7f58458e9db92` “break RH leases before delete-on-close”.
- Later on `all-next`, `0e753899627b5` only changes
`oplock_break_drain_none(&brk_list)` → `(&brk_list, p_ci)` — **already
present locally** via `5de0527f78243`. Not a prerequisite of this
patch.
- `git log all-next -S 'created && !lc'` shows **only** `abe5acb342822`
— no follow-up rewrite of this call.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Namjae Jeon is listed as **KERNEL SMB3 SERVER (KSMBD)**
maintainer in `MAINTAINERS`. Recent local ksmbd lease work includes
lease lookup, RH lease break, lease context validation.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: **Standalone.** Uses existing
`smb_send_parent_lease_break_noti()`, `created`, and `lc`. `git show
abe5acb342822 | git apply --check` **succeeds** on this tree (oplock.c
offset −232, smb2pdu.c offset −1136).
Candidate SHA on `all-next`: **`abe5acb342822`** (in `ksmbd-
for-7.3-rc1`, described as `v7.3-rc1~77^2~20`). **Not** in HEAD.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c abe5acb342822`: lore search returned server errors; **no
thread URL**.
- lore.kernel.org WebFetch: **403**.
- Found via LKML: [GIT PULL] ksmbd server update for 7.3-rc1 (Namjae
Jeon, 2026-08-23) lists this commit and calls out **“parent directory
lease notifications”** among protocol-compatibility fixes.
- Linus merge `61a09cfc12147` uses the same wording.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: No Reviewed-by. Author is the maintainer and committed it to the
ksmbd tree. Recipients of the original mail **unverified** (lore 403 /
b4 failure).
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No syzbot/bugzilla. Trigger is Microsoft BVT
**BVT_DirectoryLeasing_ReadWriteHandleCaching** (Windows protocol test:
client A holds a directory RWH lease; client B creates a child without a
lease context; A must get a break).
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Not labeled `N/M`. Adjacent commits are AppInstanceVersion
takeover / durable reconnect — unrelated. Independent.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: **UNVERIFIED** (lore 403). No evidence it was rejected for
stable. Absence of Cc: stable is expected here.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1: KEY FUNCTIONS**
Record: `smb_send_parent_lease_break_noti()`, `smb2_open()`.
**Step 5.2: TRACE CALLERS**
Record (this tree, `git grep`):
- `smb_send_parent_lease_break_noti` — only `smb2_open()`.
- After the patch: two sites in `smb2_open` (`created && !lc`, and
existing lease-context path).
- `smb2_open` is the SMB2 CREATE handler — authenticated SMB clients.
Related: `smb_lazy_parent_lease_break_close()` on close after write
(`reserve_lease_break`); not this CREATE gap.
**Step 5.3: TRACE CALLEES**
Record: `ksmbd_inode_lookup_lock(parent)`, `down_read(p_ci->m_lock)`,
walk `m_op_list`, `compare_guid_key()`, `oplock_break_add()`,
`oplock_break_drain_none()`, `ksmbd_inode_put()`. Same as today’s
helper.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Userspace SMB2 CREATE → `smb2_open` → (new) parent lease break.
Reachable whenever ksmbd is running with leases/`smb2 leases` and a
client holds a directory lease. Windows 8+ SMB3 clients request
directory leases by default. **Yes, client-triggerable.**
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Same missing-break pattern already fixed for rename
(`3fc74c65b3674`, in this tree). Unlink/close uses
`smb_lazy_parent_lease_break_close`. This patch is the CREATE-without-
lease counterpart.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: **Yes.**
```1221:1236:fs/smb/server/oplock.c
if (lctx->version != 2)
return;
// ...
(!(lctx->flags &
SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE) ||
!compare_guid_key(opinfo, fp->conn->ClientGUID,
lctx->parent_lease_key))) {
```
```3530:3541:fs/smb/server/smb2pdu.c
if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE && lc) {
// ...
smb_send_parent_lease_break_noti(fp, lc);
```
Bug introduced **v6.7** (`d47d9886aeef7`). Capability advertised in
`init_smb3_0_server()` / `init_smb3_02_server()`. Docs: “Directory
leases(v2 lease) Supported.”
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: **Clean apply with offset.** Local helper already has
`oplock_break_drain_none(&brk_list, p_ci)` from `5de0527f78243`; that
line is outside the candidate hunks. `git apply --check` succeeded.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: Rename/delete-on-close lease-break fixes are here. **This
CREATE-without-lease notify is not.** Subject grep found no equivalent.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: **[ksmbd / fs/smb/server] [IMPORTANT]** — in-kernel SMB3 server
for NAS/embedded. Not core VFS; not staging. Config `SMB_SERVER`,
default n.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: **Actively developed.** This pending 6.12 tree already carries
many ksmbd protocol and lease fixes (partial responses, RH lease break,
lease context validation, oplock UAF). Mature enough that directory
leasing has been “Supported” since ~6.7.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: **Config/driver-specific:** `CONFIG_SMB_SERVER` with SMB2 leases
and SMB3 directory leasing. Affects Windows/SMB3 clients that cache
directories against ksmbd.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record:
- Client A holds a v2 directory lease.
- Client B creates a child **without** a lease create context (`created
&& !lc`).
- Common for a second client or simple SMB CREATE; exactly the BVT
setup.
- Authenticated SMB client, not a local unprivileged syscall.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: **Stale directory cache / protocol violation.** Not
oops/deadlock/fs corruption. Clients can miss newly created names until
some other break. **Severity: MEDIUM** (interoperability / user-visible
wrong directory contents), same class as the rename lease-break fix
already in this tree.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- **Benefit:** High for ksmbd+Windows SMB3: advertised directory leasing
actually invalidates on child create.
- **Risk:** Very low — ~8 lines, existing helper, applies cleanly, no
new locks/APIs.
- **Ratio:** Favor backport.
---
## PHASE 9: FINAL SYNTHESIS
**Step 9.1: COMPILE THE EVIDENCE**
**FOR:**
- Real protocol bug in **advertised** directory leasing (docs +
`SMB2_GLOBAL_CAP_DIRECTORY_LEASING`).
- User-visible: stale Windows directory cache; Microsoft BVT failure.
- Buggy code in this 6.12 tree since v6.7.
- Small, obviously correct, applies cleanly.
- Same class as `3fc74c65b3674` already in this tree.
- Maintainer-authored; in `ksmbd-for-7.3-rc1` as a protocol-
compatibility fix.
- No extra prerequisites.
**AGAINST:**
- Not a crash, UAF, or security issue.
- No Fixes:/Cc: stable (expected; not a negative).
- No public user bugzilla; test-suite driven.
- `SMB_SERVER` is optional.
**UNRESOLVED:** Original lore review thread (b4/lore 403). No NAK found
in the 7.3-rc1 pull.
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — logic is clear; cited BVT;
maintainer committed it.
2. Fixes a real bug that affects users? **PASS** — missing required
lease break; stale listings.
3. Important issue? **PASS** at protocol-correctness / “oh, that's not
good” — not CRITICAL crash, but user-visible on an advertised file-
server feature. Matches other ksmbd lease-break backports in this
tree.
4. Small and contained? **PASS** — 2 files, ~8 lines.
5. No new features or APIs? **PASS** — completes existing notify helper;
no new uAPI.
6. Can apply to the local tree? **PASS** — `git apply --check`
succeeded.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: None (not a device ID/quirk/DT/build/docs exception). Qualifies
as a normal contained bugfix.
**Step 9.4: MAKE YOUR DECISION**
This should be backported to **this 6.12 tree**. Directory leasing is
already on; CREATE without a lease context is a hole in the existing
break path; the fix is tiny and applies cleanly. Treating it as a new
feature would be wrong: the feature is already shipped and documented as
supported.
---
## What the commit solves (and why it matters here)
On 6.12, ksmbd advertises SMB3 directory leasing. Parent breaks were
only sent when the **child CREATE included a lease context**. A second
client creating a file the usual way (no lease context) left the
directory lease intact, so Windows clients could keep a cached listing
that omitted the new name. That fails
`BVT_DirectoryLeasing_ReadWriteHandleCaching` and breaks real SMB3
directory caching.
The patch (1) lets the existing helper accept `lctx == NULL` and break
active parent leases, and (2) calls it after a successful create when
`!lc`. Lease-key filtering for CREATE-with-lease is unchanged.
## Risk vs benefit
Benefit is correct directory invalidation for ksmbd users with
Windows/SMB3 clients. Risk is extra lease breaks only when a child is
actually created — required by the protocol. No new locking scheme; same
helper already used in `smb2_open`.
## Concerns
- Context offset vs mainline (`oplock_break_drain_none` already takes
`p_ci` here) — **does not block apply**.
- Remaining gap (pre-existing): CREATE with a **v1** lease still returns
early (`lctx->version != 2`). This patch correctly does not expand
that; it only adds the NULL-context path the BVT hits.
- Not a panic/UAF; still appropriate because this tree already backports
the same kind of ksmbd lease-break completeness fixes.
---
## Verification
- **[Phase 1]** `git log -1 --format='%B' abe5acb342822`: only Namjae
SOB; BVT named; no Fixes/Cc/Reported-by.
- **[Phase 1]** `git describe HEAD` / Makefile: **p-6.12-3 / 6.12.111**.
- **[Phase 2]** Read local `smb_send_parent_lease_break_noti` and
`smb2_open`; confirmed NULL deref assumption and lease-context-only
call.
- **[Phase 2]** Confirmed `created` set after `smb2_creat`; `lc` only
from `parse_lease_state`.
- **[Phase 3]** `git blame`: helper/call site from `d47d9886aeef7`
(2023-12-08); `git describe --contains` → **v6.7-rc6**.
- **[Phase 3]** `git merge-base --is-ancestor d47d9886aeef7 HEAD` → yes;
`abe5acb342822` → **not** in HEAD.
- **[Phase 3]** `git show abe5acb342822 | git apply --check --verbose` →
both files apply (offsets −232 / −1136).
- **[Phase 3]** `git log all-next -S 'created && !lc'` → only this
commit; no follow-up.
- **[Phase 4]** `b4 dig -c abe5acb342822` → lore errors, no match.
- **[Phase 4]** WebFetch lore.kernel.org → 403.
- **[Phase 4]** LKML GIT PULL 7.3-rc1 lists this commit; merge
`61a09cfc12147` mentions parent directory lease notifications.
- **[Phase 5]** `git grep smb_send_parent_lease_break_noti` → only
`smb2_open` + declaration.
- **[Phase 5]** `smb2ops.c`: `SMB2_GLOBAL_CAP_DIRECTORY_LEASING` set for
SMB3.0/3.02 when leases enabled.
- **[Phase 6]** Docs `ksmbd.rst`: “Directory leases(v2 lease)
Supported.”
- **[Phase 6]** Similar fix `3fc74c65b3674` is already an ancestor of
HEAD.
- **[Phase 7]** `MAINTAINERS`: Namjae Jeon is ksmbd maintainer.
- **[Phase 8]** Failure mode verified from code + BVT name: stale
directory lease, not a kernel oops.
- **UNVERIFIED:** Original lore review comments / NAKs (lore
unavailable). Not used to drive the verdict; maintainer merge is
verified.
The fix is small, applies to this tree, and closes a real hole in
advertised SMB3 directory leasing.
**YES**
fs/smb/server/oplock.c | 9 +++++----
fs/smb/server/smb2pdu.c | 3 +++
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
index 08e3e4504b03f..7d78d4ae43acb 100644
--- a/fs/smb/server/oplock.c
+++ b/fs/smb/server/oplock.c
@@ -1271,7 +1271,7 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
struct ksmbd_inode *p_ci = NULL;
LIST_HEAD(brk_list);
- if (lctx->version != 2)
+ if (lctx && lctx->version != 2)
return;
p_ci = ksmbd_inode_lookup_lock(fp->filp->f_path.dentry->d_parent);
@@ -1284,9 +1284,10 @@ void smb_send_parent_lease_break_noti(struct ksmbd_file *fp,
continue;
if (opinfo->o_lease->state != SMB2_OPLOCK_LEVEL_NONE &&
- (!(lctx->flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE) ||
- !compare_guid_key(opinfo, fp->conn->ClientGUID,
- lctx->parent_lease_key))) {
+ (!lctx ||
+ (!(lctx->flags & SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE) ||
+ !compare_guid_key(opinfo, fp->conn->ClientGUID,
+ lctx->parent_lease_key)))) {
if (!atomic_inc_not_zero(&opinfo->refcount))
continue;
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index e7b1cab45ab2d..7d9c8246edfd6 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -3565,6 +3565,9 @@ int smb2_open(struct ksmbd_work *work)
goto err_out1;
}
} else {
+ if (created && !lc)
+ smb_send_parent_lease_break_noti(fp, NULL);
+
if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE && lc) {
if (S_ISDIR(file_inode(filp)->i_mode)) {
lc->req_state &= ~SMB2_LEASE_WRITE_CACHING_LE;
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-6.1] ksmbd: handle allocated range queries on dense files
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (3 preceding siblings ...)
2026-10-19 13:46 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: notify parent directory leases on child create Sasha Levin
@ 2026-10-19 13:46 ` Sasha Levin
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: report actual xattr value length in stream enumeration Sasha Levin
` (17 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:46 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 350684e0498512d06963858b810101f58563810b ]
FSCTL_QUERY_ALLOCATED_RANGES currently relies on SEEK_DATA and SEEK_HOLE
for every file. That works for files with holes, but it is not a good
match for dense files.
A zeroed range in a dense file may be represented as an unwritten extent
and skipped by SEEK_DATA. The server can then return no allocated ranges
even though the file should still be treated as allocated from the
protocol point of view.
For dense files, report the requested range clipped to EOF as allocated
instead of probing holes. Keep using SEEK_DATA and SEEK_HOLE for files
marked with FILE_ATTRIBUTE_SPARSE_FILE, and wait for writeback before
probing so punch-hole updates are visible to the filesystem seek
implementation.
This fixes the case where a query after zeroing data could return no
ranges for a dense file.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
Connection lost, reconnecting to https://agentn.us.api5.cursor.sh
(attempt 1)...
Retry attempt 1...
Local tree is **6.12.111** (`pending-6.12`). The buggy
`ksmbd_vfs_fqar_lseek()` path is in this checkout; the candidate is not.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
Step 1.1: PARSE THE SUBJECT LINE
Record: **[ksmbd] [handle] FSCTL_QUERY_ALLOCATED_RANGES on dense (non-
sparse) files should not use SEEK_DATA/SEEK_HOLE**
Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
Record:
- Signed-off-by: Namjae Jeon \<linkinjeon@kernel.org\> (ksmbd
maintainer)
- No Fixes, Reported-by, Tested-by, Reviewed-by, Acked-by, Link, or Cc:
stable
- Ignore pipeline markers (none in the provided message besides the
evaluation copy)
- Notable: maintainer-authored; no syzbot/CVE tags
Upstream SHA recovered from GitHub:
`350684e0498512d06963858b810101f58563810b` (Namjae Jeon, 2026-07-11;
+26/-3 in `fs/smb/server/vfs.c`). Merged via ksmbd-for-7.3-rc1.
Step 1.3: ANALYZE THE COMMIT BODY TEXT
Record:
- **Bug:** FSCTL_QUERY_ALLOCATED_RANGES always uses SEEK_DATA/SEEK_HOLE.
After FSCTL_SET_ZERO_DATA on a dense file, ksmbd uses
`FALLOC_FL_ZERO_RANGE`, which can leave unwritten extents. SEEK_DATA
skips those, so the server can return **no allocated ranges**.
- **Symptom:** Protocol-incorrect empty range list after zeroing a dense
file. Copy/backup clients that copy only allocated ranges can skip the
zeroed region and leave **stale data** on the destination.
- **Root cause:** Linux SEEK_DATA treats unwritten extents as holes; SMB
dense files must still be reported as allocated (MS-FSA).
- **Fix:** For non-sparse files, return the request clipped to EOF as
one allocated range. For sparse files, keep SEEK_DATA/SEEK_HOLE and
`file_write_and_wait_range()` first so punch-hole is visible.
- **Versions:** No version listed. Code has been in tree since cifsd
file ops (2021).
Step 1.4: DETECT HIDDEN BUG FIXES
Record: Not a disguised cleanup. Subject “handle” plus body “This fixes
the case where a query after zeroing data could return no ranges” is an
explicit protocol/correctness fix. Extra i_size clipping (`start >=
size`, `!length`, `i_size_read`) is a real underflow/EOF-handling
improvement in the same function.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
Step 2.1: INVENTORY THE CHANGES
Record:
- File: `fs/smb/server/vfs.c` only (+26/-3; GitHub)
- Function: `ksmbd_vfs_fqar_lseek()`
- Scope: single-function surgical change
- `ksmbd_vfs_zero_data()` is **not** modified (only described as context
in the message)
Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
Record:
- **EOF clip (before):** `if (start + length > inode->i_size) length =
inode->i_size - start` using unlocked `inode->i_size`. If `start >
i_size`, length goes negative; the loop then does not run.
- **EOF clip (after):** `size = i_size_read(inode)`; return 0 if `start
>= size` or `!length`; then clip `length` to `size - start`.
- **Dense path (before):** always SEEK_DATA/SEEK_HOLE.
- **Dense path (after):** if `!(m_fattr &
FILE_ATTRIBUTE_SPARSE_FILE_LE)`, write one
`FILE_ALLOCATED_RANGE_BUFFER` for `[query_start, query_length]` and
return.
- **Sparse path (after):** `file_write_and_wait_range(f, start, end-1)`
then the existing SEEK loop.
Step 2.3: IDENTIFY THE BUG MECHANISM
Record:
- **Category:** logic/protocol correctness (allocated-range under-
reporting), plus sparse writeback visibility
- **Mechanism:** `iomap_seek_data()` treats `IOMAP_UNWRITTEN` as a hole
unless pagecache has data (`fs/iomap/seek.c`). `FALLOC_FL_ZERO_RANGE`
on dense files creates unwritten extents → SEEK_DATA returns `-ENXIO`
→ empty SMB range list.
- MS-FSA (FSCTL_QUERY_ALLOCATED_RANGES): if `Open.Stream.IsSparse` is
FALSE, return a single range of the requested offset/length. Win32:
non-sparse files return one entry covering the request.
- Sparse writeback: after punch-hole, seek can see stale extents until
writeback.
Step 2.4: ASSESS THE FIX QUALITY
Record:
- Dense shortcut matches MS-FSA and is easy to verify.
- `in_count` is already rejected as 0 before `ranges[0]` is written.
- `file_write_and_wait_range()` exists in this tree
(`include/linux/fs.h`) and `vfs.c` already includes `linux/fs.h`.
- **Regression risk:** non-sparse files that still have Linux holes
(write-beyond-EOF, sparse attr cleared without materializing) will be
reported as fully allocated. That matches Windows QUERY semantics;
reads still return zeros. Bandwidth can increase for holey non-sparse
files. Later mainline commit `25e414db7033` removed this shortcut for
CIFS FIEMAP (see Phase 3).
- No new API, no lock-order change, no data-structure change.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
Step 3.1: BLAME THE CHANGED LINES
Record:
- SEEK_DATA/SEEK_HOLE loop: `f44158485826c0` (“cifsd: add file
operations”, 2021-03-16; in tree 2021-05-10). Present since ksmbd was
merged.
- `vfs_llseek(..., SEEK_DATA/SEEK_HOLE)`: `067baa9a37b32b` (2022).
- Dense vs sparse zeroing: original `f44158485826c0` already used
PUNCH_HOLE for sparse and ZERO_RANGE for dense. `18e39fb960e6a` added
`FALLOC_FL_KEEP_SIZE`.
- Bug is old, not post-6.12.
Step 3.2: FOLLOW THE FIXES: TAG
Record: No Fixes: tag. Buggy code is the original fqar implementation,
ancestor of HEAD (`git merge-base --is-ancestor f44158485826c0 HEAD`
succeeded).
Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
Record:
- Candidate **not** in this tree (`git merge-base --is-ancestor
350684e0498512d06963858b810101f58563810b HEAD` failed).
- Follow-up **not** in this tree:
`25e414db703334954747cb1b3eedf914b093ff8c` “ksmbd: report holes in
allocated range queries” (2026-07-26, +148/-46, 3 files).
- That follow-up **removes** the dense early-return, renames the helper,
writes real zeros for dense SET_ZERO_DATA, and materializes holes when
clearing sparse. It is a later redesign, not a prerequisite.
- Sibling “handle empty QUERY_ALLOCATED_RANGES output” is also absent;
this patch does not need it (it does not touch `smb2pdu.c`).
- Current `ksmbd_vfs_fqar_lseek()` matches the pre-image of the
candidate; apply is offset-only.
Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
Record: Namjae Jeon is the ksmbd maintainer. Recent local ksmbd work is
protocol/security fixes already on this branch. This commit is
maintainer-authored for 7.3-rc1, listed in the ksmbd pull as smbtorture-
validated protocol compatibility.
Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
Record: Standalone. Uses existing `i_size_read`,
`file_write_and_wait_range`, `FILE_ATTRIBUTE_SPARSE_FILE_LE`,
`ksmbd_vfs_fqar_lseek`. No rename, no new helper. Follow-up is larger
and depends on empty-output handling that 6.12 does not have; this
commit does not.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
Record:
- `b4 dig -c 350684e0498512d06963858b810101f58563810b`: lore.kernel.org
returned errors; no thread URL.
- lore WebFetch: HTTP 403.
- Openwall `[GIT PULL] ksmbd server update for 7.3-rc1` (2026-08-23)
lists this commit among allocated-range / sparse-file protocol fixes
“validated with smbtorture”.
- GitHub commit page confirms the same message and +26/-3 vfs.c diff as
the candidate.
UNVERIFIED: v1/v2 review comments, NAKs, explicit Cc: stable on the
original mail.
Step 4.2: CHECK WHO REVIEWED THE PATCH
Record: Commit has only the author’s SOB (Steve French did not SOB this
one; it went through Namjae’s ksmbd tree). `b4 dig -w` failed with lore
errors.
UNVERIFIED: original To/Cc list.
Step 4.3: SEARCH FOR THE BUG REPORT
Record:
- No Reported-by on the commit.
- 2023 thread “Issues with FIEMAP, xfstests, Samba, ksmbd and CIFS”
(lkml/fsdevel) describes the same class: SET_ZERO_DATA vs
PUNCH_HOLE/ZERO_RANGE and SEEK_DATA/HOLE returning no allocated range.
- MS-FSA: non-sparse → single allocated range of the request.
- Win32 FSCTL_QUERY_ALLOCATED_RANGES: non-sparse output is one entry
covering the requested range.
Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
Record: 7.3-rc1 cluster:
- persist/reject/allow FSCTL_SET_SPARSE
- handle empty QUERY_ALLOCATED_RANGES output
- **this commit**
- later: report holes in allocated range queries (`25e414db7033`)
This function-level change is self-contained. The follow-up replaces the
dense shortcut rather than depending on it.
Step 4.5: CHECK STABLE MAILING LIST HISTORY
Record: lore.kernel.org/stable search not available (403). No evidence
this was rejected for stable.
UNVERIFIED: stable@ discussion.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
Record: `ksmbd_vfs_fqar_lseek()` only.
Step 5.2: TRACE CALLERS
Record: Single caller: `fsctl_query_allocated_ranges()` in
`fs/smb/server/smb2pdu.c`, from `smb2_ioctl()`
`FSCTL_QUERY_ALLOCATED_RANGES`. Userspace/SMB-client reachable (backup,
robocopy, CIFS FIEMAP, smbtorture). Not interrupt context.
Step 5.3: TRACE CALLEES
Record: After the patch: `i_size_read`, `file_write_and_wait_range`
(sparse only), `vfs_llseek(SEEK_DATA/SEEK_HOLE)` (sparse only). Zeroing
still goes through `ksmbd_vfs_zero_data()` →
`vfs_fallocate(FALLOC_FL_ZERO_RANGE)` for dense files.
Step 5.4: FOLLOW THE CALL CHAIN
Record: SMB2 IOCTL (authenticated session, valid file id) →
`fsctl_query_allocated_ranges` → `ksmbd_vfs_fqar_lseek`. Triggered by
normal Windows/Linux SMB clients. Combined with SET_ZERO_DATA on a non-
sparse handle, this is a realistic path.
Step 5.5: SEARCH FOR SIMILAR PATTERNS
Record: CIFS client `smb3_llseek()` already special-cases non-sparse
files (`!(cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)` skips
QUERY_ALLOCATED_RANGES and treats the file as fully allocated) and
flushes before querying. Samba/Windows do the same for dense files.
ksmbd was the outlier.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
Record: Yes. `ksmbd_vfs_fqar_lseek()` at `fs/smb/server/vfs.c` still
always SEEK_DATA/SEEK_HOLE. Dense zeroing still uses
`FALLOC_FL_ZERO_RANGE`. Introduced 2021; this 6.12.111 tree has it.
`query_start` / dense early-return are absent.
Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
Record: **Clean apply with line offset** (function is ~1015 here vs ~947
in the 7.3 pre-image). Surrounding function body matches the candidate
hunk. `file_write_and_wait_range` is present.
Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
Record: No “dense files”, “report holes”, or “empty QUERY_ALLOCATED”
commits in `fs/smb/server/`. Current empty `in_count == 0` still returns
`-EINVAL` in `fsctl_query_allocated_ranges`; unrelated.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
Record: **ksmbd (fs/smb/server)** — SMB3 in-kernel server. **IMPORTANT**
for NAS/embedded/enterprise SMB users; default `n` so not universal. Not
staging.
Step 7.2: ASSESS SUBSYSTEM ACTIVITY
Record: Active on this branch (many recent protocol/security ksmbd
backports). This is long-standing protocol behavior, not a bug in brand-
new 7.3-only code.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
Step 8.1: DETERMINE WHO IS AFFECTED
Record: ksmbd users (`CONFIG_SMB_SERVER`). Dense-file path hits handles
without `FILE_ATTRIBUTE_SPARSE_FILE` (FSCTL_SET_SPARSE off, no fake-
sparse DOS attr). Sparse path (writeback wait) hits sparse files,
including the common fake-fscaps sparse marking.
Step 8.2: DETERMINE THE TRIGGER CONDITIONS
Record:
- Dense bug: SET_ZERO_DATA (or other ZERO_RANGE) then
QUERY_ALLOCATED_RANGES on a non-sparse file, on filesystems where
unwritten extents are SEEK holes (ext4/xfs via iomap).
- Sparse writeback: QUERY after punch-hole before writeback.
- Authenticated SMB client; not unprivileged local syscall except via a
mounted share.
Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
Record:
- Failure: empty allocated-range list for data that SMB considers
allocated (zeros). Copy/backup that skips holes can leave **old
contents** instead of zeros.
- Severity: **HIGH** for data integrity of SMB copy/zero workflows; not
a kernel oops/UAF.
- Sparse stale seek: wrong ranges until writeback; usually zeros-vs-
holes, less severe.
Step 8.4: CALCULATE RISK-BENEFIT RATIO
Record:
- **Benefit:** HIGH for ksmbd dense-file zero+query and Windows-
compatible QUERY; writeback wait is a small sparse correctness win.
- **Risk:** LOW-MEDIUM. ~25 lines, one function. Behavior change: non-
sparse files with Linux holes look fully allocated (MS-FSA-correct;
more network copy of zeros, not stale data). Follow-up `25e414db7033`
later dropped the shortcut for CIFS FIEMAP; that is a later redesign,
not a crash report against this patch.
- Ratio: benefit outweighs risk on this 6.12 tree.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
Step 9.1: COMPILE THE EVIDENCE
FOR:
- Real protocol bug since 2021; present in 6.12.111
- Under-reporting allocated ranges after dense ZERO_RANGE can cause
client copies to skip zeros → stale destination data
- Matches MS-FSA / Win32 / CIFS-client dense handling
- Small, contained, applies cleanly
- iomap SEEK_DATA skipping `IOMAP_UNWRITTEN` verified in this tree
- Sparse `file_write_and_wait_range` is independently correct and kept
in later mainline
- Maintainer patch; listed in 7.3-rc1 ksmbd pull as smbtorture-related
protocol work
- No new features/APIs
AGAINST:
- Not a kernel crash/UAF/deadlock
- Core dense shortcut was removed 15 days later in `25e414db7033`
because CIFS FIEMAP saw holes as allocated
- No Fixes/Reported-by/Reviewed-by (absence expected; review thread
UNVERIFIED due to lore)
- ksmbd is opt-in
UNRESOLVED:
- Original lore review/NAKs (lore 403, b4 dig failed)
- stable@ history
Step 9.2: APPLY THE STABLE RULES CHECKLIST
1. Obviously correct and tested? **PASS** — MS-FSA match; logic is local
and readable. Testing claimed via 7.3-rc1 smbtorture set, not a named
Tested-by.
2. Fixes a real bug that affects users? **PASS** — wrong
QUERY_ALLOCATED_RANGES after zeroing dense files.
3. Important issue? **PASS** — application-level data integrity on
copy/backup after SET_ZERO_DATA, not a panic. Severity HIGH for that
path.
4. Small and contained? **PASS** — one function, ~25 lines.
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — buggy function present; hunk
matches; helpers exist.
Step 9.3: CHECK FOR EXCEPTION CATEGORIES
Record: None (not a device ID/quirk/DT/build/doc exception). Qualifies
as a normal bugfix.
Step 9.4: MAKE YOUR DECISION
This tree still has the 2021 SEEK_DATA-only QUERY path and dense
`FALLOC_FL_ZERO_RANGE`. The patch is the small MS-FSA-correct fix for
empty ranges after zeroing. The later mainline redesign is not a reason
to leave 6.12 returning no ranges; over-reporting allocation is safer
than under-reporting, and the follow-up is a larger 3-file change that
needs other 7.3 ksmbd work.
The problem is protocol-incorrect FSCTL_QUERY_ALLOCATED_RANGES on dense
files after zeroing, which can make copy/backup skip zeros and keep
stale data. It meets stable rules: real user-visible bug, small, no new
API, clean apply on this 6.12 tree. Risk is a Windows-correct change in
reported ranges for holey non-sparse files, not a crash.
Verification:
- [Phase 1] Subject/tags: ksmbd “handle”; only Namjae Jeon SOB; no
Fixes/syzbot
- [Phase 1] Body: empty ranges after zeroing dense files via SEEK_DATA
vs unwritten extents
- [Phase 2] Diff: +26/-3 `ksmbd_vfs_fqar_lseek` only; dense early-return
+ sparse writeback + i_size_read EOF clip
- [Phase 2] `fs/iomap/seek.c`: `IOMAP_UNWRITTEN` skipped by SEEK_DATA
unless pagecache has data
- [Phase 2] MS-FSA: non-sparse returns one range; Win32 docs agree
- [Phase 3] blame: `f44158485826c0` (2021) introduced fqar SEEK loop;
ancestor of HEAD
- [Phase 3] `git merge-base --is-ancestor 350684e04985 HEAD` → not in
this tree
- [Phase 3] follow-up `25e414db7033` not in tree; removes dense
shortcut; not required for this backport
- [Phase 3] current function body matches candidate pre-image (apply
with offset)
- [Phase 4] b4 dig: lore errors, no thread; openwall 7.3-rc1 pull lists
the commit
- [Phase 4] UNVERIFIED: original review comments / stable@
- [Phase 5] only caller `fsctl_query_allocated_ranges` ← SMB2
FSCTL_QUERY_ALLOCATED_RANGES
- [Phase 5] CIFS client already special-cases non-sparse files in
`smb3_llseek()`
- [Phase 6] `git describe HEAD` → `p-6.12-3-gc504cf0baa3d8`; `make
kernelversion` → 6.12.111
- [Phase 6] `file_write_and_wait_range` declared in
`include/linux/fs.h`; `vfs.c` includes `linux/fs.h`
- [Phase 8] Failure mode: empty allocated ranges after dense zero →
skipped copy → stale data; HIGH for that SMB path
**YES**
fs/smb/server/vfs.c | 29 ++++++++++++++++++++++++++---
1 file changed, 26 insertions(+), 3 deletions(-)
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index f894092901bc5..cd0d3c13da3e7 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -1034,7 +1034,8 @@ int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length,
{
struct file *f = fp->filp;
struct inode *inode = file_inode(fp->filp);
- loff_t maxbytes = (u64)inode->i_sb->s_maxbytes, end;
+ loff_t maxbytes = (u64)inode->i_sb->s_maxbytes, end, query_start;
+ loff_t query_length, size;
loff_t extent_start, extent_end;
int ret = 0;
@@ -1050,11 +1051,33 @@ int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length,
if (length > maxbytes || (maxbytes - length) < start)
length = maxbytes - start;
- if (start + length > inode->i_size)
- length = inode->i_size - start;
+ size = i_size_read(inode);
+ if (start >= size)
+ return 0;
+
+ if (!length)
+ return 0;
+
+ if (start + length > size)
+ length = size - start;
*out_count = 0;
+ query_start = start;
+ query_length = length;
end = start + length;
+ if (!(fp->f_ci->m_fattr & FILE_ATTRIBUTE_SPARSE_FILE_LE)) {
+ ranges[0].file_offset = cpu_to_le64(query_start);
+ ranges[0].length = cpu_to_le64(query_length);
+ *out_count = 1;
+ return 0;
+ }
+
+ if (start < end) {
+ ret = file_write_and_wait_range(f, start, end - 1);
+ if (ret)
+ return ret;
+ }
+
while (start < end && *out_count < in_count) {
extent_start = vfs_llseek(f, start, SEEK_DATA);
if (extent_start < 0) {
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-6.6] ksmbd: report actual xattr value length in stream enumeration
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (4 preceding siblings ...)
2026-10-19 13:46 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: handle allocated range queries on dense files Sasha Levin
@ 2026-10-19 13:47 ` Sasha Levin
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] smb/server: cancel async requests when closing connection Sasha Levin
` (16 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:47 UTC (permalink / raw)
To: patches, stable
Cc: Gael Blivet, Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Gael Blivet <gael.blivet@gmail.com>
[ Upstream commit 689f1eb3719d61700b58f984ac8602837f004f8c ]
get_file_stream_info() (FileStreamInformation QUERY_INFO) reported
each enumerated stream's StreamSize/StreamAllocationSize as
stream_name_len -- the byte length of the stream's *name*, not its
data. This is the same bug class already fixed for EndOfFile/
AllocationSize on an open stream handle (ksmbd_stream_eof()), just
missed at this second site: a client enumerating streams sees a size
derived from the name string length instead of the stream's actual
content length, inconsistent with what querying the same stream by
handle reports.
Compute the real value length the same way ksmbd_stream_eof() does,
via ksmbd_vfs_casexattr_len() on the already-known xattr key.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Gael Blivet <gael.blivet@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The patch applies cleanly on this 6.12 tree. I’ll now walk through the
nine-phase analysis and the YES/NO decision.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: `[ksmbd] [report] report actual xattr value length in stream
enumeration`
Subsystem prefix is `ksmbd`. The verb is “report” (correctness: the
server currently reports the wrong length). Intent:
FileStreamInformation must return the stream’s data size, not the xattr
name length.
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record (from the candidate text and from `689f1eb3719d` /
`628ee3ef79ba3`):
- `Assisted-by: Claude:claude-sonnet-5`
- `Signed-off-by: Gael Blivet <gael.blivet@gmail.com>`
- `Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>` (candidate /
ksmbd tree)
- `Acked-by: Namjae Jeon` + `Signed-off-by: Steve French` on
`628ee3ef79ba3`
- No `Fixes:` tag (expected)
- No `Cc: stable` (expected)
- No `Reported-by`, `Tested-by`, `Reviewed-by`, `Link:`
Notable: ksmbd maintainer sign-off/ack. No syzbot. Ignore any pipeline
“Upstream commit” / Sasha Levin SOB.
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** `get_file_stream_info()` (SMB2 QUERY_INFO
`FileStreamInformation`) stores `stream_name_len` in `StreamSize` and
`StreamAllocationSize`. That is the xattr *name* byte length, not the
stream payload length.
- **Symptom:** A client enumerating ADS sees sizes derived from the name
string (`user.DosStream.<name>:$DATA`), inconsistent with MS-FSCC and
with querying the same stream by handle (after the related
`ksmbd_stream_eof()` fix).
- **Failure mode:** Wrong stream sizes to Windows `FindFirstStream` /
copy / backup. Clients that trust `StreamSize` can truncate ADS data.
- **Version info:** None in the message. The buggy assignment dates to
the original cifsd SMB3 code (2021).
- **Root cause:** Name length reused as content size; second site of the
same class as `ksmbd_stream_eof()`.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not disguised. Explicit protocol-correctness fix: report xattr
**value** length instead of **name** length.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `fs/smb/server/smb2pdu.c` only
- Scope: ~16 insertions, 2 deletions; one function
- Function: `get_file_stream_info()`
- Classification: single-file surgical fix
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record (verified against this tree at lines 5173–5175):
- **Before:** After converting the stream name to UTF-16, set
`StreamSize = StreamAllocationSize = stream_name_len`
(`stream_name_len` = xattr name minus `user.DosStream.` prefix, e.g.
`"Zone.Identifier:$DATA"`).
- **After:** Call `ksmbd_vfs_casexattr_len(file_mnt_idmap(fp->filp),
path->dentry, stream_name, strlen(stream_name)+1)`, treat negative as
0, store that as both sizes.
- **Path:** Normal QUERY_INFO `FILE_STREAM_INFORMATION` for each ADS
xattr. Unnamed `::$DATA` still uses `stat.size` (unchanged, correct).
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **Logic / correctness (wrong field used as size).** Not
UAF/leak/race. MS-FSCC `FILE_STREAM_INFORMATION.StreamSize` is “size in
bytes of the stream.” The code used the key name length. Fix queries the
xattr value length via existing `ksmbd_vfs_casexattr_len()` →
`vfs_getxattr(..., NULL, 0)`.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- Obviously correct: same helper already used for stream xattr lookup
(`smb2_set_stream_name_xattr`, EA delete).
- v2 changelog (lore): `strlen(stream_name)+1` so the match is exact,
not a prefix match (`strncasecmp` in `ksmbd_vfs_casexattr_len`).
- Minimal; no API/structure changes.
- Regression risk: low. Extra `listxattr`+size probe per ADS (perf
only). Lookup failure reports size 0 instead of name length (safer).
Does not call `ksmbd_stream_eof()` (that helper is not in this tree).
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- `git blame -L 5174,5175 fs/smb/server/smb2pdu.c` → `e2f34481b24db`
(“cifsd: add server-side procedures for SMB3”, Namjae Jeon, 2021-03-16
/ committed 2021-05-10).
- Bug has been in ksmbd since the driver landed. `git merge-base --is-
ancestor e2f34481b24db HEAD` → yes.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. Introducer is `e2f34481b24db`, present in this
tree.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record:
- Companion on `origin/master`: `a9417bb1889e` (“report actual xattr
value length for stream EndOfFile/AllocationSize”) adds
`ksmbd_stream_eof()`. **Not** in this 6.12 tree (`git merge-base --is-
ancestor a9417bb1889e3 HEAD` failed).
- This enumeration patch does **not** call `ksmbd_stream_eof()`; it
inlines the same `ksmbd_vfs_casexattr_len` pattern.
- Recent local `smb2pdu.c` work is other QUERY_INFO buffer/overflow
fixes; nothing already corrects `StreamSize`.
- Standalone vs series: mailed as patch 3 of a 3-patch v2 set (lock on
`stream_del_pending`, mdssvc log spam, this). Those other two are
independent. This hunk does not need them.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Gael Blivet has no ksmbd commits in this 6.12 tree. On mainline,
a batch of stream/protocol fixes for 7.3-rc1. Maintainer Namjae applied
this immediately.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record:
- Needs `ksmbd_vfs_casexattr_len()` and `file_mnt_idmap()` — both exist
here (`vfs.h:108`, `include/linux/fs.h:2745`, used throughout
`smb2pdu.c`).
- Does **not** require `ksmbd_stream_eof()`.
- `git apply --check` of `689f1eb3719d` succeeded: hunks at 5110 and
5173 (offset −842).
Can apply standalone: **yes**.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c 689f1eb3719d` →
https://patch.msgid.link/20260709165141.2111-3-g.blivet@me.com
- Thread saved to mbox (`b4 dig -m`).
- v1→v2: declare `slen`/`ssize` at function top; pass name length
including NUL (exact match). Applied version is v2.
- Maintainer Namjae Jeon (2026-07-10): “Applied it to #ksmbd-for-next-
next. Thanks!”
- No NAK, no stable nomination in the thread.
- Landed in ksmbd 7.3-rc1 pull (“Correct alternate-data-stream and
named-stream handling”).
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record (`b4 dig -w`): To/Cc Namjae Jeon, `linux-cifs@vger.kernel.org`.
Maintainer applied it.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record:
- No `Reported-by` on the commit.
- GitHub namjaejeon/ksmbd#522 (“Unable to list streams”, 2026-01-07)
notes `dir /r` vs Samba and guesses name/length mixup at the same
lines. That report is about streams **not listing**; this patch only
fixes **size**. I do **not** treat #522 as proof this patch restores
listing. Independently, the size bug is visible in the code.
- Older related ADS bugs (e.g. #507 truncated files on SetInfo/EOF on a
stream) show Windows clients really use stream size/EOF; wrong sizes
are user-visible.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Independent of the lock and mdssvc patches in the same mail.
Companion `a9417bb1889e` (`ksmbd_stream_eof`) is the same bug class on
**open-handle** QUERY_INFO/CREATE. Not in 6.12;
`get_file_standard_info()` here still uses `stat.size` even for stream
FDs. This enumeration site is still wrong on its own and still worth
fixing.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable fetch returned 403. UNVERIFIED whether
stable@ already discussed this. Absence of `Cc: stable` is expected.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**
Record: `get_file_stream_info()`; new calls to
`ksmbd_vfs_casexattr_len()`.
**Step 5.2: TRACE CALLERS**
Record:
- Only caller: `smb2_get_info_file()` switch `FILE_STREAM_INFORMATION`
(`smb2pdu.c:5476-5478`).
- That is the SMB2 QUERY_INFO handler for `FileStreamInformation`
(Windows `FindFirstStreamW` / copy / backup).
- Context: kernel SMB server, network/syscall-equivalent from SMB
clients, not IRQ.
**Step 5.3: TRACE CALLEES**
Record: `ksmbd_vfs_casexattr_len()` (`vfs.c:1775`) lists xattrs,
`strncasecmp` match, `ksmbd_vfs_xattr_len()` → `vfs_getxattr(..., NULL,
0)` for value length. Side effect: extra xattr probes; no lock/API
change.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: SMB client → QUERY_INFO FileStreamInformation →
`get_file_stream_info`. Reachable whenever ksmbd serves a share with ADS
in user xattrs (`user.DosStream.*`). Unprivileged SMB users who can
QUERY_INFO can trigger it.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Same name-vs-value confusion: `fp->stream.size` is xattr
**name** length (`smb2_set_stream_name_xattr` sets `fp->stream.size =
xattr_stream_size`). Mainline `ksmbd_stream_eof()` fixes handle
QUERY_INFO; this patch fixes enumeration. Default `::$DATA` already uses
`stat.size`.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record:
- `git describe HEAD` → `p-6.12-3-gc504cf0baa3d8`
- `make kernelversion` → **6.12.111**
- Branch: `pending-6.12`
- Buggy code is present:
```5173:5175:fs/smb/server/smb2pdu.c
file_info->StreamNameLength = cpu_to_le32(streamlen);
file_info->StreamSize = cpu_to_le64(stream_name_len);
file_info->StreamAllocationSize =
cpu_to_le64(stream_name_len);
```
- Introduced in `e2f34481b24db` (v5.15-era cifsd), long before 6.12.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: `git apply --check` clean with line offset only. Surrounding
`get_file_stream_info` body matches. Expected difficulty: **clean
apply**.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No `ksmbd_stream_eof`, no “xattr value length” commits on
`fs/smb/server/` in this tree. Enumeration still uses `stream_name_len`.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: `fs/smb/server` (ksmbd). **IMPORTANT** for ksmbd deployments
(NAS, embedded SMB), not core mm/VFS. `CONFIG_SMB_SERVER` default n.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Actively backported in this pending-6.12 tree (QUERY_INFO
overflow, UAF, ACL, leases). Mature ADS path since 2021.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: **Driver-specific / config-specific:** ksmbd users,
Windows/macOS clients using ADS (`Zone.Identifier`, Office streams, `dir
/r`, copy/backup).
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record: QUERY_INFO FileStreamInformation on a file with
`user.DosStream.*` xattrs. Common on Windows-facing shares. Unprivileged
SMB users can trigger it. Not a race.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record:
- Failure: wrong `StreamSize`/`StreamAllocationSize` (name length,
typically tens of bytes, not payload size).
- Clients that size ADS copies from enumeration can **truncate stream
data**.
- Not a kernel oops/deadlock.
- Severity: **HIGH** for ADS data integrity / protocol correctness; not
CRITICAL kernel crash.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- **Benefit:** Correct ADS sizes on a path Windows copy/backup uses;
long-standing bug; small fix.
- **Risk:** Very low (~16 lines, existing helper, applies cleanly). Size
0 on xattr lookup failure is conservative.
- **Ratio:** Benefit outweighs risk for this 6.12 tree.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
**FOR:**
- Real, long-standing protocol bug in this tree (since cifsd 2021).
- Wrong ADS size can truncate stream copies (data integrity).
- Surgical, obviously correct; v2 matched `ksmbd_vfs_casexattr_len` NUL-
length convention.
- Maintainer applied it with no objections.
- Helpers exist; `git apply --check` succeeds.
- Does not need `ksmbd_stream_eof()`.
**AGAINST:**
- Not a crash/UAF/CVE.
- `CONFIG_SMB_SERVER` is optional.
- Companion handle-size fix (`a9417bb1889e`) is not in 6.12, so handle
QUERY_INFO still reports `stat.size` for streams; enumeration vs
handle remain inconsistent, but enumeration is independently wrong
today.
- GitHub #522 listing failure is not verified as fixed by this change.
**UNRESOLVED:**
- lore.kernel.org HTTP 403; discussion recovered via `b4` mbox.
- stable@ archives not fetched (403).
- Not verified that Windows copy always uses `StreamSize` rather than
re-querying the handle.
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — maintainer applied v2; logic
matches existing xattr-length helper.
2. Fixes a real bug that affects users? **PASS** — FileStreamInformation
returns name length as stream size; Windows ADS clients hit this
path.
3. Important issue? **PASS** — ADS size lie can truncate stream data;
protocol spec violation on a production SMB server. Not a panic, but
data-integrity for named streams.
4. Small and contained? **PASS** — one function, ~16 lines.
5. No new features or APIs? **PASS** — only fills existing SMB2 fields
correctly.
6. Can apply to the local tree? **PASS** — buggy code present; apply-
check clean.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: None (not a device ID, quirk, DT, build, or docs patch).
Qualifies as a normal contained bugfix.
**Step 9.4: MAKE YOUR DECISION**
This 6.12 tree still reports ADS `StreamSize` as the xattr name length.
The fix is the same `ksmbd_vfs_casexattr_len()` lookup already used in
this tree, applies cleanly, and does not depend on later
`ksmbd_stream_eof()`. That is appropriate for stable: real user-visible
metadata/data-integrity bug, tiny scope, low regression risk.
------------------------------------------------
What the commit solves and why it matters here
------------------------------------------------
On 6.12.111, `get_file_stream_info()` still does
`cpu_to_le64(stream_name_len)` for `StreamSize`/`StreamAllocationSize`.
A stream named `Zone.Identifier` is reported as roughly the length of
`"Zone.Identifier:$DATA"`, not the xattr payload. SMB clients that
enumerate streams and copy using that size can drop ADS content. ksmbd
is used as a kernel SMB3 server; that is a real interoperability and
data-integrity bug, not a cleanup.
------------------------------------------------
Stable rules / risk vs benefit
------------------------------------------------
Meets the rules: small, obviously correct, no new API, applies here.
Benefit is correct ADS sizes on QUERY_INFO; risk is an extra xattr size
probe per stream. Incomplete without the later handle
`ksmbd_stream_eof()` fix, but this site is independently buggy and
independently fixable.
------------------------------------------------
Verification
------------------------------------------------
- [Phase 1] Tags: no Fixes/Cc:stable/Reported-by; SOB Gael Blivet +
Namjae Jeon; Assisted-by Claude.
- [Phase 2] Diff: 16+/2- in `get_file_stream_info()`; replace
`stream_name_len` with `ksmbd_vfs_casexattr_len()` value length.
- [Phase 3] blame 5174-5175 → `e2f34481b24db` (2021); ancestor of HEAD.
- [Phase 3] Companion `a9417bb1889e` (`ksmbd_stream_eof`) **not** in
HEAD; this patch does not call it.
- [Phase 3] `git apply --check` of `689f1eb3719d`: both hunks apply
(offset −842).
- [Phase 4] `b4 dig -c 689f1eb3719d`: lore msgid
`20260709165141.2111-3-g.blivet@me.com`; v2 applied by Namjae
(“Applied it to #ksmbd-for-next-next”).
- [Phase 4] `b4 dig -w`: Namjae + linux-cifs; no NAK.
- [Phase 4] UNVERIFIED: stable@ discussion (HTTP 403).
- [Phase 5] Only caller `smb2_get_info_file` /
`FILE_STREAM_INFORMATION`; helper exists in `vfs.c:1775`.
- [Phase 6] Tree is 6.12.111 (`pending-6.12`); buggy assignment present
at 5174-5175.
- [Phase 6] `file_mnt_idmap` and `ksmbd_vfs_casexattr_len` present.
- [Phase 8] Failure mode: wrong ADS size → possible truncated stream
copy; severity HIGH for ADS integrity, not kernel crash.
- UNVERIFIED: whether GitHub #522 (streams not listed) is the same bug;
not used to drive YES.
**YES**
fs/smb/server/smb2pdu.c | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 9c5275d3640cc..277c03fe2a4e4 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -5166,6 +5166,8 @@ static int get_file_stream_info(struct ksmbd_work *work,
struct kstat stat;
const struct path *path = &fp->filp->f_path;
ssize_t xattr_list_len;
+ ssize_t slen;
+ loff_t ssize;
int nbytes = 0, streamlen, stream_name_len, next, idx = 0;
int buf_free_len;
int ret;
@@ -5227,8 +5229,20 @@ static int get_file_stream_info(struct ksmbd_work *work,
streamlen *= 2;
kfree(stream_buf);
file_info->StreamNameLength = cpu_to_le32(streamlen);
- file_info->StreamSize = cpu_to_le64(stream_name_len);
- file_info->StreamAllocationSize = cpu_to_le64(stream_name_len);
+ /*
+ * stream_name_len is the byte length of the xattr's *name*,
+ * not its value -- same class of bug ksmbd_stream_eof()
+ * (smb2pdu.c) already fixes for EndOfFile/AllocationSize on
+ * a stream handle; this enumeration path needs the same
+ * real xattr value length, not the name length reused as a
+ * size.
+ */
+ slen = ksmbd_vfs_casexattr_len(file_mnt_idmap(fp->filp),
+ path->dentry, stream_name,
+ strlen(stream_name) + 1);
+ ssize = slen < 0 ? 0 : (loff_t)slen;
+ file_info->StreamSize = cpu_to_le64(ssize);
+ file_info->StreamAllocationSize = cpu_to_le64(ssize);
nbytes += next;
buf_free_len -= next;
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-5.15] smb/server: cancel async requests when closing connection
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (5 preceding siblings ...)
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: report actual xattr value length in stream enumeration Sasha Levin
@ 2026-10-19 13:48 ` Sasha Levin
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: allow FSCTL_SET_SPARSE without input buffer Sasha Levin
` (15 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:48 UTC (permalink / raw)
To: patches, stable
Cc: ChenXiaoSong, Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: ChenXiaoSong <chenxiaosong@kylinos.cn>
[ Upstream commit 4fd5bad647bfa45eb86bfd2f03ba1bef3fcd5851 ]
An async request may still be waiting when a connection is closed.
This can stop the connection from closing.
Cancel active async requests before waiting for them to finish.
Suggested-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.12.111** (`p-6.12-3-gc504cf0baa3d8`). The hang is
in this tree: `ksmbd_conn_handler_loop()` waits for `r_count == 0`
without cancelling blocked SMB2_LOCK async work.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
Step 1.1: PARSE THE SUBJECT LINE
Record: **[smb/server (ksmbd)] [cancel] [cancel async requests when
closing connection]**
Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
Record:
- Suggested-by: Namjae Jeon `<linkinjeon@kernel.org>` (ksmbd maintainer;
he asked for this)
- Signed-off-by: ChenXiaoSong `<chenxiaosong@kylinos.cn>` (author)
- Signed-off-by: Namjae Jeon `<linkinjeon@kernel.org>` (maintainer
applied it)
- No Fixes:, Reported-by:, Tested-by:, Reviewed-by:, Link:, or Cc:
stable (absence is expected)
Step 1.3: ANALYZE THE COMMIT BODY TEXT
Record:
- Bug: an async request can still be waiting when the connection closes
- Symptom: connection teardown never finishes (`wait_event` on `r_count`
never wakes)
- Root cause: teardown waits for pending work but does not invoke the
same `cancel_fn` path that SMB2_CANCEL uses
- Version info: none in the message; mechanism is independent of
CHANGE_NOTIFY
Step 1.4: DETECT HIDDEN BUG FIXES
Record: Not a disguised cleanup. It is an explicit hang fix. The series
cover letter says “in preparation for change notify,” but this patch
describes a pre-existing teardown hang. In this 6.12 tree CHANGE_NOTIFY
is still `STATUS_NOT_IMPLEMENTED`; SMB2_LOCK already waits
asynchronously.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
Step 2.1: INVENTORY THE CHANGES
Record:
- File: `fs/smb/server/connection.c` only (~21 lines added)
- New helper: `ksmbd_conn_cancel_async_requests()`
- Call site: `ksmbd_conn_handler_loop()` after
`ksmbd_conn_set_releasing()`, before `wait_event(conn->r_count_q,
...)`
- Scope: single-file surgical fix
Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
Record:
- Before: handler loop exits → set RELEASING → sleep until `r_count ==
0` → disconnect. A worker blocked in `ksmbd_vfs_posix_lock_wait()`
never drops `r_count`.
- After: same path, but first walk `conn->async_requests` under
`request_lock`, mark ACTIVE work `KSMBD_WORK_CANCELLED`, and call
`cancel_fn` so waiters wake and drain.
Step 2.3: IDENTIFY THE BUG MECHANISM
Record:
- Category: hang / stuck kthread (logic/correctness: missing
cancellation on teardown)
- Mechanism: SMB2_LOCK deferred wait holds an `r_count` ref. Teardown
did not call `smb2_remove_blocked_lock()` (`locks_delete_block` +
`locks_wake_up`). Same pattern as existing `smb2_cancel()`. Non-ACTIVE
work is skipped (avoids the known `file_lock` UAF on
CANCELLED/CLOSED).
Step 2.4: ASSESS THE FIX QUALITY
Record:
- Quality: obviously correct; copies the `smb2_cancel()` ACTIVE +
`cancel_fn` pattern
- Regression risk: low. `cancel_fn` under `request_lock` is already how
`smb2_cancel()` works. `cancel_fn` may be NULL (oplock interim work);
the new code checks that. Patch 3 of the series closes a remaining
TOCTOU if `setup_async_work()` runs after this walk; that is a
separate, rarer race, not a reason to reject this patch.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
Step 3.1: BLAME THE CHANGED LINES
Record:
- `wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0)` comes
from `a14c573870a664` (“ksmbd: use wait_event instead of
schedule_timeout()”, Jul 2022)
- `ksmbd_conn_set_releasing()` from `abcc506a9a7197` (2023)
- Async cancel via `cancel_fn` has existed since cifsd
(`e2f34481b24db2`, 2021)
- Buggy teardown wait has been in this lineage for years, including 6.12
Step 3.2: FOLLOW THE FIXES: TAG
Record: No Fixes: tag. Not applicable.
Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
Record:
- Related: `ddb9239828336` / `89ae9df09d2c1` — UAF if `cancel_fn` is
fired on non-ACTIVE deferred locks (already in this tree; this patch
uses the same ACTIVE guard)
- `setup_async_work()` / `release_async_work()` already present
- This commit is not in HEAD (`git log --grep='cancel async requests
when closing'` on `fs/smb/server/` is empty)
Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
Record: ChenXiaoSong has other ksmbd backports in this tree (PDU size,
etc.). Namjae Jeon is the ksmbd maintainer and both suggested and
applied this.
Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
Record: No code dependency on series patch 1 (signing). Patch 3
(`setup_async_work` refuses new async on EXITING/RELEASING) is
complementary, not required for the helper or call site. All symbols
(`KSMBD_WORK_ACTIVE`, `async_requests`, `request_lock`, `cancel_fn`,
`ksmbd_debug(CONN, ...)`) exist here. Standalone apply is viable.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
Record:
- `b4 dig` cannot match a SHA that is not in this checkout (lore search
from `b4` also 403’d)
- Thread recovered from lore mirrors: https://ratatoskr.run/linux-
cifs/2026/07/17307517/t
- Series: `[PATCH v3 0/3] smb/server: fix some bugs in preparation for
change notify support`
- v2→v3: this patch switched to `list_for_each_entry_safe()`
- Namjae: “Applied 0001 and 0002 patch to #ksmbd-for-next-next.” Patch 3
was rewritten separately.
- Later landed in the ksmbd 7.3-rc1 pull as “smb/server: cancel async
requests when closing connection”
- No NAK. No reviewer objection to patch 2.
Step 4.2: CHECK WHO REVIEWED THE PATCH
Record: Suggested-by and applied by Namjae Jeon. Recipients were linux-
cifs / ksmbd maintainers (from the v3 thread).
Step 4.3: SEARCH FOR THE BUG REPORT
Record: No syzbot/bugzilla. Found while implementing CHANGE_NOTIFY;
author states the hang is a pre-existing bug. Trigger is concrete:
disconnect while SMB2_LOCK is deferred.
Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
Record: Patch 1 is unrelated signing. Patch 3/Namjae follow-up (“avoid
registering async requests during connection close”) is a race follow-
up. Patch 2 was applied on its own.
Step 4.5: CHECK STABLE MAILING LIST HISTORY
Record: No useful stable-list hit for this subject. Not previously
rejected for stable (search did not surface a ksmbd discussion of this
patch).
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
Record: added `ksmbd_conn_cancel_async_requests()`; one call from
`ksmbd_conn_handler_loop()`.
Step 5.2: TRACE CALLERS
Record:
- `ksmbd_conn_handler_loop()` is the per-connection kthread (TCP/RDMA
receive loop)
- After loop exit (client drop, PDU error, `ksmbd_conn_alive()` false,
module stop)
Step 5.3: TRACE CALLEES
Record: `spin_lock(request_lock)`, list walk,
`work->cancel_fn(work->cancel_argv)`. For lock waiters,
`smb2_remove_blocked_lock()` → `ksmbd_vfs_posix_lock_unblock()` /
`locks_wake_up()`.
Step 5.4: FOLLOW THE CALL CHAIN
Record: Userspace/SMB client can trigger it: SMB2_LOCK that returns
`FILE_LOCK_DEFERRED` → `setup_async_work(..., smb2_remove_blocked_lock,
...)` → `ksmbd_vfs_posix_lock_wait()` → client disconnect → handler
`wait_event(r_count)`. Reachable from a normal SMB session. In 6.12 the
only long-lived async waiter with `cancel_fn` is SMB2_LOCK
(`smb2_notify()` is a stub; oplock `setup_async_work(in_work, NULL,
NULL)` is immediately released).
Step 5.5: SEARCH FOR SIMILAR PATTERNS
Record: `smb2_cancel()` and `set_close_state_blocked_works()` already
cancel this way. Teardown was the missing caller.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
Record: Yes. `fs/smb/server/connection.c` ~522–524:
```
out:
ksmbd_conn_set_releasing(conn);
/* Wait till all reference dropped to the Server object*/
wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0);
```
`ksmbd_conn_cancel_async_requests` is absent. `r_count` is inc’d in
`queue_ksmbd_work()` and dec’d only when `handle_ksmbd_work()` finishes.
Introduced with `a14c573870a664` (2022), present throughout 6.12.
Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
Record: First hunk (new helper after `ksmbd_conn_try_dequeue_request`)
matches this tree. Second hunk context includes a later
`ksmbd_debug(CONN, "Wait for all pending requests...")` line that 6.12
does not have. Expected difficulty: **minor context tweak** — insert the
one call after `ksmbd_conn_set_releasing(conn)`.
Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
Record: No equivalent cancel-on-close. UAF guards on `smb2_cancel()` are
already here and align with this patch’s ACTIVE check.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
Record: `fs/smb/server` (ksmbd). **IMPORTANT** for systems that enable
`CONFIG_SMB_SERVER`; not core VFS/mm. Default is `n`.
Step 7.2: ASSESS SUBSYSTEM ACTIVITY
Record: Actively developed; many ksmbd stable backports already on this
6.12 branch. The hang itself is old, not a 7.x-only feature bug.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
Step 8.1: DETERMINE WHO IS AFFECTED
Record: ksmbd users (`CONFIG_SMB_SERVER`) who have a client block on
SMB2_LOCK and then drop the connection. Also anyone unloading ksmbd
while such a connection exists (`stop_sessions()` keeps looping until
connections are gone).
Step 8.2: DETERMINE THE TRIGGER CONDITIONS
Record: Byte-range lock conflict + disconnect/network drop. Not every
connection; common SMB clients do use locks. Unprivileged SMB clients on
an exported share can trigger it. Not a tiny race: the waiter is already
parked on `flc_wait`.
Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
Record: Connection kthread sleeps forever in `wait_event`; connection
never fully released; module teardown can stall in `stop_sessions()`.
**Severity: HIGH** (hang / stuck kthread; not a panic, not data
corruption).
Step 8.4: CALCULATE RISK-BENEFIT RATIO
Record:
- Benefit: high for ksmbd — prevents teardown/unload hangs
- Risk: low — ~21 lines, one file, established cancel path
- Ratio: favors backport
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
Step 9.1: COMPILE THE EVIDENCE
FOR:
- Real hang in this 6.12 tree when SMB2_LOCK is deferred across
disconnect
- Small, obviously correct, maintainer-suggested and applied
- Same cancel protocol as `smb2_cancel()`, with the ACTIVE guard already
required here
- No missing types/helpers in this tree
AGAINST:
- Series was framed around CHANGE_NOTIFY (not in 6.12 as a real waiter)
- Follow-up patch 3 not included (rarer TOCTOU)
- ksmbd is config-optional
- No public crash report / syzbot
UNRESOLVED:
- Could not `b4 dig` a local SHA (commit not in this checkout)
- lore.kernel.org fetches returned 403; used ratatoskr/openwall mirrors
instead
- No stable-list discussion found
Step 9.2: APPLY THE STABLE RULES CHECKLIST
1. Obviously correct and tested? **PASS** — mirrors `smb2_cancel()`;
maintainer applied v3
2. Fixes a real bug that affects users? **PASS** — teardown hang on
deferred lock + disconnect
3. Important issue? **PASS** — hang / stuck connection kthread (HIGH)
4. Small and contained? **PASS** — one file, ~21 lines
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — bug present; one-line context
adjustment for missing debug print
Step 9.3: CHECK FOR EXCEPTION CATEGORIES
Record: None (not an ID/quirk/DT/build/docs exception). It is a normal
hang fix.
Step 9.4: MAKE YOUR DECISION
This is a hang fix that belongs on 6.12. The CHANGE_NOTIFY framing is
not a reason to skip it: the waiter that deadlocks teardown is already
SMB2_LOCK. Patch 3 is a nice follow-up, not a prerequisite for this
change to be correct for already-queued async work.
Verification:
- [Phase 1] Parsed tags: Suggested-by/SOB Namjae Jeon; author
ChenXiaoSong; no Fixes/Cc/Reported-by
- [Phase 2] Diff: +21 lines in `connection.c`; helper + one call before
`wait_event`
- [Phase 3] `git describe HEAD` / `make kernelversion`: 6.12.111,
`p-6.12-3-gc504cf0baa3d8`
- [Phase 3] `git blame` on wait path: `a14c573870a664` (2022) introduced
`wait_event` without async cancel
- [Phase 3] `git log --grep='cancel async requests when closing' --
fs/smb/server/`: empty — not in this tree
- [Phase 3] `git merge-base --is-ancestor ddb9239828336 HEAD`: yes —
ACTIVE-state UAF guard already present
- [Phase 3] Confirmed `ksmbd_conn_try_dequeue_request` /
`ksmbd_conn_lock` match insertion context
- [Phase 4] b4 dig on a local SHA: lore 403; candidate commit not in
tree
- [Phase 4] v3 thread: Namjae applied 0001 and 0002; patch 3 rewritten
- [Phase 4] 7.3-rc1 ksmbd pull lists this subject
- [Phase 5] `setup_async_work` callers: `smb2_lock` (real waiter) and
oplock (NULL cancel_fn, immediate release)
- [Phase 5] `smb2_notify()` in this tree returns
`STATUS_NOT_IMPLEMENTED`
- [Phase 6] Local lines 521–524: set_releasing then wait_event, no
cancel
- [Phase 6] Backport: helper applies cleanly; call site needs dropping
unavailable debug context
- [Phase 8] Failure mode verified: `queue_ksmbd_work` incs `r_count`;
lock wait never returns so `ksmbd_conn_r_count_dec` never runs
- UNVERIFIED: original lore.kernel.org HTML (403); no stable@ thread
found
**YES**
fs/smb/server/connection.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c
index 16fcedf45739f..8f1b70e39362e 100644
--- a/fs/smb/server/connection.c
+++ b/fs/smb/server/connection.c
@@ -232,6 +232,26 @@ void ksmbd_conn_try_dequeue_request(struct ksmbd_work *work)
wake_up_all(&conn->req_running_q);
}
+static void ksmbd_conn_cancel_async_requests(struct ksmbd_conn *conn)
+{
+ struct ksmbd_work *work, *tmp;
+
+ ksmbd_debug(CONN, "Cancel pending async requests on releasing connection\n");
+ spin_lock(&conn->request_lock);
+ list_for_each_entry_safe(work, tmp, &conn->async_requests,
+ async_request_entry) {
+ if (work->state != KSMBD_WORK_ACTIVE)
+ continue;
+
+ ksmbd_debug(CONN, "Cancel async request id %d\n",
+ work->async_id);
+ work->state = KSMBD_WORK_CANCELLED;
+ if (work->cancel_fn)
+ work->cancel_fn(work->cancel_argv);
+ }
+ spin_unlock(&conn->request_lock);
+}
+
void ksmbd_conn_lock(struct ksmbd_conn *conn)
{
mutex_lock(&conn->srv_mutex);
@@ -543,6 +563,7 @@ int ksmbd_conn_handler_loop(void *p)
out:
ksmbd_conn_set_releasing(conn);
+ ksmbd_conn_cancel_async_requests(conn);
/* Wait till all reference dropped to the Server object*/
ksmbd_debug(CONN, "Wait for all pending requests(%d)\n", atomic_read(&conn->r_count));
wait_event(conn->r_count_q, atomic_read(&conn->r_count) == 0);
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: allow FSCTL_SET_SPARSE without input buffer
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (6 preceding siblings ...)
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] smb/server: cancel async requests when closing connection Sasha Levin
@ 2026-10-19 13:48 ` Sasha Levin
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: protect private extended attributes Sasha Levin
` (14 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:48 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 86c84cc760080929b7be44bceebe5854957b99da ]
FSCTL_SET_SPARSE without an input buffer sets a file sparse. Treat a
zero-length input buffer as SetSparse=true and keep rejecting truncated
non-empty buffers.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
Local tree is **6.12.111** (`p-6.12-3-gc504cf0baa3d8`). The candidate is
mainline `86c84cc76008` (“ksmbd: allow FSCTL_SET_SPARSE without input
buffer”). It is **not** in this checkout; the overly strict length check
**is**.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[ksmbd] [allow] [accept FSCTL_SET_SPARSE with a zero-length
input buffer]**
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- **Signed-off-by:** Namjae Jeon `<linkinjeon@kernel.org>` (author and,
on GitHub, committer)
- **No** Fixes:, Reported-by:, Tested-by:, Reviewed-by:, Acked-by:,
Link:, or Cc: stable
- Absence of Fixes/Cc: stable is expected for this review pipeline and
is **not** a negative signal
- Ignore any “[Upstream commit …]” / “Signed-off-by: Sasha Levin”
markers if present in candidate prep
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** MS-FSCC FSCTL_SET_SPARSE with no data element must set the
sparse flag (SetSparse=TRUE). ksmbd currently rejects InputCount==0.
- **Symptom:** Client gets an invalid-parameter style failure (`-EINVAL`
from this path) instead of marking the file sparse.
- **Root cause (from message + code):** A length check requires
`in_buf_len >= sizeof(struct file_sparse)` (1 byte), so a spec-legal
empty buffer is treated as truncated.
- **Version info in the message:** none
- **Failure mode:** interoperability / protocol reject, not a kernel
oops
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: **Not disguised cleanup.** Subject says “allow”, but this
restores documented protocol behavior that the 2021 ioctl validation
made too strict. It is a spec-compliance bug fix, not a new API.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- **File:** `fs/smb/server/smb2pdu.c` only (**+8 / −2** upstream)
- **Function:** `smb2_ioctl()`, `case FSCTL_SET_SPARSE:`
- **Scope:** single-file surgical change
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- **Before:** `if (in_buf_len < sizeof(struct file_sparse)) return
-EINVAL;` then pass `buffer` to `fsctl_set_sparse()`.
- **After:** reject only **non-empty truncated** buffers; if `in_buf_len
== 0`, pass a stack `file_sparse` with SetSparse=1; otherwise keep
using the request buffer.
- **Path:** ioctl handling for one FSCTL; not init, not an error-path
leak fix.
Verified current 6.12 code (exact pre-image of the patch):
```8496:8505:fs/smb/server/smb2pdu.c
case FSCTL_SET_SPARSE:
if (in_buf_len < sizeof(struct file_sparse)) {
ret = -EINVAL;
goto out;
}
ret = fsctl_set_sparse(work, id, (struct file_sparse
*)buffer);
if (ret < 0)
goto out;
break;
```
`struct file_sparse` is a packed 1-byte `SetSparse` field
(`fs/smb/server/smb2pdu.h`). `in_buf_len` is
`le32_to_cpu(req->InputCount)` (`unsigned int`). For a 1-byte struct,
`in_buf_len && in_buf_len < 1` is never true; the real behavioral change
is **InputCount == 0**.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record:
- **Category:** logic / protocol correctness (over-strict length check)
- **Mechanism:** 2021 validation blocked the documented empty-buffer
form to avoid reading `SetSparse` from a zero-length buffer. The fix
keeps that OOB protection (does not dereference `buffer` when
`in_buf_len == 0`) and supplies SetSparse=true locally.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- **Obviously correct** vs MS-FSCC 2.3.83 and vs Samba `vfswrap_fsctl()`
(`set_sparse = true` unless `in_len >= 1 && in_data[0] == 0`).
- **Minimal.** No unrelated edits.
- **Regression risk low:** existing 1-byte path unchanged; share/handle
checks in `fsctl_set_sparse()` still apply
(`KSMBD_TREE_CONN_FLAG_WRITABLE` and
`FILE_WRITE_DATA|FILE_WRITE_ATTRIBUTES`, already in this tree via
`c5ab11263e3c8`).
- `*(u8 *)&sparse = 1` is equivalent to `sparse.SetSparse = 1` for this
struct.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- `case FSCTL_SET_SPARSE:` from `e2f34481b24d` (“cifsd: add server-side
procedures for SMB3”, 2021) — **in this tree**
- Length check from `f7db8fd03a4bc5` (“ksmbd: add validation in
smb2_ioctl”, 2021-10-13) — **in this tree**
- Buffer base from `c6cd2e8d2d9aa7` (InputOffset, not `&req->Buffer[0]`)
- Bug has been present for the entire 6.12 lifetime (introduced 2021)
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: **No Fixes: tag.** Introducer of the too-strict check is
`f7db8fd03a4bc5`, present here.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record:
- Same-day mainline series around sparse (2026-07-08), including:
- `159e727f763d` persist FSCTL_SET_SPARSE state
- `31169f41778a` reject FSCTL_SET_SPARSE on directories
- `86c84cc76008` **this** empty-buffer change
- Those other patches change advertisement/persistence and directory
rejection. **This hunk does not use those new structures.**
- Recent 6.12 ksmbd work on `smb2pdu.c` is unrelated (compound/query-
info, leases, etc.).
- **Standalone** for backport of the empty-buffer check.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Namjae Jeon is the **ksmbd maintainer**. Many ksmbd fixes in
this tree are his. That is a strong quality signal, not a substitute for
importance.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record:
- Needs existing `fsctl_set_sparse()`, `struct file_sparse`, and
`in_buf_len` — all present.
- Does **not** require persist-xattr or directory-reject commits.
- `git merge-base --is-ancestor 86c84cc76008 HEAD` → **not an ancestor**
(candidate not in this tree).
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c 86c84cc76008` (and `-a`/`-w`): lore.kernel.org returned an
error; **no thread matched**
- Direct lore fetch: **403 / Anubis bot wall**
- GitHub commit: https://github.com/torvalds/linux/commit/86c84cc7600809
29b7be44bceebe5854957b99da (2026-07-08 / committed 2026-08-17)
- **UNVERIFIED:** reviewer comments, v2/v3, NAKs, in-thread Cc: stable
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: Message has only the author’s SOB. Maintainer self-applied.
**UNVERIFIED** original To/Cc list (`b4 -w` failed).
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No Reported-by/Link. Bug is specified by protocol, not a syzbot
crash.
Verified spec (MS-FSCC 2.3.83): *“The message either has no data
elements at all or it contains a FILE_SET_SPARSE_BUFFER element. If
there is no data element, the sparse flag for the file is set, exactly
as if … SetSparse value of TRUE.”*
Win32 `FSCTL_SET_SPARSE`: *“If the lpInBuffer parameter is NULL, the
operation will behave the same as if … SetSparse … were TRUE.”*
Samba `vfs_default.c`: empty/`in_len==0` → `file_set_sparse(..., true)`.
smbtorture includes `test_ioctl_sparse_set_nobuf`.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Same-day sparse series exists; this patch is the empty-buffer
piece and is **self-contained**. Later `smb2pdu.c` mainline commits
(Aug–Sep 2026) do not revert or retune this hunk.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: **UNVERIFIED** (lore/stable search blocked). No evidence this
was rejected for stable.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**
Record: `smb2_ioctl()` (modified); `fsctl_set_sparse()` (callee,
unchanged by this patch).
**Step 5.2: TRACE CALLERS**
Record:
- `smb2_ioctl` registered as `[SMB2_IOCTL_HE].proc` in
`fs/smb/server/smb2ops.c`
- Reachable from authenticated SMB2 IOCTL over the network
(`CONFIG_SMB_SERVER`)
- Not interrupt context; request path from ksmbd workers
**Step 5.3: TRACE CALLEES**
Record: `fsctl_set_sparse()` looks up the handle, checks writability,
sets/clears `FILE_ATTRIBUTE_SPARSE_FILE_LE`, optionally writes DOS
xattr, `ksmbd_fd_put()`.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: SMB client → SMB2 IOCTL → `smb2_ioctl` → FSCTL_SET_SPARSE.
**Yes, userspace/network reachable.** Linux CIFS client currently sends
a 1-byte buffer (`smb2_set_sparse` → `SMB2_ioctl(..., &setsparse, 1,
...)`), so Linux-to-ksmbd already works. Windows `DeviceIoControl` with
NULL buffer and Samba torture `*_nobuf` hit the broken path.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Other FSCTLs in the same switch still require a non-empty input
struct (`SET_ZERO_DATA`, copychunk, duplicate extents). Only SET_SPARSE
is specified as valid with no data element. No sibling copy-paste of
this empty-buffer rule in 6.12 ksmbd.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: **Yes**, `fs/smb/server/smb2pdu.c` `smb2_ioctl()`
FSCTL_SET_SPARSE case, lines 8496–8505. Introduced 2021
(`f7db8fd03a4bc5`). Local version **6.12.111**.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: Pre-image matches exactly (line numbers ~8496 vs mainline
~9470). **Expected clean apply** with only context offset. No struct/API
mismatch.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record:
- Permission checks: **yes** (`c5ab11263e3c8`)
- Empty-buffer handling: **no**
- Persist/advertise sparse overhaul (`159e727f763d`) and directory
reject (`31169f41778a`): **not in this tree**, and **not required**
for this fix
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: **ksmbd** (`fs/smb/server/`, `CONFIG_SMB_SERVER`). **IMPORTANT**
for SMB server deployments (Windows/macOS clients), not core mm/VFS. Not
staging.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Actively patched in 6.12.y (leases, query-info, durable
reconnect, SET_SPARSE permission). Mature server with ongoing protocol-
correctness backports.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: **Driver/config-specific:** ksmbd (`CONFIG_SMB_SERVER`) users
whose clients send FSCTL_SET_SPARSE with InputCount=0 (Windows NULL
`lpInBuffer`, Samba torture nobuf). Not universal.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record:
- Trigger: SMB2 IOCTL FSCTL_SET_SPARSE with zero InputCount
- Common for **Windows** documented API; **not** the Linux CIFS client
path (sends 1 byte)
- Authenticated client with a writable handle (existing checks)
- Not a race
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record:
- **Failure:** request rejected; file not marked sparse
- **Not** oops, UAF, deadlock, or silent data corruption
- **Severity: MEDIUM** — user-visible protocol break for a documented,
commonly used FSCTL
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- **Benefit:** Windows/spec clients can set sparse the way MS-FSCC and
Samba already do; smbtorture nobuf can pass
- **Risk:** very low (≈10-line ioctl case, no locking/API change, still
go through `fsctl_set_sparse()`)
- **Ratio:** favorable
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
**FOR backporting:**
- Real protocol bug: empty SET_SPARSE must set sparse (MS-FSCC + Win32 +
Samba)
- Buggy length check has been in this tree since 2021
- Small, obviously correct; does not reintroduce the OOB the 2021
validation prevented
- Applies cleanly; no missing helpers
- ksmbd maintainer authored it
- Same class of ksmbd protocol-correctness fixes already land in 6.12.y
- Existing permission checks still gate the operation
**AGAINST:**
- Not a crash, UAF, leak, or CVE-class issue
- No user report / Tested-by / lore review recovered
- Same-day mainline series also changes sparse persistence/advertising;
this patch is the least dependent piece of that work
- Linux CIFS client already sends a 1-byte buffer
- On 6.12, `smb2_get_dos_mode()` still ORs SPARSE onto every regular
file when `share_fake_fscaps` has `FILE_SUPPORTS_SPARSE_FILES`, which
can mask some client need to SET_SPARSE
**UNRESOLVED:**
- Mailing-list review, stable nomination, and whether a newer revision
existed (`b4`/lore blocked)
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — matches MS-FSCC/Samba;
maintainer-authored. No independent Tested-by (typical for this
size).
2. Fixes a real bug that affects users? **PASS** — spec-legal
Windows/Samba requests fail on ksmbd.
3. Important issue? **PASS** (medium) — interoperability failure on a
documented FSCTL, which stable-kernel-rules.rst here also covers as
an “oh, that’s not good” user-visible bug; not a kernel panic.
4. Small and contained? **PASS** — one case in one file, +8/−2.
5. No new features or APIs? **PASS** — does not add a userspace API;
restores required SMB behavior.
6. Can apply to the local tree? **PASS** — pre-image present, would
apply with line-number offset only.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: Not a device-ID/quirk/DT/build/docs exception. Qualifies as a
normal small protocol bugfix.
**Step 9.4: MAKE YOUR DECISION**
This should be backported to **this** 6.12.111 tree. The code the patch
fixes is here, the change is surgical, and rejecting empty
FSCTL_SET_SPARSE is a real Windows/Samba interoperability bug, not a new
feature and not blocked by the later persist-sparse series.
What it solves for stable users: ksmbd no longer returns invalid
parameter when a client sends the documented empty SET_SPARSE request;
the file is marked sparse via the existing `fsctl_set_sparse()` path.
Risk vs benefit: very low risk, clear spec-backed benefit. No extra
commits are required for the empty-buffer path to work here.
===============================================================
Verification
===============================================================
- [Phase 1] Parsed message/tags: only Namjae Jeon SOB; no
Fixes/Reported-by/Cc: stable
- [Phase 2] Diff: +8/−2 in `smb2_ioctl` FSCTL_SET_SPARSE; empty buffer →
stack SetSparse=1; non-empty path unchanged
- [Phase 2] Confirmed `struct file_sparse` is one packed `__u8`;
`in_buf_len` is `unsigned int` from `InputCount`
- [Phase 2] Confirmed `fsctl_set_sparse()` already has share/handle
write checks in this tree (`c5ab11263e3c8`)
- [Phase 3] `git describe HEAD` / Makefile: 6.12.111
(`p-6.12-3-gc504cf0baa3d8`)
- [Phase 3] `git blame`: length check from `f7db8fd03a4bc5` (2021); case
from `e2f34481b24d`; both ancestors of HEAD
- [Phase 3] `git merge-base --is-ancestor 86c84cc76008 HEAD` → not in
this tree
- [Phase 3] Related mainline series (`159e727f763d`, `31169f41778a`) not
required; this hunk is independent
- [Phase 4] `b4 dig -c/-a/-w 86c84cc76008`: lore error, no thread —
UNVERIFIED review
- [Phase 4] GitHub: commit `86c84cc760080929b7be44bceebe5854957b99da`
matches the candidate text
- [Phase 4] MS-FSCC 2.3.83 and Win32 FSCTL_SET_SPARSE: empty/NULL buffer
= SetSparse TRUE
- [Phase 4] Samba `vfswrap_fsctl` FSCTL_SET_SPARSE: `in_len==0` → set
sparse true
- [Phase 5] Caller: `smb2ops.c` SMB2_IOCTL_HE → `smb2_ioctl`; Linux
client sends 1-byte buffer in `smb2_set_sparse()`
- [Phase 6] Local pre-image unique match at `smb2pdu.c` 8496–8505;
expected clean apply
- [Phase 7] Subsystem ksmbd / CONFIG_SMB_SERVER, actively maintained on
this branch
- [Phase 8] Failure: client EINVAL, severity MEDIUM; not oops/UAF
- UNVERIFIED: lore/stable discussion and any mailing-list NAKs (lore
403)
**YES**
fs/smb/server/smb2pdu.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 6b3cf2dadeecd..f383d1e5e5cb7 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -8612,15 +8612,21 @@ int smb2_ioctl(struct ksmbd_work *work)
rsp);
break;
case FSCTL_SET_SPARSE:
- if (in_buf_len < sizeof(struct file_sparse)) {
+ {
+ struct file_sparse sparse = {0};
+
+ if (in_buf_len && in_buf_len < sizeof(struct file_sparse)) {
ret = -EINVAL;
goto out;
}
- ret = fsctl_set_sparse(work, id, (struct file_sparse *)buffer);
+ *(u8 *)&sparse = 1;
+ ret = fsctl_set_sparse(work, id, in_buf_len ?
+ (struct file_sparse *)buffer : &sparse);
if (ret < 0)
goto out;
break;
+ }
case FSCTL_SET_ZERO_DATA:
{
struct file_zero_data_information *zero_data;
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: protect private extended attributes
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (7 preceding siblings ...)
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: allow FSCTL_SET_SPARSE without input buffer Sasha Levin
@ 2026-10-19 13:48 ` Sasha Levin
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: allow I/O on directory named streams Sasha Levin
` (13 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:48 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 4ea46ea602fc7055eee4b5b0e84f90f22da7f7e7 ]
SMB clients can currently create an EA named NTACL because SMB EAs are
mapped into the user namespace while the ksmbd security descriptor is
stored as security.NTACL. Allowing the reserved logical name makes the
server-private ACL metadata appear writable through the SMB EA API.
Reject NTACL, DOSATTRIB, and DosStream-prefixed EA names without regard
to case. Filter the same private names from EA query results so stale or
externally-created user namespace attributes cannot be exposed.
This fixes smb2.ea.acl_xattr when acl_xattr_name is configured as
NTACL.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit message forensics
**Step 1.1 — Subject**
- Record: `[ksmbd] [protect] keep server-private xattr names off the SMB
EA API`
**Step 1.2 — Tags**
- Record: `Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>` (ksmbd
maintainer; author and committer).
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Acked-
by:`, `Link:`, or `Cc: stable`. Absence of `Fixes:`/`Cc: stable` is
expected for this review and is not a negative signal.
**Step 1.3 — Body**
- Record: SMB EAs are stored as `user.*` xattrs. ksmbd keeps NT ACL
metadata in `security.NTACL`. Clients can still create an EA named
`NTACL`, so the reserved logical name looks writable over SMB
SET_INFO/QUERY_INFO EA. The patch rejects `NTACL`, `DOSATTRIB`, and
`DosStream.`-prefixed names case-insensitively on set, and filters the
same names from query results so leftover `user.*` copies are not
exposed. Failure mode: reserved metadata can be written or listed
through the EA API. Symptom: Samba smbtorture `smb2.ea.acl_xattr`
fails when `acl_xattr_name=NTACL`. Introduced with original ksmbd EA
mapping; not a new 7.x-only bug.
**Step 1.4 — Hidden bug fix?**
- Record: Yes. “Protect” is a security/integrity fix, not cleanup. SET
currently does not reject reserved names. GET already skipped
`DosStream.` / `DOSATTRIB` with case-sensitive `strncmp`, but not
`NTACL` and not case variants.
## Phase 2: Diff analysis
**Step 2.1 — Inventory**
- Record: `fs/smb/server/smb2pdu.c` only (`+22/-6`). Functions: new
`smb2_is_private_ea()`; `smb2_set_ea()`; `smb2_get_ea()`.
Classification: single-file surgical fix.
**Step 2.2 — Flow**
- Record:
- SET: after the EA name-length check, reserved names return `-EACCES`
instead of `ksmbd_vfs_setxattr`/`remove_xattr` on `user.<name>`.
- GET: STREAM and DOSATTRIB `strncmp` skips become one
`smb2_is_private_ea()` skip (adds `NTACL`, case-insensitive).
Specific-name QUERY still cannot return those names.
**Step 2.3 — Bug mechanism**
- Record: Logic/correctness plus a hardware/protocol reserved-name
filter (category g/h). Same-namespace collisions: `user.DOSATTRIB`
(DOS flags/create time) and `user.DosStream.*` (named streams).
`security.NTACL` is a different namespace, so SET of EA `NTACL`
creates `user.NTACL` rather than overwriting the SD; the patch still
blocks that reserved name and hides any leftover `user.NTACL`.
**Step 2.4 — Fix quality**
- Record: Obviously correct. `strncasecmp` + exact length for
`NTACL`/`DOSATTRIB`, prefix match for streams. `-EACCES` maps to
`STATUS_ACCESS_DENIED` in both `smb2_set_info()` and CREATE error
mapping, matching smbtorture. Regression risk is low: only reserved
Samba/ksmbd names are rejected. Query of a private name still yields
`STATUS_NO_EAS_ON_FILE` rather than ACCESS_DENIED; that is pre-
existing GET skip behavior, not a new crash path.
## Phase 3: Git history
**Step 3.1 — Blame**
- Record: Unfiltered SET and GET STREAM/DOSATTRIB skips come from
`e2f34481b24db` (“cifsd: add server-side procedures for SMB3”,
2021-03-16). Present since ksmbd entered the kernel (5.15 era). `git
merge-base --is-ancestor e2f34481b24db HEAD` succeeds.
**Step 3.2 — Fixes tag**
- Record: None. Buggy behavior is the original EA mapping, not a later
regression.
**Step 3.3 — File history**
- Record: Recent 6.12 ksmbd work is unrelated (buffer sizes, leases,
durable reconnect). No competing private-EA helper in this tree.
**Step 3.4 — Author**
- Record: Namjae Jeon is the ksmbd maintainer. Surrounding 7.3 ksmbd
commits are other protocol/security fixes; this commit is standalone
(`4ea46ea602fc`).
**Step 3.5 — Dependencies**
- Record: Needs `SD_PREFIX`, `DOS_ATTRIBUTE_PREFIX`, `STREAM_PREFIX`
from `fs/smb/server/xattr.h` (included via `vfs.h` in `smb2pdu.c`).
All exist here. `strncasecmp` is in `include/linux/string.h`. Applies
standalone.
## Phase 4: Mailing list / external
**Step 4.1**
- Record: SHA `4ea46ea602fc7055eee4b5b0e84f90f22da7f7e7` (v7.3-rc1). `b4
dig -c 4ea46ea602fc` failed: lore.kernel.org returned errors (Anubis
bot challenge). WebFetch to lore also 403. UNVERIFIED: original thread
text, NAKs, reviewer Cc:stable.
**Step 4.2**
- Record: UNVERIFIED recipients. Commit is authored and committed by the
subsystem maintainer; Linus merged it in `ksmbd-for-7.3-rc1`
(`61a09cfc12147`), described as smbtorture-validated protocol fixes
and security hardening.
**Step 4.3**
- Record: Samba `source4/torture/smb2/ea.c` `torture_smb2_acl_xattr`
(`smb2.ea.acl_xattr`) requires `acl_xattr_name`, checks the name is
not listed, and expects SET to fail with `NT_STATUS_ACCESS_DENIED`.
Confirmed from samba-team/samba master.
**Step 4.4**
- Record: Standalone. No later revert or follow-up on
`smb2_is_private_ea` through v7.3-rc1 (`git grep` still shows the
helper at three sites).
**Step 4.5**
- Record: UNVERIFIED on lore.kernel.org/stable (lore blocked). No in-
tree revert.
## Phase 5: Code semantics
**Step 5.1**
- Record: `smb2_is_private_ea`, `smb2_set_ea`, `smb2_get_ea`.
**Step 5.2**
- Record: `smb2_set_ea` callers: CREATE EA context (`smb2_open` path
~3322) and `FILE_FULL_EA_INFORMATION` in `smb2_set_info_file` (~6644).
`smb2_get_ea` caller: `smb2_get_info_file` (~5493). Reachable from
SMB2 CREATE / SET_INFO / QUERY_INFO.
**Step 5.3**
- Record: SET uses `ksmbd_vfs_setxattr` / `ksmbd_vfs_remove_xattr` after
prefixing `XATTR_USER_PREFIX`. GET uses `ksmbd_vfs_listxattr` /
`ksmbd_vfs_getxattr`. Internal DOS/stream/SD writers
(`ksmbd_vfs_set_dos_attrib_xattr`, stream helpers,
`ksmbd_vfs_set_sd_xattr`) do not go through `smb2_set_ea`, so server-
internal writes remain allowed.
**Step 5.4**
- Record: Yes, from userspace: authenticated SMB client with
`FILE_WRITE_EA` / `FILE_READ_EA`. Those rights are normally part of
generic write/read.
**Step 5.5**
- Record: GET already special-cased STREAM and DOSATTRIB; SET did not.
Same reserved names as Samba (`user.DOSATTRIB`, `user.DosStream.*`,
`security.NTACL`).
## Phase 6: This tree (6.12.111)
**Step 6.1**
- Record: Local tree is `pending-6.12`, `git describe`
`p-6.12-3-gc504cf0baa3d8`, `make kernelversion` **6.12.111**.
Candidate is **not** an ancestor of HEAD. Buggy SET/GET code is
present (`smb2_set_ea` at 2392, `smb2_get_ea` at 4758).
`smb2_is_private_ea` is absent.
**Step 6.2**
- Record: `git apply --check` of `4ea46ea602fc` succeeded (hunks at
2379, 2436, 4852; offsets only). Clean apply.
**Step 6.3**
- Record: No alternate fix. GET still uses case-sensitive
STREAM/DOSATTRIB skips and does not filter NTACL.
## Phase 7: Subsystem
**Step 7.1**
- Record: `fs/smb/server` (ksmbd). Criticality: IMPORTANT — network file
server, optional (`CONFIG_SMB_SERVER` default n), but a common stable
attack/integrity surface.
**Step 7.2**
- Record: Actively maintained. This bug is old (original EA code), not a
7.3-only feature.
## Phase 8: Impact and risk
**Step 8.1**
- Record: ksmbd users only (NAS, appliances, distro ksmbd). Not
universal.
**Step 8.2**
- Record: Trigger: SMB2 SET_INFO FULL_EA or CREATE with EA context using
reserved names. Common for any client that can write EAs. Unprivileged
local processes cannot hit it unless they are SMB clients; an
authenticated SMB user can.
**Step 8.3**
- Record: Failure mode: overwrite `user.DOSATTRIB` (hidden/system/create
time) and `user.DosStream.*` (stream data); expose or plant
`user.NTACL`. Severity: **HIGH** (metadata/stream integrity and
reserved-name ACL confusion). Not a kernel oops. Default ksmbd ACL
store is `security.NTACL`, so SET EA `NTACL` does not overwrite the
SD; DOSATTRIB/streams are the real same-namespace collisions.
**Step 8.4**
- Record: Benefit high for ksmbd hosts. Risk very low (~20-line filter,
no locking/API change). Ratio favors backport.
## Phase 9: Synthesis
**Step 9.1 — Evidence**
FOR:
- Real reserved-name hole on a network server: SET can write
`user.DOSATTRIB` and `user.DosStream.*`.
- GET can leak `user.NTACL` if that xattr exists.
- Matches Samba’s long-standing hide/reject of those names; smbtorture
`smb2.ea.acl_xattr` expects ACCESS_DENIED.
- Small, maintainer-authored, in v7.3-rc1 with no revert.
- Applies cleanly to this 6.12 tree; macros and callers exist.
- `-EACCES` already maps to `STATUS_ACCESS_DENIED`.
AGAINST:
- Not a crash/UAF.
- NTACL SD lives in `security.*`, so this is not a direct ACL overwrite
on default ksmbd.
- Commit message is partly a test fix.
- Lore review UNVERIFIED.
UNRESOLVED:
- Original lore thread / reviewer stable nomination (lore blocked).
**Step 9.2 — Stable rules**
1. Obviously correct and tested? **PASS** (applies cleanly; smbtorture
named; maintainer).
2. Real user-visible bug? **PASS** (EA write/list of private metadata).
3. Important (crash/security/corruption/deadlock)? **PASS** (HIGH:
metadata/stream integrity on an SMB server; security-boundary).
4. Small and contained? **PASS** (+22/-6, one file).
5. No new features/APIs? **PASS** (reject/filter only).
6. Applies to this tree? **PASS** (`git apply --check` succeeded).
**Step 9.3 — Exceptions**
- Record: Not a device-ID/quirk/DT/build/docs exception. Qualifies as a
normal security/integrity bug fix.
**Step 9.4 — Decision**
Backport to this 6.12 tree. The important part is not the Samba test
name; it is that authenticated clients can currently smash DOS attribute
and named-stream xattrs that ksmbd treats as private.
---
### What this solves for 6.12 users
ksmbd maps SMB EAs to `user.*`. It stores DOS attributes in
`user.DOSATTRIB` and streams in `user.DosStream.*`. `smb2_set_ea()` does
not reject those names, so a client with `FILE_WRITE_EA` can overwrite
that metadata. Query already hid some of those names, but not `NTACL`
and not case variants. The patch closes SET and GET.
### Stable-rules / risk
Meets all six criteria. Benefit is integrity of ksmbd private xattrs;
risk is a tight ACCESS_DENIED on reserved names that Samba has treated
as private for years.
### Verification
- [Phase 1] Parsed message/tags on `4ea46ea602fc`; only author SOB; no
Fixes/Link.
- [Phase 2] Full `git show 4ea46ea602fc` diff: helper + SET `-EACCES` +
GET filter.
- [Phase 2] Confirmed `-EACCES` → `STATUS_ACCESS_DENIED` at
`smb2_set_info` err_out (~6761) and CREATE err_out (~3812).
- [Phase 2] Confirmed `XATTR_NAME_DOS_ATTRIBUTE` = `user.`+`DOSATTRIB`,
`XATTR_NAME_STREAM` = `user.`+`DosStream.`, `XATTR_NAME_SD` =
`security.`+`NTACL` in `xattr.h`.
- [Phase 3] `git blame` SET/GET: `e2f34481b24db` (2021); ancestor of
HEAD.
- [Phase 3] `git merge-base --is-ancestor 4ea46ea602fc HEAD` → no (not
in 6.12).
- [Phase 4] `b4 dig -c 4ea46ea602fc` → lore error. UNVERIFIED mailing-
list discussion.
- [Phase 4] Samba `torture_smb2_acl_xattr` expects SET ACCESS_DENIED and
no list leak.
- [Phase 4] Merge `61a09cfc12147` mentions smbtorture protocol fixes /
security hardening.
- [Phase 4] `smb2_is_private_ea` still in v7.3-rc1; no revert.
- [Phase 5] Callers: CREATE EA context, SET_INFO FULL_EA, QUERY_INFO EA.
- [Phase 6] `git describe HEAD` = `p-6.12-3-gc504cf0baa3d8`;
kernelversion 6.12.111.
- [Phase 6] `git apply --check` of the commit succeeded with line
offsets only.
- [Phase 8] Same-namespace overwrite of DOSATTRIB/streams verified in
`vfs.c` / `smb2_update_xattrs`.
- UNVERIFIED: lore reviewers, CVE assignment, whether any distro already
carries a different backport.
**YES**
fs/smb/server/smb2pdu.c | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index e73edf006df72..4f8e2a6307602 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -2378,6 +2378,22 @@ static noinline int create_smb2_pipe(struct ksmbd_work *work)
return err;
}
+static bool smb2_is_private_ea(const char *name, size_t name_len)
+{
+ if (name_len == SD_PREFIX_LEN &&
+ !strncasecmp(name, SD_PREFIX, SD_PREFIX_LEN))
+ return true;
+ if (name_len == DOS_ATTRIBUTE_PREFIX_LEN &&
+ !strncasecmp(name, DOS_ATTRIBUTE_PREFIX,
+ DOS_ATTRIBUTE_PREFIX_LEN))
+ return true;
+ if (name_len >= STREAM_PREFIX_LEN &&
+ !strncasecmp(name, STREAM_PREFIX, STREAM_PREFIX_LEN))
+ return true;
+
+ return false;
+}
+
/**
* smb2_set_ea() - handler for setting extended attributes using set
* info command
@@ -2419,6 +2435,10 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
rc = -EINVAL;
break;
}
+ if (smb2_is_private_ea(eabuf->name, eabuf->EaNameLength)) {
+ rc = -EACCES;
+ break;
+ }
memcpy(attr_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
memcpy(&attr_name[XATTR_USER_PREFIX_LEN], eabuf->name,
@@ -4828,17 +4848,13 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp,
if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
continue;
- if (!strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX,
- STREAM_PREFIX_LEN))
- continue;
-
if (req->InputBufferLength &&
strncmp(&name[XATTR_USER_PREFIX_LEN], ea_req->name,
ea_req->EaNameLength))
continue;
- if (!strncmp(&name[XATTR_USER_PREFIX_LEN],
- DOS_ATTRIBUTE_PREFIX, DOS_ATTRIBUTE_PREFIX_LEN))
+ if (smb2_is_private_ea(&name[XATTR_USER_PREFIX_LEN],
+ name_len - XATTR_USER_PREFIX_LEN))
continue;
if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-6.1] ksmbd: allow I/O on directory named streams
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (8 preceding siblings ...)
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: protect private extended attributes Sasha Levin
@ 2026-10-19 13:48 ` Sasha Levin
2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-5.15] smb: server: Free session data in user_session.c with kfree_sensitive() Sasha Levin
` (12 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:48 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 8184c425a19d44f138d42b44cc363917c08e5f1c ]
Named streams are stored as extended attributes on the base inode. The
VFS read and write helpers reject directory inodes before or together
with checking whether the handle represents a stream.
Permit read and write operations when a directory-backed handle is a
named stream. Continue rejecting direct I/O on ordinary directory
handles.
This fixes creation of the directory stream in smb2.getinfo.complex.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit message forensics
**Step 1.1: PARSE THE SUBJECT LINE**
Record: `[ksmbd] [allow] permit read/write on named streams whose base
inode is a directory`
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- `Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>` (ksmbd
maintainer; author)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Acked-
by:`, `Link:`, or `Cc: stable@`
- Absence of `Fixes:`/`Cc: stable` is expected for this review pipeline
and is not a negative signal
- Ignore any later `[Upstream commit ...]` / `Signed-off-by: Sasha
Levin` markers; they are candidate-prep, not selection
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** Named streams are stored as xattrs on the base inode.
`ksmbd_vfs_read()` and `ksmbd_vfs_write()` reject directory inodes
before (read) or together with (write) the stream-handle check, so a
directory-backed stream never reaches `ksmbd_vfs_stream_read()` /
`ksmbd_vfs_stream_write()`.
- **Symptom:** SMB read/write of a named stream on a directory fails
(`-EISDIR` / `-EACCES`). Samba smbtorture `smb2.getinfo.complex`
cannot create `DNAME:streamtwo`.
- **Version info in the message:** none.
- **Root cause:** directory inode check is applied to the base inode,
not to whether the handle is a stream.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not disguised. This is an explicit protocol-correctness fix for
existing ADS I/O. “Allow” here means “stop rejecting a path that already
exists,” not a new API.
## Phase 2: Diff analysis
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `fs/smb/server/vfs.c` — 3 insertions, 2 deletions
- Functions: `ksmbd_vfs_read()`, `ksmbd_vfs_write()`
- Scope: single-file surgical fix
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- **Read, before:** `S_ISDIR(inode)` → immediate `-EISDIR`, so
`ksmbd_stream_fd()` is never reached.
- **Read, after:** reject only `S_ISDIR && !ksmbd_stream_fd(fp)`. Stream
handles fall through to `ksmbd_vfs_stream_read()` (xattr).
- **Write, before:** inside the SMB access check, `S_ISDIR` forces
`-EACCES` even for stream fds.
- **Write, after:** same access check, but directory rejection is
skipped for `ksmbd_stream_fd(fp)`, then the existing stream-write
branch runs.
- Ordinary directory I/O is still rejected. Stream I/O still never calls
`kernel_read()` / `kernel_write()`.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **Logic / protocol correctness.** Directory ADS is valid SMB.
The VFS helpers treated the base directory inode as “no I/O allowed” and
never used the xattr stream path.
**Step 2.4: ASSESS THE FIX QUALITY**
Record: Obviously correct and minimal. `ksmbd_stream_fd()` is an
existing inline (`fp->stream.name != NULL`). After the exemption, both
functions still take the stream branch and `goto out` / return before
VFS file I/O, so the `__kernel_write_iter` WARNING that motivated the
earlier directory-write ban is not reintroduced. Regression risk is very
low.
## Phase 3: Git history investigation
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- Read `S_ISDIR` check: `f44158485826c0` (“cifsd: add file operations”,
2021). Directory stream **reads** have been broken since ksmbd’s
original file ops.
- Write `S_ISDIR` check: `2a879da5c34a1` (“ksmbd: fix the warning from
__kernel_write_iter”), upstream `b37f2f332b40`, present here as
`v6.12.25~99`. That stable backport banned all directory writes to
avoid `WARNING: CPU: ... at fs/read_write.c:599 __kernel_write_iter`.
It sits **before** the stream-fd check, so it also blocked directory
**stream** writes that previously went through xattrs.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. The write-side bug is a follow-on to
`2a879da5c34a1` / `b37f2f332b40`, which **is** in this tree.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record: Stream I/O already exists here (`ksmbd_vfs_stream_read/write`,
`d62ba16563a86` OOB check, `5c54a557bde18` empty-stream write fix,
`a8f5d39971bba` opener creds for ADS). Neighboring 7.3 stream patches
(copychunk, AAPL FinderInfo, stream delete, `::$DATA` validation) are
**not** prerequisites for this 3-line change. Standalone.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Namjae Jeon is the ksmbd maintainer. This landed in the ksmbd
7.3-rc1 pull among other ADS/protocol fixes. Same author previously
landed `2fb9b5dc80cab` (“allow write with FILE_APPEND_DATA”) on stable
for a similar client-visible I/O rejection.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: Uses only `ksmbd_stream_fd()`, already in
`fs/smb/server/vfs_cache.h` and included from `vfs.c`. Parent
`4ea46ea602fc7` (“protect private extended attributes”) is **not** in
this tree and is not required. `git show 8184c425a19d4 | git apply
--check` succeeds on this tree.
## Phase 4: Mailing list and external research
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record: `b4 dig -c 8184c425a19d4` failed (lore.kernel.org returned an
error / Anubis bot wall). Same for lore search URLs. Fallback: the
commit is listed in Namjae’s **[GIT PULL] ksmbd server update for
7.3-rc1** (2026-08-23) as `ksmbd: allow I/O on directory named streams`,
under “Correct alternate-data-stream and named-stream handling,” not
under “New features.”
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: UNVERIFIED at patch-thread level (lore unreachable). The pull is
from the subsystem maintainer to Linus.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: Samba `smb2.getinfo.complex` (`source4/torture/smb2/getinfo.c`)
does:
- `torture_setup_complex_dir(..., DNAME)`
- `torture_setup_complex_file(..., DNAME ":streamtwo")`
Historically noted as “streams on directories does not work.” That is a
real client/test failure, not a theoretical one.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Part of the large 7.3 ksmbd dump, but this hunk is self-
contained. Later stream patches improve enumeration, delete, copychunk,
AAPL; they are not needed for this I/O gate.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: UNVERIFIED (lore blocked). No in-tree discussion of rejecting
this fix.
## Phase 5: Code semantic analysis
**Step 5.1: IDENTIFY KEY FUNCTIONS**
Record: `ksmbd_vfs_read()`, `ksmbd_vfs_write()`, helper
`ksmbd_stream_fd()`.
**Step 5.2: TRACE CALLERS**
Record:
- `ksmbd_vfs_read()` ← `smb2_read()` (`smb2pdu.c`)
- `ksmbd_vfs_write()` ← `smb2_write()` and `smb2_write_rdma_channel()`
Reachable from normal SMB2 READ/WRITE on a connected share.
`connection_type` is set from the negotiated dialect, so the write-side
directory check applies to SMB2/SMB3.
**Step 5.3: TRACE CALLEES**
Record: Stream path uses `ksmbd_vfs_getcasexattr` / `ksmbd_vfs_setxattr`
on the dentry. Directories support xattrs; no `kernel_write()` on the
directory inode.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Userspace SMB client → SMB2 CREATE of `dir:streamtwo` (open
already allowed when `s_type` is not explicit `$DATA`) → SMB2 WRITE →
`ksmbd_vfs_write()` currently returns `-EACCES`. Triggerable by any
client with streams enabled (`KSMBD_SHARE_FLAG_STREAMS`).
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Other `S_ISDIR` checks in ksmbd (oplock, setattr, query info)
are separate. No duplicate I/O gate that would still block this path
after the patch.
## Phase 6: Cross-referencing against the local tree
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: Yes. Local tree is **6.12.111** (`pending-6.12`,
`p-6.12-3-gc504cf0baa3d8`). Current code:
```377:378:fs/smb/server/vfs.c
if (S_ISDIR(inode->i_mode))
return -EISDIR;
```
```503:505:fs/smb/server/vfs.c
if (work->conn->connection_type) {
if (!(fp->daccess & (FILE_WRITE_DATA_LE |
FILE_APPEND_DATA_LE)) ||
S_ISDIR(file_inode(fp->filp)->i_mode)) {
```
`8184c425a19d4` is **not** an ancestor of HEAD. Write-side regression
introduced in **v6.12.25**.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: Clean apply (`git apply --check` exit 0). Surrounding functions
match the upstream hunk context. `ksmbd_stream_fd()` already present.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No equivalent directory-stream I/O exemption. Stream write
OOB/empty-xattr fixes are present but do not address `S_ISDIR`.
## Phase 7: Subsystem and maintainer context
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: `fs/smb/server` (ksmbd). **IMPORTANT** — in-kernel SMB3 server
used by NAS/embedded/distro images. Not core mm/VFS, not staging.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Actively maintained; this tree already carries many ksmbd
protocol and memory-safety backports. Mature ADS support has existed
since the cifsd era (2021).
## Phase 8: Impact and risk assessment
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: ksmbd users with `KSMBD_SHARE_FLAG_STREAMS` who have
Windows/Samba/macOS clients using named streams on directories (Explorer
ADS, smbtorture, some backup/metadata workflows).
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record: SMB2 WRITE/READ on a handle opened as `dir:stream`. Common in
protocol tests; less common than file ADS, but a supported SMB feature.
Unprivileged share users can trigger it if they can create streams.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: Client I/O fails (`STATUS` derived from `-EISDIR`/`-EACCES`);
not a panic, UAF, or silent corruption. **MEDIUM**
functional/interoperability, **HIGH** as a **stable-to-stable write
regression** since v6.12.25.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- **Benefit:** Restores directory ADS I/O; undoes over-broad fallout
from the `__kernel_write_iter` stable fix; unblocks
`smb2.getinfo.complex`.
- **Risk:** Very low (3 lines, existing helper, stream path still
bypasses `kernel_write`).
- **Ratio:** favorable.
## Phase 9: Final synthesis
**Step 9.1: COMPILE THE EVIDENCE**
FOR:
- Real SMB protocol bug: named streams live in xattrs; directory base
inodes must still allow stream I/O.
- Write path is a **regression** from `2a879da5c34a1` (v6.12.25) already
on this 6.12.y tree.
- Existing ADS stack is in this tree; this only opens the gate to it.
- 3-line, obviously correct, applies cleanly.
- Maintainer-authored; validated via smbtorture `smb2.getinfo.complex`.
- Does not restore the directory `kernel_write` WARNING.
AGAINST:
- Not a crash/security/corruption issue.
- Directory ADS is a narrower client feature than file ADS.
- Read-side rejection has existed since 2021 (enabling reads is
correctness, not a 6.12.y regression).
UNRESOLVED:
- Original lore review thread (b4/lore blocked).
- Whether reviewers asked for `Cc: stable`.
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — logic is local and was
exercised by smbtorture.
2. Fixes a real bug that affects users? **PASS** — SMB clients cannot
I/O directory named streams.
3. Important issue? **PASS** — interoperability failure plus a write-
side regression from a prior stable commit. Not a panic, but user-
visible and already shipped in 6.12.y.
4. Small and contained? **PASS** — 3 lines, one file.
5. No new features or APIs? **PASS** — no new syscall/sysfs; streams
already advertised.
6. Can apply to the local tree? **PASS** — clean apply; helpers exist.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: None of device-ID / quirk / DT / build / docs. Qualifies on
ordinary bug-fix rules.
**Step 9.4: MAKE YOUR DECISION**
This tree already contains ksmbd named-stream I/O and the v6.12.25
directory-write ban. The ban is correct for ordinary directory handles
but incorrectly covers stream handles, which never use `kernel_write()`.
Backporting this exemption restores intended ADS behavior with
negligible risk.
---
What this solves for 6.12.y: Windows/Samba clients that write a named
stream on a directory (as `smb2.getinfo.complex` does with
`DNAME:streamtwo`) currently get `-EACCES` on write and `-EISDIR` on
read. After v6.12.25 that write failure is a regression from a WARNING
fix. The patch is a 3-line predicate change; stream I/O still goes
through xattrs, so the WARNING does not come back.
Verification:
- [Phase 1] Parsed tags: only maintainer SOB; no Fixes/Reported-by/Cc:
stable
- [Phase 2] Diff: 3 lines in `ksmbd_vfs_read`/`ksmbd_vfs_write`; exempts
`ksmbd_stream_fd()` from `S_ISDIR`
- [Phase 3] `git blame`: read check from `f44158485826c0` (2021); write
check from `2a879da5c34a1` (`v6.12.25~99`)
- [Phase 3] `git merge-base --is-ancestor 2a879da5c34a1 HEAD` → yes;
`8184c425a19d4` → no
- [Phase 3] `git apply --check` of `8184c425a19d4` → clean
- [Phase 4] `b4 dig -c 8184c425a19d4` failed (lore error)
- [Phase 4] 7.3-rc1 GIT PULL lists this under ADS handling, not new
features
- [Phase 4] Samba `getinfo.c` creates `DNAME ":streamtwo"` in
`smb2.getinfo.complex`
- [Phase 5] Callers: `smb2_read` / `smb2_write` / RDMA write; stream
callees are xattr helpers
- [Phase 6] `git describe HEAD` → `p-6.12-3-gc504cf0baa3d8`; `make
kernelversion` → 6.12.111; buggy `S_ISDIR` present
- [Phase 8] Failure mode: failed SMB stream I/O, plus write regression
since v6.12.25; not a panic
- UNVERIFIED: lore review comments / stable ML discussion (lore blocked)
**YES**
fs/smb/server/vfs.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index 3ac5f3f48121d..47c289ad9c3dc 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -372,7 +372,7 @@ int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count,
ssize_t nbytes = 0;
struct inode *inode = file_inode(filp);
- if (S_ISDIR(inode->i_mode))
+ if (S_ISDIR(inode->i_mode) && !ksmbd_stream_fd(fp))
return -EISDIR;
if (unlikely(count == 0))
@@ -500,7 +500,8 @@ int ksmbd_vfs_write(struct ksmbd_work *work, struct ksmbd_file *fp,
if (work->conn->connection_type) {
if (!(fp->daccess & (FILE_WRITE_DATA_LE | FILE_APPEND_DATA_LE)) ||
- S_ISDIR(file_inode(fp->filp)->i_mode)) {
+ (S_ISDIR(file_inode(fp->filp)->i_mode) &&
+ !ksmbd_stream_fd(fp))) {
pr_err("no right to write(%pD)\n", fp->filp);
err = -EACCES;
goto out;
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-5.15] smb: server: Free session data in user_session.c with kfree_sensitive()
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (9 preceding siblings ...)
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: allow I/O on directory named streams Sasha Levin
@ 2026-10-19 13:49 ` Sasha Levin
2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: return buffer too small for short security queries Sasha Levin
` (11 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:49 UTC (permalink / raw)
To: patches, stable
Cc: Thomas Huth, Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Thomas Huth <thuth@redhat.com>
[ Upstream commit 9a4bd6507c21f66e84dc021705a4b9d84773111e ]
struct ksmbd_session contains some arrays with sensitive information, like
sess_key, smb3encryptionkey, smb3decryptionkey and smb3signingkey. Thus
let's make sure that this information cannot leak via the heap and use
kfree_sensitive() to free it.
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
I have the local 6.12.111 code, the upstream commit, and the mailing-
list thread. Compiling the nine-phase analysis next.
## Phase 1: Commit message forensics
**Step 1.1: Subject line**
- Record: `[smb/ksmbd server] [Free / use kfree_sensitive] Wipe ksmbd
session objects (and Preauth_HashValue) so session keys cannot remain
in freed heap memory`
**Step 1.2: Tags** (from upstream
`d4a6d1c94f7a383c16fd5f5e912a39a640d1cb9d`; ignore pipeline SOBs)
- No `Fixes:`
- No `Reported-by:` / `Tested-by:` / `Reviewed-by:` / `Cc: stable`
- `Acked-by: Namjae Jeon <linkinjeon@kernel.org>` (ksmbd maintainer)
- `Signed-off-by: Thomas Huth <thuth@redhat.com>` (author)
- `Signed-off-by: Steve French <stfrench@microsoft.com>` (CIFS
maintainer; present on the merged commit)
- Candidate-prep copy also had `Signed-off-by: Namjae Jeon`; merged form
uses Acked-by instead
- Record: Maintainer ack, no user report, no syzbot, no CVE tag
**Step 1.3: Body**
- Record: `[Bug] ksmbd_session holds sess_key, smb3encryptionkey,
smb3decryptionkey, smb3signingkey and a Preauth_HashValue buffer, then
frees them with kfree(), so those secrets can remain in the slab.
[Symptom] Potential heap disclosure of SMB session/crypto keys after
session teardown. [Versions] None stated. [Root cause] Sensitive
material is returned to the allocator without memzero_explicit.]`
- Cover letter (series v2 0/5): “It's good security practice to clear
sensitive data… and to use kfree_sensitive() for data that is returned
to the heap.”
**Step 1.4: Hidden bug fix?**
- Record: Not disguised cleanup. It is an explicit secret-wipe / heap-
disclosure hardening change. Functional behavior of session teardown
is unchanged except the object is zeroed before free.
## Phase 2: Diff analysis
**Step 2.1: Inventory**
- Record: `[fs/smb/server/mgmt/user_session.c: 2 insertions, 2
deletions] [function: ksmbd_session_destroy] [scope: single-file, two-
call-site surgical change]`
**Step 2.2: Code flow**
- Record: Before, `ksmbd_session_destroy()` calls
`kfree(sess->Preauth_HashValue)` then `kfree(sess)` after logoff/file-
table/user/RPC/channel teardown. After, those two frees use
`kfree_sensitive()`, which `memzero_explicit`s the whole allocation
then `kfree`s. Normal teardown path only; not an error-path
restructure.
Verified in this tree at:
```159:175:fs/smb/server/mgmt/user_session.c
void ksmbd_session_destroy(struct ksmbd_session *sess)
{
if (!sess)
return;
ksmbd_tree_conn_session_logoff(sess);
ksmbd_destroy_file_table(sess);
if (sess->user)
ksmbd_free_user(sess->user);
ksmbd_launch_ksmbd_durable_scavenger();
ksmbd_session_rpc_clear_list(sess);
free_channel_list(sess);
kfree(sess->Preauth_HashValue);
ksmbd_release_id(&session_ida, sess->id);
ida_destroy(&sess->tree_conn_ida);
kfree(sess);
}
```
Sensitive fields verified in `struct ksmbd_session` (`user_session.h`):
`sess_key`, `smb3encryptionkey`, `smb3decryptionkey`, `smb3signingkey`,
plus `Preauth_HashValue`.
**Step 2.3: Bug mechanism**
- Record: `[Memory safety / cryptographic material leftover] [kfree()
does not clear; kfree_sensitive() zeros via memzero_explicit then
frees. Category: information leak / CWE-226 class, not UAF/crash.]`
**Step 2.4: Fix quality**
- Record: `[Obviously correct drop-in. kfree_sensitive() is NULL-safe
like kfree(). Session is kzalloc'd, so ksize/kfree_sensitive is the
right API. No API/lock/struct change.] [Regression risk: very low.
Docs warn kfree_sensitive is not for hot paths; session destroy is
logoff/expire/teardown, not a packet hot path.]`
## Phase 3: Git history
**Step 3.1: Blame**
- Record: `ksmbd_session_destroy` and `kfree(sess->Preauth_HashValue)`
from `e2f34481b24db2` (“cifsd: add server-side procedures for SMB3”),
contained in `v5.15-rc1`. `kfree(sess)` from `822bc8ea514ecd` (2021).
Encryption key fields from `5a0ca7700591a5` (2021). Bug has been in
this code since ksmbd entered mainline.
**Step 3.2: Fixes: tag**
- Record: No `Fixes:` tag. Not applicable. Introducer is the original
ksmbd session code, which is in this tree (`git merge-base --is-
ancestor` of those SHAs vs HEAD succeeded).
**Step 3.3: File history**
- Record: Recent 6.12.y ksmbd session work is lifetime/UAF/ida (e.g.
`9d58ac0643e5b` destroy tree_conn_ida, session leak/UAF fixes). None
already switches these two `kfree`s. Not blocked by later refactor in
this file.
**Step 3.4: Author**
- Record: Thomas Huth (Red Hat); not the ksmbd maintainer. Series of
five independent kfree_sensitive conversions. Maintainer Namjae Jeon
acked and applied to `#ksmbd-for-next-next`. Steve French signed off
on the merge.
**Step 3.5: Dependencies**
- Record: Patch 3/5 of “Clear sensitive data before freeing it”. Sibling
patches touch `auth.c`, `user_config.c`, `connection.c`, `smb2pdu.c`.
This hunk does not call new helpers and does not depend on those other
diffs. `linux/slab.h` already included. `kfree_sensitive()` exists in
this tree (`mm/slab_common.c`, exported). Standalone apply: yes.
## Phase 4: Mailing list / external
**Step 4.1: Original discussion**
- Record: `[Lore]
https://patch.msgid.link/20260811154620.2425851-4-thuth@redhat.com`
- Series: v1 (4 patches, 2026-08-10) → v2 (5 patches, 2026-08-11). This
file hunk is unchanged v1→v2.
- v1 review (Namjae): also wipe `struct preauth_session` in
`ksmbd_preauth_session_destroy()`. That was handled in v2 patch 5
(`smb2pdu.c` session-setup paths), not in this commit. This commit is
still self-contained.
- No NAK. No reviewer asked for `Cc: stable`. Maintainer: “Applied them
to #ksmbd-for-next-next.”
**Step 4.2: Recipients (b4 dig -w)**
- Record: Thomas Huth; Namjae Jeon; Steve French; Sergey Senozhatsky;
Tom Talpey; linux-kernel@. Subsystem maintainers were on To/Cc and the
ksmbd maintainer acked.
**Step 4.3: Bug report**
- Record: No syzbot/bugzilla/CVE for this change. Author framed it as
hygiene; spots “identified with AI” then written by hand.
**Step 4.4: Series context**
- Record: Five independent wipe sites. This one wipes the session object
that actually embeds the SMB3 keys. Related remaining `kfree(chann)`
of `struct channel` (contains `smb3signingkey`) is not part of this
commit; that does not make this hunk incorrect.
**Step 4.5: Stable list**
- Record: No stable@ discussion found for this subject. Unverified that
it was previously rejected for stable.
Upstream SHA (not in this branch):
`d4a6d1c94f7a383c16fd5f5e912a39a640d1cb9d`. `git merge-base --is-
ancestor d4a6d1c94f7a3 HEAD` failed (exit 1).
## Phase 5: Semantic analysis
**Step 5.1: Functions**
- Record: `ksmbd_session_destroy` only.
**Step 5.2: Callers**
- Record: Same file: `ksmbd_expire_session`, `ksmbd_sessions_deregister`
(two sites), `ksmbd_user_session_put`, `__session_create` error path.
- `ksmbd_user_session_put` is used from `smb2pdu.c` (session
setup/logoff), `server.c`, `auth.c`, and register failure.
- Context: SMB session lifetime (logoff, expire, connection teardown,
create failure). Not IRQ. Reachable from a connected SMB client.
**Step 5.3: Callees**
- Record: tree-connect logoff, file table destroy, `ksmbd_free_user`,
durable scavenger, RPC clear, `free_channel_list`, then the two frees.
Side effect of the patch is only the wipe-before-free.
**Step 5.4: Reachability**
- Record: Yes. Any ksmbd login then logoff/disconnect/expire hits this.
CONFIG_SMB_SERVER (default n), module `ksmbd`. Network-facing when
enabled.
**Step 5.5: Similar patterns**
- Record: CIFS client already uses `kfree_sensitive` widely for session
keys/passwords in this tree. ksmbd server only uses it in `auth.c`
(`kfree_sensitive(ctx_arc4)`). `free_channel_list`/`ksmbd_chann_del`
still `kfree` channel objects that embed `smb3signingkey`.
`ksmbd_preauth_session_destroy` still `kfree`s `preauth_session` (hash
embedded). Same class of leftover secrets; this patch still covers the
primary session key material.
## Phase 6: This tree (6.12.111)
**Step 6.1: Buggy code present?**
- Record: Yes. `pending-6.12` / `make kernelversion` = 6.12.111. Exact
`kfree(sess->Preauth_HashValue)` and `kfree(sess)` still in
`ksmbd_session_destroy`. Introduced with ksmbd (v5.15), long before
6.12.
**Step 6.2: Backport difficulty**
- Record: Clean apply. Mailing-list hunk context
(`ksmbd_launch_ksmbd_durable_scavenger` … `ida_destroy`) matches this
tree. Upstream later added `delete_proc_session(sess)` above these
lines; that symbol is absent here but is not in the 3-line context of
the actual change. `kfree_sensitive` already declared in
`include/linux/slab.h`.
**Step 6.3: Related fixes already here?**
- Record: No equivalent wipe of these two allocations. `git log
--grep=kfree_sensitive -- fs/smb/server` has no matching session-
destroy commit.
## Phase 7: Subsystem context
**Step 7.1**
- Record: `[ksmbd / fs/smb/server] [IMPORTANT for systems with
CONFIG_SMB_SERVER: NAS/embedded SMB3 server; not CORE for every 6.12
user]`
**Step 7.2**
- Record: Actively maintained; this 6.12.y branch already carries many
ksmbd security/UAF backports. Code path itself is mature (since 5.15).
## Phase 8: Impact and risk
**Step 8.1: Who is affected**
- Record: Config-specific (`CONFIG_SMB_SERVER`). Users running ksmbd
(SMB3 kernel server).
**Step 8.2: Trigger**
- Record: Session destroy on logoff, idle expire, connection teardown,
or failed session create. Common on any real ksmbd workload.
Triggering the leftover keys does not require a race; the wipe
omission is deterministic. Reading the leftover keys does require
another info leak, a dump, or similar.
**Step 8.3: Failure mode**
- Record: `[Residual SMB session/encryption/signing keys and preauth
hash in slab after free] [Severity: MEDIUM as a standalone disclosure
(needs another read of freed/reused heap), HIGH in combination with an
uninitialized-kmalloc leak or memory dump because the secrets can
decrypt prior SMB3 traffic or expose session key material]`
**Step 8.4: Risk-benefit**
- Record: `[Benefit: medium for ksmbd deployments — clears the actual
SMB3 key material on every session end] [Risk: very low — 2 lines,
dedicated API, teardown path only] [Ratio: favorable]`
## Phase 9: Synthesis
**Evidence FOR**
- Deterministic failure to clear SMB3 session keys, signing keys,
encryption/decryption keys, and Preauth_HashValue on session destroy.
- `kfree_sensitive()` exists specifically for this; CIFS client in this
tree already uses it for the same class of secrets.
- Two-line, obviously correct, maintainer-acked, already merged
upstream.
- Applies cleanly to 6.12.111; no new API; no lock/data-structure
change.
- ksmbd is a network-facing file server; leftover keys after logoff are
real cryptographic material, not a style nit.
- Official stable rules include “a real security issue”; this is secret
leftover in heap (CWE-226), not a feature.
**Evidence AGAINST**
- Cover letter calls it “good security practice,” not a demonstrated
crash/CVE. No `Reported-by`, no exploit write-up.
- Official rule: no “this could be a problem” without how it is
exploited. Direct userspace leak is not shown; it is residual data
until slab reuse or a dump.
- Incomplete hygiene: channel objects and
`ksmbd_preauth_session_destroy()` still use `kfree` in this file.
- `CONFIG_SMB_SERVER` defaults to n.
**Unresolved**
- No stable@ thread found (search quality limited;
lore.kernel.org/stable returned unrelated hits).
- Semcode MCP not available; callers traced with `git grep`.
**Stable rules checklist**
1. Obviously correct and tested? **PASS** — drop-in `kfree` →
`kfree_sensitive`; maintainer ack; applied upstream.
2. Fixes a real bug that affects users? **PASS** — session objects with
live SMB3 keys are freed without wiping; that is leftover secret
material on a path every ksmbd session takes.
3. Important issue? **PASS** (security: key leftover; not
oops/deadlock). Severity is secret wipe, not a panic.
4. Small and contained? **PASS** — 2 lines, one function.
5. No new features/APIs? **PASS**.
6. Can apply to this tree? **PASS** — same function body aside from
later `delete_proc_session`, which this hunk does not need.
**Exception category:** None of ID/quirk/DT/build/docs. Security wipe of
existing allocations.
This is not a crash fix, but it is a small, obviously correct wipe of
real SMB3 key material on session teardown, the code is present in
6.12.111, and regression risk is negligible. That meets the stable bar
for a real security issue on ksmbd.
Verification:
- [Phase 1] Parsed subject/body/tags from candidate text and `git log -1
d4a6d1c94f7a3`; maintainer Acked-by; no Fixes/Reported-by/Cc: stable
- [Phase 2] Read `ksmbd_session_destroy` and `struct ksmbd_session` in
this tree; confirmed two `kfree` sites and key arrays
- [Phase 2] Read `kfree_sensitive()` in `mm/slab_common.c` (zeros via
`memzero_explicit`, then `kfree`)
- [Phase 3] `git blame -L 159,175` user_session.c; introducer
`e2f34481b24db2` contained in v5.15-rc1
- [Phase 3] `git merge-base --is-ancestor` of introducer and of
`d4a6d1c94f7a3` vs HEAD: introducer yes, this fix no
- [Phase 3] `git log --oneline -20 --
fs/smb/server/mgmt/user_session.c`: no prior equivalent wipe
- [Phase 4] `b4 dig -c d4a6d1c94f7a3` / `-a` / `-w`: v1 then v2; lore
https://patch.msgid.link/20260811154620.2425851-4-thuth@redhat.com;
Namjae applied v2; no NAK; no stable nomination
- [Phase 4] Cover letter and v1 review (preauth_session) fetched from
openwall/lkml/patchew
- [Phase 5] `git grep ksmbd_session_destroy` / `ksmbd_user_session_put`:
session logoff/expire/teardown/create-error
- [Phase 5] Confirmed `__session_create` uses `kzalloc`;
`user_session.c` includes `linux/slab.h`
- [Phase 6] `git describe HEAD` → `p-6.12-3-gc504cf0baa3d8`; `make
kernelversion` → 6.12.111
- [Phase 6] `delete_proc_session` absent here; does not block the two-
line hunk
- [Phase 7] `CONFIG_SMB_SERVER` in `fs/smb/server/Kconfig`, default n
- [Phase 8] Failure mode: leftover session keys in slab after destroy
- UNVERIFIED: no dedicated stable@ discussion located
The two-line `kfree_sensitive()` conversion belongs in this 6.12 tree:
the buggy frees are here, the API is here, and it wipes real SMB3
session keys on teardown with negligible risk.
**YES**
fs/smb/server/mgmt/user_session.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c
index 3a2591434b5f8..973db0466575e 100644
--- a/fs/smb/server/mgmt/user_session.c
+++ b/fs/smb/server/mgmt/user_session.c
@@ -168,10 +168,10 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
ksmbd_launch_ksmbd_durable_scavenger();
ksmbd_session_rpc_clear_list(sess);
free_channel_list(sess);
- kfree(sess->Preauth_HashValue);
+ kfree_sensitive(sess->Preauth_HashValue);
ksmbd_release_id(&session_ida, sess->id);
ida_destroy(&sess->tree_conn_ida);
- kfree(sess);
+ kfree_sensitive(sess);
}
struct ksmbd_session *__session_lookup(unsigned long long id)
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-6.6] ksmbd: return buffer too small for short security queries
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (10 preceding siblings ...)
2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-5.15] smb: server: Free session data in user_session.c with kfree_sensitive() Sasha Levin
@ 2026-10-19 13:50 ` Sasha Levin
2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: honor client signing-required in all modes Sasha Levin
` (10 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:50 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 2103add92a02505bdd536ba6fce7f64a427222a2 ]
SMB2 QUERY_INFO security requests with an output buffer too small for
the self-relative security descriptor header can fall through descriptor
construction and be reported as STATUS_INVALID_INFO_CLASS.
After validating the file handle, reject buffers shorter than struct
smb_ntsd with STATUS_BUFFER_TOO_SMALL before building the descriptor.
This fixes smb2.getinfo.qsec_buffercheck.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.12.111** (`pending-6.12`). The candidate is
mainline `2103add92a02` (“ksmbd: return buffer too small for short
security queries”). It is not an ancestor of HEAD, but the buggy path is
present and the patch applies.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
Step 1.1: PARSE THE SUBJECT LINE
Record: [ksmbd] [return] SMB2 QUERY_INFO security with a too-small
output buffer should return STATUS_BUFFER_TOO_SMALL instead of a wrong
NT status.
Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
Record:
- Signed-off-by: Namjae Jeon \<linkinjeon@kernel.org\> (ksmbd
maintainer)
- No Fixes:, Reported-by:, Tested-by:, Reviewed-by:, Acked-by:, Link:,
or Cc: stable
- Absence of Fixes/Cc-stable is expected for this review pipeline and is
not a negative signal
- Pipeline-added markers (Upstream commit / Sasha Levin SOB) ignored per
instructions
Step 1.3: ANALYZE THE COMMIT BODY TEXT
Record:
- Bug: SMB2 QUERY_INFO (security) with OutputBufferLength smaller than
`struct smb_ntsd` can still run descriptor construction and be
reported as STATUS_INVALID_INFO_CLASS
- Symptom: wrong NT status on short security queries; Samba smbtorture
`smb2.getinfo.qsec_buffercheck` fails
- Author’s root cause: missing early reject after the file handle is
validated
- Fix: if OutputBufferLength \< sizeof(struct smb_ntsd), set
STATUS_BUFFER_TOO_SMALL, put the fd, return -ENOSPC
Step 1.4: DETECT HIDDEN BUG FIXES
Record: Not a disguised cleanup. It is an explicit protocol/error-code
fix. The “fall through descriptor construction” wording matches a real
control-flow bug, not style.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
Step 2.1: INVENTORY THE CHANGES
Record:
- File: `fs/smb/server/smb2pdu.c` (+6 / -0)
- Function: `smb2_get_info_sec()`
- Scope: single-file surgical fix, one insertion after
`ksmbd_lookup_fd_slow()`
Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
Record:
- Before: after a successful fd lookup, the function always builds POSIX
ACL fattr / optional SD xattr, allocates a scratch SD, calls
`build_sec_desc()`, then `buffer_check_err()`.
- After: if `OutputBufferLength < sizeof(struct smb_ntsd)` (20 bytes),
return immediately with STATUS_BUFFER_TOO_SMALL and `ksmbd_fd_put()`.
- Path: error path for client-provided undersized QUERY_INFO security
buffers (including the Samba test’s 0- and 1-byte probes).
Step 2.3: IDENTIFY THE BUG MECHANISM
Record:
- Category: logic / protocol correctness (wrong NT status)
- Mechanism verified in this tree:
1. Samba `qsec_buffercheck` uses AdditionalInformation=0 and
OutputBufferLength 0 then 1.
2. `smb_acl_sec_desc_scratch_len()` with no OWNER/GROUP/DACL flags
returns `sizeof(struct smb_ntsd)` = 20.
3. `build_sec_desc()` also sets `secdesclen` to 20.
4. The OOB-fix guard `ALIGN(secdesclen, 8) > scratch_len` is 24 > 20,
so rc = -EFBIG with Status still 0.
5. `smb2_query_info()` maps unmapped errors with Status==0 to
STATUS_INVALID_INFO_CLASS.
- That matches the commit message. MS-SMB2 3.3.5.20.3 requires
STATUS_BUFFER_TOO_SMALL when OutputBufferLength is zero or
insufficient for the security descriptor.
Step 2.4: ASSESS THE FIX QUALITY
Record:
- Obviously correct: a self-relative NTSD is at least `sizeof(struct
smb_ntsd)`; smaller buffers cannot hold one.
- `ksmbd_fd_put()` is required after `ksmbd_lookup_fd_slow()`; no leak.
- `smb2_query_info()` does not remap -ENOSPC when Status is already set,
so BUFFER_TOO_SMALL is preserved.
- Regression risk is low: only OutputBufferLength < 20 on QUERY_INFO
security changes, from a wrong error to the spec-required one.
- Incomplete vs MS-SMB2: the error response still has ByteCount 0
(`smb2_set_err_rsp()`), so the required size is not returned. The
torture test only asserts the status. That does not make the patch
incorrect.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
Step 3.1: BLAME THE CHANGED LINES
Record:
- Insertion point is immediately after the fd lookup, which dates to
e2f34481b24db2 (Namjae Jeon, 2021, original cifsd QUERY_INFO security
path).
- The INVALID_INFO_CLASS outcome for this short-buffer case comes from
d48c64fb80ad7 (“ksmbd: fix OOB write in QUERY_INFO for compound
requests”, 2026-03-25), which added scratch_len + ALIGN check +
buffer_check_err. That commit **is** in this tree.
Step 3.2: FOLLOW THE FIXES: TAG
Record: No Fixes: tag. Functionally this is a follow-up to
d48c64fb80ad7, which is already in HEAD.
Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
Record: Related QUERY_INFO buffer-status commits already in this tree:
- fb29c008e1f3b ksmbd: return buffer overflow for partial filesystem
info (fixes smb2.getinfo.qfs_buffercheck)
- df33d8243ce6b ksmbd: fix partial file information responses (mainline
parent of this candidate)
- ab1da5f071fae ksmbd: keep compound responses on query info errors
- ff021a8abacab ksmbd: fix partial normalized name responses
This is the security-info counterpart of qfs_buffercheck, not a large
series that needs extra unapplied patches.
Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
Record: Namjae Jeon is the ksmbd maintainer (MAINTAINERS / Kconfig
SMB_SERVER). Many of his QUERY_INFO buffer-handling fixes are already on
this branch.
Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
Record: Standalone. Needs `smb2_get_info_sec()`, `struct smb_ntsd`,
`ksmbd_fd_put()`, STATUS_BUFFER_TOO_SMALL, and the existing query_info
error mapper — all present. `git apply --check` of 2103add92a succeeded
(hunk offset only). Parent 6b8b79226bc3 (“fix partial file information
responses”) is in the tree as df33d8243ce6b.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
Record:
- Mainline SHA confirmed via GitHub API:
2103add92a02505bdd536ba6fce7f64a427222a2
- `b4 dig -c 2103add92a` failed: lore.kernel.org returned server errors
(exact patch-id, author+subject, and in-body From all failed)
- lore WebFetch also 403
- UNVERIFIED: mailing-list review comments, NAKs, Cc: stable from
reviewers, series revisions
Step 4.2: CHECK WHO REVIEWED THE PATCH
Record: Commit has only the author’s SOB. UNVERIFIED original To/Cc (b4
-w not usable without lore).
Step 4.3: SEARCH FOR THE BUG REPORT
Record: Samba smbtorture `source4/torture/smb2/getinfo.c`
`torture_smb2_qsec_buffercheck()`:
- QUERY_INFO SECURITY, output_buffer_length 0 → expect
NT_STATUS_BUFFER_TOO_SMALL
- same with length 1 → expect NT_STATUS_BUFFER_TOO_SMALL
This is a documented interoperability test against Windows/Samba
behavior, not a theoretical check.
Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
Record: Not labeled X/Y. Parent is the already-backported partial file-
info fix. Sister test qfs_buffercheck is already fixed in this tree. No
extra series member is required for this hunk.
Step 4.5: CHECK STABLE MAILING LIST HISTORY
Record: UNVERIFIED (lore.kernel.org/stable search not available; 403).
Decision does not rely on stable-list history.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
Record: `smb2_get_info_sec()` only.
Step 5.2: TRACE CALLERS
Record:
- `smb2_query_info()` → case SMB2_O_INFO_SECURITY
- Registered in `fs/smb/server/smb2ops.c` as SMB2_QUERY_INFO_HE
- Reachable from any SMB2 client that issues QUERY_INFO security
(Windows ACL UI, `icacls`, Samba, etc.)
Step 5.3: TRACE CALLEES
Record: New path calls `ksmbd_fd_put()` and returns. It avoids
`ksmbd_acls_fattr`, `ksmbd_vfs_get_sd_xattr`,
`smb_acl_sec_desc_scratch_len`, `build_sec_desc`.
Step 5.4: FOLLOW THE CALL CHAIN
Record: Userspace/network reachable: authenticated SMB2 QUERY_INFO on an
open handle. Unprivileged local users cannot hit it unless they can
speak SMB to a ksmbd share; remote SMB clients can.
Step 5.5: SEARCH FOR SIMILAR PATTERNS
Record: Same QUERY_INFO buffer-status pattern already fixed for
filesystem info (qfs_buffercheck) and file info. Security info was the
remaining class for this Samba suite.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
Record: Yes. `smb2_get_info_sec()` at `fs/smb/server/smb2pdu.c:5789` has
the lookup then immediately `file_mnt_idmap()` with no
OutputBufferLength vs `sizeof(struct smb_ntsd)` check. `git merge-base
--is-ancestor 2103add92a HEAD` is false. `git describe HEAD` =
p-6.12-3-gc504cf0baa3d8, `make kernelversion` = 6.12.111.
Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
Record: Clean apply (`git apply --check` succeeded; offset -507 lines
because mainline’s file is larger). No API mismatch.
Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
Record: qfs_buffercheck / partial file info / compound query-info error
handling are here. This exact BUFFER_TOO_SMALL early reject is not. No
alternate fix for qsec_buffercheck found (`git log --grep=qsec` empty on
fs/smb/server).
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
Record: ksmbd (`fs/smb/server`, CONFIG_SMB_SERVER, default n).
Criticality: IMPORTANT for ksmbd deployments (network file server),
PERIPHERAL for kernels that do not enable it.
Step 7.2: ASSESS SUBSYSTEM ACTIVITY
Record: Actively maintained; recent 6.12 backports are mostly ksmbd
protocol and lifetime fixes from Namjae Jeon.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
Step 8.1: DETERMINE WHO IS AFFECTED
Record: ksmbd users (CONFIG_SMB_SERVER). Windows/Samba clients querying
security descriptors with a short or zero output buffer.
Step 8.2: DETERMINE THE TRIGGER CONDITIONS
Record: Common for ACL probes: OutputBufferLength 0 or 1 (exactly what
the Samba test sends; Windows often probes with a small buffer then
retries). Authenticated SMB client on a share; not a local unprivileged
syscall.
Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
Record: Wrong NT status (INVALID_INFO_CLASS instead of
BUFFER_TOO_SMALL). Clients that treat INVALID_INFO_CLASS as
“unsupported” will not retry with a larger buffer, so ACL queries can
fail. Not a kernel oops/UAF. Severity: MEDIUM (interop / functional
failure on a file server), HIGH for ksmbd ACL usability.
Step 8.4: CALCULATE RISK-BENEFIT RATIO
Record:
- Benefit: restores MS-SMB2-required status for short security queries;
unbreaks smb2.getinfo.qsec_buffercheck; repairs fallout from an OOB
fix already in this tree.
- Risk: very low (6 lines, error path only, fd_put balanced).
- Ratio: favorable.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
Step 9.1: COMPILE THE EVIDENCE
FOR:
- Real protocol bug: MS-SMB2 3.3.5.20.3 MUST return
STATUS_BUFFER_TOO_SMALL for insufficient security QUERY_INFO buffers
- Concrete user-visible failure: Samba torture qsec_buffercheck; Windows
ACL size-probe pattern
- Mechanism verified in this tree: ALIGN(secdesclen,8) > scratch_len →
-EFBIG → INVALID_INFO_CLASS
- Follow-up to d48c64fb80ad7, which is already in 6.12.111 (stable-to-
stable)
- 6-line surgical change, fd_put correct, Status not overwritten
- Applies cleanly
- Same class as qfs_buffercheck, already backported here
- Maintainer-authored
AGAINST:
- Not a crash, UAF, or data-corruption fix
- Incomplete vs spec (no 4-byte required length in the error body)
- ksmbd is optional (default n)
- No Fixes:/Cc:stable (expected; not used as a NO)
UNRESOLVED:
- lore/b4 discussion (lore returned errors)
- Whether any reviewer NAK’d (no evidence either way)
Step 9.2: APPLY THE STABLE RULES CHECKLIST
1. Obviously correct and tested? PASS — size check vs NTSD header;
author cites passing qsec_buffercheck; logic confirmed in-tree
2. Fixes a real bug that affects users? PASS — wrong SMB status on
security queries; Windows/Samba clients
3. Important issue? PASS — interoperability failure on a network file
server; fallout from an already-applied OOB fix. Not a panic, but
user-visible ACL query failure
4. Small and contained? PASS — +6 lines, one function
5. No new features or APIs? PASS — error-code correction only
6. Can apply to the local tree? PASS — apply --check succeeded;
prerequisites present
Step 9.3: CHECK FOR EXCEPTION CATEGORIES
Record: None (not a device ID/quirk/DT/build/docs exception). Qualifies
as a normal small bugfix.
Step 9.4: MAKE YOUR DECISION
This should be backported to this 6.12 tree. The buggy path exists, the
OOB-fix regression is here, the patch is tiny and applies, and the wrong
status is a real ksmbd interop bug.
What the commit solves for stable users:
ksmbd currently answers short SMB2 QUERY_INFO security requests with
STATUS_INVALID_INFO_CLASS (or INFO_LENGTH_MISMATCH when extra secinfo
flags are set). Clients that probe with a 0-byte buffer then retry never
learn that they only needed a larger buffer. The patch returns
STATUS_BUFFER_TOO_SMALL after the handle is validated, which is what MS-
SMB2 requires and what Samba’s qsec_buffercheck expects.
Risk vs benefit:
Benefit is restoring ACL query probing on ksmbd 6.12. Risk is a 6-line
error-path change with balanced fd_put. No new APIs, no extra
prerequisites.
Verification:
- [Phase 1] Parsed tags: only Namjae Jeon SOB; no Fixes/Reported-
by/Link/Cc stable
- [Phase 2] Diff: +6 in smb2_get_info_sec after fd lookup;
STATUS_BUFFER_TOO_SMALL + ksmbd_fd_put + return -ENOSPC
- [Phase 2] Confirmed sizeof packed smb_ntsd is 20 bytes
(le16+le16+4×le32)
- [Phase 2] Confirmed smb2_query_info() keeps pre-set Status for -ENOSPC
(does not map to INVALID_INFO_CLASS)
- [Phase 2] Confirmed ALIGN(20,8)=24 > scratch_len 20 produces -EFBIG →
INVALID_INFO_CLASS for AdditionalInformation=0
- [Phase 3] git describe HEAD: p-6.12-3-gc504cf0baa3d8; kernelversion
6.12.111
- [Phase 3] git merge-base --is-ancestor 2103add92a HEAD: not ancestor
- [Phase 3] git merge-base --is-ancestor d48c64fb80ad7 HEAD: yes (OOB
fix present)
- [Phase 3] git blame: lookup from e2f34481b24db2 (2021); ALIGN/scratch
from d48c64fb80ad7
- [Phase 3] Parent 6b8b79226bc3 is in tree as df33d8243ce6b
- [Phase 3] git apply --check: clean (offset -507)
- [Phase 4] GitHub API: mainline SHA
2103add92a02505bdd536ba6fce7f64a427222a2
- [Phase 4] b4 dig: UNVERIFIED (lore server error)
- [Phase 4] Samba getinfo.c: qsec_buffercheck expects BUFFER_TOO_SMALL
for lengths 0 and 1
- [Phase 4] MS-SMB2 3.3.5.20.3: MUST return BUFFER_TOO_SMALL when
OutputBufferLength is zero or insufficient
- [Phase 5] Caller: smb2_query_info via SMB2_QUERY_INFO_HE; network-
reachable
- [Phase 6] Buggy code at smb2pdu.c:5840–5846; no existing qsec fix in
git log
- [Phase 8] Failure mode: wrong NT status → ACL probe/retry failure;
severity MEDIUM/HIGH for ksmbd users
- UNVERIFIED: lore review thread, stable@ discussion, whether error-data
required-size follow-up exists in later mainline
**YES**
fs/smb/server/smb2pdu.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 9bb885fa1ac66..0fbbb47f94644 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -5902,6 +5902,12 @@ static int smb2_get_info_sec(struct ksmbd_work *work,
if (!fp)
return -ENOENT;
+ if (le32_to_cpu(req->OutputBufferLength) < sizeof(struct smb_ntsd)) {
+ rsp->hdr.Status = STATUS_BUFFER_TOO_SMALL;
+ ksmbd_fd_put(work, fp);
+ return -ENOSPC;
+ }
+
idmap = file_mnt_idmap(fp->filp);
inode = file_inode(fp->filp);
ksmbd_acls_fattr(&fattr, idmap, inode);
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: honor client signing-required in all modes
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (11 preceding siblings ...)
2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: return buffer too small for short security queries Sasha Levin
@ 2026-10-19 13:50 ` Sasha Levin
2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: preserve access denied status for copychunk Sasha Levin
` (9 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:50 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit bc2f3f3dd69424f76e2ed3dc53d29bfd6c9966d4 ]
The SMB2 NEGOTIATE request's SMB2_NEGOTIATE_SIGNING_REQUIRED bit requires
the server to set Connection.ShouldSign. KSMBD represents that state with
conn->sign, but previously set it only when its signing configuration was
auto or disabled.
Set conn->sign whenever the client requires signing, independently of the
server's signing mode. Keep the mandatory server-mode handling unchanged.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit message forensics
**Step 1.1 — Subject**
Record: `[ksmbd] [honor] honor client signing-required in all modes`
**Step 1.2 — Tags**
Record:
- `Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>` (ksmbd
maintainer; author and committer of upstream `bc2f3f3dd694`)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Link:`, or
`Cc: stable` (absence expected for this review)
- Pipeline `Signed-off-by: Sasha Levin` ignored per instructions
**Step 1.3 — Body**
Record:
- Bug: MS-SMB2 requires `Connection.ShouldSign` when the client sets
`SMB2_NEGOTIATE_SIGNING_REQUIRED` on NEGOTIATE. ksmbd stores that in
`conn->sign`, but only set it when `server_conf.signing` was `AUTO` or
`DISABLED`.
- Symptom: with `server signing = enabled`, a client that requires
signing does not get `conn->sign` set. Later session signing
(`sess->sign`) can stay off unless SESSION_SETUP repeats the flag.
- Failure mode: protocol MUST violation; session may not be treated as
signing-required.
- Version: present since ksmbd was merged; not a new-code-only bug.
**Step 1.4 — Hidden fix?**
Record: Not disguised. It is an explicit protocol/security correctness
fix.
## Phase 2: Diff analysis
**Step 2.1 — Inventory**
Record:
- File: `fs/smb/server/smb2pdu.c` (upstream +2/−4; this tree matches at
lines 1252–1263)
- Function: `smb2_handle_negotiate()`
- Scope: single-file surgical logic change
**Step 2.2 — Before → after**
Record:
- Before: `conn->sign = true` only if `(AUTO || DISABLED) && client
SIGNING_REQUIRED`, else if `MANDATORY` (force required +
`conn->sign`).
- After: if client SIGNING_REQUIRED → `conn->sign = true` in every
server mode. `MANDATORY` handling is a separate `if` (not `else if`)
and is otherwise unchanged.
- Path: SMB2 NEGOTIATE, once per connection.
**Step 2.3 — Bug mechanism**
Record: Logic/correctness (protocol security).
`KSMBD_CONFIG_OPT_ENABLED` (1) was the missing case. Userspace maps
`server signing = enabled` to that value.
**Step 2.4 — Fix quality**
Record: Obviously correct vs MS-SMB2 3.3.5.4. Minimal. Changing `else
if` to `if` is equivalent for AUTO/DISABLED/MANDATORY. Regression risk
is very low; the only new behavior is honoring client-required signing
when the server mode is ENABLED.
## Phase 3: Git history
**Step 3.1 — Blame**
Record: Buggy condition is from `e2f34481b24db` (“cifsd: add server-side
procedures for SMB3”, 2021-05-10). Whitespace-only tweak in
`64b39f4a2fd29`. Present since ksmbd entered mainline (~v5.15).
**Step 3.2 — Fixes: tag**
Record: None. Introduction commit is an ancestor of this tree (`git
merge-base --is-ancestor e2f34481b24db HEAD` succeeded).
**Step 3.3 — File history**
Record: Recent `smb2pdu.c` work is leases, durable reconnect, negotiate
races — not this signing condition. Standalone, not “patch X/Y”.
**Step 3.4 — Author**
Record: Namjae Jeon is the ksmbd maintainer. Nearby work is other ksmbd
protocol/security fixes, not a prerequisite series for this hunk.
**Step 3.5 — Dependencies**
Record: None. Uses existing `conn->sign`, `server_conf.signing`, and
`SMB2_NEGOTIATE_SIGNING_REQUIRED_LE`. `git apply --check` of a line-
adjusted patch is clean.
## Phase 4: Mailing list / external
**Step 4.1 — Original discussion**
Record: Upstream SHA `bc2f3f3dd69424f76e2ed3dc53d29bfd6c9966d4`
(authored 2026-07-17, committed 2026-08-17). `b4 dig` failed:
lore.kernel.org returned errors (bot protection). No thread URL
retrieved.
**Step 4.2 — Reviewers**
Record: UNVERIFIED via b4. Namjae is both author and committer; typical
for ksmbd maintainer commits.
**Step 4.3 — Bug report**
Record: No `Reported-by` / syzbot / bugzilla. The 7.3-rc1 ksmbd pull
(Namjae Jeon, 2026-08-23) lists “signing-required handling” under
“SMB2/SMB3 protocol validation and security issues” and mentions
smbtorture-validated compatibility fixes.
**Step 4.4 — Series**
Record: Independent of the 7.3 features landed the same day (replay,
sequence window, Time Machine). This hunk does not use those structures.
**Step 4.5 — stable@**
Record: lore.kernel.org/stable search returned 403. No stable-specific
NAK found.
## Phase 5: Code semantics
**Step 5.1 — Functions**
Record: `smb2_handle_negotiate()` only.
**Step 5.2 — Callers**
Record: Called from `fs/smb/server/smb_common.c` during SMB2 dialect
negotiate, under `conn->srv_mutex`. That is the first SMB2 command on a
connection (TCP 445). User-reachable on every ksmbd connection.
**Step 5.3 — Callees / effects**
Record: `conn->sign` is `Connection.ShouldSign`. It is consumed in NTLM
and Kerberos session setup to set `sess->sign`. `sess->sign` causes
response signing in `__handle_ksmbd_work()`.
**Step 5.4 — Reachability**
Record: Yes, from the network. Gated on `CONFIG_SMB_SERVER` (default n).
**Step 5.5 — Similar patterns**
Record: SESSION_SETUP has a second check: `req->SecurityMode &
SMB2_NEGOTIATE_SIGNING_REQUIRED`. Compliant clients (MS-SMB2 MUST, Linux
CIFS) usually set the same flag on SESSION_SETUP, so `sess->sign` can
still be set. That is a fallback, not a reason the NEGOTIATE bug is
absent. SMB1-style negotiate around line 307 only advertises REQUIRED in
MANDATORY mode and does not set `conn->sign`.
Verified in this tree: `smb2_is_sign_req()` still only looks at
`SMB2_FLAGS_SIGNED` on the request. This patch does not add reject-
unsigned-when-required. It only sets ShouldSign so session signing state
can follow the spec.
## Phase 6: This tree (6.12.111)
**Step 6.1 — Buggy code present?**
Record: Yes, `fs/smb/server/smb2pdu.c` lines 1255–1263. Local tree:
`p-6.12-3-gc504cf0baa3d8`, `make kernelversion` = **6.12.111**. Upstream
commit is **not** an ancestor (`git merge-base --is-ancestor
bc2f3f3dd694 HEAD` failed).
**Step 6.2 — Backport difficulty**
Record: Clean apply after shifting hunks (~1252 vs upstream ~1687).
Surrounding negotiate code matches.
**Step 6.3 — Related fixes already here?**
Record: `1ae94dd9dea50` (“mark invalid session responses as signed”) is
a different FLAGS_SIGNED error-path issue. No existing fix for the
ENABLED-mode `conn->sign` gap.
## Phase 7: Subsystem
**Step 7.1**
Record: `fs/smb/server` (ksmbd). Criticality: IMPORTANT (network-facing
SMB3 server; not core mm/VFS, but production NAS/OpenWrt/etc.).
**Step 7.2**
Record: Actively maintained; this 6.12 tree already carries many later
ksmbd security/protocol backports.
## Phase 8: Impact and risk
**Step 8.1 — Who**
Record: ksmbd users (`CONFIG_SMB_SERVER`) with `server signing =
enabled`. ksmbd-tools `cp_get_group_kv_config_opt()` maps `"enabled"` →
`KSMBD_CONFIG_OPT_ENABLED`. Default in tools is `auto` (already
correct). `"enabled"` is still a parsed, distinct value (Samba-style
configs often use it). Man page documents disabled/auto/mandatory;
userspace still accepts enabled.
**Step 8.2 — Trigger**
Record: Client sets NEGOTIATE `SMB2_NEGOTIATE_SIGNING_REQUIRED` while
server mode is ENABLED. Common for Windows/Linux clients that require
signing. Unprivileged remote clients can send that bit.
**Step 8.3 — Failure mode**
Record: Protocol MUST missed; `Connection.ShouldSign` stays false.
Severity: **MEDIUM–HIGH** (integrity of SMB traffic / spec security
negotiation), not a panic. Mitigated if SESSION_SETUP also carries
SIGNING_REQUIRED.
**Step 8.4 — Risk vs benefit**
Record: Benefit: honor client-required signing in the one broken mode;
matches spec and maintainer intent. Risk: very low (4-line boolean, no
locks/APIs/new features). Ratio: favorable.
## Phase 9: Synthesis
**For backporting**
- Real MS-SMB2 MUST violation in existing 6.12 code
- Security-related signing negotiation on a network file server
- Tiny, obviously correct, applies cleanly
- Maintainer-authored; 7.3-rc1 pull grouped it with protocol/security
fixes
- `server signing = enabled` is a real userspace mapping
**Against**
- Default `auto` already sets `conn->sign`
- SESSION_SETUP fallback for compliant clients
- No crash/syzbot/CVE
- Does not fully enforce unsigned-request rejection (`is_sign_req` still
flag-based)
**Unresolved**
- Full lore review thread (lore 403 / b4 failed)
- No stable@ discussion retrieved
**Stable rules**
1. Obviously correct and tested? **PASS** (logic vs spec; maintainer-
committed)
2. Real bug affecting users? **PASS** (ENABLED mode + client
SIGNING_REQUIRED)
3. Important (security/protocol integrity)? **PASS** (signing-required
handling; not a panic)
4. Small and contained? **PASS** (+2/−4, one function)
5. No new features/APIs? **PASS**
6. Applies to this tree? **PASS** (clean apply)
No exception category (not a device ID/quirk/DT/build/docs-only change).
It is a normal small protocol fix.
The ENABLED hole is the mode where admins reasonably expect signing to
work, and it is the only mode that ignored a client REQUIRED bit. Cost
of backporting to 6.12.y is negligible.
Verification:
- [Phase 1] Parsed message/tags: only Namjae SOB; no Fixes/Reported-by
- [Phase 2] Diff: `smb2_handle_negotiate()` condition; ENABLED was
skipped
- [Phase 3] `git blame` / `-L`: introduced in `e2f34481b24db` (v5.15-era
cifsd)
- [Phase 3] `git merge-base --is-ancestor e2f34481b24db HEAD`: yes
- [Phase 3] `git merge-base --is-ancestor bc2f3f3dd694 HEAD`: no (not in
this tree)
- [Phase 3] `git apply --check`: clean on 6.12 `smb2pdu.c`
- [Phase 4] GitHub API: upstream
`bc2f3f3dd69424f76e2ed3dc53d29bfd6c9966d4`
- [Phase 4] `b4 dig -c bc2f3f3dd694`: lore errors, no thread
- [Phase 4] 7.3-rc1 GIT PULL: “signing-required handling” under
protocol/security
- [Phase 5] Caller: `smb_common.c` SMB2 NEGOTIATE; `conn->sign` →
`sess->sign` in session setup
- [Phase 5] `smb2_is_sign_req()` does not use `conn->sign` (verified)
- [Phase 6] `git describe HEAD`: `p-6.12-3-gc504cf0baa3d8`; `make
kernelversion`: 6.12.111; buggy `if` present at 1255–1263
- [Phase 8] ksmbd-tools `config_parser.c`: `"enabled"` →
`KSMBD_CONFIG_OPT_ENABLED`; default `"server signing = auto"`
- UNVERIFIED: mailing-list NAKs/Cc: stable (lore unavailable)
This is a small, contained protocol-security fix that already matches
this tree’s ksmbd negotiate path and should be backported.
**YES**
fs/smb/server/smb2pdu.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index cc3a3da410eaf..e7b1cab45ab2d 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -1253,11 +1253,9 @@ int smb2_handle_negotiate(struct ksmbd_work *work)
rsp->SecurityMode = SMB2_NEGOTIATE_SIGNING_ENABLED_LE;
conn->use_spnego = true;
- if ((server_conf.signing == KSMBD_CONFIG_OPT_AUTO ||
- server_conf.signing == KSMBD_CONFIG_OPT_DISABLED) &&
- req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED_LE)
+ if (req->SecurityMode & SMB2_NEGOTIATE_SIGNING_REQUIRED_LE)
conn->sign = true;
- else if (server_conf.signing == KSMBD_CONFIG_OPT_MANDATORY) {
+ if (server_conf.signing == KSMBD_CONFIG_OPT_MANDATORY) {
server_conf.enforced_signing = true;
rsp->SecurityMode |= SMB2_NEGOTIATE_SIGNING_REQUIRED_LE;
conn->sign = true;
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: preserve access denied status for copychunk
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (12 preceding siblings ...)
2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: honor client signing-required in all modes Sasha Levin
@ 2026-10-19 13:50 ` Sasha Levin
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: fix heap out-of-bounds write in krb5_authenticate() Sasha Levin
` (8 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:50 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit f7c0366e0a80bf8cd5eacc5479927abb50958b5e ]
The copychunk error mapping handles -EACCES in an independent if
statement. The following error chain therefore reaches its final else
clause and overwrites STATUS_ACCESS_DENIED with
STATUS_UNEXPECTED_IO_ERROR.
Join the -EACCES check to the remaining error chain so an access failure
is returned as STATUS_ACCESS_DENIED.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
I have the full picture: the one-line `if`/`else if` bug is in this
6.12.111 tree, it applies cleanly, and the original submitter explicitly
asked for stable. Writing up the nine-phase analysis.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[ksmbd]** **[preserve]** preserve access denied status for
copychunk.
Subsystem is the in-kernel SMB3 server. “Preserve” here means “stop
overwriting a correctly computed NTSTATUS,” which is a correctness fix,
not a feature.
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Mainline commit `f7c0366e0a80bf8cd5eacc5479927abb50958b5e` (author
Namjae Jeon, AuthorDate 2026-07-07, CommitDate 2026-08-17):
- Signed-off-by: Namjae Jeon \<linkinjeon@kernel.org\> (ksmbd
maintainer; he both authored and committed it)
- No Fixes:, Reported-by, Tested-by, Reviewed-by, Acked-by, Link:, or
Cc: stable on the committed version
The absence of Fixes:/Cc: stable on the committed object is expected for
this review pipeline and is not a negative signal.
An independent mailing-list submission of the **same one-line change**
did carry those tags (see Phase 4):
- Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
- Cc: stable@vger.kernel.org
- Reviewed-by: ChenXiaoSong
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** In `fsctl_copychunk()`, `-EACCES` is handled by a standalone
`if`. The next `if (ret == -EAGAIN) / else if ... / else` chain then
runs anyway.
- **Symptom:** `STATUS_ACCESS_DENIED` is written, then immediately
overwritten by `STATUS_UNEXPECTED_IO_ERROR`.
- **Failure mode:** SMB clients doing server-side copy (FSCTL_COPYCHUNK
/ FSCTL_COPYCHUNK_WRITE) see a generic I/O error instead of access
denied. The copy is still rejected; the protocol status is wrong.
- **Version info:** none in the committed message. The UnionTech
submission pins it to the original cifsd SMB3 engine commit.
- **Root cause:** missing `else` so `-EACCES` falls into the final
`else`.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not hidden. The message describes a real control-flow bug.
“Preserve” is the action verb for keeping the correct status.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `fs/smb/server/smb2pdu.c` — 1 line changed (`if` → `else if`)
- Function: `fsctl_copychunk()`
- Scope: single-file surgical fix
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
This tree currently has:
```7988:8005:fs/smb/server/smb2pdu.c
if (ret < 0) {
if (ret == -EACCES)
rsp->hdr.Status = STATUS_ACCESS_DENIED;
if (ret == -EAGAIN)
rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT;
else if (ret == -EBADF)
rsp->hdr.Status = STATUS_INVALID_HANDLE;
else if (ret == -EFBIG || ret == -ENOSPC)
rsp->hdr.Status = STATUS_DISK_FULL;
else if (ret == -EINVAL)
rsp->hdr.Status = STATUS_INVALID_PARAMETER;
else if (ret == -EISDIR)
rsp->hdr.Status = STATUS_FILE_IS_A_DIRECTORY;
else if (ret == -E2BIG)
rsp->hdr.Status = STATUS_INVALID_VIEW_SIZE;
else
rsp->hdr.Status = STATUS_UNEXPECTED_IO_ERROR;
}
```
Record: Before, `-EACCES` sets `STATUS_ACCESS_DENIED`, then misses
`-EAGAIN` and every later `else if`, and the final `else` overwrites it
with `STATUS_UNEXPECTED_IO_ERROR`. After, `-EACCES` is exclusive and the
status sticks. Other errno mappings are unchanged. This is the
`ksmbd_vfs_copy_file_ranges()` error path, not probe/init.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **Logic / correctness.** Missing `else` on an errno-to-NTSTATUS
ladder. `-EACCES` is a real return from `ksmbd_vfs_copy_file_ranges()`:
```1840:1847:fs/smb/server/vfs.c
if (!(src_fp->daccess & (FILE_READ_DATA_LE | FILE_EXECUTE_LE)))
{
pr_err("no right to read(%pD)\n", src_fp->filp);
return -EACCES;
}
if (!(dst_fp->daccess & (FILE_WRITE_DATA_LE |
FILE_APPEND_DATA_LE))) {
pr_err("no right to write(%pD)\n", dst_fp->filp);
return -EACCES;
}
```
`vfs_copy_file_range()` can also return `-EACCES`. The access check
still denies the copy; only the SMB status is wrong.
**Step 2.4: ASSESS THE FIX QUALITY**
Record: Obviously correct. One token. No API, locking, or allocation
change. Regression risk is negligible: `-EACCES` already matched nothing
else in the chain.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record: `git blame -L 7988,8005 fs/smb/server/smb2pdu.c` attributes the
whole ladder to `e2f34481b24db2` (“cifsd: add server-side procedures for
SMB3”, Namjae Jeon, 2021-03-16). That is the original ksmbd/cifsd SMB3
engine, present since the server was merged (v5.15-era). The bug is old,
not recent churn.
**Step 3.2: FOLLOW THE FIXES: TAG**
Committed object has no Fixes: tag. The equivalent linux-cifs patch
tagged `e2f34481b24d`. `git merge-base --is-ancestor e2f34481b24db2
HEAD` succeeded — the introducing commit is in this tree. No later
rewrite of this ladder was found in this checkout.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record: Recent `smb2pdu.c` work in this tree is unrelated (partial
QUERY_INFO responses, compound errors, lease/durable-handle fixes).
Neighboring mainline copychunk work from the same day (`fd309860ef245`
overlapping-copy data preservation, `8482150a0743c` ADS copychunk) is
**not** in HEAD and is **not** required: this change only joins two
`if`s in the error map. Standalone.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Namjae Jeon is the ksmbd maintainer (`git log --author="Namjae
Jeon" -- fs/smb/server/`). He authored and committed this. Same-day
mainline commits touch other copychunk behavior but do not alter this
mapping.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: None. `git show f7c0366e0a80b | git apply --check` succeeded on
this tree (hunk offset -764 lines). No new helpers or structs.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c f7c0366e0a80b` failed (lore returned an error to b4).
- Direct lore search found the same fix submitted independently:
https://lore.kernel.org/linux-
cifs/2DC5EE1DC892643F+20260731072020.1307022-1-raoxu@uniontech.com/
Xu Rao (UnionTech), 2026-07-31, subject “ksmbd: preserve
STATUS_ACCESS_DENIED for copychunk errors”. Same `if` → `else if`. Cites
**MS-SMB2 3.3.5.15.6**: FSCTL_SRV_COPYCHUNK / COPYCHUNK_WRITE must fail
with `STATUS_ACCESS_DENIED` when the source open lacks `FILE_READ_DATA`
or the destination lacks `FILE_WRITE_DATA`/`FILE_APPEND_DATA`.
**Fixes:** e2f34481b24d. **Cc: stable@vger.kernel.org.** No NAK.
Namjae’s committed patch (author date 2026-07-07) is the same change,
queued earlier in ksmbd-for-next and merged via `ksmbd-for-7.3-rc1`
(`git describe --contains` → `v7.3-rc1~77^2~124`).
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: UnionTech patch To/Cc: Namjae Jeon, Steve French, Sergey
Senozhatsky, Tom Talpey, linux-cifs, LKML, **stable@vger.kernel.org**.
ChenXiaoSong replied with Reviewed-by.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No syzbot/bugzilla. Two independent authors (maintainer +
UnionTech) found the same missing-`else`. Spec citation is MS-SMB2
3.3.5.15.6.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Not a numbered series. Same-day copychunk patches are
independent and not in this tree; this line does not need them.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable search for this subject did not turn up a
prior rejection. The UnionTech mail itself was Cced to stable.
ChenXiaoSong noted the bug was already fixed in ksmbd-for-next-next (htt
ps://github.com/smfrench/smb3-
kernel/commit/35e11e324a2f97d2974ef08d308063c9c5f9e9d8) — that is the
maintainer tree copy of this same fix, not a reason to skip stable.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**
Record: `fsctl_copychunk()` only.
**Step 5.2: TRACE CALLERS**
Record: Only caller is `smb2_ioctl()` for `FSCTL_COPYCHUNK` /
`FSCTL_COPYCHUNK_WRITE` (`fs/smb/server/smb2pdu.c` around 8466–8495).
`smb2_ioctl` is registered as `SMB2_IOCTL_HE` in
`fs/smb/server/smb2ops.c`. Reachable from any authenticated SMB2/SMB3
client issuing a copychunk FSCTL (Windows Explorer / CopyFile server-
side copy, robocopy, smbclient, etc.).
Important: `fsctl_copychunk()`’s return value is discarded. Status is
taken from `rsp->hdr.Status`, then `ksmbd_iov_pin_rsp()` sends the ioctl
response. The wrong status is what the client actually receives.
Tree-not-writable uses `ret = -EACCES; goto out;` in `smb2_ioctl()` and
maps correctly. The broken path is the **file-handle** access check
inside `ksmbd_vfs_copy_file_ranges()`.
**Step 5.3: TRACE CALLEES**
Record: `ksmbd_vfs_copy_file_ranges()` → access checks, lock checks,
`vfs_copy_file_range()`. `-EACCES` comes from the access checks (and
potentially VFS).
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: SMB2 IOCTL (network) → `smb2_ioctl` → `fsctl_copychunk` →
`ksmbd_vfs_copy_file_ranges`. Triggerable by a logged-in SMB user with
opens that lack read-on-source or write-on-dest. Not a local
unprivileged syscall, but a normal file-server path.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: The only other `if (ret == -EACCES)` in
`fs/smb/server/smb2pdu.c` is the outer `smb2_ioctl()` mapper, which
**already** uses `else if`. This copychunk ladder is the broken
instance.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: Yes. `git describe HEAD` = `p-6.12-3-gc504cf0baa3d8`; `make
kernelversion` = **6.12.111**. Buggy ladder is at
`fs/smb/server/smb2pdu.c:7988-8005`. `git merge-base --is-ancestor
f7c0366e0a80b HEAD` failed — fix is **not** in this checkout. Introduced
by `e2f34481b24d` (2021), which **is** an ancestor of HEAD.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: **Clean apply.** `git apply --check` of the mainline diff
succeeded (offset -764). Surrounding copychunk ioctl code matches aside
from line numbers. Mainline context uses `FSCTL_SRV_COPYCHUNK` in a
nearby (unchanged) check; this tree still uses `FSCTL_COPYCHUNK`. That
is outside the changed line and did not block apply.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: `git log --grep="preserve access denied" -- fs/smb/server` has
no hit. No alternate mapping fix in this tree.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: `fs/smb/server` (ksmbd), `CONFIG_SMB_SERVER`. **IMPORTANT** for
NAS/embedded/distros that ship ksmbd; not core mm/VFS for every box.
Protocol status on copychunk is user-visible for those servers.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Actively maintained (many recent ksmbd commits on this branch).
This particular ladder has been unchanged since 2021.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: Config-specific / server-specific: ksmbd users. Windows and
other SMB clients using server-side copy against ksmbd.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record: Authenticated client issues FSCTL_COPYCHUNK[_WRITE] with a
source handle lacking read/execute or a dest handle lacking write/append
(or VFS returns `-EACCES`). Common for copy-offload when opens don’t
carry the rights MS-SMB2 requires. Not a rare race.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: Wrong NTSTATUS (`STATUS_UNEXPECTED_IO_ERROR` instead of
`STATUS_ACCESS_DENIED`). Copy is still denied — not a bypass, crash, or
corruption. Clients/apps can surface “I/O device error”, retry, or
mishandle a permission failure. **Severity: MEDIUM**, but it is a
documented SMB protocol violation (MS-SMB2 3.3.5.15.6).
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- **Benefit:** Correct access-denied reporting on a standard Windows
copy-offload path; matches spec.
- **Risk:** Very low (one `else`, no behavioral change except the status
for `-EACCES`).
- **Ratio:** Favorable. Independent submitter Cced stable for this exact
change.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
FOR:
- Real, verified missing-`else` bug in this 6.12.111 tree
- `-EACCES` is a live return from `ksmbd_vfs_copy_file_ranges()`
- Client-visible SMB status is wrong; MS-SMB2 requires ACCESS_DENIED
- 1-line, obviously correct, applies cleanly
- Present since original cifsd merge; introducing commit is in HEAD
- Maintainer-authored; independently rediscovered; Reviewed-by
ChenXiaoSong; **Cc: stable** on the public patch
- No prerequisites
AGAINST:
- Not a crash, UAF, deadlock, or data-corruption fix
- Committed object dropped Fixes:/Cc: stable
- Only affects `CONFIG_SMB_SERVER`
UNRESOLVED:
- `b4 dig` could not match Namjae’s committed subject (lore error). The
UnionTech thread was recovered by direct lore search and is the same
diff.
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — control flow is unambiguous;
maintainer committed it; Reviewed-by on the twin patch.
2. Fixes a real bug that affects users? **PASS** — wrong NTSTATUS on
copychunk permission failure.
3. Important issue? **PASS** (medium, protocol) — spec-mandated
ACCESS_DENIED becomes UNEXPECTED_IO_ERROR on a common Windows copy
path; not a crash, but user-visible interoperability.
4. Small and contained? **PASS** — 1 line, one function.
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — `git apply --check`
succeeded.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: None (not a device ID/quirk/DT/build/docs exception). Qualifies
as a normal small correctness fix.
**Step 9.4: MAKE YOUR DECISION**
This belongs in 6.12.y. The buggy ladder is here, the fix is one `else`,
and it restores the NTSTATUS ksmbd already tried to set and that MS-SMB2
requires. Risk is essentially zero.
------------------------------------------------
What the commit solves for this tree
------------------------------------------------
On 6.12.111 ksmbd, `fsctl_copychunk()` maps `-EACCES` from
`ksmbd_vfs_copy_file_ranges()` to `STATUS_ACCESS_DENIED`, then the next
if/else chain overwrites it with `STATUS_UNEXPECTED_IO_ERROR`. SMB
clients doing server-side copy therefore see a generic I/O error instead
of access denied. The copy is still rejected; the protocol status is
wrong. Joining the `-EACCES` arm with `else if` is the whole fix.
It meets the stable rules: obviously correct, real user-visible bug,
tiny, no new API, applies cleanly here. Benefit is correct SMB
semantics; regression risk is negligible.
Concerns: not a panic/UAF class bug; ksmbd-only. Those do not outweigh a
one-line protocol-status fix that an independent submitter already
nominated for stable.
Verification:
- [Phase 1] Parsed committed tags: only SOB Namjae Jeon on
`f7c0366e0a80b`; no Fixes:/Cc: stable on the git object
- [Phase 1] UnionTech twin patch on lore has Fixes: e2f34481b24d and Cc:
stable@vger.kernel.org
- [Phase 2] Diff: 1 line in `fsctl_copychunk()`, `if` → `else if` on
`-EAGAIN`
- [Phase 2] Confirmed `-EACCES` returns in
`ksmbd_vfs_copy_file_ranges()` at vfs.c:1840-1847 in this tree
- [Phase 2] Confirmed overwrite path in smb2pdu.c:7988-8005 in this tree
- [Phase 3] git blame: ladder from e2f34481b24db2 (2021 cifsd SMB3
engine)
- [Phase 3] git merge-base --is-ancestor e2f34481b24db2 HEAD: yes
- [Phase 3] git merge-base --is-ancestor f7c0366e0a80b HEAD: no (fix not
present)
- [Phase 3] Neighboring copychunk commits fd309860ef245 / 8482150a0743c:
not in HEAD, not required
- [Phase 3] git apply --check of mainline diff: succeeded at offset -764
- [Phase 4] b4 dig -c f7c0366e0a80b: lore error, no match
- [Phase 4] lore thread: https://lore.kernel.org/linux-
cifs/2DC5EE1DC892643F+20260731072020.1307022-1-raoxu@uniontech.com/ —
same diff, Cc: stable, MS-SMB2 3.3.5.15.6
- [Phase 4] ChenXiaoSong Reviewed-by; noted already in ksmbd-for-next-
next
- [Phase 4] stable list: no prior rejection found
- [Phase 5] Only caller: smb2_ioctl FSCTL_COPYCHUNK/COPYCHUNK_WRITE;
return value discarded; client sees rsp->hdr.Status
- [Phase 5] Only other -EACCES map in smb2pdu.c already uses else if
- [Phase 6] git describe HEAD: p-6.12-3-gc504cf0baa3d8; kernelversion
6.12.111
- [Phase 6] git describe --contains f7c0366e0a80b: v7.3-rc1~77^2~124
(merged in ksmbd-for-7.3-rc1)
- [Phase 8] Failure mode: wrong NTSTATUS on permission failure, MEDIUM,
not a crash
- UNVERIFIED: Could not retrieve Namjae’s original mail (b4/lore subject
mismatch); content confirmed via committed diff + UnionTech thread
**YES**
fs/smb/server/smb2pdu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 4f8e2a6307602..22c49921b1c07 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -8068,7 +8068,7 @@ static int fsctl_copychunk(struct ksmbd_work *work,
if (ret < 0) {
if (ret == -EACCES)
rsp->hdr.Status = STATUS_ACCESS_DENIED;
- if (ret == -EAGAIN)
+ else if (ret == -EAGAIN)
rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT;
else if (ret == -EBADF)
rsp->hdr.Status = STATUS_INVALID_HANDLE;
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: fix heap out-of-bounds write in krb5_authenticate()
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (13 preceding siblings ...)
2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: preserve access denied status for copychunk Sasha Levin
@ 2026-10-19 13:51 ` Sasha Levin
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.6] smb: server: Make sure that passkey is not leaked on the heap in user_config.c Sasha Levin
` (7 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:51 UTC (permalink / raw)
To: patches, stable
Cc: Ilan Dudnik, Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Ilan Dudnik <ilan.dudnik@safebreach.com>
[ Upstream commit 23a0be6a84a38ac169eeab49017934e8e27c65f0 ]
In krb5_authenticate(), out_len is calculated to determine available
headroom in response_buf for the incoming Kerberos AP-REP token. However,
when SMB2_SESSION_SETUP is processed as a non-first element of a compounded
SMB2 request, the calculation omits work->next_smb2_rsp_hdr_off.
This causes out_len to overstate remaining buffer headroom by
the cumulative size of prior responses in the compound chain. Consequently,
the length check in ksmbd_krb5_authenticate()
(*out_len <= resp->spnego_blob_len) passes erroneously, allowing memcpy()
to write the AP-REP blob past the end of response_buf into adjacent kernel
heap memory.
Fix this by subtracting work->next_smb2_rsp_hdr_off when computing out_len,
ensuring it accurately reflects physical remaining buffer space.
Signed-off-by: Ilan Dudnik <ilan.dudnik@safebreach.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.12.111** (`pending-6.12`). The buggy `out_len`
math is present, and the one-line heap-OOB fix applies here.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: `[ksmbd] [fix] heap out-of-bounds write in krb5_authenticate()`
- Subsystem: ksmbd (in-kernel SMB3 server)
- Action verb: **fix**
- Claimed intent: stop a heap OOB write while building a Kerberos AP-REP
in `krb5_authenticate()`
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Upstream commit: `23a0be6a84a38ac169eeab49017934e8e27c65f0` (verified
via `git show` on `origin/master`)
Tags present:
- Signed-off-by: Ilan Dudnik \<ilan.dudnik@safebreach.com\> (author;
SafeBreach threat research)
- Signed-off-by: Namjae Jeon \<linkinjeon@kernel.org\> (ksmbd
maintainer, committer)
Tags absent (expected for this review pipeline):
- No `Fixes:`
- No `Cc: stable@vger.kernel.org`
- No `Reported-by:` / `Tested-by:` / `Reviewed-by:` / `Acked-by:` /
`Link:`
Notable: author is a security researcher; the ksmbd maintainer applied
the patch directly.
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** `out_len` is computed from `work->response_sz` minus
`SecurityBufferOffset + 4`, and does not subtract
`work->next_smb2_rsp_hdr_off`.
- **When:** SMB2 `SESSION_SETUP` as a **non-first** compound command
(`next_smb2_rsp_hdr_off > 0`).
- **Symptom:** `out_len` overstates remaining heap by the size of prior
compound responses. `ksmbd_krb5_authenticate()` then accepts a blob
that does not actually fit, and `memcpy()` writes the AP-REP past
`response_buf`.
- **Failure mode:** kernel **heap out-of-bounds write**.
- **Version info in message:** none. Code has been this way since ksmbd
was added.
- **Root cause:** remaining-space calculation uses the start of the
allocation, not the current compound slot.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not hidden. Explicit heap-OOB write fix. Not cleanup/refactor.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `fs/smb/server/smb2pdu.c` — **+1 / -1** (one line)
- Function: `krb5_authenticate()`
- Scope: **single-file surgical fix**
```2160:2164:fs/smb/server/smb2pdu.c
out_blob = (char *)&rsp->hdr.ProtocolId +
le16_to_cpu(rsp->SecurityBufferOffset);
- out_len = work->response_sz -
+ out_len = work->response_sz - work->next_smb2_rsp_hdr_off -
(le16_to_cpu(rsp->SecurityBufferOffset) + 4);
```
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- **Before:** `out_len = response_sz - (SecurityBufferOffset + 4)` =
space from the **start** of the SMB payload to the end of the
allocation.
- **After:** also subtract `next_smb2_rsp_hdr_off`, i.e. space from the
**current** compound response to the end of the allocation.
- Path: Kerberos `SESSION_SETUP` after
`ksmbd_ipc_spnego_authen_request()` succeeds, immediately before
`memcpy(out_blob, ...)`.
- First-in-compound (`next_smb2_rsp_hdr_off == 0`): behavior unchanged.
Verified layout in this tree:
- `ksmbd_resp_buf_next()` = `response_buf + next_smb2_rsp_hdr_off + 4`
- `WORK_BUFFERS` uses that for non-first compound commands
- `out_blob = rsp + SecurityBufferOffset`
- Remaining bytes = `response_sz - next_smb2_rsp_hdr_off -
SecurityBufferOffset - 4`
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record:
- **Category:** (d) memory safety — heap buffer overflow / OOB write
- **Mechanism:** length check `*out_len <= resp->spnego_blob_len` in
`ksmbd_krb5_authenticate()` uses an inflated `out_len`. Check passes;
`memcpy(out_blob, resp->payload + session_key_len,
resp->spnego_blob_len)` writes off the end of `response_buf`.
- Confirmed memcpy in this tree:
```533:572:fs/smb/server/auth.c
if (*out_len <= resp->spnego_blob_len) {
ksmbd_debug(AUTH, "buf len %d, but blob len %d\n",
*out_len, resp->spnego_blob_len);
retval = -EINVAL;
goto out;
}
...
memcpy(out_blob, resp->payload + resp->session_key_len,
resp->spnego_blob_len);
```
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- Obviously correct: remaining space must exclude prior compound
responses.
- Minimal: one term added to one expression.
- Regression risk: **very low**.
- First command: `next_smb2_rsp_hdr_off` is 0 (work is zeroed).
- If `out_len` goes negative, `*out_len <= blob_len` is true →
`-EINVAL`, no memcpy (fail closed).
- No API/data-structure/locking changes.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- `out_len = work->response_sz -` introduced in `e2f34481b24db2`
(“cifsd: add server-side procedures for SMB3”, 2021-05-10). Ancestor
of HEAD.
- Offset term `(SecurityBufferOffset + 4)` from `cb4517201b8acd`
(“ksmbd: remove smb2_buf_length in smb2_hdr”, 2021-11-11).
- Bug has been in ksmbd since it entered the kernel (~5.15), including
6.12.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. Introducer is `e2f34481b24db2`, present in this
tree (`git merge-base --is-ancestor` exit 0).
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record:
- `98422bdd4cb3c` “ksmbd: fix out of bounds read in smb2_sess_setup” (in
this tree): compound `SESSION_SETUP` used `smb2_get_msg()` on the
**start** of the buffer → OOB **read**. ZDI-CAN-21355. They passed
`req`/`rsp` from `WORK_BUFFERS` but **did not** fix `out_len`.
- Other compound OOB fixes already in 6.12 (`smb2_get_ea`, `QUERY_INFO`,
`get_file_all_info`) show this class of bug is real and has been
backported before.
- This commit is standalone (not `N/M`).
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record:
- Ilan Dudnik: two ksmbd security fixes in 7.3 (`23a0be6a84a38` and
`29f74f0f2e6df` UAF/double-free in lock publishing). Not a regular in-
tree 6.12 contributor.
- Namjae Jeon is the ksmbd maintainer and committed this.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record:
- Mainline `krb5_authenticate()` later grew `channel_key` / `auth_key`;
**6.12 does not have those**. The changed `out_len` lines are the
same.
- `next_smb2_rsp_hdr_off` exists in `ksmbd_work.h` here.
- `git show 23a0be6a84a38 | git apply --check` **succeeds** on this
tree.
- Standalone: **yes**.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c 23a0be6a84a38`: lore returned errors; no thread match.
- `curl` lore linux-cifs / all for `Ilan Dudnik` and `krb5_authenticate
heap`: **no public thread**.
- Likely private maintainer submission (typical for a security-firm heap
overflow).
- Landed via ksmbd-for-7.3-rc1 pull (Namjae Jeon, 2026-08-23). Pull
text: “Fix heap out-of-bounds accesses … in authentication, Kerberos
…”.
- Contained in `v7.3-rc1~77^2~32`.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: No public review trail. Signed off and committed by Namjae Jeon
(MAINTAINERS: KERNEL SMB3 SERVER). That is maintainer-acked.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No syzbot/bugzilla/CVE found for **this** heap OOB (other 2026
ksmbd CVEs are different bugs). Author affiliation is independently
verified (SafeBreach). UNVERIFIED: no public reproducer.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Same-author sibling `29f74f0f2e6df` is a different bug (lock
UAF). This `out_len` change does not depend on it.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore/stable hits are **other** ksmbd OOB patches (ZDI compound
sess_setup OOB-read; stack channel_key overflow). **This** commit is not
on stable@ yet. The 2023 compound sess_setup OOB-read **was**
backported, which supports backporting this related compound-buffer bug.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**
Record: `krb5_authenticate()` (caller of `ksmbd_krb5_authenticate()`).
**Step 5.2: TRACE CALLERS**
Record:
- Only caller: `smb2_sess_setup()` when `preferred_auth_mech` includes
`KSMBD_AUTH_KRB5 | KSMBD_AUTH_MSKRB5`.
- `smb2_sess_setup` is the SMB2 SESSION_SETUP handler (`server.c`
`__process_request` loop).
- Compound: after each command, `is_chained_smb2_message()` advances
`next_smb2_rsp_hdr_off`.
- `smb2_check_user_session()` returns 0 for SESSION_SETUP **without**
requiring a session, so SESSION_SETUP as a later compound element is
allowed.
**Step 5.3: TRACE CALLEES**
Record: `ksmbd_krb5_authenticate()` →
`ksmbd_ipc_spnego_authen_request()` (netlink to ksmbd.mountd) → length
check → `memcpy` of AP-REP into `out_blob`.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record:
- Reachable from the network on a ksmbd share with Kerberos
(`CONFIG_SMB_SERVER_KERBEROS5`).
- `memcpy` runs only after userspace reports `KSMBD_USER_FLAG_OK`
(successful Kerberos).
- Trigger is still realistic: compound a large command (e.g.
`QUERY_DIRECTORY` / `IOCTL`, which use `large_sz = 448 +
max_trans_size` with `max_trans_size` typically 1MB) then Kerberos
`SESSION_SETUP`.
- `is_chained_smb2_message()` continues while remaining ≥
`MAX_CIFS_SMALL_BUFFER_SIZE` (**448**). After a ~72-byte SESSION_SETUP
header, ~376 bytes remain for the blob.
- `spnego_blob_len` is `__u16`; IPC request blobs are capped at
`KSMBD_IPC_MAX_PAYLOAD` (4096). A typical AP-REP is hundreds to
thousands of bytes — larger than 376, smaller than the inflated
`out_len`.
- Userspace-reachable: **yes** (SMB client with Kerberos). Unprivileged
remote without tickets: memcpy does not run (auth fails first).
Authenticated Kerberos user: **yes**.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record:
- `smb2_resp_buf_len()` correctly uses `get_rfc1002_len(response_buf)`
for remaining space (QUERY_DIR/INFO). Kerberos setup does not.
- `ntlm_negotiate()` `memcpy(rsp->Buffer, spnego_blob, spnego_blob_len)`
has no remaining-space check (separate issue, not this commit).
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: **Yes.** `fs/smb/server/smb2pdu.c` lines 1616–1617:
```
out_len = work->response_sz -
(le16_to_cpu(rsp->SecurityBufferOffset) + 4);
```
`git merge-base --is-ancestor 23a0be6a84a38 HEAD` → **not in this tree**
(exit 1).
Bug introduced ~v5.15 (`e2f34481b24db2`).
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: **Clean apply.** `git apply --check` of `23a0be6a84a38`
succeeded. Surrounding `krb5_authenticate()` is simpler than mainline
(no `channel_key`/`auth_key`); the `out_len` lines match.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: Compound `req`/`rsp` pointer fix (`98422bdd4cb3c`) is here; it
does **not** correct `out_len`. No substitute for this overflow.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record:
- Subsystem: `fs/smb/server` (ksmbd)
- Criticality: **IMPORTANT** — network-facing file server. Not core
mm/VFS, but historically a high-CVE surface; enterprise/NAS use.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Actively maintained. Many 6.12 ksmbd security backports already
on this branch. Kerberos path is `#ifdef CONFIG_SMB_SERVER_KERBEROS5`
(`default n`).
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: ksmbd servers with `CONFIG_SMB_SERVER_KERBEROS5=y`
(AD/Kerberos). Config- and driver-specific, not universal.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record:
- Compound SMB2 with SESSION_SETUP not first, Kerberos selected,
userspace auth success, AP-REP larger than **actual** remaining heap.
- Common Windows `NEGOTIATE+SESSION_SETUP` often still has ~1MB
remaining, so a small AP-REP may fit — **not** the only case.
- Crafted compound that leaves ~448 bytes (allowed by
`is_chained_smb2_message`) **does** overflow for a normal-sized
ticket.
- Unprivileged unauthenticated remote: memcpy not reached (UNVERIFIED as
a pre-auth RCE).
- Authenticated Kerberos client: **yes** (reauth after a large compound
command).
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record:
- Failure mode: heap OOB write → memory corruption, oops/panic, possible
code execution in ksmbd workqueue context.
- Severity: **CRITICAL** (network-facing heap write). Same class as
prior ksmbd stable CVEs.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- Benefit: **very high** for Kerberos ksmbd (stops kernel heap
corruption).
- Risk: **very low** (1 line, first-command path unchanged, fail-closed
if `out_len` is negative).
- Ratio: strongly in favor of backport.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
FOR:
- Real heap OOB write on a documented, previously attacked compound
SESSION_SETUP path (ZDI-CAN-21355 was the OOB-read sibling).
- Network-facing ksmbd; memcpy after a broken length check.
- One-line, obviously correct, applies cleanly to 6.12.111.
- Bug present since ksmbd introduction; maintainer-signed; in v7.3-rc1.
- Fail-closed if `out_len` becomes negative.
- Author is a professional vulnerability researcher.
AGAINST:
- Kerberos is `default n`; only those builds.
- memcpy requires successful Kerberos (not a trivial pre-auth spray).
- No public lore thread, syzbot report, or CVE **for this SHA**
(UNVERIFIED as assigned CVE).
- Happy-path NEGOTIATE+SESSION_SETUP may not overflow if the AP-REP fits
in leftover 1MB.
UNRESOLVED:
- No public reproducer (lore empty; b4 failed).
- No CVE number found for this exact bug.
Those gaps do not outweigh a verified heap write with a one-line fix.
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — arithmetic matches buffer
layout; maintainer applied it; first-command behavior unchanged.
2. Fixes a real bug that affects users? **PASS** — compound Kerberos
SESSION_SETUP overstates headroom; memcpy OOB is in this tree.
3. Important issue? **PASS** — heap OOB write / memory corruption
(CRITICAL).
4. Small and contained? **PASS** — 1 line, one function.
5. No new features or APIs? **PASS**.
6. Can apply to the local tree? **PASS** — `git apply --check` clean;
buggy code present.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: Not ID/quirk/DT/docs. Ordinary security bugfix; no exception
needed.
**Step 9.4: MAKE YOUR DECISION**
This is a one-line remaining-space correction that stops a kernel heap
overflow in ksmbd’s Kerberos session-setup path. The buggy calculation
exists in 6.12.111, the patch applies cleanly, and the downside is
negligible. It belongs in this stable tree.
Verification:
- [Phase 1] Parsed message/tags: SOB Dudnik + Namjae Jeon; no Fixes/Cc
stable/Reported-by. SHA `23a0be6a84a38ac169eeab49017934e8e27c65f0`.
- [Phase 1] `git show --no-walk --format=fuller 23a0be6a84a38`:
AuthorDate 2026-08-07, CommitDate 2026-08-17, committer Namjae Jeon.
- [Phase 2] Diff: one line in `krb5_authenticate()` adding `-
work->next_smb2_rsp_hdr_off`.
- [Phase 2] Read local `ksmbd_resp_buf_next` / `WORK_BUFFERS` /
`ksmbd_krb5_authenticate` memcpy; remaining-space formula matches the
fix.
- [Phase 3] `git blame -L 1610,1630 fs/smb/server/smb2pdu.c`: out_len
from `e2f34481b24db2` (2021).
- [Phase 3] `git merge-base --is-ancestor e2f34481b24db2 HEAD` → 0
(present). `23a0be6a84a38` → 1 (not in this tree).
- [Phase 3] Related: `98422bdd4cb3c` compound sess_setup OOB-read (ZDI-
CAN-21355) is in this tree; does not fix out_len.
- [Phase 4] `b4 dig -c 23a0be6a84a38`: lore errors, no match.
- [Phase 4] lore.kernel.org linux-cifs/all: no Ilan Dudnik / this
subject thread.
- [Phase 4] ksmbd-for-7.3-rc1 pull lists this commit under heap-
OOB/Kerberos security fixes; `git describe --contains` →
`v7.3-rc1~77^2~32`.
- [Phase 4] lore/stable: other ksmbd OOB backports, not this SHA.
- [Phase 5] `krb5_authenticate` only from `smb2_sess_setup`;
SESSION_SETUP skips session check; compound loop in `server.c` +
`init_chained_smb2_rsp`.
- [Phase 5] `MAX_CIFS_SMALL_BUFFER_SIZE` 448; `SMB3_DEFAULT_TRANS_SIZE`
1MB; `spnego_blob_len` is `__u16`; IPC request cap 4096.
- [Phase 6] Local tree: `git describe HEAD` → `p-6.12-3-gc504cf0baa3d8`;
`make kernelversion` → **6.12.111**.
- [Phase 6] Buggy out_len at smb2pdu.c:1616-1617; `git apply --check` of
23a0be6a84a38 **clean**.
- [Phase 7] MAINTAINERS: Namjae Jeon + Steve French, linux-cifs.
- [Phase 8] Heap OOB write after successful Kerberos on compound
SESSION_SETUP; severity CRITICAL.
- UNVERIFIED: public reproducer, CVE ID, mailing-list review comments
(no public thread).
The fix is small, surgical, and meets all stable kernel criteria.
**YES**
fs/smb/server/smb2pdu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 7d9c8246edfd6..5a61beef9cc44 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -1607,7 +1607,7 @@ static int krb5_authenticate(struct ksmbd_work *work,
in_len = le16_to_cpu(req->SecurityBufferLength);
out_blob = (char *)&rsp->hdr.ProtocolId +
le16_to_cpu(rsp->SecurityBufferOffset);
- out_len = work->response_sz -
+ out_len = work->response_sz - work->next_smb2_rsp_hdr_off -
(le16_to_cpu(rsp->SecurityBufferOffset) + 4);
retval = ksmbd_krb5_authenticate(sess, in_blob, in_len,
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-6.6] smb: server: Make sure that passkey is not leaked on the heap in user_config.c
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (14 preceding siblings ...)
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: fix heap out-of-bounds write in krb5_authenticate() Sasha Levin
@ 2026-10-19 13:51 ` Sasha Levin
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: honor byte-range locks for zero data Sasha Levin
` (6 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:51 UTC (permalink / raw)
To: patches, stable
Cc: Thomas Huth, Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Thomas Huth <thuth@redhat.com>
[ Upstream commit 2c5a176882695f73b52482df03b0017b006ef2d1 ]
Use kfree_sensitive() to free the user->passkey (and the struct
ksmbd_login_response in ksmbd_login_user() that contains the same
information) to avoid that this information could leak somewhere
else via the heap.
Signed-off-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
I have enough to decide: the NTLM passkey wipe is present in this 6.12
tree, the helpers already exist, and the change is a three-line secret-
clearing fix. Fetching the series cover letter wrapped up the remaining
mailing-list context.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[smb: server:] [Make sure] [passkey is not leaked on the heap
in user_config.c]**
- Subsystem: `smb: server:` (ksmbd in-kernel SMB3 server)
- Action verb: “Make sure” — safety/correctness language, not a feature
- Claimed intent: wipe `user->passkey` (and the IPC login response that
holds the same hash) before returning the memory to the heap
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- **Fixes:** none (expected for this review pipeline)
- **Reported-by:** none
- **Tested-by:** none
- **Reviewed-by:** none on the commit itself
- **Acked-by:** none
- **Link:** none in the commit message
- **Cc: stable:** none (expected; not a negative signal)
- **Signed-off-by:** Thomas Huth \<thuth@redhat.com\> (author); Namjae
Jeon \<linkinjeon@kernel.org\> (ksmbd maintainer). Ignore any Sasha
Levin SOB from candidate preparation.
Notable pattern: no syzbot/CVE/reporter tags. This came from a
maintainer-applied hardening series, not a crash report.
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** `user->passkey` and `struct ksmbd_login_response` (which
contains `hash[]`) are freed with ordinary `kfree()`/`kvfree()`, so
the NTLM password hash remains in the slab until the object is reused.
- **Symptom/failure mode:** heap leftover of authentication secret
material; a later kmalloc of the same cache can return pages still
holding the hash (classic kfree-vs-kfree_sensitive info leak).
- **Version information:** none in the message.
- **Root cause (author):** passkey-bearing objects were not cleared
before free.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not a disguised cleanup. The message is explicit about a secret
leak. It is a security hygiene fix (wipe-before-free), not a crash/UAF.
Still a real bug class the kernel already treats as such via
`kfree_sensitive()`.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `fs/smb/server/mgmt/user_config.c` only
- Scope: **3 substitutions, ~3 lines**, single-file surgical
- Functions: `ksmbd_login_user()`, `ksmbd_alloc_user()` error path,
`ksmbd_free_user()`
- Surrounding mainline context in the candidate (hash_sz bounds check,
`kmalloc_obj`) is **not** part of this commit’s semantic change; it is
later-tree context.
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
1. `ksmbd_login_user()` `out:` path: `kvfree(resp)` →
`kvfree_sensitive(resp, sizeof(*resp))`. This is the **normal** login
path (and the login-failure path). `resp` is the IPC login response
from ksmbd.mountd and contains `hash[]`.
2. `ksmbd_alloc_user()` `err_free:`: `kfree(user->passkey)` →
`kfree_sensitive(user->passkey)`. **Error** path after the hash was
copied into `user->passkey`.
3. `ksmbd_free_user()`: same `kfree` → `kfree_sensitive` for
`user->passkey`. **Normal** session teardown / reauth mismatch path.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record:
- **Category:** security / sensitive-data leak (heap residual), not
UAF/race/crash
- **Mechanism:** `resp->hash` is the NT hash (`KSMBD_REQ_MAX_HASH_SZ` is
18; auth uses `CIFS_ENCPWD_SIZE` of 16 as HMAC-MD5 key in
`calc_ntlmv2_hash()`). After `kfree`/`kvfree`, that hash stays in the
slab. `kfree_sensitive()` does `memzero_explicit()` over `ksize()`
then `kfree()`. `kvfree_sensitive()` does `memzero_explicit(addr,
len)` then `kvfree()`.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- Obviously correct: drop-in replacement; `kfree_sensitive(NULL)` is a
documented no-op (needed on `err_free` when `passkey` alloc failed);
`kvfree_sensitive` skips `ZERO_OR_NULL_PTR`.
- Minimal: three call-site changes, no API/structure change.
- Regression risk: **very low**. Same free, plus a small
`memzero_explicit`. `passkey` is ~16 bytes; `sizeof(*resp)` is a fixed
login-response struct. No lock/order/API change.
- Incomplete vs the rest of ksmbd (auth.c still `kvfree(resp)` on the
SPNEGO path) — that is a **sibling** series patch, not a dependency of
this one.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- `kvfree(resp)`: introduced as cifsd code in `79f6b11a104f3a` (“cifsd:
remove wrappers of kvmalloc/kvfree”, 2021) on top of `e2f34481b24db2`
(“cifsd: add server-side procedures for SMB3”, 2021-05-10).
- `kfree(user->passkey)` in `ksmbd_free_user()`: `822bc8ea514ecd`
(“cifsd: use kfree to free memory allocated by kmalloc or kzalloc”,
2021) — switched from kvfree wrappers to `kfree`.
- `kfree(user->passkey)` on `err_free`: `a77e0e02af1c2` (“ksmbd: add
support for supplementary groups”, 2024-10-11).
- The leak has been in the SMB server **since cifsd/ksmbd was merged
(~v5.15 era)**. Present in this 6.12 tree.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. Not applicable. The buggy free sites predate
this tree’s branch point and are in HEAD.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record (this tree, `-- fs/smb/server/mgmt/user_config.c`):
- `c9f2872e91b9f` — leak of `ksmbd_ipc_login_request_ext()` buffer
(already in this tree; candidate context includes `kvfree(resp_ext)`).
- `7dd0c858e1909` — ipc_validate_msg size checks
- `a77e0e02af1c2` — supplementary groups
- No existing `kfree_sensitive` conversion in this file.
- Standalone relative to later hash_sz/`kmalloc_obj` work (those strings
are **absent** here).
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Thomas Huth has **no** other commits under `fs/smb/` in this
checkout (series is newer than 6.12). Namjae Jeon is the ksmbd
maintainer and signed the patch off. Cover letter: 5-patch series “Clear
sensitive data before freeing it”; this is **v2 2/5**.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record:
- Needs `kfree_sensitive()` / `kvfree_sensitive()` — both exist in this
tree (`include/linux/slab.h`, implemented in `mm/slab_common.c` /
`mm/util.c`).
- Does **not** need `kmalloc_obj` or the hash_sz guard (those are only
nearby mainline context).
- Other patches in the series (auth.c, user_session.c, connection.c,
smb2pdu.c) are independent per-file wipes. This file’s change applies
**standalone**.
- `user_config.c` already includes `<linux/slab.h>`.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c <sha>`: **not run** — the candidate SHA is not in this
checkout (evaluating a candidate, not an in-tree commit).
- Found via search: **[PATCH v2 2/5]** Message-ID
`20260811154620.2425851-3-thuth@redhat.com`
- Cover:
https://patchew.org/linux/20260811154620.2425851-1-thuth@redhat.com/
- Openwall: https://lists.openwall.net/linux-kernel/2026/08/11/1820
- v2 vs v1: cover letter says v2 fixed `kvfree_sensitive` **size in
patch 1 (auth.c)**, added a connection.c hunk, and added the smb2pdu.c
patch. **This user_config.c patch was not the one that needed a size-
calculation fix.**
- Namjae Jeon: “Applied them to #ksmbd-for-next-next.” No NAK found.
- Author framed it as “good security practice”; spots found with AI,
patches written by hand; asked for careful review. Maintainer still
applied the series.
- No reviewer `Cc: stable` found.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: To/Cc from the v2 mail: Namjae Jeon (ksmbd maintainer), Steve
French (CIFS/SMB maintainer), linux-kernel, Sergey Senozhatsky, Tom
Talpey. Maintainer applied it. No separate Reviewed-by on this patch.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No syzbot, bugzilla, or user crash. This is proactive secret-
wipe, not a reported oops. Severity from the author: heap leftover of
passkey/hash.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Series of 5 independent kfree_sensitive/memzero_explicit
patches:
1. auth.c stack/heap
2. **user_config.c passkey (this one)**
3. user_session.c
4. connection.c
5. smb2pdu.c Preauth_HashValue
This patch does not depend on 1/3/4/5 applying first.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: No stable-list hit for this passkey wipe (search did not turn up
a prior stable request or a rejection). UNVERIFIED that a later stable
thread exists beyond what search returned. lore.kernel.org fetches
returned 403 in this environment; discussion was recovered from
patchew/openwall.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**
Record: `ksmbd_login_user`, `ksmbd_alloc_user`, `ksmbd_free_user`
**Step 5.2: TRACE CALLERS**
Record (this tree):
- `ksmbd_login_user()` ← `session_user()` in `fs/smb/server/smb2pdu.c` ←
SMB2 SESSION_SETUP / `ntlm_authenticate()`. **Network-reachable** on
every NTLM login.
- `ksmbd_alloc_user()` ← `ksmbd_login_user()` and
`ksmbd_krb5_authenticate()` in `auth.c` (CONFIG_SMB_SERVER_KERBEROS5).
- `ksmbd_free_user()` ← session teardown in `user_session.c`; reauth
mismatch / anonymous reuse in `smb2pdu.c`; kerberos reauth in
`auth.c`.
**Step 5.3: TRACE CALLEES**
Record:
- `ksmbd_ipc_login_request()` → netlink to ksmbd.mountd; response
allocated with `kvzalloc(sz)` in `handle_response()`
(`transport_ipc.c:294`), so `kvfree`/`kvfree_sensitive` is the right
family.
- `user->passkey = kmalloc(resp->hash_sz, ...)` then `memcpy` from
`resp->hash` — `kfree_sensitive` is the right family.
- `calc_ntlmv2_hash()` uses `user_passkey()` as HMAC-MD5 key
(`CIFS_ENCPWD_SIZE`). Confirmed: this is the NT hash, not a username.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Unprivileged SMB client sends SESSION_SETUP → kernel looks up
user via IPC → hash lives in `resp` then `user->passkey` → on
logout/free, hash is currently left in the slab. Path is **reachable
from the network** whenever ksmbd is enabled and serving NTLM users. Not
a syscall-from-unprivileged-local-only issue; it is a **server-side
credential residual**.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: The SMB **client** in this same tree already uses
`kfree_sensitive` widely for passwords/`auth_key`
(`fs/smb/client/smb2pdu.c`, `sess.c`, `fs_context.c`, `misc.c`, …).
ksmbd server side in this tree still uses plain `kfree`/`kvfree` for
passkey (only `auth.c` has one `kfree_sensitive(ctx_arc4)`). Same bug
class, server lagging the client.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: **Yes.** Local tree is **6.12.111** (`pending-6.12`,
`p-6.12-3-gc504cf0baa3d8`).
```31:31:fs/smb/server/mgmt/user_config.c
kvfree(resp);
```
```74:74:fs/smb/server/mgmt/user_config.c
kfree(user->passkey);
```
```84:84:fs/smb/server/mgmt/user_config.c
kfree(user->passkey);
```
No `kvfree_sensitive` / `kfree_sensitive` in this file today. Bug
introduced with cifsd (2021), long before 6.12.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: **Minor context, not semantic.** This tree has
`kmalloc(sizeof(struct ksmbd_user), ...)` not `kmalloc_obj`, and **no**
`hash_sz > sizeof(resp->hash)` guard. The three substitution sites exist
verbatim (`kvfree(resp);` ×1, `kfree(user->passkey);` ×2). A 3-line
backport applies; a raw mainline patch with 41-line context around
`ksmbd_alloc_user` would conflict. `kvfree(resp_ext)` from
`c9f2872e91b9f` is already here, matching the candidate’s
`ksmbd_login_user` shape.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No passkey wipe already in this file. Client-side
`kfree_sensitive` does not cover ksmbd server objects.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: **ksmbd (CONFIG_SMB_SERVER)** under `fs/smb/server/`.
**IMPORTANT** (not core mm/VFS): optional in-kernel SMB3 server used on
NAS/embedded; default `n`. Network-facing auth path.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Actively maintained (many recent ksmbd fixes on this branch:
OOB, ACL, session, credit). Mature enough that the passkey free path has
been stable since 2021.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: **config-specific / driver-specific:** systems with
`CONFIG_SMB_SERVER` (ksmbd) and live SMB sessions. Distros that ship
ksmbd for NAS (openSUSE, some embedded, ksmbd-tools users).
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record:
- Trigger: **every successful NTLM login** (`ksmbd_login_user` always
frees `resp` containing the hash) and **every `ksmbd_free_user`**
(session destroy / failed reauth).
- Common on any ksmbd server with password auth.
- Local unprivileged userspace does not need to call a special syscall;
a remote SMB client causes the kernel to hold then free the hash.
Recovering the leftover bytes still needs another heap-read primitive
or slab reuse that exposes old contents — that is the usual
`kfree_sensitive` threat model.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: **Failure mode:** NT hash residual in kmalloc/kvmalloc heap.
**Severity: HIGH** (credential/info leak; pass-the-hash material). Not a
panic. Not theoretical-only in kind: this is why `kfree_sensitive`
exists, and the CIFS client already wipes the same class of secrets.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- **Benefit:** HIGH for ksmbd users — wipes NTLM hashes that currently
survive free on a hot auth path.
- **Risk:** VERY LOW — 3 lines, existing helpers, NULL-safe, no behavior
change except zeroing freed secret bytes.
- **Ratio:** strongly favors backport.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
**FOR:**
- Real leftover NT hash (`resp->hash` / `user->passkey`) on heap after
login IPC and session free
- Reachable from SMB SESSION_SETUP on deployed ksmbd
- 3-line, obviously correct, uses APIs that exist in 6.12
- Buggy frees present in this tree since 2021
- Maintainer (Namjae Jeon) applied the series
- Same pattern already used by `fs/smb/client/` in this tree
- `kfree_sensitive(NULL)` safe on the alloc-failure path
**AGAINST:**
- Hardening / defense-in-depth, no CVE/syzbot/user report
- Part of a 5-patch series (others also wipe secrets; this file does not
need them)
- ksmbd is optional (`default n`)
- Raw mainline hunk context includes later `kmalloc_obj` / hash_sz check
(needs a tiny backport, not the later features)
**UNRESOLVED:**
- Could not run `b4 dig` against a local SHA (candidate not in this git
object store)
- lore.kernel.org HTTP 403; discussion recovered from patchew/openwall
- No evidence this was previously rejected for stable
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — drop-in sensitive-free;
maintainer applied v2.
2. Fixes a real bug that affects users? **PASS** — NTLM hash left in
slab after ksmbd login/logout.
3. Important issue? **PASS** — security info leak of auth material
(HIGH, not a crash).
4. Small and contained? **PASS** — 3 lines, one file.
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — sites and helpers exist;
context tweak only (no `kmalloc_obj` required).
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: Not a device-ID/quirk/DT/build/docs exception. Qualifies as a
**small security fix** (secret wipe), which stable regularly takes.
**Step 9.4: MAKE YOUR DECISION**
This should be backported to **this** 6.12 tree. The bug is here, the
helpers are here, and the change is a surgical wipe of NTLM passkeys
that ksmbd currently leaves in the heap after every login IPC and
session free. Risk is negligible; benefit is wiping high-value
credential material on a network-facing path.
### What the commit solves for this tree
On 6.12.111 ksmbd still does `kvfree(resp)` on the login response (which
includes `hash[KSMBD_REQ_MAX_HASH_SZ]`) and `kfree(user->passkey)` after
copying that hash. Those bytes are the NT hash used as the NTLMv2 HMAC
key. Switching to `kvfree_sensitive` / `kfree_sensitive` zeros them
before the slab can reuse the object. That matches what the SMB client
in this same tree already does for passwords.
### Risk vs benefit
Benefit is wiping secrets on a common ksmbd auth path. Risk is a few
extra `memzero_explicit` bytes on free. No locking, no API, no control-
flow change.
### Concerns
A verbatim mainline apply may need a 3-line backport because this tree
lacks `kmalloc_obj` and the later `hash_sz` cap; those are **not**
prerequisites. Sibling series patches (auth.c SPNEGO `kvfree(resp)`,
session/connection/preauth) are independent and do not block this file’s
fix.
Verification:
- [Phase 1] Parsed subject/body/tags: no Fixes/Reported-by/Cc:stable;
SOBs Thomas Huth + Namjae Jeon
- [Phase 2] Diff: 3 substitutions in user_config.c; `kvfree(resp)` and
two `kfree(user->passkey)`
- [Phase 2] Confirmed `KSMBD_REQ_MAX_HASH_SZ` is 18 and
`calc_ntlmv2_hash()` uses `user_passkey()` as HMAC-MD5 key
(`CIFS_ENCPWD_SIZE` 16)
- [Phase 3] `git blame`: `kvfree(resp)` from 2021 cifsd
(`79f6b11a104f3a` / `e2f34481b24db2`); passkey `kfree` from
`822bc8ea514ecd` / `a77e0e02af1c2`
- [Phase 3] `git merge-base --is-ancestor` of those SHAs vs HEAD: all
present (exit 0)
- [Phase 3] `git log --author="Thomas Huth" -- fs/smb/`: empty in this
tree (series is newer)
- [Phase 4] Patchew/openwall: v2 2/5 of “Clear sensitive data before
freeing it”; Namjae applied to ksmbd-for-next-next; no NAK
- [Phase 4] lore.kernel.org WebFetch: 403; b4 dig: no local candidate
SHA — discussion recovered from patchew/openwall
- [Phase 5] Callers: `smb2pdu.c` SESSION_SETUP
`session_user()`/`ntlm_authenticate()`, `auth.c` krb5 path,
`user_session.c` teardown
- [Phase 5] `handle_response()` uses `kvzalloc` — `kvfree_sensitive` is
the correct free family
- [Phase 6] `git describe HEAD` / `make kernelversion`: **6.12.111**
(`pending-6.12`); buggy kfree/kvfree still in file;
`kfree_sensitive`/`kvfree_sensitive` declared in
`include/linux/slab.h`
- [Phase 6] Local file has no `kmalloc_obj` / hash_sz cap; three target
call sites exist verbatim
- [Phase 8] Failure mode: NT-hash residual in heap after login/free;
severity HIGH; regression risk very low
- UNVERIFIED: full lore mailbox / b4 patch-id match; whether a later CVE
was assigned
**YES**
fs/smb/server/mgmt/user_config.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/smb/server/mgmt/user_config.c b/fs/smb/server/mgmt/user_config.c
index 0e5fcd6f95c15..909f219c79faa 100644
--- a/fs/smb/server/mgmt/user_config.c
+++ b/fs/smb/server/mgmt/user_config.c
@@ -28,7 +28,7 @@ struct ksmbd_user *ksmbd_login_user(const char *account)
user = ksmbd_alloc_user(resp, resp_ext);
kvfree(resp_ext);
out:
- kvfree(resp);
+ kvfree_sensitive(resp, sizeof(*resp));
return user;
}
@@ -82,7 +82,7 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp,
err_free:
kfree(user->name);
- kfree(user->passkey);
+ kfree_sensitive(user->passkey);
kfree(user);
return NULL;
}
@@ -92,7 +92,7 @@ void ksmbd_free_user(struct ksmbd_user *user)
ksmbd_ipc_logout_request(user->name, user->flags);
kfree(user->sgid);
kfree(user->name);
- kfree(user->passkey);
+ kfree_sensitive(user->passkey);
kfree(user);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-6.1] ksmbd: honor byte-range locks for zero data
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (15 preceding siblings ...)
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.6] smb: server: Make sure that passkey is not leaked on the heap in user_config.c Sasha Levin
@ 2026-10-19 13:51 ` Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: reject blocking compound lock requests Sasha Levin
` (5 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:51 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 8b57448a147d2378088e63cd473e7f2a967d6802 ]
FSCTL_SET_ZERO_DATA changes file allocation state and must respect
byte-range locks over the affected part of the file. Check the requested
range, clipped to EOF, before issuing the fallocate operation.
Return STATUS_FILE_LOCK_CONFLICT when the range conflicts with an
existing lock. Ranges starting past EOF are left untouched by the lock
check so they continue to succeed.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.12.111** (`pending-6.12`). The buggy
`FSCTL_SET_ZERO_DATA` path is present here, the lock helper already
exists, and the patch applies cleanly. This is a real lock-bypass data-
integrity bug, not a new feature.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
**Step 1.1: PARSE THE SUBJECT LINE**
Record: `[ksmbd] [honor] honor byte-range locks for FSCTL_SET_ZERO_DATA`
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Original commit: `8b57448a147d2378088e63cd473e7f2a967d6802` (Namjae
Jeon, 2026-08-17)
Tags present:
- `Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>` (author + ksmbd
maintainer)
- No `Fixes:`, `Cc: stable`, `Reported-by`, `Tested-by`, `Reviewed-by`,
`Acked-by`, or `Link:` (absence of Fixes/Cc:stable is expected for
this review)
Record: Maintainer-authored; no user/syzbot report tags.
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- Bug: `FSCTL_SET_ZERO_DATA` changes allocation (punch-hole / zero-
range) without checking SMB byte-range locks.
- Symptom: a client can zero or punch a range another handle has locked;
the locker does not get `STATUS_FILE_LOCK_CONFLICT`.
- Root cause: `ksmbd_vfs_zero_data()` calls `vfs_fallocate()` with no
`check_lock_range()`.
- Intentional edge: ranges starting past EOF skip the lock check so they
still succeed.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not a disguised cleanup. Explicit protocol/correctness fix:
missing lock enforcement on a mutating FSCTL.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
**Step 2.1: INVENTORY THE CHANGES**
Record:
- `fs/smb/server/vfs.c`: +12 in `ksmbd_vfs_zero_data()`
- `fs/smb/server/smb2pdu.c`: +6/-1 in `smb2_ioctl()`
`FSCTL_SET_ZERO_DATA`
- Total: 18 insertions, 1 deletion
- Scope: single-subsystem, two-file surgical fix
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- **vfs.c before:** break Level II oplocks, then
`vfs_fallocate(PUNCH_HOLE or ZERO_RANGE | KEEP_SIZE)` with no lock
check.
- **vfs.c after:** same, but for non-POSIX shares, if `off < i_size`,
call `check_lock_range(filp, off, min(off+len, size)-1, WRITE)` and
return `-EAGAIN` on conflict.
- **smb2pdu.c before:** any `ret < 0` goes to ioctl `out`, which maps
unknown errors to `STATUS_INVALID_PARAMETER`.
- **smb2pdu.c after:** `-EAGAIN` sets `STATUS_FILE_LOCK_CONFLICT`, `ret
= 0`, then `goto out` so the generic mapper does not overwrite the
status.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record:
- Category: logic / protocol correctness, with data-integrity impact.
- Mechanism: SMB byte-range locks in ksmbd are POSIX locks;
`vfs_fallocate()` does not consult them (verified in `fs/open.c`:
permission/lease/overflow checks only). Read, write, truncate, and
copychunk already call `check_lock_range()`; zero-data did not. A
WRITE lock on another handle, or a READ lock vs this WRITE, is ignored
and the range is zeroed/punched.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- Quality: high. Same pattern as `ksmbd_vfs_write()` /
`ksmbd_vfs_truncate()` / `ksmbd_vfs_copy_file_ranges()`.
- `posix_extensions` skip matches those callers.
- Clipping to EOF avoids `start > end` if the request extends past EOF.
- Regression risk: low. Only behavioral change is rejecting previously-
illegal zeroing of locked ranges. `ret = 0` plus pre-set status is a
bit awkward versus adding `-EAGAIN` in the ioctl `out` mapper, but it
works: `out` only overwrites status when `ret < 0 || Status == 0`, so
`STATUS_FILE_LOCK_CONFLICT` is preserved and `smb2_set_err_rsp()`
still runs.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- `ksmbd_vfs_zero_data()` introduced by Namjae Jeon in 2021
(`fs/cifsd/vfs.c`, blame `f44158485826c0` / `64b39f4a2fd293`).
- Never had a lock check. Present throughout 6.12.
- `override_creds` wrapper already in this tree via `fb1cae6302d58`
(`ksmbd: use opener credentials for FSCTL mutations`).
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No `Fixes:` tag. Buggy code is the original zero-data
implementation, not a later regression.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record:
- Already in this tree: `f751d6e39d4c9` “Do not skip lock checks for
single-byte ranges”; `ca53bb17f4e82` “add a permission check for
FSCTL_SET_ZERO_DATA”; `fe20d492a69a6` lock-owner tracking.
- On `origin/master`, parent `3c707d4b3f926` (“fix permission checks for
file allocation ioctls”) is independent (SPARSE/QUERY_ALLOCATED_RANGES
access bits), not required for this lock check.
- No `patch X/Y` in the subject. Standalone.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Namjae Jeon is the ksmbd maintainer (`Signed-off-by` on both
authorship and merge). This tree already carries many of his ksmbd
stable fixes.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: None. `check_lock_range()` is `static` in the same `vfs.c`
(lines 325–358). `STATUS_FILE_LOCK_CONFLICT` already exists.
`posix_extensions` and `i_size_read`/`min()` are present. `git apply
--check` of `8b57448a147d2` succeeded (smb2pdu offset −1234, vfs.c
offset +71).
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c 8b57448a147d2`: lore returned server errors; no thread URL.
- WebFetch of lore.kernel.org search URLs: HTTP 403.
- UNVERIFIED: reviewer comments, v2/v3 history, explicit Cc:stable in
review.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record: UNVERIFIED via b4. Commit is maintainer-authored and merged to
`origin/master`.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No `Reported-by` / bugzilla / syzbot. Bug is identified from
protocol analysis, not a crash report.
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Nearby `origin/master` ksmbd FSCTL work (`support file level
trim`, allocation ioctl permission, allocated-range holes) is related
thematically, not a hard dependency. Samba’s `fsctl_zero_data()` takes a
WRITE strict lock and returns `NT_STATUS_FILE_LOCK_CONFLICT` on failure
(source3/smbd/smb2_ioctl_filesys.c). That matches this fix.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: UNVERIFIED (lore 403). No local evidence this was rejected for
stable.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**
Record: `ksmbd_vfs_zero_data()`, `smb2_ioctl()` (`FSCTL_SET_ZERO_DATA`),
callee `check_lock_range()`.
**Step 5.2: TRACE CALLERS**
Record:
- `ksmbd_vfs_zero_data()`: only `smb2_ioctl()` FSCTL_SET_ZERO_DATA
(`fs/smb/server/smb2pdu.c:8548`).
- `smb2_ioctl()`: SMB2 command table `SMB2_IOCTL_HE` in
`fs/smb/server/smb2ops.c`.
- Reachable from authenticated SMB clients issuing ioctl on an open
writable handle.
**Step 5.3: TRACE CALLEES**
Record: `check_lock_range()` walks `flc_posix` under `flc_lock`;
conflicts if overlapping READ lock vs WRITE, or WRITE lock owned by
another `filp`. `vfs_fallocate()` does not check those locks.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: SMB2 IOCTL → `smb2_ioctl` → `ksmbd_vfs_zero_data` →
`vfs_fallocate` (punch/zero). Userspace/network reachable on any ksmbd
share without POSIX extensions (the common Windows-client case).
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Same `!posix_extensions` + `check_lock_range` + `-EAGAIN`
pattern in `ksmbd_vfs_read` (396–400), `ksmbd_vfs_write` (521–527),
`ksmbd_vfs_truncate` (835–849), `ksmbd_vfs_copy_file_ranges`
(1854–1866). Zero-data was the missing sibling. Read/write/setinfo
already map `-EAGAIN` to `STATUS_FILE_LOCK_CONFLICT`; ioctl did not,
which is why smb2pdu.c is patched.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: Yes. Local `ksmbd_vfs_zero_data()` at
`fs/smb/server/vfs.c:995-1013` has no lock check. `git merge-base --is-
ancestor 8b57448a147d2 HEAD` failed (not in this tree). Bug present
since ksmbd’s 2021 introduction; well before 6.12.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: Clean apply with line offset. Local ioctl `out` mapper still
lacks `-EAGAIN`, so both hunks are required. No refactor blocking the
patch.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: Permission check for SET_ZERO_DATA is here (`ca53bb17f4e82`);
lock-check skip-for-1-byte fix is here (`f751d6e39d4c9`). Neither
implements this FSCTL lock check. No duplicate fix.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: ksmbd (`fs/smb/server`, `CONFIG_SMB_SERVER`, default n).
Criticality: IMPORTANT for ksmbd deployments (NAS, distros), not core
mm/VFS. File-server data path.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Actively maintained; this 6.12 tree already backports many ksmbd
protocol, lock, and UAF fixes. Mature enough that missing lock checks
are long-standing, not new-code churn.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: ksmbd users, non-POSIX SMB shares, clients that use byte-range
locks and `FSCTL_SET_ZERO_DATA` (Windows sparse/zero APIs, some
databases/backup tools).
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record: Handle A holds an SMB lock; handle B (or another client) issues
`FSCTL_SET_ZERO_DATA` overlapping that range with `FILE_WRITE_DATA`. Not
every I/O, but a realistic multi-client/multi-handle case. Authenticated
SMB user; not unprivileged local syscall.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: Locked file data can be silently zeroed or punched. Failure
mode: data corruption / lock-semantics violation. Severity: HIGH (not a
kernel oops).
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- Benefit: high for ksmbd — restores lock integrity on a data-destroying
FSCTL; aligns with Samba/Windows.
- Risk: very low — 18 lines, existing helper, applies cleanly, only
rejects operations that should have failed.
- Ratio: strongly favors backport.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
**Step 9.1: COMPILE THE EVIDENCE**
FOR:
- Real bug: SET_ZERO_DATA ignores byte-range locks while
read/write/truncate/copychunk do not.
- User-visible: silent zero/punch of locked ranges (data integrity).
- Samba returns `NT_STATUS_FILE_LOCK_CONFLICT` for the same FSCTL.
- Small, obviously correct, maintainer-authored.
- Helpers and surrounding lock policy already in 6.12; patch applies
cleanly.
- This tree already backported the same class (`f751d6e39d4c9`) and
SET_ZERO_DATA access control (`ca53bb17f4e82`).
AGAINST:
- No crash/UAF/syzbot report.
- ksmbd is optional (`CONFIG_SMB_SERVER`).
- No mailing-list confirmation (lore unreachable).
- Slightly weaker than Samba on past-EOF ranges (intentional per commit
message).
UNRESOLVED:
- Original lore thread / reviewer NAKs (b4 and lore failed).
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — matches existing ksmbd lock
checks; maintainer SOB. (No extra Tested-by.)
2. Fixes a real bug that affects users? **PASS** — lock bypass on a
mutating FSCTL.
3. Important issue (crash, security, corruption, deadlock)? **PASS** —
data corruption / exclusive-lock violation. HIGH, not panic.
4. Small and contained? **PASS** — 18/+1 lines, two files, one FSCTL.
5. No new features or APIs? **PASS** — enforces existing SMB lock rules.
6. Can apply to the local tree? **PASS** — `git apply --check`
succeeded.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: None (not a device-ID/quirk/DT/build/doc exception). Qualifies
as a normal important bugfix.
**Step 9.4: MAKE YOUR DECISION**
Backport. The 6.12 tree has the buggy path, the same
`check_lock_range()` policy, and already takes ksmbd lock-correctness
fixes. Benefit is lock-integrity on a data-destroying ioctl; risk is
minimal.
### What the commit solves
On this 6.12 tree, `FSCTL_SET_ZERO_DATA` breaks oplocks and calls
`vfs_fallocate()` without `check_lock_range()`. POSIX/SMB locks are not
enforced by `vfs_fallocate()`, so another handle can zero or punch a
locked range. The patch checks the range clipped to EOF and returns
`STATUS_FILE_LOCK_CONFLICT`, matching Samba and ksmbd’s other mutating
paths.
### Stable rules
Surgical, no new API, applies here, fixes real data-integrity/protocol
failure. Not a feature add.
### Risk vs benefit
Benefit: prevent silent destruction of locked file data on ksmbd. Risk:
low; only newly failed requests are ones that violated locks.
### Concerns
Mailing-list review could not be fetched. Parent permission-ioctl commit
is not required. `ret = 0` before `goto out` is slightly unusual but
correct given this ioctl error mapper.
Verification:
- [Phase 1] Parsed tags on `8b57448a147d2`: only Namjae Jeon SOB; no
Fixes/Cc:stable/Reported-by
- [Phase 1] `git describe HEAD` / Makefile: `p-6.12-3-gc504cf0baa3d8`,
VERSION 6.12.111, branch `pending-6.12`
- [Phase 2] Diff: +12 vfs.c `ksmbd_vfs_zero_data`, +6/-1 smb2pdu.c
FSCTL_SET_ZERO_DATA
- [Phase 2] Local `smb2_ioctl` `out` (8694–8708) maps unknown errors to
`STATUS_INVALID_PARAMETER`, not lock conflict — smb2pdu hunk required
- [Phase 2] `vfs_fallocate()` in `fs/open.c:246` has no posix-lock check
- [Phase 3] Blame: zero_data from 2021 cifsd; no lock check ever; `git
merge-base --is-ancestor 8b57448a147d2 HEAD` → not ancestor
- [Phase 3] Related in-tree: `f751d6e39d4c9` (1-byte lock skip),
`ca53bb17f4e82` (SET_ZERO_DATA FILE_WRITE_DATA)
- [Phase 3] Parent `3c707d4b3f926` is independent permission tweak, not
a prerequisite
- [Phase 3] `git apply --check` of `8b57448a147d2`: both hunks apply
(offsets −1234 / +71)
- [Phase 4] `b4 dig -c 8b57448a147d2`: lore errors, no thread —
UNVERIFIED review discussion
- [Phase 4] lore WebFetch 403 — UNVERIFIED stable-list discussion
- [Phase 4] Samba `fsctl_zero_data` uses STRICT_LOCK WRITE and returns
`NT_STATUS_FILE_LOCK_CONFLICT` (web/source confirmation)
- [Phase 5] Only caller of `ksmbd_vfs_zero_data` is `smb2_ioctl`;
dispatched via `SMB2_IOCTL_HE`
- [Phase 5] `check_lock_range` already used for
read/write/truncate/copychunk in this tree
- [Phase 6] Local `ksmbd_vfs_zero_data` (vfs.c:995–1013) matches pre-
patch; bug exists here
- [Phase 8] Failure mode: zero/punch of locked ranges → data integrity
HIGH
- UNVERIFIED: original lore review comments and whether anyone nominated
this for stable on the list
**YES**
fs/smb/server/smb2pdu.c | 7 ++++++-
fs/smb/server/vfs.c | 12 ++++++++++++
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index c18590d8ee2b9..6b3cf2dadeecd 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -8665,8 +8665,13 @@ int smb2_ioctl(struct ksmbd_work *work)
ret = ksmbd_vfs_zero_data(work, fp, off, len);
ksmbd_fd_put(work, fp);
- if (ret < 0)
+ if (ret == -EAGAIN) {
+ rsp->hdr.Status = STATUS_FILE_LOCK_CONFLICT;
+ ret = 0;
goto out;
+ } else if (ret < 0) {
+ goto out;
+ }
}
break;
}
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index 47c289ad9c3dc..f894092901bc5 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -1003,6 +1003,18 @@ int ksmbd_vfs_zero_data(struct ksmbd_work *work, struct ksmbd_file *fp,
int err;
smb_break_all_levII_oplock(work, fp, 1);
+ if (!work->tcon->posix_extensions) {
+ loff_t size = i_size_read(file_inode(fp->filp));
+
+ if (off < size) {
+ err = check_lock_range(fp->filp, off,
+ min(off + len, size) - 1,
+ WRITE);
+ if (err)
+ return -EAGAIN;
+ }
+ }
+
saved_cred = override_creds(fp->filp->f_cred);
if (fp->f_ci->m_fattr & FILE_ATTRIBUTE_SPARSE_FILE_LE)
err = vfs_fallocate(fp->filp,
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: reject blocking compound lock requests
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (16 preceding siblings ...)
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: honor byte-range locks for zero data Sasha Levin
@ 2026-10-19 13:52 ` Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.12] ksmbd: reject SMB3.1.1 binding with mismatched cipher Sasha Levin
` (4 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:52 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 16a7f7c2ecf3c893b65f0fb78fa7a7171ae0ba9e ]
Clients set SMB2_LOCKFLAG_FAIL_IMMEDIATELY when a LOCK request contains
multiple lock elements, and servers reject requests that omit it.
Accepting such a request can leave earlier elements locked while a later
element waits asynchronously, enabling prolonged partial lock ownership
and avoidable deadlocks.
Return STATUS_INVALID_PARAMETER before processing any element when a
multi-element lock request contains a blocking lock. Unlock arrays remain
unaffected.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
This is a protocol-validation deadlock fix in ksmbd’s SMB2 LOCK path. It
belongs in this 6.12 tree: the buggy loop has been here since ksmbd was
added, and the change is a seven-line reject of a request the spec and
Samba already forbid.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
Step 1.1: PARSE THE SUBJECT LINE
Record: [ksmbd] [reject] [refuse multi-element SMB2 LOCK requests that
omit SMB2_LOCKFLAG_FAIL_IMMEDIATELY]
“Reject” is a bug-fix verb: stop accepting invalid protocol that can
hang the server.
Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
Record:
- Signed-off-by: Namjae Jeon `<linkinjeon@kernel.org>` (ksmbd
maintainer; ignore any pipeline SOB)
- No Fixes:, Reported-by, Tested-by, Reviewed-by, Acked-by, Link:, or
Cc: stable
- Absence of Fixes/Cc:stable is expected for this review and is not a
negative signal
Step 1.3: ANALYZE THE COMMIT BODY TEXT
Record:
- Bug: a LOCK with more than one element may omit FAIL_IMMEDIATELY (a
blocking lock). ksmbd currently processes elements in order, so
earlier ranges can be granted while a later range waits
asynchronously.
- Symptom: prolonged partial lock ownership and avoidable deadlocks.
- Spec intent: clients set FAIL_IMMEDIATELY on multi-element LOCK;
servers reject requests that omit it with STATUS_INVALID_PARAMETER.
- Unlock arrays are intentionally left unchanged.
- No kernel-version range in the message.
Step 1.4: DETECT HIDDEN BUG FIXES
Record: Not a disguised cleanup. It is an explicit protocol/deadlock
fix.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
Step 2.1: INVENTORY THE CHANGES
Record:
- File: `fs/smb/server/smb2pdu.c` only (~7 lines added, 0 removed)
- Function: `smb2_lock()`
- Scope: single-file surgical validation in the existing lock-element
loop
Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
Record:
Before: after building `lock_list`, the loop validates cmd/flags/mix,
then may call `vfs_lock_file()`. A blocking element uses
`F_SETLKW`/`FL_SLEEP`, can return `FILE_LOCK_DEFERRED`, send
STATUS_PENDING, and `ksmbd_vfs_posix_lock_wait()`. Earlier elements
already granted stay on `rollback_list` / `conn->lock_list` during that
wait.
After: if `lock_count > 1`, the first element is not UNLOCK, and the
current element lacks FAIL_IMMEDIATELY, set `err = -EINVAL` and `goto
out` before `vfs_lock_file()` on that element. `out`/`out2` already map
`-EINVAL` to STATUS_INVALID_PARAMETER and roll back granted locks.
Step 2.3: IDENTIFY THE BUG MECHANISM
Record: [Logic / protocol correctness + deadlock prevention]
- Spec (MS-SMB2 3.3.5.14.2): if Locks[] has more than one entry and any
lacks FAIL_IMMEDIATELY, the server SHOULD fail with
STATUS_INVALID_PARAMETER.
- Client rule (MS-SMB2 3.2.4.19): if Locks[] has more than one element,
the client MUST set FAIL_IMMEDIATELY.
- Mechanism: reject blocking multi-element LOCKs so ksmbd cannot hold
earlier ranges while waiting on a later one.
Step 2.4: ASSESS THE FIX QUALITY
Record:
- Obviously correct: same check Samba already does in
`smbd_smb2_lock_send()`.
- Minimal: one condition, existing error path.
- Regression risk: very low for compliant clients (they always set the
flag). A non-compliant client that used blocking multi-locks would
start getting STATUS_INVALID_PARAMETER — that is the intended spec
behavior.
- Caveat: the check is inside the processing loop, so a later blocking
element can still apply earlier FAIL_IMMEDIATELY locks and then roll
them back. That matches existing `out:` rollback, not a new leak.
Samba checks the whole array first; this is slightly later but still
correct.
- The new `if` runs before `list_del(&smb_lock->llist)`, so the current
element is still on `lock_list` and is freed on `out:`. No leak.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
Step 3.1: BLAME THE CHANGED LINES
Record: The processing loop was introduced in `e2f34481b24db` (“cifsd:
add server-side procedures for SMB3”, 2021-05-10). `git merge-base --is-
ancestor e2f34481b24db HEAD` succeeds. This has been in ksmbd since it
landed, including this 6.12 tree.
Step 3.2: FOLLOW THE FIXES: TAG
Record: No Fixes: tag. Not applicable. The missing check dates to the
original smb2_lock implementation.
Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
Record: Recent `smb2pdu.c` work in this tree is other protocol/security
fixes (partial info, leases, etc.), not this check. Related historical
lock bugs already here include UAFs and leaks in deferred-lock/cancel
(`ddb9239828336`, `89ae9df09d2c1`, `463bbd7969851`, `a0609097fd10d`).
This patch is standalone, not “2/N”.
Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
Record: Namjae Jeon is the ksmbd maintainer. Many of this tree’s ksmbd
stable-style fixes are his. The 7.3-rc1 ksmbd pull lists this commit
among lock/async correctness updates.
Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
Record: No new helpers or fields. It uses `lock_count`,
`lock_ele[0].Flags`, `smb_lock->flags`, and `SMB2_LOCKFLAG_*`, all
present here. Nearby 7.3 lock work (replay sequences, deferred-lock
discard) is not required. Standalone.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
Record: lore.kernel.org search returned 403; `b4 dig -c` needs a commit
that is not in this checkout. The commit is listed in Namjae’s `[GIT
PULL] ksmbd server update for 7.3-rc1` (2026-08-23, Message-ID
`CAKYAXd8PROT1-3CXk2MnJco2KNKH_4iiN-Ypo5vOFWLPhRki4Q@mail.gmail.com`),
tag `ksmbd-for-7.3-rc1`. Full v1/v2 review thread: UNVERIFIED.
Step 4.2: CHECK WHO REVIEWED THE PATCH
Record: UNVERIFIED for the original To/Cc list. It went through the
ksmbd maintainer pull to Linus. No NAK found in the pull description.
Step 4.3: SEARCH FOR THE BUG REPORT
Record: No syzbot/bugzilla link. Motivation is MS-SMB2 + deadlock
analysis, not a named CVE. Samba documents the same SHOULD-fail rule
with a comment citing 3.3.5.14.2.
Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
Record: Same 7.3 pull also has lock-sequence replay, deferred-lock
discard, and detach-before-free. Those are separate. This one is self-
contained validation.
Step 4.5: CHECK STABLE MAILING LIST HISTORY
Record: lore.kernel.org/stable search returned 403. No evidence this was
already rejected for stable. UNVERIFIED whether AUTOSEL already queued
it.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
Record: `smb2_lock()` only.
Step 5.2: TRACE CALLERS
Record: Dispatched as `smb2_0_server_cmds[SMB2_LOCK_HE].proc =
smb2_lock` in `fs/smb/server/smb2ops.c`. Reached from
`__handle_ksmbd_work()` → `cmds->proc(work)` in `fs/smb/server/server.c`
for any SMB2 LOCK on an authenticated session with a valid file id.
Step 5.3: TRACE CALLEES
Record: Existing path uses `vfs_lock_file()`, `setup_async_work()`,
`smb2_send_interim_resp()`, `ksmbd_vfs_posix_lock_wait()`. The wait is
`wait_event(flock->c.flc_wait, !flock->c.flc_blocker)` —
uninterruptible. That is why a blocking multi-lock can pin a ksmbd
worker while earlier ranges stay held.
Step 5.4: FOLLOW THE CALL CHAIN
Record: Userspace/network reachable: SMB client → TCP → ksmbd worker →
`smb2_lock()`. Needs an authenticated session and open handle, not
CAP_SYS_ADMIN. Typical NAS user can send it.
Step 5.5: SEARCH FOR SIMILAR PATTERNS
Record: Samba `source3/smbd/smb2_lock.c` rejects `in_lock_count > 1`
when the first element is a blocking SHARED/EXCLUSIVE lock, then walks
remaining elements and fails any without FAIL_IMMEDIATELY. Same bug
class, already fixed in Samba.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
Record: Yes. Local tree is **6.12.111** (`pending-6.12`, `git describe`
`p-6.12-3-gc504cf0baa3d8`). `smb2_lock()` at
`fs/smb/server/smb2pdu.c:7535` still starts the loop at 7635 with no
multi-element FAIL_IMMEDIATELY check. Bug introduced with ksmbd
(v5.15-era `e2f34481b24db`), present here. `git log --grep='reject
blocking compound lock' -- fs/smb/server/` is empty.
Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
Record: Insertion point matches. Upstream hunk context uses
`smb2_lock_init(..., !lock_length, &lock_list)`; this tree still has
`smb2_lock_init(flock, cmd, flags, &lock_list)`. Expect a minor context
conflict, trivial to apply by hand. No semantic dependency on the extra
`!lock_length` argument.
Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
Record: No equivalent check. Existing FAIL_IMMEDIATELY use only skips
connection-list conflict checks for blocking single locks (`goto
no_check_cl`). That is the opposite of rejecting multi-element blocking
locks.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
Record: [fs/smb/server (ksmbd)] [IMPORTANT for CONFIG_SMB_SERVER;
default n]. Network-facing file server. Lock bugs affect all ksmbd
shares.
Step 7.2: ASSESS SUBSYSTEM ACTIVITY
Record: Actively maintained; this 6.12 branch already carries many ksmbd
protocol and UAF fixes. Mature lock path, old bug.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
Step 8.1: DETERMINE WHO IS AFFECTED
Record: Config-specific: `CONFIG_SMB_SERVER`. Authenticated SMB clients
of ksmbd NAS/embedded/Android-style servers.
Step 8.2: DETERMINE THE TRIGGER CONDITIONS
Record: SMB2 LOCK with LockCount > 1 and at least one non-unlock element
without FAIL_IMMEDIATELY. Windows/Samba clients must set the flag, so
well-behaved traffic never hits it. A buggy or malicious authenticated
client can. Unprivileged in the kernel sense; needs a ksmbd login and
file handle.
Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
Record: [Deadlock / worker hang / cross-client lock inversion] [HIGH]
Not a KASAN crash. Holding range A while waiting uninterruptibly for
range B is a real deadlock and can stall a ksmbd workqueue thread. That
is why the protocol forbids it.
Step 8.4: CALCULATE RISK-BENEFIT RATIO
Record:
- Benefit: high for ksmbd hosts — closes a remote deadlock/DoS via
illegal LOCK arrays; aligns with Samba/MS-SMB2.
- Risk: very low — 7 lines, existing `-EINVAL` path, no ABI, no lock-
order change.
- Ratio: strongly favors backport.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
Step 9.1: COMPILE THE EVIDENCE
FOR:
- Real deadlock/partial-ownership bug on a network file server
- MS-SMB2 3.3.5.14.2 and Samba implement the same reject
- Tiny, obviously correct, uses existing error/rollback
- Buggy code present in this 6.12 tree since ksmbd introduction
- Maintainer-authored; in the 7.3-rc1 ksmbd pull
- Reachable by authenticated SMB clients
AGAINST:
- Spec is SHOULD, not MUST (footnote 373); Windows may differ
- Compliant clients never send this
- No Reported-by / syzbot / CVE
- Original lore review thread not retrieved
UNRESOLVED:
- Exact lore URL / series revisions (b4/lore 403)
- Whether AUTOSEL already picked it for some series
Step 9.2: APPLY THE STABLE RULES CHECKLIST
1. Obviously correct and tested? PASS — matches Samba; ksmbd maintainer;
uses existing STATUS_INVALID_PARAMETER path
2. Fixes a real bug that affects users? PASS — deadlock/partial lock
ownership on ksmbd
3. Important issue? PASS — deadlock / server-worker hang, not a style
tweak
4. Small and contained? PASS — 7 lines, one function
5. No new features or APIs? PASS — validation only
6. Can apply to the local tree? PASS — same loop; at most a trivial
`smb2_lock_init` context tweak
Step 9.3: CHECK FOR EXCEPTION CATEGORIES
Record: None. Qualifies as a normal important bug fix, not a device-
ID/quirk/DT exception.
Step 9.4: MAKE YOUR DECISION
Backport to this 6.12 tree. The bug is here, the fix is surgical, and
leaving ksmbd willing to block on multi-element LOCKs is a deadlock
hazard for a network-facing server.
What it solves for stable users: ksmbd currently accepts multi-range
LOCK requests that omit FAIL_IMMEDIATELY. It can grant earlier ranges,
then sleep uninterruptibly on a later range
(`ksmbd_vfs_posix_lock_wait()`), which enables lock-order deadlocks and
stuck workers. The patch returns STATUS_INVALID_PARAMETER first (unlock
arrays unchanged).
Risk vs benefit: benefit is deadlock prevention on ksmbd; risk is a one-
condition reject of traffic no compliant client sends.
Concerns: apply context around `smb2_lock_init()` may need a one-line
tweak; no other prerequisites.
Verification:
- [Phase 1] Tags: only Namjae Jeon SOB; no Fixes/Reported-by/Link
- [Phase 2] Diff: 7 lines in `smb2_lock()` loop; `-EINVAL` →
STATUS_INVALID_PARAMETER at smb2pdu.c:7889-7891; check is before
`list_del`/`vfs_lock_file`
- [Phase 2] Local blocking path: FILE_LOCK_DEFERRED →
`ksmbd_vfs_posix_lock_wait()` at smb2pdu.c:7760-7788; wait is
`wait_event()` in vfs.c:1894-1896
- [Phase 3] Blame: loop from e2f34481b24db (2021); ancestor of HEAD; fix
not in this tree
- [Phase 3] No Fixes: tag to follow
- [Phase 3] Related history: deferred-lock UAFs already in tree; this
check is independent
- [Phase 4] GIT PULL 7.3-rc1 lists this subject; lore/b4 thread
UNVERIFIED (403 / no local SHA)
- [Phase 4] MS-SMB2 3.3.5.14.2 SHOULD-fail; 3.2.4.19 client MUST set
FAIL_IMMEDIATELY on multi-element LOCK
- [Phase 4] Samba smb2_lock.c:342-378 implements the same
INVALID_PARAMETER reject
- [Phase 5] Caller: smb2ops.c:187 SMB2_LOCK_HE → server.c:147
`cmds->proc`
- [Phase 6] `make kernelversion` 6.12.111; buggy loop at smb2pdu.c:7635;
`smb2_lock_init` here has 4 args vs upstream 5 in hunk context
- [Phase 6] `git log --grep='reject blocking compound lock' --
fs/smb/server/` empty
- [Phase 8] Failure mode: deadlock/worker hang, not oops; authenticated
SMB client can trigger
- UNVERIFIED: original lore review comments, AUTOSEL status, Windows
footnote 373 runtime behavior
**YES**
fs/smb/server/smb2pdu.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index ad6faaf54b991..cc3a3da410eaf 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -7748,6 +7748,13 @@ int smb2_lock(struct ksmbd_work *work)
}
list_for_each_entry_safe(smb_lock, tmp, &lock_list, llist) {
+ if (lock_count > 1 &&
+ !(le32_to_cpu(lock_ele[0].Flags) & SMB2_LOCKFLAG_UNLOCK) &&
+ !(smb_lock->flags & SMB2_LOCKFLAG_FAIL_IMMEDIATELY)) {
+ err = -EINVAL;
+ goto out;
+ }
+
if (smb_lock->cmd < 0) {
err = -EINVAL;
goto out;
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-6.12] ksmbd: reject SMB3.1.1 binding with mismatched cipher
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (17 preceding siblings ...)
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: reject blocking compound lock requests Sasha Levin
@ 2026-10-19 13:52 ` Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: fix AsyncId zeroed before use in smb2_lock() cancel response Sasha Levin
` (3 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:52 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 7019a11f79dc408f2b47b1027240e7f198784c9a ]
SMB3.1.1 multichannel connections belonging to the same session must use
the same negotiated encryption cipher.
ksmbd validates the dialect and client GUID during session binding, but
does not compare the cipher negotiated by the new connection with the
cipher used by the existing session channels. This allows a channel
negotiated with AES-128-CCM to bind to a session using AES-128-GCM.
Compare the new connection's cipher with an existing session channel and
return STATUS_INVALID_PARAMETER when they differ.
This fixes smb2.session.bind_negative_smb3encGtoCs.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Local tree
This checkout is **6.12.111** (`pending-6.12`, `git describe` =
`p-6.12-3-gc504cf0baa3d8`). The verdict is only for this tree.
Upstream commit analyzed: `7019a11f79dc408f2b47b1027240e7f198784c9a`
(not in this tree). `git apply --check` of that diff against local
`fs/smb/server/smb2pdu.c` succeeds.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1: Subject**
Record: `[ksmbd] [reject] SMB3.1.1 session binding must not succeed when
the new connection negotiated a different encryption cipher`
**Step 1.2: Tags**
Record:
- Signed-off-by: Namjae Jeon `<linkinjeon@kernel.org>` (author and
committer)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Acked-
by:`, `Link:`, or `Cc: stable`
- Absence of `Fixes:`/`Cc: stable` is expected for this review path and
is not treated as a negative signal
**Step 1.3: Body**
Record:
- Bug: SMB3.1.1 multichannel session binding checks dialect and client
GUID, but not cipher. A connection that negotiated AES-128-CCM can
bind to a session whose existing channel uses AES-128-GCM.
- Symptom: invalid bind is accepted; smbtorture
`smb2.session.bind_negative_smb3encGtoCs` fails (expects
`STATUS_INVALID_PARAMETER`).
- Root cause: missing comparison of `conn->cipher_type` against an
existing session channel.
- Fix: under `sess->chann_lock`, compare ciphers and return `-EINVAL` →
`STATUS_INVALID_PARAMETER`.
- No kernel-version range in the message.
**Step 1.4: Hidden bug fix?**
Record: Not hidden. Explicit protocol-validation fix for encryption-
cipher mismatch on bind.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1: Inventory**
Record:
- File: `fs/smb/server/smb2pdu.c` only (`+15` lines)
- Function: `smb2_sess_setup()`
- Scope: single-file surgical insertion in the existing SMB 3.x
multichannel binding branch, immediately after the dialect check
**Step 2.2: Code flow**
Record:
- Before: after `conn->dialect != sess->dialect`, binding proceeds to
the signed-request and GUID checks.
- After: if dialect is SMB 3.1.1, take `down_read(&sess->chann_lock)`,
walk `sess->ksmbd_chann_list`, if `conn->cipher_type !=
chann->conn->cipher_type` set `rc = -EINVAL`, then `up_read` and `goto
out_err`.
- Path: SESSION_SETUP with `SMB2_SESSION_REQ_FLAG_BINDING` on SMB 3.1.1
with multichannel enabled. Existing `out_err` maps `-EINVAL` to
`STATUS_INVALID_PARAMETER` (local lines 1916–1917).
**Step 2.3: Bug mechanism**
Record:
- Category: protocol/crypto correctness (logic), not UAF/leak/race.
- Mechanism: cipher is per-connection (`conn->cipher_type`, set in
`decode_encrypt_ctxt()` at NEGOTIATE). Session encryption/decryption
keys are session-wide (`sess->smb3encryptionkey` /
`smb3decryptionkey`) and are **not** regenerated on bind
(`generate_encryptionkey` is skipped when
`SMB2_SESSION_REQ_FLAG_BINDING` is set, local lines 1545–1546).
`ksmbd_crypt_message()` then selects GCM vs CCM and 128 vs 256 from
**this connection’s** `cipher_type` while using those shared session
keys. Accepting a mismatched cipher therefore attaches a channel that
will encrypt/decrypt with the wrong AEAD (and possibly the wrong key
length) for the session keys.
- The `break` after the first channel is intentional: one existing
channel is enough because all channels of a session are supposed to
share one cipher.
**Step 2.4: Fix quality**
Record:
- Obviously correct: same lock and `xa_for_each` pattern as
`free_channel_list()` / `ksmbd_sessions_deregister()`. Lock order
matches existing `smb2_sess_setup` (`ksmbd_conn_lock` then
`chann_lock`).
- Minimal: 15 lines, no API/struct change.
- Regression risk: low. Well-behaved clients already use one cipher for
all channels; the new path only rejects invalid binds. `chann->conn`
is set when the channel is allocated (`chann->conn = conn` in
`ntlm_authenticate`) and the channel is erased under `chann_lock`
before free.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1: Blame**
Record:
- Binding path originates in `f5a544e3bab7` (“ksmbd: add support for
SMB3 multichannel”, 2021); it is an ancestor of this HEAD.
- Dialect check: `af7c39d971e43c` (2022); also an ancestor.
- Cipher field: `connection.h` `cipher_type` present in this tree.
- Missing cipher compare has been true for as long as ksmbd had SMB
3.1.1 encryption + multichannel, including all of 6.12.
**Step 3.2: Fixes: tag**
Record: none. No `Fixes:` follow-up required.
**Step 3.3: File history**
Record:
- Local recent `smb2pdu.c` work is other ksmbd validation/UAF fixes;
none already implement this cipher compare (`git log -S 'cipher_type
!= chann'` on this file is empty here).
- On `origin/master`, the only commit with this compare is
`7019a11f79dc4` itself (no later rework).
- Neighbor bind_negative work (`f49bca41c12f9`, `3e67423336f08`,
`1f12738b0ed7b`, `1c5daa2ea924be`) is **not** in this tree and is
about signing of rejected responses / user mismatch, not a
prerequisite for this hunk.
**Step 3.4: Author**
Record: Namjae Jeon is the ksmbd maintainer. Many of his protocol-
validation commits are already in this 6.12 tree.
**Step 3.5: Dependencies**
Record: Standalone. Needs `sess->chann_lock`, `sess->ksmbd_chann_list`,
`struct channel { ... *conn }`, `conn->cipher_type`, `SMB311_PROT_ID` —
all present locally. Not labeled `patch X/Y`. `4b706360ffb7e` (channel
limit) is not required.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1: Original discussion**
Record: `b4 dig -c 7019a11f79dc4` (and `-C`) failed: lore.kernel.org
returned an error. WebFetch of lore URLs returned 403. Mailing-list
review text is **UNVERIFIED**.
**Step 4.2: Recipients**
Record: Could not run `b4 dig -w` successfully. Commit has only the
maintainer’s SOB (author = committer).
**Step 4.3: Bug report / spec / test**
Record (verified):
- Samba smbtorture `test_session_bind_negative_smb3encGtoCs`
(source4/torture/smb2/session.c): SMB 3.1.1, encryption required,
channel 1 AES-128-GCM, bind channel AES-128-CCM, same ClientGUID,
expects `NT_STATUS_INVALID_PARAMETER`.
- Microsoft Open Specifications blog “SMB 3.1.1 Encryption in Windows
10”: “Session binding (multichannel) requires that all channels bound
to a given session negotiate the same encryption cipher as the master
session’s connection” and that all channels share the same encryption
keys.
- MS-SMB2 3.3.5.5 (SESSION_SETUP) documents dialect/GUID/signed/state
checks that ksmbd already performs; the published HTML for that
section does **not** spell out a CipherId compare (the Windows/Samba
behavior and the blog do).
**Step 4.4: Series**
Record: Cluster of July 2026 `bind_negative_*` ksmbd fixes on
`origin/master`. This commit is self-contained; it does not depend on
the signing-response patches.
**Step 4.5: Stable list**
Record: lore.kernel.org/stable search not reachable (403).
**UNVERIFIED** whether it was previously discussed for stable.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1: Functions**
Record: `smb2_sess_setup()` only.
**Step 5.2: Callers**
Record: `fs/smb/server/smb2ops.c` command table `[SMB2_SESSION_SETUP_HE]
= { .proc = smb2_sess_setup }`. Invoked for every SMB2 SESSION_SETUP on
the ksmbd server. Network-reachable.
**Step 5.3: Callees**
Record: `down_read`/`up_read`, `xa_for_each` on
`sess->ksmbd_chann_list`. Existing error path `goto out_err`.
**Step 5.4: Reachability**
Record: Yes, from a remote SMB client if `CONFIG_SMB_SERVER` and
`KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL` are enabled. Trigger: SMB 3.1.1
session, then a second connection that negotiates a different cipher and
sends a signed binding SESSION_SETUP. Unprivileged in the sense of “any
client that can authenticate to ksmbd”; not a local syscall UAF.
**Step 5.5: Similar patterns**
Record: Dialect mismatch already rejected in the same function. Samba
has a second test `bind_negative_smb3encGtoCd` (different GUID); this
tree already rejects GUID mismatch via `memcmp(conn->ClientGUID,
sess->ClientGUID)`.
---
## PHASE 6: CROSS-REFERENCE AGAINST THIS TREE
**Step 6.1: Buggy code present?**
Record: Yes. Local `smb2_sess_setup()` at `fs/smb/server/smb2pdu.c`
~1743–1757 does dialect/GUID checks and has **no** cipher compare.
`7019a11f79dc4` is not an ancestor of HEAD.
**Step 6.2: Backport difficulty**
Record: **Clean apply** (`git apply --check` exit 0). Line-number offset
only vs mainline.
**Step 6.3: Related fixes already here?**
Record: No `bind_negative` ksmbd commits in this tree. No other cipher-
on-bind check.
---
## PHASE 7: SUBSYSTEM CONTEXT
**Step 7.1**
Record: `fs/smb/server` (ksmbd). Criticality: **IMPORTANT** — in-kernel
SMB3 server, remote attack surface, not core mm/VFS, not staging.
**Step 7.2**
Record: Actively maintained; this 6.12 tree already carries many ksmbd
validation backports (`reject repeated SMB2 NEGOTIATE`, DACL bounds,
etc.).
---
## PHASE 8: IMPACT AND RISK
**Step 8.1: Who is affected**
Record: Users of ksmbd with SMB3 multichannel enabled. Not universal.
**Step 8.2: Trigger**
Record: Uncommon for production Windows/Samba clients (they keep one
cipher). Fully reachable from a custom or test client. Requires an
existing authenticated session plus a signed bind (not an
unauthenticated bypass).
**Step 8.3: Failure mode**
Record: Today the invalid bind **succeeds**. Later encrypt/decrypt on
that channel uses the new connection’s AEAD with session keys derived
for the original cipher → AEAD failure / broken encrypted I/O, not a
demonstrated kernel oops. Spec/Windows require rejection with
`STATUS_INVALID_PARAMETER`. Severity: **MEDIUM** (protocol/crypto
invariant), not a panic/UAF.
**Step 8.4: Risk–benefit**
Record:
- Benefit: enforces a documented SMB 3.1.1 encryption invariant on a
network server; matches Windows/Samba; tiny.
- Risk: very low — 15 lines, existing locks, rejects only illegal binds.
- Ratio: favorable for this tree because the code exists, the patch
applies cleanly, and ksmbd crypto protocol holes are worth closing
even when the trigger is rare.
---
## PHASE 9: SYNTHESIS
**Step 9.1: Evidence**
FOR:
- Real missing check: dialect is validated, cipher is not.
- Session keys are shared; cipher is per-connection; mismatch is a
crypto/protocol bug, not cosmetic.
- Samba negative test and Microsoft encryption blog require same cipher
on all bound channels.
- 15 lines, maintainer-authored, applies cleanly to 6.12.111.
- All data structures and the insertion site exist here; bug is old
(multichannel + 3.1.1 encryption).
AGAINST:
- No crash, UAF, deadlock, or known CVE.
- Production clients typically never send this.
- No `Reviewed-by`; lore discussion could not be fetched.
- Adjacent bind_negative signing patches are not in this tree (not
required for this hunk).
UNRESOLVED:
- Original mailing-list review / any NAK (lore unreachable).
- Whether MS-SMB2 3.3.5.5 normative text currently names CipherId (blog
+ Samba/Windows behavior still require the check).
**Step 9.2: Stable rules**
1. Obviously correct and tested? **PASS** — small, same locking as
existing channel walks; covered by smbtorture
`bind_negative_smb3encGtoCs`.
2. Real bug affecting users? **PASS** — ksmbd accepts a bind the
protocol forbids; encrypted traffic on that channel is then
inconsistent.
3. Important (crash/security/corruption/deadlock)? **PASS** (lower end)
— encryption-cipher invariant on a remote SMB server, not a panic.
Important enough given ksmbd’s role and the size of the fix.
4. Small and contained? **PASS** — +15 lines, one function.
5. No new features/APIs? **PASS**.
6. Applies to this tree? **PASS** — clean apply; buggy code present.
**Step 9.3: Exception category**
Record: none (not a device ID/quirk/DT/build/docs exception). Qualifies
as a normal small protocol/crypto bugfix.
**Step 9.4: Decision**
Backport to this 6.12 tree. The missing check is in this code, the fix
is surgical, and rejecting mismatched SMB 3.1.1 ciphers on bind is the
correct, low-risk behavior for stable ksmbd.
---
## Why this matters for 6.12 stable users
ksmbd already refuses a bind when the **dialect** does not match. It
still allows a second SMB 3.1.1 channel to join the same session with a
**different** negotiated cipher (e.g. AES-128-CCM vs AES-128-GCM).
Encryption keys are session-scoped and not rebuilt on bind; each
connection then picks GCM/CCM and key length from its own `cipher_type`.
That is a protocol and crypto consistency bug on a network-facing
server. The patch only adds the missing compare and returns
`STATUS_INVALID_PARAMETER`, which is what Windows/Samba tests expect.
Risk is low: correct clients are unchanged. The hunk applies here
without prerequisites.
### Verification
- [Phase 1] Parsed message/tags: maintainer SOB only; no
Fixes/Cc/Reported-by.
- [Phase 2] Diff: +15 lines in `smb2_sess_setup()` binding branch;
`-EINVAL` already maps to `STATUS_INVALID_PARAMETER`.
- [Phase 2] Confirmed bind skips `generate_encryptionkey` (local
1545–1546); `ksmbd_crypt_message()` uses `conn->cipher_type` (auth.c
1135–1155).
- [Phase 3] `git describe HEAD` / `make kernelversion`: 6.12.111. `git
merge-base --is-ancestor 7019a11f79dc4 HEAD` → not in tree.
- [Phase 3] `f5a544e3bab7` and `af7c39d971e43c` are ancestors; dialect
check present, cipher check absent (local ~1754–1757).
- [Phase 3] `git apply --check` of `7019a11f79dc4` → clean.
- [Phase 3] No later origin/master rework of this compare; related
bind_negative signing commits are not ancestors and are not required.
- [Phase 4] `b4 dig` lore error; lore WebFetch 403. Samba test and MS
encryption blog fetched successfully.
- [Phase 5] Caller: `smb2ops.c` SESSION_SETUP proc. Channel
lock/list/`cipher_type` exist in this tree.
- [Phase 6] Insertion site matches; no local substitute fix.
- [Phase 8] Failure mode: invalid encrypted channel accepted; AEAD
mismatch on subsequent I/O. Severity MEDIUM, regression risk very low.
- UNVERIFIED: lore review thread, stable@ discussion, explicit CipherId
sentence in current MS-SMB2 3.3.5.5 HTML.
**YES**
fs/smb/server/smb2pdu.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index ccefd325e52e3..d64753124dd9a 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -1747,6 +1747,21 @@ int smb2_sess_setup(struct ksmbd_work *work)
goto out_err;
}
+ if (conn->dialect == SMB311_PROT_ID) {
+ struct channel *chann;
+ unsigned long index;
+
+ down_read(&sess->chann_lock);
+ xa_for_each(&sess->ksmbd_chann_list, index, chann) {
+ if (conn->cipher_type != chann->conn->cipher_type)
+ rc = -EINVAL;
+ break;
+ }
+ up_read(&sess->chann_lock);
+ if (rc)
+ goto out_err;
+ }
+
if (!(req->hdr.Flags & SMB2_FLAGS_SIGNED)) {
rc = -EINVAL;
goto out_err;
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-6.1] ksmbd: fix AsyncId zeroed before use in smb2_lock() cancel response
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (18 preceding siblings ...)
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.12] ksmbd: reject SMB3.1.1 binding with mismatched cipher Sasha Levin
@ 2026-10-19 13:52 ` Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: fix durable handle v2 default timeout units (60 -> 60000) Sasha Levin
` (2 subsequent siblings)
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:52 UTC (permalink / raw)
To: patches, stable
Cc: Gael Blivet, Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Gael Blivet <gael.blivet@gmail.com>
[ Upstream commit 7b461610882c8baa64d56dade57cdbfb686739fa ]
release_async_work() zeroes work->async_id before the CANCELLED path
calls smb2_send_interim_resp(work, STATUS_CANCELLED), which reads
work->async_id to build the response's AsyncId field. The cancellation
response for a cancelled blocked-lock request is sent with AsyncId=0
instead of the id the client received in the original STATUS_PENDING
response for this request.
Checked against every other release_async_work() call site in this
file: smb2_read()/smb2_write() don't send a further async response
afterward (their status goes out on the synchronous path instead), and
smb2_notify()'s two async paths already transfer the id to a separate
struct before releasing, so this reordering is scoped to smb2_lock()
only.
Send the STATUS_CANCELLED response while work->async_id is still valid,
then release the async work afterward.
Signed-off-by: Gael Blivet <gael.blivet@gmail.com>
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.12.111** (`pending-6.12`). The buggy `smb2_lock()`
cancel path is present here; it was introduced by a UAF backport already
on this branch. This is a small protocol-correctness follow-up for that
regression.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
Step 1.1: PARSE THE SUBJECT LINE
Record: **[ksmbd]** **[fix]** AsyncId is cleared before the SMB2 lock-
cancel interim response is built, so the client gets AsyncId=0.
Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
Record (from the candidate text, ignoring pipeline-added Sasha Levin SOB
/ Upstream markers):
- **Signed-off-by:** Gael Blivet `<gael.blivet@gmail.com>`
- **Assisted-by:** Claude:claude-sonnet-5
- **Signed-off-by:** Namjae Jeon `<linkinjeon@kernel.org>` (candidate
text)
Verified mainline object `af25b28a866c85662723f437d2f2bd433b3ecf92`
(same patch-id) actually has:
- **Acked-by:** Namjae Jeon
- **Signed-off-by:** Steve French
- No **Fixes:**, no **Cc: stable**, no **Reported-by**, no **Tested-
by**, no **Link:**
Absence of Fixes/Cc:stable is expected for this review and is not a
negative signal.
Step 1.3: ANALYZE THE COMMIT BODY TEXT
Record:
- **Bug:** `release_async_work()` sets `work->async_id = 0` before
`smb2_send_interim_resp(work, STATUS_CANCELLED)`. That helper copies
`work->async_id` into the SMB2 header AsyncId field.
- **Symptom:** A cancelled blocked lock is answered with **AsyncId=0**,
not the id from the earlier STATUS_PENDING interim response.
- **Root cause:** Ordering: release-then-send on the CANCELLED path.
- **Author’s audit:** Other `release_async_work()` sites in that file do
not send another async response afterward (read/write) or copy the id
aside first (notify on mainline). Reorder is scoped to `smb2_lock()`
only.
- **Version info:** None in the message. The ordering bug is a side-
effect of the earlier UAF reshuffle (see Phase 3).
Step 1.4: DETECT HIDDEN BUG FIXES
Record: Not hidden. It is an explicit protocol-correctness fix: the
cancel response is unusable if AsyncId does not match the pending
request.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
Step 2.1: INVENTORY THE CHANGES
Record:
- **File:** `fs/smb/server/smb2pdu.c` — **+9 / −6** (net +3), one hunk
- **Function:** `smb2_lock()`
- **Scope:** single-file surgical reorder of existing calls; no
API/struct changes
Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
Local tree today (`smb2_lock` deferred-wait cleanup):
```7794:7814:fs/smb/server/smb2pdu.c
list_del(&smb_lock->llist);
release_async_work(work);
if (work->state == KSMBD_WORK_ACTIVE)
goto retry;
locks_free_lock(flock);
if (work->state == KSMBD_WORK_CANCELLED)
{
rsp->hdr.Status =
STATUS_CANCELLED;
kfree(smb_lock);
smb2_send_interim_resp(work,
STATUS_CANCELLED);
work->send_no_response = 1;
goto out;
}
rsp->hdr.Status =
STATUS_RANGE_NOT_LOCKED;
```
After the patch:
- **CANCELLED:** send STATUS_CANCELLED **while `async_id` is live**,
then `release_async_work()`, then `locks_free_lock()`, then `goto out`
- **ACTIVE:** `release_async_work()` then `goto retry` (unchanged)
- **other non-ACTIVE (e.g. CLOSED):** `release_async_work()` then
`locks_free_lock()` then STATUS_RANGE_NOT_LOCKED (unchanged)
`smb2_send_interim_resp()` really does use the id:
```731:733:fs/smb/server/smb2pdu.c
rsp_hdr = smb_get_msg(in_work->response_buf);
rsp_hdr->Flags |= SMB2_FLAGS_ASYNC_COMMAND;
rsp_hdr->Id.AsyncId = cpu_to_le64(work->async_id);
```
and `release_async_work()` really zeroes it:
```707:710:fs/smb/server/smb2pdu.c
if (work->async_id) {
ksmbd_release_id(&conn->async_ida, work->async_id);
work->async_id = 0;
}
```
Step 2.3: IDENTIFY THE BUG MECHANISM
Record: **Logic / protocol correctness** (wrong AsyncId on the cancel
response).
Not a UAF/leak/null-deref in this patch itself. The UAF invariant from
`463bbd79698513` is kept: `release_async_work()` still runs **before**
`locks_free_lock(flock)` on every terminal path, so `smb2_cancel()`
cannot invoke `smb2_remove_blocked_lock()` on a freed `file_lock`.
Step 2.4: ASSESS THE FIX QUALITY
Record: Obviously correct from the code. Minimal. No new locks, APIs, or
control-flow besides reordering existing calls.
**Regression risk:** Low. The extra window is only
`smb2_send_interim_resp()` before dequeue; `cancel_fn` still sees a live
`flock`. Same three `work->state` outcomes as today.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
Step 3.1: BLAME THE CHANGED LINES
Record: The current “release, then maybe send CANCELLED” block was
written by **`463bbd79698513`** (“ksmbd: fix UAF of struct file_lock in
SMB2_LOCK deferred-lock cancellation”, Greg backport 2026-07-18). That
commit **is an ancestor of HEAD**.
`release_async_work()` itself is from `3a9b557f44ea8f` (2023). Interim
AsyncId is filled from `work->async_id` since `9ac45ac7cf65b` (2023),
also in this tree.
Step 3.2: FOLLOW THE FIXES: TAG
Record: No Fixes: tag. The commit that introduced **this** bug is the
UAF reshuffle:
- This tree: `463bbd79698513af4dad50fe1c573825f297ca2e`
- Upstream: `d20d1c8ba5765` (present as an object; already backported
here)
Before `463bbd`, the CANCELLED path sent STATUS_CANCELLED **without**
calling `release_async_work()` first (that skip was the UAF). After
`463bbd`, release always happens first, which zeros AsyncId and breaks
the cancel response.
Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
Record: Related lock/cancel UAF series already in this tree, in order:
- `89ae9df09d2c1` double SMB2_CANCEL UAF
- `ddb9239828336` CLOSE then CANCEL UAF
- `463bbd7969851` deferred-lock cancellation UAF (introduces this
AsyncId bug)
This patch is a **standalone follow-up** to `463bbd`, not part of a
numbered series. No extra prerequisite beyond that UAF fix, which is
already here.
Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
Record: Gael Blivet has **no other ksmbd commits on this branch**.
Namjae Jeon (ksmbd maintainer) **Acked** the patch on-list and applied
it (`#ksmbd-for-next-next`); Steve French signed it into the CIFS tree.
Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
Record: Needs `release_async_work()`, `smb2_send_interim_resp()` filling
AsyncId from `work->async_id`, and the `463bbd` lock-wait layout. All
are in this tree. Applies standalone. A string match of the local hunk
confirmed the old block is present and the new block is not.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
Record:
- Mainline SHA: **`af25b28a866c85662723f437d2f2bd433b3ecf92`** (not an
ancestor of this HEAD)
- Lore/msgid:
`https://patch.msgid.link/20260717073721.7487-1-g.blivet@me.com`
- **v1 only** (`b4 dig -a`); applied version is that v1
- Namjae reply (same thread): “Applied it to #ksmbd-for-next-next.
Thanks!” — **no NAK, no requested changes, no stable discussion**
Step 4.2: CHECK WHO REVIEWED THE PATCH
Record (`b4 dig -w`): To/Cc were **Namjae Jeon** and **linux-
cifs@vger.kernel.org**. Maintainer reviewed and applied.
Step 4.3: SEARCH FOR THE BUG REPORT
Record: No syzbot/bugzilla/Reported-by. The bug is deduced from code
after the UAF reorder; that analysis matches the local sources.
Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
Record: Standalone one-patch series. The author’s note about
`smb2_read()`/`smb2_write()`/`smb2_notify()` async sites describes
**mainline**; in **this** 6.12 tree `smb2_notify()` is a
`STATUS_NOT_IMPLEMENTED` stub and only `smb2_lock()` (plus oplock) uses
`setup_async_work()`. That does not change the `smb2_lock()` fix.
Step 4.5: CHECK STABLE MAILING LIST HISTORY
Record: lore.kernel.org search URLs returned 403. `b4 dig` found only
the linux-cifs thread (2 messages). **UNVERIFIED:** no evidence this was
already NAK’d or requested on stable@; no evidence it was rejected.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
Record: `smb2_lock()` only. It uses `release_async_work()`,
`smb2_send_interim_resp()`, `locks_free_lock()`.
Step 5.2: TRACE CALLERS
Record: `smb2_lock` is registered as the SMB2_LOCK handler in
`fs/smb/server/smb2ops.c` (`[SMB2_LOCK_HE] = { .proc = smb2_lock}`).
Reachable from an authenticated ksmbd client issuing a blocking byte-
range lock, then SMB2_CANCEL.
Step 5.3: TRACE CALLEES
Record:
- `setup_async_work()` allocates `async_id` and registers
`smb2_remove_blocked_lock`
- `smb2_send_interim_resp()` copies the SMB2 header and sets AsyncId
from `work->async_id`
- `release_async_work()` unlinks from `conn->async_requests`, clears
`cancel_fn`, frees `cancel_argv`, releases and zeros `async_id`
- `smb2_remove_blocked_lock()` only unblocks/wakes the `file_lock`
(verified in `smb2pdu.c`)
Step 5.4: FOLLOW THE CALL CHAIN
Record: Userspace-triggerable over SMB (needs a ksmbd share and a
blocking lock). Not a local unprivileged syscall UAF, but a real server
path for Windows/`LockFileEx`-style blocking locks plus cancel.
Step 5.5: SEARCH FOR SIMILAR PATTERNS
Record: In this tree, `release_async_work()` call sites are
`smb2_lock()`, `connection.c` teardown, and `oplock.c`. Only
`smb2_lock()` sends STATUS_CANCELLED afterward. Matches the author’s
“scope to smb2_lock only” claim **for this tree**.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
Record: **Yes.** `pending-6.12` / **6.12.111** (`git describe`:
`p-6.12-3-gc504cf0baa3d8`). The exact pre-patch block is at
`fs/smb/server/smb2pdu.c:7794-7808`. The bug was introduced **in this
series** by the `463bbd79698513` stable backport (2026-07-18), not by
original v6.12.
Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
Record: **Clean apply.** Context around `list_del(&smb_lock->llist)` /
`release_async_work` / CANCELLED send matches the candidate; only line
numbers differ (mainline ~9319 vs local ~7794 because this file is
smaller here). Confirmed with a direct string match of the old hunk.
Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
Record: `git log --grep="AsyncId zeroed" -- fs/smb/server/` is empty on
this branch. `af25b28a866c8` **is not** an ancestor of HEAD. The UAF fix
is here; this follow-up is not.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
Record: **ksmbd** (`fs/smb/server/`, `CONFIG_SMB_SERVER`). **IMPORTANT**
for systems that run the in-kernel SMB3 server (NAS/embedded); not core
mm/VFS for every machine. Default is `n`.
Step 7.2: ASSESS SUBSYSTEM ACTIVITY
Record: Actively patched on this branch (many recent ksmbd fixes in
`smb2pdu.c`). Mature SMB2 lock/cancel path, recently hit by several UAF
fixes.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
Step 8.1: DETERMINE WHO IS AFFECTED
Record: **Driver/config-specific:** ksmbd users (`CONFIG_SMB_SERVER`)
who issue **blocking SMB2_LOCK** and then **SMB2_CANCEL**.
Step 8.2: DETERMINE THE TRIGGER CONDITIONS
Record: Common SMB lock-cancel pattern (blocking lock held by another
client, then cancel). Needs SMB authentication to the server. Timing:
after the wait returns with `KSMBD_WORK_CANCELLED`.
Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
Record: **Protocol mismatch → client cannot correlate the cancel
completion with the STATUS_PENDING AsyncId.** Typical client effect is a
**hung/outstanding lock request until timeout**, not a kernel oops.
Severity **HIGH** for ksmbd lock-cancel (user-visible hang), not
CRITICAL kernel crash.
Step 8.4: CALCULATE RISK-BENEFIT RATIO
Record:
- **Benefit:** High for this tree specifically — restores correct cancel
matching **after a UAF backport that regressed it**.
- **Risk:** Very low — ~15-line reorder, UAF dequeue-before-free
preserved, maintainer-acked.
- **Ratio:** Strongly favors backport.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
Step 9.1: COMPILE THE EVIDENCE
**FOR:**
- Real bug: cancel response AsyncId is 0; clients match async work by
AsyncId
- Regression introduced by `463bbd79698513`, **already in this 6.12.y
tree**
- Small, obviously correct, applies cleanly
- Maintainer ack + applied upstream (`af25b28a866c8`)
- Does not undo the UAF fix (still `release_async_work` before
`locks_free_lock`)
**AGAINST:**
- Not a kernel oops/KASAN bug; protocol/hang rather than panic
- ksmbd is opt-in (`CONFIG_SMB_SERVER` default n)
- No Fixes:/Cc:stable/syzbot (expected; not a reason to reject)
- Author’s read/write/notify audit refers to newer mainline, not this
tree (irrelevant to the lock hunk)
**UNRESOLVED:**
- Could not search lore.kernel.org/stable/?q=… (HTTP 403); `b4` only saw
the linux-cifs v1 + maintainer apply
Step 9.2: APPLY THE STABLE RULES CHECKLIST
1. Obviously correct and tested? **PASS** — ordering is visible in
source; maintainer applied v1 with no revisions
2. Fixes a real bug that affects users? **PASS** — wrong AsyncId on
lock-cancel completion
3. Important issue? **PASS** — client-visible hang/mismatch on cancel;
**stable-to-stable regression** after the UAF backport
4. Small and contained? **PASS** — one function, +9/−6
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS** — hunk matches local
`smb2_lock()`
Step 9.3: CHECK FOR EXCEPTION CATEGORIES
Record: None (not a device-id/quirk/DT/build/docs exception). It
qualifies as a normal bugfix, specifically a **follow-up to a prior
stable backport**.
Step 9.4: MAKE YOUR DECISION
Backport. Leaving `463bbd79698513` in 6.12.y without this reorder keeps
a regression: lock-cancel replies with AsyncId=0. The fix is tiny and
keeps the UAF-safety ordering.
What problem it solves for stable users: after the deferred-lock UAF
fix, a cancelled blocking SMB2_LOCK still sends STATUS_CANCELLED, but
with AsyncId already cleared, so SMB2 clients cannot match it to the
STATUS_PENDING they already got.
Risk vs benefit: benefit is restoring lock-cancel completion on ksmbd;
risk is a short send-before-dequeue window on a still-valid `file_lock`.
===============================================================
Verification:
- [Phase 1] Parsed tags: no Fixes/Cc:stable/Reported-by; mainline
`af25b28a866c8` has Acked-by Namjae + SOB Steve French
- [Phase 2] Diff: +9/−6 in `smb2_lock()`; send CANCELLED before
`release_async_work()`; confirmed `async_id` zeroed in
`release_async_work()` and copied in `smb2_send_interim_resp()`
- [Phase 3] blame: buggy order from `463bbd79698513` (2026-07-18
backport of `d20d1c8ba5765`); `git merge-base --is-ancestor
463bbd79698513 HEAD` → yes
- [Phase 3] related UAF commits `89ae9df09d2c1` and `ddb9239828336` are
ancestors; this patch is the missing follow-up
- [Phase 4] `b4 dig -c af25b28a866c8`:
https://patch.msgid.link/20260717073721.7487-1-g.blivet@me.com
- [Phase 4] `b4 dig -a`: v1 only
- [Phase 4] `b4 dig -w`: Namjae + linux-cifs
- [Phase 4] mbox: Namjae “Applied it to #ksmbd-for-next-next”; no NAK
- [Phase 4] lore.kernel.org HTTP search: 403 — UNVERIFIED for stable@
archive
- [Phase 5] `smb2_lock` is SMB2_LOCK proc; `smb2_remove_blocked_lock`
only wakes the flock
- [Phase 6] `git describe HEAD` = `p-6.12-3-gc504cf0baa3d8`; `make
kernelversion` = 6.12.111; buggy code at smb2pdu.c:7794-7808;
`af25b28a866c8` is NOT ancestor; hunk string-matched
- [Phase 7] CONFIG_SMB_SERVER default n; subsystem actively receiving
lock/cancel UAF fixes
- [Phase 8] Failure mode: wrong AsyncId → client cannot complete
cancelled lock (hang/timeout), not kernel oops
- UNVERIFIED: whether every SMB client treats AsyncId=0 as a timeout vs
ignore; spec matching is by AsyncId, so mismatch is real regardless
**YES**
fs/smb/server/smb2pdu.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index ea5a130ef83ce..ad6faaf54b991 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -7909,22 +7909,25 @@ int smb2_lock(struct ksmbd_work *work)
spin_unlock(&fp->f_lock);
list_del(&smb_lock->llist);
- release_async_work(work);
-
- if (work->state == KSMBD_WORK_ACTIVE)
- goto retry;
-
- locks_free_lock(flock);
if (work->state == KSMBD_WORK_CANCELLED) {
rsp->hdr.Status = STATUS_CANCELLED;
kfree(smb_lock);
smb2_send_interim_resp(work,
STATUS_CANCELLED);
+ release_async_work(work);
+ locks_free_lock(flock);
work->send_no_response = 1;
goto out;
}
+ release_async_work(work);
+
+ if (work->state == KSMBD_WORK_ACTIVE)
+ goto retry;
+
+ locks_free_lock(flock);
+
rsp->hdr.Status =
STATUS_RANGE_NOT_LOCKED;
kfree(smb_lock);
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-6.6] ksmbd: fix durable handle v2 default timeout units (60 -> 60000)
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (19 preceding siblings ...)
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: fix AsyncId zeroed before use in smb2_lock() cancel response Sasha Levin
@ 2026-10-19 13:52 ` Sasha Levin
2026-10-19 13:53 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: enable TCP keepalive for accepted connections Sasha Levin
2026-10-19 13:53 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: fix SMB2 byte-range lock end offset Sasha Levin
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:52 UTC (permalink / raw)
To: patches, stable
Cc: Gael Blivet, Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Gael Blivet <gael.blivet@gmail.com>
[ Upstream commit c1d7bbfc5e081875053723d1a69eb2cf341eaaf1 ]
When a client's Durable Handle Request V2 sets Timeout=0 ("let the
server choose"), fp->durable_timeout was set to 60. Every other use
of this field is in milliseconds: DURABLE_HANDLE_MAX_TIMEOUT (300000)
in smb2pdu.h, the nonzero branch immediately above
(min_t(unsigned int, dh_info.timeout, DURABLE_HANDLE_MAX_TIMEOUT),
where dh_info.timeout is the wire value and already milliseconds per
spec), and the scavenger in vfs_cache.c, which adds it directly to
jiffies_to_msecs(jiffies).
60 is off by 1000x: the handle becomes scavenger-eligible 60
milliseconds after close instead of 60 seconds. A client requesting
Timeout=0 is relying entirely on the server's default to cover the
gap between a dropped connection and its reconnect -- 60ms is not
enough time for even a fast network blip to be detected and
reconnected, so any real disruption loses the race and a subsequent
DH2C reconnect fails with a durable-handle lookup miss instead of
succeeding.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Gael Blivet <gael.blivet@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.12.111** (`p-6.12-3-gc504cf0baa3d8`). The buggy
`fp->durable_timeout = 60` assignment is still in this checkout; the
upstream fix is not.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[ksmbd]** **[fix]** durable handle v2 default timeout units
(60 → 60000). Subsystem is the in-kernel SMB server. Action verb is
explicitly **fix**.
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Upstream commit `337e5ea7498178b3e50b39c266268a8b4d5b48d6` (not an
ancestor of this tree):
- **Assisted-by:** Claude:claude-sonnet-5
- **Signed-off-by:** Gael Blivet \<gael.blivet@gmail.com\>
- **Acked-by:** Namjae Jeon \<linkinjeon@kernel.org\> (ksmbd maintainer;
query text shows this as SOB from candidate prep)
- **Signed-off-by:** Steve French \<stfrench@microsoft.com\> (CIFS/SMB
maintainer)
- **No Fixes:** tag (expected for this review queue)
- **No Cc: stable** (expected)
- **No Reported-by / Tested-by / Link**
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** When Durable Handle Request V2 has `Timeout=0` (“let the
server choose”), `fp->durable_timeout` is set to **60**.
- **Root cause:** Every other use of this field is **milliseconds**:
wire Timeout per [MS-SMB2], `DURABLE_HANDLE_MAX_TIMEOUT` (300000), the
nonzero `min_t` branch, and the scavenger adding it to
`jiffies_to_msecs(jiffies)`.
- **Symptom:** Handle becomes scavenger-eligible **60 ms** after close
instead of **60 seconds**. A client using the server default cannot
reconnect after a real disconnect; DH2C fails with a durable-handle
lookup miss.
- **Version info in message:** none. Introducer is in this tree (see
Phase 3).
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not hidden. This is an explicit units/correctness fix (1000×),
not cleanup.
---
## PHASE 2: DIFF ANALYSIS - LINE BY LINE
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `fs/smb/server/smb2pdu.c` — **+8 / −1**
- Function: `smb2_open()`
- Classification: **single-file surgical fix**
- Functional change: one assignment `60` → `60000`
- Extra: comment before `reconnected_fp:` about `conn->is_aapl` on
reconnect (documentation only)
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record (this tree, `smb2_open()` around 3651–3663):
**Before:** `DURABLE_REQ_V2` + `dh_info.timeout == 0` →
`fp->durable_timeout = 60`.
**After:** same path → `fp->durable_timeout = 60000`.
Nonzero Timeout is unchanged (`min_t(..., DURABLE_HANDLE_MAX_TIMEOUT)`).
Path is the **normal CREATE** path when the client requests a v2 durable
handle with Timeout=0, not an error path.
On close/disconnect, `vfs_cache.c` does:
```1276:1278:fs/smb/server/vfs_cache.c
if (fp->durable_timeout)
fp->durable_scavenger_timeout =
jiffies_to_msecs(jiffies) + fp->durable_timeout;
```
The scavenger then expires the handle when `jiffies_to_msecs(jiffies)`
passes that deadline.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record: **[Logic / units / correctness]** Default timeout stored as 60
**seconds-as-if-ms**. Spec Timeout is milliseconds; 0 means server
default. Result: reconnect window is 60 ms instead of 60 s.
Also advertised to the client: `create_durable_v2_rsp_buf()` sends
`buf->Timeout = cpu_to_le32(fp->durable_timeout)`, so the client is told
the window is 60 ms.
**Step 2.4: ASSESS THE FIX QUALITY**
Record: Obviously correct: same constant the author intended, in the
units the rest of the code already uses. Samba uses 60×1000 ms when
Timeout=0; Windows DurableOpenTimeout is 60 s. Risk is low: handles may
linger 60 s instead of 60 ms after disconnect, which is the designed
behavior. Cap remains 300000 ms. Comment is unrelated but harmless;
`conn->is_aapl` and `reconnected_fp` exist in this tree.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1: BLAME THE CHANGED LINES**
Record: `fp->durable_timeout = 60` introduced in **`c8efcc786146a`**
(“ksmbd: add support for durable handles v1/v2”, Namjae Jeon,
2024-03-12). First appeared in **v6.9-rc1**. Present here. Nearby
`min_t` cap from **`289ebd9afeb94`** (build warning fix), also in this
tree.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No Fixes: tag. Introducer is `c8efcc786146a`, confirmed ancestor
of HEAD.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record: Recent `smb2pdu.c` work is other ksmbd fixes (normalized names,
compound errors, leases). No competing timeout-unit fix. Standalone vs
series: submitted as **patch 3/8** of “follow-up fixes”; cover letter
says patch 3 is **unrelated** to the rest (a separate 1000× units bug).
Other patches are stream delete, mdssvc logs, FSCTL bounds, xattr size,
DOS attrib init, stream unlink/fallocate.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Gael Blivet has **no** commits in this tree under
`fs/smb/server/`. Maintainer **Namjae Jeon** acked and applied this
patch (except 2/8 and 5/8, which are different patches). Steve French
signed off.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record: None for the assignment change. Durable-handle v2, scavenger,
and `DURABLE_HANDLE_MAX_TIMEOUT` are already here. Comment needs only
`reconnected_fp` / `is_aapl`, both present. **Can apply standalone.**
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- `b4 dig -c 337e5ea749817` →
https://patch.msgid.link/20260709000548.66445-4-g.blivet@me.com
- Series: `[PATCH 0/8] ksmbd: follow-up fixes to previously-merged
patches` (2026-07-09)
- `b4 dig -a`: **v1 only** (no later revisions of this patch)
- Lore HTTP fetch returned 403; full thread retrieved with `b4 mbox` (12
messages)
- Cover letter: patch 3 found in a durable-handle-v2 reconnect
investigation; Timeout=0 clients lose the reconnect race
- Namjae on cover: **“Applied them except 0002, 0005 patch to #ksmbd-
for-next-next.”** Patch 3 applied as submitted. No NAK, no stable
discussion.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record (`b4 dig -w`): Gaël Blivet-Bailly, **Namjae Jeon**, **linux-
cifs@vger.kernel.org**. Maintainer ack + apply.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record: No syzbot/bugzilla. Spec: [MS-SMB2] 2.2.13.2.11 Timeout is
**milliseconds**; 0 = server default. Samba sets default **1 minute
(60×1000 ms)** and caps at 300×1000. Windows DurableOpenTimeout is 60 s
(response Timeout sometimes 180 s). Linux CIFS client defaults
`handle_timeout = 0` (“most clients default to 0”).
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Other 7 patches are independent bugs. This one does not need
them.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable fetch 403. No stable mention in the
downloaded thread. **UNVERIFIED:** whether anyone already asked for this
on stable@.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF**
Record: `smb2_open()` only.
**Step 5.2: TRACE CALLERS**
Record: `smb2_open` is `SMB2_CREATE` in `fs/smb/server/smb2ops.c`.
Reachable from any SMB3 client CREATE with DH2Q. Durable parsing only if
`KSMBD_GLOBAL_FLAG_DURABLE_HANDLE` is set (ksmbd-tools `durable handles
= yes`; tools default is no).
**Step 5.3: TRACE CALLEES**
Record: Timeout consumed by scavenger (`ksmbd_durable_scavenger`) and
advertised in `create_durable_v2_rsp_buf()`. Parsed from wire via
`le32_to_cpu(durable_v2_blob->Timeout)`.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: Userspace SMB client → SMB2 CREATE + DH2Q Timeout=0 →
`smb2_open` → later disconnect → scavenger expires in 60 ms → DH2C miss.
CIFS client sends Timeout=0 by default. **Yes, userspace-reachable** for
servers with durable handles enabled.
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: Only this `= 60` default. V1 durable requests do not set
`durable_timeout` (stays 0; scavenger skips). Separate issue, not this
patch.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: **Yes.** `fs/smb/server/smb2pdu.c:3659`: `fp->durable_timeout =
60;`. Introduced v6.9-rc1; this is 6.12.111. `git merge-base --is-
ancestor 337e5ea749817 HEAD` is **false** — fix not present.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: Mainline hunk is around line 4186 vs 3659 here (later AAPL/open
growth). Context around the assignment matches. Expected apply: **clean
or trivial offset**. Comment applies; `is_aapl` exists at 3614–3620.
Mainline `app_instance_id` memcpy in the *provided* candidate context is
**not** in this tree; the **actual** upstream diff does not touch that —
only `60`→`60000` plus the comment.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No other timeout-units fix. `289ebd9afeb94` only changed `min()`
to `min_t()`.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: **ksmbd** (`fs/smb/server/`). **IMPORTANT** (in-kernel SMB3
server), not mm/VFS core. Affects ksmbd users with durable handles
enabled (Windows/macOS SMB3 reconnect).
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Active — many recent ksmbd fixes on this 6.12 branch. Durable-
handle code itself has been in tree since 6.9.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: **Config/feature-specific:** ksmbd with durable handles enabled.
Not all kernel users. Clients that send Timeout=0 (Linux CIFS default,
typical Windows). Clients that send a nonzero Timeout are unchanged.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record: Enable durable handles; CREATE with DH2Q Timeout=0; drop the TCP
connection; reconnect with DH2C. Common for SMB3 durable opens.
Unprivileged SMB clients can trigger it if the share allows them. Not a
timing race of locking — the window is just far too short.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record: **Failure:** durable reconnect fails (lookup miss); open does
not survive a network blip. **Not** panic, UAF, or silent data
corruption. **Severity: HIGH** for that feature (feature is effectively
broken for the default Timeout=0 case), **MEDIUM–HIGH** overall (opt-in,
but that is exactly who needs reconnect).
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- **Benefit: HIGH** for durable-handle users — reconnect works for the
common Timeout=0 case.
- **Risk: VERY LOW** — one integer, same units as the rest of the code,
within the existing 300 s cap. Extra comment is inert.
- **Ratio:** strong yes.
---
## PHASE 9: FINAL SYNTHESIS
**Step 9.1: COMPILE THE EVIDENCE**
**FOR:**
- Real 1000× units bug; Timeout=0 is the spec/common client default.
- Scavenger and DH2Q response both treat the field as milliseconds.
- Durable reconnect after a real disconnect fails today.
- One-line functional change; obviously correct; maintainer acked and
applied.
- Buggy code is in this 6.12 tree since v6.9; fix is not.
- Applies with no prerequisites.
**AGAINST:**
- Durable handles are opt-in (tools default off).
- Not a crash/UAF/CVE.
- Extra AAPL comment is unrelated (harmless).
- No Fixes:/Cc: stable (not a negative per rules).
**UNRESOLVED:**
- Direct stable@ lore search (HTTP 403).
- No public user bugzilla for this specific 60 ms window (found by
reconnect investigation).
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — units match spec and
adjacent code; maintainer applied it.
2. Fixes a real bug that affects users? **PASS** — Timeout=0 durable
reconnect fails.
3. Important issue? **PASS** — protocol feature that exists to survive
disconnects is broken in the default-timeout path (not panic, but
user-visible functional failure).
4. Small and contained? **PASS** — 1 file, 1 assignment (+ comment).
5. No new features or APIs? **PASS**
6. Can apply to the local tree? **PASS**
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: None (not a device ID/quirk/DT/build/doc-only). Ordinary
correctness fix.
**Step 9.4: MAKE YOUR DECISION**
This belongs on 6.12. The durable-handle v2 default is stored in the
wrong units, so any client that asks the server to pick a timeout
(including the in-tree CIFS client) gets a 60 ms reconnect window. That
is not a usable durable handle. The fix is a single constant aligned
with Samba (60 s) and with every other millisecond use of the field.
Risk is negligible; the code and introducer are already in this tree.
### What problem this solves for stable users
ksmbd users who enabled durable handles (Windows/macOS/SMB3 reconnect)
currently lose the handle ~60 ms after a drop when the client sent
Timeout=0. The reconnect CREATE then misses. After this change, the
default window is 60 seconds, matching the intended design and the
protocol’s millisecond Timeout field.
### Risk vs benefit
Benefit is restoring the feature those users turned on. Risk is holding
durable state for 60 s instead of 60 ms after disconnect — intended, and
still far below the 300 s cap.
---
Verification:
- [Phase 1] Subject/tags from `git show 337e5ea749817`: fix, Assisted-by
Claude, Acked-by Namjae Jeon, SOB Steve French; no
Fixes/Cc:stable/Reported-by
- [Phase 2] Diff: `fp->durable_timeout = 60` → `60000` plus AAPL
reconnect comment in `smb2_open()`
- [Phase 2] This tree: same assignment at
`fs/smb/server/smb2pdu.c:3659`; scavenger adds timeout to
`jiffies_to_msecs(jiffies)` at `vfs_cache.c:1276-1278`; response
Timeout at `oplock.c:1818`; parse is
`le32_to_cpu(durable_v2_blob->Timeout)` at `smb2pdu.c:2868-2869`;
`DURABLE_HANDLE_MAX_TIMEOUT` is 300000
- [Phase 3] `git blame`: line from `c8efcc786146a` (v6.9-rc1); `git
merge-base --is-ancestor c8efcc786146a HEAD` true; `289ebd9afeb94`
also in tree
- [Phase 3] `git merge-base --is-ancestor 337e5ea749817 HEAD` false;
object exists in repo
- [Phase 3] `git log -S 'durable_timeout = 60' --
fs/smb/server/smb2pdu.c` → only introducer
- [Phase 4] `b4 dig -c 337e5ea749817`:
patch.msgid.link/20260709000548.66445-4-g.blivet@me.com, PATCH 3/8
- [Phase 4] `b4 dig -a`: v1 only; `b4 dig -w`: Namjae + linux-cifs
- [Phase 4] `b4 mbox`: cover letter calls patch 3 standalone units bug;
Namjae applied all but 2/8 and 5/8
- [Phase 4] MS-SMB2 Timeout is milliseconds, 0 = server default
(WebFetch)
- [Phase 4] Samba default 60×1000 ms; Windows DurableOpenTimeout 60 s
- [Phase 4] lore.kernel.org HTTP 403; used b4 mbox instead
- [Phase 5] `smb2_open` is SMB2_CREATE handler; gated on
`KSMBD_GLOBAL_FLAG_DURABLE_HANDLE`
- [Phase 5] CIFS client `ctx->handle_timeout = 0` (`fs_context.c:1839`);
DH2Q Timeout from that (`smb2pdu.c:2461`)
- [Phase 6] `git describe HEAD` / `make kernelversion`: p-6.12-3 /
6.12.111; Makefile VERSION=6 PATCHLEVEL=12 SUBLEVEL=111
- [Phase 8] Failure: DH2C lookup miss after disconnect; not a panic
- UNVERIFIED: stable@ mailing list archive via HTTP; no public user
bugzilla for this 60 ms window
**YES**
fs/smb/server/smb2pdu.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 22c49921b1c07..ccefd325e52e3 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -3681,10 +3681,17 @@ int smb2_open(struct ksmbd_work *work)
min_t(unsigned int, dh_info.timeout,
DURABLE_HANDLE_MAX_TIMEOUT);
else
- fp->durable_timeout = 60;
+ fp->durable_timeout = 60000;
}
}
+ /*
+ * conn->is_aapl detection above (this function's create-context
+ * parsing) is skipped on the reconnect path below, since a
+ * reconnect always arrives on a fresh connection -- if the client
+ * cares, it sends its own AAPL context on this same CREATE, which
+ * this function's normal (non-reconnect) parsing already handles.
+ */
reconnected_fp:
rsp->StructureSize = cpu_to_le16(89);
opinfo = opinfo_get(fp);
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: enable TCP keepalive for accepted connections
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (20 preceding siblings ...)
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: fix durable handle v2 default timeout units (60 -> 60000) Sasha Levin
@ 2026-10-19 13:53 ` Sasha Levin
2026-10-19 13:53 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: fix SMB2 byte-range lock end offset Sasha Levin
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:53 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 56549c18a4f75309161ca780feaa4d17904e3ee9 ]
A client that disappears without sending a FIN or RST can leave its
ksmbd connection in ESTABLISHED indefinitely. ksmbd sets a socket
receive timeout, but the connection receive loop retries timeout errors
without a limit, so the connection remains in conn_list and consumes the
per-IP connection quota.
Enable SO_KEEPALIVE on accepted TCP sockets so the TCP stack can detect a
silent peer failure. The keepalive idle time, interval, and probe count
remain controlled by the existing TCP sysctl settings.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.12.111** (`pending-6.12`). The buggy
accept/receive path is present, and this is a small, real connection-
leak fix that belongs here.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1: PARSE THE SUBJECT LINE**
Record: **[ksmbd]** **[enable]** Enable TCP keepalive on accepted ksmbd
sockets so a silent peer does not leave the connection ESTABLISHED
forever.
**Step 1.2: PARSE ALL COMMIT MESSAGE TAGS**
Record:
- **Signed-off-by:** Namjae Jeon `<linkinjeon@kernel.org>` (ksmbd
maintainer)
- No **Fixes:**, **Reported-by:**, **Tested-by:**, **Reviewed-by:**,
**Acked-by:**, **Link:**, or **Cc: stable** on this commit (absence
expected for this review)
- Companion later commit `80b6367ec37f` has `Link:
https://github.com/openwrt/openwrt/issues/24744` (different bug: FIN-
WAIT-1 orphans)
**Step 1.3: ANALYZE THE COMMIT BODY TEXT**
Record:
- **Bug:** Client vanishes without FIN/RST; ksmbd connection stays
ESTABLISHED.
- **Mechanism:** `sk_rcvtimeo` is set, but the receive loop retries
timeout/`-EAGAIN` with no limit, so the conn stays in `conn_list` and
consumes the per-IP quota.
- **Fix:** `sock_set_keepalive()` on the accepted socket;
idle/interval/probes stay on existing TCP sysctls.
- **Symptom:** leaked kthreads/sockets and eventual refusal of new
clients from that IP.
- **Version info:** none in the message. Code path has been in-tree
since the 2023 unlimited-retry change.
**Step 1.4: DETECT HIDDEN BUG FIXES**
Record: Not disguised. It is explicitly a leak/stuck-connection fix that
uses an existing socket option. Not a new userspace API.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1: INVENTORY THE CHANGES**
Record:
- File: `fs/smb/server/transport_tcp.c` (**+6 / -0**)
- Function: `ksmbd_kthread_fn()` (accept path)
- Scope: single-file surgical fix (one call + comment)
**Step 2.2: UNDERSTAND THE CODE FLOW CHANGE**
Record:
- **Before:** After accept, set `sk_rcvtimeo` / `sk_sndtimeo`, then
`ksmbd_tcp_new_connection()`.
- **After:** Same, plus `sock_set_keepalive(client_sk->sk)` so TCP
probes a silent peer.
- Path: normal accept of a new SMB TCP connection.
**Step 2.3: IDENTIFY THE BUG MECHANISM**
Record:
- **Category:** resource leak / stuck connection (logic/correctness),
mitigated by a standard TCP keepalive workaround.
- **Broken behavior:** `ksmbd_conn_handler_loop()` reads the RFC1002
header with `max_retries = -1`. `ksmbd_tcp_readv()` treats negative
`max_retries` as unlimited `-EAGAIN` retries. `KSMBD_TCP_RECV_TIMEOUT`
is `7 * HZ`, so a dead peer yields `-EAGAIN` forever.
- `ksmbd_conn_alive()` only drops idle conns when `deadtime > 0` **and**
`open_files_count == 0`. A crashed client with open files stays alive
forever.
- **Fix:** `sock_set_keepalive()` → `tcp_set_keepalive()` → keepalive
timer. Failed probes produce RST/`tcp_write_err()`, `kernel_recvmsg()`
returns 0/error, handler exits, conn leaves `conn_list`.
**Step 2.4: ASSESS THE FIX QUALITY**
Record:
- Obviously correct: same helper NFS/RPC and RDS already use
(`sock_set_keepalive` since 2020).
- Minimal; comment-only extra.
- Regression risk **low**: default keepalive is 2 hours + 9 probes ×
75s. Healthy SMB clients send traffic/echoes. No new sysctl/API. Does
not change the unlimited-retry policy for truly idle-but-alive
sessions.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1: BLAME THE CHANGED LINES**
Record:
- Timeout assignment: present since original cifsd/ksmbd
(`0626e6641f6b`, 2021).
- Unlimited retry: **`be6f42fad5f5fd`** “ksmbd: don't terminate inactive
sessions after a few seconds” (**v6.3-rc4**, 2023-03-22). That commit
is in this tree and was itself `Cc: stable`. Keepalive was never added
then.
**Step 3.2: FOLLOW THE FIXES: TAG**
Record: No Fixes: tag. Conceptual introducer is `be6f42fad5f5fd`,
present here.
**Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES**
Record:
- Recent `transport_tcp.c` work: per-IP limits, `sock_create_kern`,
`active_num_conn` leaks.
- Same-day companion: **`80b6367ec37f`** “keep TCP timers alive for
kernel sockets” (`sk_net_refcnt_upgrade` on the **listen** socket).
That is a **different** bug (FIN-WAIT-1 orphans after `tcp_close()`
clears timers on kernel sockets). Not required for keepalive on a
still-held ESTABLISHED socket.
- Standalone for the ESTABLISHED leak.
**Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS**
Record: Namjae Jeon is the ksmbd maintainer; many recent ksmbd fixes in
this tree.
**Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS**
Record:
- Needs `sock_set_keepalive()` — in this tree (`ce3d9544cecac`, 2020),
`EXPORT_SYMBOL`.
- `connection.h` already includes `<net/sock.h>`.
- Companion `sk_net_refcnt_upgrade` is **not** a prerequisite for this
ESTABLISHED-path fix.
- Can apply standalone.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION**
Record:
- Upstream SHA: **`56549c18a4f75309161ca780feaa4d17904e3ee9`**
- Lore:
https://patch.msgid.link/20260820135420.5634-1-linkinjeon@kernel.org
- Submitted 2026-08-20 as `[PATCH]` (with the timer patch as `-2`);
merged in ksmbd 7.3-rc1 pull (“Improve TCP connection reliability…”)
- `b4 dig -a`: v1 keepalive + v2 timer companion, same day. No later
unapplied revision.
- Mbox: author-only; no NAK, no extra review comments (maintainer tree).
- WebFetch of lore URLs returned 403; thread recovered via `b4`.
**Step 4.2: CHECK WHO REVIEWED THE PATCH**
Record (`b4 dig -w`): linux-cifs@vger.kernel.org, Sergey Senozhatsky,
Tom Talpey, Atte Heikkilä, ChenXiaoSong. No NAK found.
**Step 4.3: SEARCH FOR THE BUG REPORT**
Record:
- Direct Reported-by: none on this commit.
- Real-world match: [cifsd-team/ksmbd#627](https://github.com/cifsd-
team/ksmbd/issues/627) — Windows 11, stale ESTABLISHED sockets,
connection limit exhausted (default ~32), only restart helps. Kernel
6.19.9 in that report; **same receive-loop logic is in 6.12**.
- Related: namjaejeon/ksmbd#517 (ESTABLISHED after client power-off;
`deadtime = 10` did not help — consistent with open files skipping
deadtime).
**Step 4.4: CHECK FOR RELATED PATCHES AND SERIES**
Record: Two-patch reliability pair. Patch 1 = this (keepalive). Patch 2
= listen-socket netns upgrade for post-close timers. This patch is
useful alone.
**Step 4.5: CHECK STABLE MAILING LIST HISTORY**
Record: lore.kernel.org/stable search 403. No evidence this was already
rejected for 6.12. Not in this tree (`git merge-base --is-ancestor
56549c18… HEAD` failed).
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1: IDENTIFY KEY FUNCTIONS**
Record: modified `ksmbd_kthread_fn`; callees `sock_set_keepalive` /
`tcp_set_keepalive`; related `ksmbd_tcp_readv`,
`ksmbd_conn_handler_loop`, `ksmbd_conn_alive`.
**Step 5.2: TRACE CALLERS**
Record:
- `ksmbd_kthread_fn` ← `kthread_run` in `ksmbd_tcp_run_kthread` (listen
on 445).
- Header read: `ksmbd_conn_handler_loop` → `t->ops->read(..., -1)` →
`ksmbd_tcp_read` → `ksmbd_tcp_readv`.
- Process context, one kthread per connection. Userspace-reachable: any
SMB client connect.
**Step 5.3: TRACE CALLEES**
Record: `sock_set_keepalive` locks the sock, calls
`sk->sk_prot->keepalive(sk, true)` (`tcp_set_keepalive` for TCP), sets
`SOCK_KEEPOPEN`. `tcp_set_keepalive` arms
`inet_csk_reset_keepalive_timer`. Failed probes: `tcp_send_active_reset`
+ `tcp_write_err`.
**Step 5.4: FOLLOW THE CALL CHAIN**
Record: SMB connect to 445 → accept → keepalive enabled → handler recv
loop. Unprivileged network clients can leave zombie conns (especially
after crash/VPN drop). **Reachable.**
**Step 5.5: SEARCH FOR SIMILAR PATTERNS**
Record: `net/sunrpc/xprtsock.c` and `net/rds/tcp_listen.c` already call
`sock_set_keepalive`. ksmbd was the outlier.
---
## PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
**Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?**
Record: **Yes.**
- Tree: **pending-6.12 / 6.12.111** (`p-6.12-3-gc504cf0baa3d8`)
- Accept path at `ksmbd_kthread_fn` (~L325–329): timeouts set, **no**
keepalive.
- Unlimited retry in `ksmbd_tcp_readv` (L409–423) and `max_retries = -1`
(connection.c L444).
- Introduced v6.3 (`be6f42fad5f5fd`); present for the whole 6.12
lifetime.
- Keepalive commit is **not** an ancestor of HEAD.
**Step 6.2: CHECK FOR BACKPORT COMPLICATIONS**
Record: **Clean apply.** Insertion point matches this file exactly
(`sk_sndtimeo` then `ksmbd_tcp_new_connection`). `sock_set_keepalive`
already exported.
**Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE**
Record: No keepalive on ksmbd sockets. `deadtime` is optional userspace
config and skipped when files are open. Not a substitute.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY**
Record: **fs/smb/server (ksmbd)**. **IMPORTANT** (in-kernel SMB3 server:
NAS, OpenWrt, appliances). Not core mm/VFS, but production file service.
**Step 7.2: ASSESS SUBSYSTEM ACTIVITY**
Record: Active (connection-limit, sock_create_kern, leak fixes). Mature
enough that this long-standing hole matters.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1: DETERMINE WHO IS AFFECTED**
Record: **Driver/config-specific:** `CONFIG_SMB_SERVER`. Typical stable
users: NAS, routers, embedded SMB.
**Step 8.2: DETERMINE THE TRIGGER CONDITIONS**
Record:
- Trigger: client crash, sleep, VPN drop, power-off without FIN/RST.
- Common on laptops/Wi‑Fi/VPN.
- Unprivileged remote clients can fill the per-IP quota
(`max_ip_connections` is in this tree).
- Timing: default first probe after **2 hours**, then ~11 minutes of
probes. Slow but **finite**, vs never.
**Step 8.3: DETERMINE THE FAILURE MODE SEVERITY**
Record:
- Failure: kthread + socket + `conn_list` entry leak; per-IP/global
connection quota exhaustion; new mounts fail until ksmbd restart.
- **Severity: HIGH** (service outage / resource leak). Not a panic, but
a real production hang of the SMB service.
**Step 8.4: CALCULATE RISK-BENEFIT RATIO**
Record:
- **Benefit: HIGH** for ksmbd users (closes zombies, restores quota).
- **Risk: VERY LOW** (6 lines, existing helper, sysctl-controlled,
conservative defaults).
- Ratio strongly favors backport.
---
## PHASE 9: FINAL SYNTHESIS
**Step 9.1: COMPILE THE EVIDENCE**
**FOR:**
- Real stuck-connection / quota DoS, not style.
- Unlimited `-EAGAIN` retry (`be6f42fad5f5fd`, in this tree, previously
sent to stable) without keepalive is the hole.
- `deadtime` does not cover open-file + silent peer.
- User reports of ESTABLISHED pile-up (#627).
- 6-line, obviously correct, existing API.
- Applies cleanly to 6.12.111.
- Maintainer-authored; same pattern as sunrpc/RDS.
**AGAINST:**
- Looks like “enable a feature,” but it only turns on SO_KEEPALIVE.
- Default 2-hour idle before probes (slow, still a fix).
- No Fixes:/Cc: stable on this commit (not a negative per review rules).
- Companion timer patch is separate (do not block this on it).
**UNRESOLVED:**
- lore.kernel.org HTTP 403 (thread recovered via b4).
- No on-list Reviewed-by (maintainer submission).
**Step 9.2: APPLY THE STABLE RULES CHECKLIST**
1. Obviously correct and tested? **PASS** — one well-known helper; in
mainline 7.3.
2. Fixes a real bug that affects users? **PASS** — leaked ESTABLISHED
conns / quota; #627.
3. Important issue? **PASS** — service DoS / resource leak on a file
server (HIGH).
4. Small and contained? **PASS** — +6 lines, one function.
5. No new features or APIs? **PASS** — existing SO_KEEPALIVE / sysctls
only.
6. Can apply to the local tree? **PASS** — code and helper exist; clean
insert.
**Step 9.3: CHECK FOR EXCEPTION CATEGORIES**
Record: Not a device-ID/DT/build/docs exception. Fits “hardware/protocol
workaround”: enable kernel TCP keepalive so dead peers are detected.
**Step 9.4: MAKE YOUR DECISION**
This tree has the unlimited recv-timeout retry and no keepalive. The
patch is the missing counterpart to the 2023 stable change that stopped
tearing down idle sessions. Benefit is real for ksmbd; risk is
negligible.
---
### What it solves for stable users
A client that disappears without FIN/RST leaves ksmbd in ESTABLISHED:
the handler retries receive timeouts forever, holding a kthread and a
`conn_list` slot (and the per-IP quota). That matches field reports of
Windows clients filling the connection limit until ksmbd is restarted.
Keepalive lets TCP fail the socket so the handler can tear the conn
down.
### Risk vs benefit
Benefit: prevents unbounded connection growth and SMB accept failures.
Risk: one `sock_set_keepalive()` with default 2-hour keepalive — will
not drop healthy sessions on a short idle.
### Concerns
None that block 6.12. The later `sk_net_refcnt_upgrade` patch is a
separate FIN-WAIT-1 orphan fix, not required for this ESTABLISHED-path
change.
---
### Verification
- **[Phase 1]** Parsed message: enable keepalive; SOB Namjae Jeon; no
Fixes/Reported-by.
- **[Phase 2]** Diff: +6 in `ksmbd_kthread_fn`;
`sock_set_keepalive(client_sk->sk)` after timeouts.
- **[Phase 2]** Confirmed `ksmbd_tcp_readv` unlimited retry when
`max_retries < 0`; handler uses `-1` for header read.
- **[Phase 2]** Confirmed `ksmbd_conn_alive()` returns true if
`open_files_count > 0`, ignoring deadtime.
- **[Phase 2]** Confirmed `sock_set_keepalive` → `tcp_set_keepalive`
(`net/core/sock.c`, `net/ipv4/tcp_timer.c`).
- **[Phase 3]** `git describe HEAD` / `make kernelversion`: **p-6.12-3 /
6.12.111**.
- **[Phase 3]** Blame: unlimited retry from `be6f42fad5f5fd` (v6.3);
`git merge-base --is-ancestor be6f42fad5f5f HEAD` succeeded.
- **[Phase 3]** `git merge-base --is-ancestor
56549c18a4f75309161ca780feaa4d17904e3ee9 HEAD` failed (not in this
tree).
- **[Phase 3]** `sock_set_keepalive` introduced `ce3d9544cecac` (2020);
present here.
- **[Phase 4]** `b4 dig -c 56549c18…`: lore `20260820135420.5634-1`;
series with timer patch `-2`.
- **[Phase 4]** `b4 dig -w`: linux-cifs, Senozhatsky, Talpey, et al.
- **[Phase 4]** `b4 dig -a`: v1 keepalive + companion timer patch; no
later unapplied rev.
- **[Phase 4]** GitHub ksmbd#627: stale ESTABLISHED / quota exhaustion.
- **[Phase 4]** Companion `80b6367ec37f`: listen-socket
`sk_net_refcnt_upgrade` for post-close timers — different bug.
- **[Phase 5]** Call chain: accept kthread → `ksmbd_tcp_new_connection`
→ `ksmbd_conn_handler_loop` → unlimited `read(..., -1)`.
- **[Phase 5]** Same helper in sunrpc/RDS.
- **[Phase 6]** Local accept path L325–329 has no keepalive; context
matches the patch.
- **[Phase 6]** `connection.h` includes `<net/sock.h>`.
- **[Phase 8]** Defaults: `TCP_KEEPALIVE_TIME` 2h, `PROBES` 9, `INTVL`
75s (`include/net/tcp.h`).
- **UNVERIFIED:** HTTP fetch of lore.kernel.org (403); recovered via b4.
Whether every distro sets `deadtime` (irrelevant: deadtime skipped
with open files).
**YES**
fs/smb/server/transport_tcp.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c
index 472d387098767..ede54bb049532 100644
--- a/fs/smb/server/transport_tcp.c
+++ b/fs/smb/server/transport_tcp.c
@@ -312,6 +312,12 @@ static int ksmbd_kthread_fn(void *p)
ksmbd_debug(CONN, "connect success: accepted new connection\n");
client_sk->sk->sk_rcvtimeo = KSMBD_TCP_RECV_TIMEOUT;
client_sk->sk->sk_sndtimeo = KSMBD_TCP_SEND_TIMEOUT;
+ /*
+ * Detect peers that disappear without sending a FIN or RST.
+ * Otherwise the connection handler can retry receive timeouts
+ * indefinitely and keep the connection in conn_list.
+ */
+ sock_set_keepalive(client_sk->sk);
ksmbd_tcp_new_connection(client_sk);
}
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: fix SMB2 byte-range lock end offset
[not found] <20261019135441.1420968-1-sashal@kernel.org>
` (21 preceding siblings ...)
2026-10-19 13:53 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: enable TCP keepalive for accepted connections Sasha Levin
@ 2026-10-19 13:53 ` Sasha Levin
22 siblings, 0 replies; 23+ messages in thread
From: Sasha Levin @ 2026-10-19 13:53 UTC (permalink / raw)
To: patches, stable; +Cc: Namjae Jeon, Sasha Levin, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 54d90311f9b4eb23f3b0b62650b0cfddb11a12ef ]
SMB2 describes a byte-range lock using an offset and a length, while
Linux file_lock uses an inclusive end offset. smb2_lock() currently sets
fl_end to start + length and consequently locks one extra byte for every
nonzero-length request.
Translate nonzero lengths to start + length - 1 and reject ranges that
cannot be represented by loff_t instead of silently truncating them at
OFFSET_MAX. Track zero-length locks from the request length so one-byte
ranges are not mistaken for zero-length locks after endpoint conversion.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The local tree is **6.12.111** (`pending-6.12`). The candidate is
mainline `54d90311f9b4e` (`ksmbd: fix SMB2 byte-range lock end offset`).
It is not in this checkout, and the buggy `smb2_lock()` conversion is.
===============================================================
PHASE 1: COMMIT MESSAGE FORENSICS
===============================================================
Step 1.1: PARSE THE SUBJECT LINE
Record: [ksmbd] [fix] [SMB2 byte-range lock end offset is off by one vs
Linux file_lock inclusive ends]
Step 1.2: PARSE ALL COMMIT MESSAGE TAGS
Record:
- Signed-off-by: Namjae Jeon \<linkinjeon@kernel.org\> (ksmbd
maintainer)
- No Fixes:
- No Reported-by / Tested-by / Reviewed-by / Acked-by
- No Link:
- No Cc: stable
Absence of Fixes/Cc:stable is expected for this review pipeline and is
not a negative signal.
Step 1.3: ANALYZE THE COMMIT BODY TEXT
Record:
- Bug: SMB2 describes a lock as (offset, length). Linux `file_lock` uses
an inclusive `fl_end`. `smb2_lock()` sets `fl_end = start + length`,
so every nonzero-length lock covers one extra byte.
- Symptom: adjacent-byte I/O or locks can hit a false conflict;
unlock/lock ranges disagree with Windows/Samba; huge ranges are
silently truncated at `OFFSET_MAX` instead of being rejected.
- Root cause: missing `length - 1` conversion, plus `start == end` used
as a zero-length detector (that becomes wrong once 1-byte locks
correctly get `start == end`).
- No kernel version called out in the message. Pull text for 7.3-rc1
lists this among protocol-compatibility lock fixes.
Step 1.4: DETECT HIDDEN BUG FIXES
Record: Not disguised. It is an explicit off-by-one / range-translation
bug fix, plus a necessary zero-length tracking correction so the
conversion does not reclassify 1-byte locks as empty.
===============================================================
PHASE 2: DIFF ANALYSIS - LINE BY LINE
===============================================================
Step 2.1: INVENTORY THE CHANGES
Record:
- File: `fs/smb/server/smb2pdu.c` only (+14 / -30)
- Functions: `smb2_lock_init()`, `smb2_lock()`
- Scope: single-file surgical fix
Step 2.2: UNDERSTAND THE CODE FLOW CHANGE
Record:
1. `smb2_lock_init()`: stop inferring `zero_len` from `start == end`;
take it from the SMB2 request length (`!lock_length`).
2. Range setup in `smb2_lock()`:
- Before: clamp start/length to `OFFSET_MAX`, set `fl_end = start +
length`, then reject wrap with `fl_end < fl_start`.
- After: reject if start or inclusive end cannot be represented in
`loff_t`; set `fl_end = start + length - 1` (or `start` if length
is 0).
3. Zero-byte conflict tests: `< end` → `<= end` so the last locked byte
is included.
4. Non-zero overlap test: ad-hoc half-open checks → standard inclusive
overlap (`start1 <= end2 && start2 <= end1`), matching VFS
`locks_overlap()`.
Step 2.3: IDENTIFY THE BUG MECHANISM
Record: [Logic / correctness, plus bounds]
- Off-by-one: POSIX `fl_end` is inclusive (`fs/locks.c` uses `fl_end =
fl_start + (l_len - 1)`).
- Classification: after that conversion, a 1-byte lock has `start ==
end`. Using that as `zero_len` would skip `vfs_lock_file()` (`if
(smb_lock->zero_len) goto skip`).
- Overflow: old code silently truncated at `OFFSET_MAX`; new code
returns `STATUS_INVALID_LOCK_RANGE`.
- Conflict checks: old comparisons assumed exclusive-ish ends and missed
some inclusive overlaps.
Step 2.4: ASSESS THE FIX QUALITY
Record: Obviously correct. Same conversion as VFS
`flock_to_posix_lock()` and the CIFS client (`fl_end = start + (length ?
length - 1 : 0)`). Overlap test matches `locks_overlap()`. Minimal, no
API change. Regression risk is low: adjacent-byte I/O that was wrongly
denied will now succeed; unrepresentable ranges that were clamped will
now fail, which matches the spec.
===============================================================
PHASE 3: GIT HISTORY INVESTIGATION
===============================================================
Step 3.1: BLAME THE CHANGED LINES
Record:
- Core `fl_end = fl_start + lock_length` comes from `e2f34481b24db2`
(“cifsd: add server-side procedures for SMB3”, 2021-05-10), first in
v5.15-rc1.
- `OFFSET_MAX` clamping: `50bf80a553ccb5` (“cifsd: fix xfstests
generic/504 test failure”).
- `zero_len` / conflict checks: `d63528eb0d43c4` (Hyunchul Lee,
2021-07-10).
The bug has been in ksmbd since the server was merged.
Step 3.2: FOLLOW THE FIXES: TAG
Record: No Fixes: tag. The introducing commit is in this tree (`git
merge-base --is-ancestor e2f34481b24db2 HEAD` succeeded).
Step 3.3: CHECK FILE HISTORY FOR RELATED CHANGES
Record:
- Already in this tree: `f751d6e39d4c9` “ksmbd: Do not skip lock checks
for single-byte ranges” — `check_lock_range()` uses inclusive `start +
length - 1`. That makes the remaining `smb2_lock()` off-by-one more
inconsistent, not less.
- Later on fs-next, not required here: `5ce5227cd60b7` “recognize
replayed SMB2 lock sequences” (replay feature, not a prerequisite).
Standalone.
Step 3.4: CHECK THE AUTHOR'S OTHER COMMITS
Record: Namjae Jeon is the ksmbd maintainer (MAINTAINERS + Git). This is
not a drive-by change.
Step 3.5: CHECK FOR DEPENDENT/PREREQUISITE COMMITS
Record: No new helpers. `smb2_lock_init()` has a single caller. `git
apply --check` of `54d90311f9b4e` succeeds on this tree (hunk offsets
only). Standalone.
===============================================================
PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
===============================================================
Step 4.1: FIND THE ORIGINAL PATCH DISCUSSION
Record:
- `b4 dig -c 54d90311f9b4e` (with and without `-C`/`-a`):
lore.kernel.org returned errors; no thread URL.
- WebFetch of lore.kernel.org: HTTP 403.
- LKML `[GIT PULL] ksmbd server update for 7.3-rc1` lists this commit in
Namjae’s 7.3-rc1 pull, among lock/protocol-compatibility fixes.
UNVERIFIED: individual review comments, v2/v3 revisions, reviewer
Cc:stable.
Step 4.2: CHECK WHO REVIEWED THE PATCH
Record: Only the maintainer SOB is on the commit. `b4 dig -w` failed.
Subsystem maintainer authored it.
Step 4.3: SEARCH FOR THE BUG REPORT
Record: No Reported-by on this commit. Older ksmbd-tools issue #68 shows
real users hitting `smb2_lock` “end offset(ffffffffffffffff) is smaller
than the start offset” — the overflow path this patch now rejects
instead of wrapping. That report is historical (cifsd era), not a direct
report of this patch.
Step 4.4: CHECK FOR RELATED PATCHES AND SERIES
Record: Adjacent 7.3 lock patches are replay/UAF/compound features. This
conversion fix does not depend on them. Related inclusive-range I/O fix
is already in this tree.
Step 4.5: CHECK STABLE MAILING LIST HISTORY
Record: lore.kernel.org/stable search could not be fetched (403). No
verified stable NAK. This tree does not already contain “lock end
offset”.
===============================================================
PHASE 5: CODE SEMANTIC ANALYSIS
===============================================================
Step 5.1: IDENTIFY KEY FUNCTIONS IN THE DIFF
Record: `smb2_lock_init()`, `smb2_lock()`
Step 5.2: TRACE CALLERS
Record:
- `smb2_lock()` is the SMB2_LOCK handler
(`smb2_0_server_cmds[SMB2_LOCK_HE]` in `fs/smb/server/smb2ops.c`).
- `smb2_lock_init()` is only called from `smb2_lock()`.
Reachable from any SMB2/SMB3 client that issues LOCK.
Step 5.3: TRACE CALLEES
Record: `vfs_lock_file()`, `locks_free_lock()`, `smb_flock_init()`,
ksmbd connection lock-list walk. Zero-length locks still skip
`vfs_lock_file()` by design (POSIX `l_len == 0` means lock-to-EOF, which
is not SMB zero-byte lock semantics).
Step 5.4: FOLLOW THE CALL CHAIN
Record: Network SMB2 LOCK → `smb2_lock()` → VFS POSIX locks / ksmbd lock
list → later `check_lock_range()` on read/write/truncate. Userspace-
reachable over the network. Not a rare config path if
`CONFIG_SMB_SERVER` is enabled.
Step 5.5: SEARCH FOR SIMILAR PATTERNS
Record: Same inclusive conversion already exists in `fs/locks.c` and
`fs/smb/client/cifssmb.c`. I/O-side `check_lock_range()` in this tree
already uses `pos + count - 1`. Only the LOCK request path was still off
by one.
===============================================================
PHASE 6: CROSS-REFERENCING AGAINST THE LOCAL TREE
===============================================================
Step 6.1: DOES THE BUGGY CODE EXIST IN THIS TREE?
Record: Yes. `fs/smb/server/smb2pdu.c` around 7584–7602 still does
`fl_end = fl_start + lock_length` and `if (lock->start == lock->end)
lock->zero_len = 1`. Introduced with cifsd in v5.15, present in
6.12.111.
`git merge-base --is-ancestor 54d90311f9b4e HEAD` failed — the fix is
not here.
Step 6.2: CHECK FOR BACKPORT COMPLICATIONS
Record: Clean apply (`git apply --check` succeeded; hunks at 7488+).
Nearby mainline-only context (`lock_count > 64`, `kzalloc_obj`) is not
part of this commit’s hunks. Expected difficulty: clean apply.
Step 6.3: CHECK IF RELATED FIXES ARE ALREADY HERE
Record: Inclusive I/O lock checks (`f751d6e39d4c9`) are here. No prior
“lock end offset” fix. Applying this makes LOCK and I/O use the same
inclusive model.
===============================================================
PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
===============================================================
Step 7.1: IDENTIFY THE SUBSYSTEM AND ITS CRITICALITY
Record: [fs/smb/server (ksmbd)] [IMPORTANT for ksmbd users / PERIPHERAL
vs core VFS]. Byte-range locks are a core SMB feature for Windows apps,
databases, and exclusive file access. `CONFIG_SMB_SERVER` defaults to n.
Step 7.2: ASSESS SUBSYSTEM ACTIVITY
Record: Actively maintained; this 6.12 tree already carries many ksmbd
stable backports. The author is the maintainer.
===============================================================
PHASE 8: IMPACT AND RISK ASSESSMENT
===============================================================
Step 8.1: DETERMINE WHO IS AFFECTED
Record: ksmbd/SMB3 server users (`CONFIG_SMB_SERVER`). Every SMB2 LOCK
with nonzero length.
Step 8.2: DETERMINE THE TRIGGER CONDITIONS
Record: Common for any client using byte-range locks (Office, databases,
installers, some build tools). Network-facing; an unprivileged SMB user
who can open a file can issue LOCK. Not a rare race.
Step 8.3: DETERMINE THE FAILURE MODE SEVERITY
Record:
- Over-lock of one extra byte → false `STATUS_FILE_LOCK_CONFLICT` /
denied I/O on the adjacent byte; apps can fail or block. HIGH for
ksmbd shares that use locking.
- Silent clamp of huge ranges → requested bytes past `OFFSET_MAX` stay
unlocked. Integrity hole, rare offsets. MEDIUM.
- If this conversion were done without passing original `zero_len`,
1-byte locks would skip VFS — that would be under-lock / data-race.
The patch prevents that. HIGH if mishandled; the patch handles it.
Severity overall: HIGH for locking correctness, not a kernel oops.
Step 8.4: CALCULATE RISK-BENEFIT RATIO
Record:
- Benefit: correct exclusive ranges vs Windows/Samba/VFS; fewer false
conflicts; no silent truncation.
- Risk: very low (14/30 lines, one file, applies cleanly, matches
established conversion).
- Ratio: strongly favors backporting.
===============================================================
PHASE 9: FINAL SYNTHESIS
===============================================================
Step 9.1: COMPILE THE EVIDENCE
FOR:
- Real, long-standing off-by-one in mandatory SMB byte-range locks
(since v5.15).
- User-visible false conflicts on the extra byte; protocol mismatch with
Windows/Samba.
- Silent `OFFSET_MAX` truncation replaced by a spec-style invalid-range
error.
- Zero-length vs 1-byte classification fixed so inclusive ends do not
skip `vfs_lock_file()`.
- Overlap tests aligned with VFS `locks_overlap()`.
- Small, maintainer-authored, applies cleanly here.
- This tree already uses inclusive ends on the I/O path, so leaving LOCK
wrong is inconsistent.
AGAINST:
- No crash/UAF/CVE; no Reported-by on this commit.
- ksmbd is opt-in, not core VFS.
- Could not retrieve the original review thread (lore errors).
UNRESOLVED:
- Original mailing-list review comments / explicit stable nomination.
Step 9.2: APPLY THE STABLE RULES CHECKLIST
1. Obviously correct and tested? PASS — matches VFS and CIFS client
math; maintainer SOB; in the 7.3-rc1 ksmbd pull.
2. Fixes a real bug that affects users? PASS — wrong lock coverage on
every nonzero SMB2 LOCK.
3. Important issue? PASS — mandatory lock correctness (false conflicts;
possible under-lock on truncated huge ranges). Not a panic, but it is
data-access / sharing integrity.
4. Small and contained? PASS — one file, +14/-30.
5. No new features or APIs? PASS.
6. Can apply to the local tree? PASS — `git apply --check` clean; buggy
code present.
Step 9.3: CHECK FOR EXCEPTION CATEGORIES
Record: Not a device-ID/quirk/DT/build/docs exception. Ordinary
correctness fix.
Step 9.4: MAKE YOUR DECISION
This should be backported to this 6.12 tree. The extra locked byte is a
real protocol bug on a path every locking SMB client hits. The patch is
small, correct, has no prerequisites that this tree lacks, and applies
cleanly.
Verification:
- [Phase 1] Parsed subject/body/tags on `54d90311f9b4e`; maintainer SOB
only; no Fixes/Reported-by/Cc:stable.
- [Phase 2] Diff: `smb2_lock_init` + `smb2_lock` in
`fs/smb/server/smb2pdu.c`, +14/-30; inclusive `fl_end`, request-based
`zero_len`, overlap `<=`.
- [Phase 2] Confirmed VFS conversion at `fs/locks.c:515-518` (`fl_end =
fl_start + (l_len - 1)`) and `locks_overlap()` at 621-624.
- [Phase 2] Confirmed CIFS client uses the same formula at
`fs/smb/client/cifssmb.c:2122-2124`.
- [Phase 2] Confirmed zero-len locks skip `vfs_lock_file()` at
`smb2pdu.c:7742-7748` in this tree.
- [Phase 3] `git blame`: buggy `fl_end = start + length` from
`e2f34481b24db2` (v5.15-rc1); clamp from `50bf80a553ccb5`.
- [Phase 3] `git merge-base --is-ancestor e2f34481b24db2 HEAD`
succeeded; `54d90311f9b4e` is not an ancestor of HEAD.
- [Phase 3] Follow-up `5ce5227cd60b7` is lock-replay, not a
prerequisite.
- [Phase 4] `b4 dig -c 54d90311f9b4e` failed (lore errors). LKML 7.3-rc1
ksmbd pull lists this commit.
- [Phase 4] UNVERIFIED: original lore review thread (403/server error).
- [Phase 5] `smb2_lock` is `SMB2_LOCK_HE` proc; `smb2_lock_init` has one
caller.
- [Phase 6] `make kernelversion` / Makefile: 6.12.111, branch
`pending-6.12`, `git describe HEAD` = `p-6.12-3-gc504cf0baa3d8`.
- [Phase 6] Live code at `smb2pdu.c:7602` still uses `fl_start +
lock_length`.
- [Phase 6] `git show 54d90311f9b4e | git apply --check` succeeded.
- [Phase 6] Related `f751d6e39d4c9` (inclusive I/O checks) is already in
HEAD.
- [Phase 7] MAINTAINERS: ksmbd maintained by Namjae Jeon;
`CONFIG_SMB_SERVER` default n.
- [Phase 8] Failure mode: false lock conflicts / incorrect coverage on
SMB2 LOCK; severity HIGH for ksmbd locking users, not a kernel oops.
- UNVERIFIED: Could not read lore.kernel.org patch review or stable@
discussion.
The extra-byte lock is a real, old ksmbd protocol bug. The fix is small,
matches VFS, and applies cleanly to 6.12.111.
**YES**
fs/smb/server/smb2pdu.c | 44 +++++++++++++----------------------------
1 file changed, 14 insertions(+), 30 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 277c03fe2a4e4..ea5a130ef83ce 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -7604,7 +7604,7 @@ static int smb2_set_flock_flags(struct file_lock *flock, int flags)
}
static struct ksmbd_lock *smb2_lock_init(struct file_lock *flock,
- unsigned int cmd, int flags,
+ unsigned int cmd, int flags, bool zero_len,
struct list_head *lock_list)
{
struct ksmbd_lock *lock;
@@ -7618,8 +7618,7 @@ static struct ksmbd_lock *smb2_lock_init(struct file_lock *flock,
lock->start = flock->fl_start;
lock->end = flock->fl_end;
lock->flags = flags;
- if (lock->start == lock->end)
- lock->zero_len = 1;
+ lock->zero_len = zero_len;
INIT_LIST_HEAD(&lock->clist);
INIT_LIST_HEAD(&lock->flist);
INIT_LIST_HEAD(&lock->llist);
@@ -7712,32 +7711,18 @@ int smb2_lock(struct ksmbd_work *work)
lock_start = le64_to_cpu(lock_ele[i].Offset);
lock_length = le64_to_cpu(lock_ele[i].Length);
- if (lock_start > U64_MAX - lock_length) {
+ if (lock_start > OFFSET_MAX ||
+ (lock_length &&
+ lock_length - 1 > OFFSET_MAX - lock_start)) {
pr_err("Invalid lock range requested\n");
rsp->hdr.Status = STATUS_INVALID_LOCK_RANGE;
locks_free_lock(flock);
goto out;
}
- if (lock_start > OFFSET_MAX)
- flock->fl_start = OFFSET_MAX;
- else
- flock->fl_start = lock_start;
-
- lock_length = le64_to_cpu(lock_ele[i].Length);
- if (lock_length > OFFSET_MAX - flock->fl_start)
- lock_length = OFFSET_MAX - flock->fl_start;
-
- flock->fl_end = flock->fl_start + lock_length;
-
- if (flock->fl_end < flock->fl_start) {
- ksmbd_debug(SMB,
- "the end offset(%llx) is smaller than the start offset(%llx)\n",
- flock->fl_end, flock->fl_start);
- rsp->hdr.Status = STATUS_INVALID_LOCK_RANGE;
- locks_free_lock(flock);
- goto out;
- }
+ flock->fl_start = lock_start;
+ flock->fl_end = lock_length ?
+ flock->fl_start + lock_length - 1 : flock->fl_start;
/* Check conflict locks in one request */
list_for_each_entry(cmp_lock, &lock_list, llist) {
@@ -7753,7 +7738,8 @@ int smb2_lock(struct ksmbd_work *work)
}
}
- smb_lock = smb2_lock_init(flock, cmd, flags, &lock_list);
+ smb_lock = smb2_lock_init(flock, cmd, flags, !lock_length,
+ &lock_list);
if (!smb_lock) {
err = -EINVAL;
locks_free_lock(flock);
@@ -7827,7 +7813,7 @@ int smb2_lock(struct ksmbd_work *work)
/* check zero byte lock range */
if (cmp_lock->zero_len && !smb_lock->zero_len &&
cmp_lock->start > smb_lock->start &&
- cmp_lock->start < smb_lock->end) {
+ cmp_lock->start <= smb_lock->end) {
spin_unlock(&conn->llist_lock);
up_read(&conn_list_lock);
pr_err("previous lock conflict with zero byte lock range\n");
@@ -7836,17 +7822,15 @@ int smb2_lock(struct ksmbd_work *work)
if (smb_lock->zero_len && !cmp_lock->zero_len &&
smb_lock->start > cmp_lock->start &&
- smb_lock->start < cmp_lock->end) {
+ smb_lock->start <= cmp_lock->end) {
spin_unlock(&conn->llist_lock);
up_read(&conn_list_lock);
pr_err("current lock conflict with zero byte lock range\n");
goto out;
}
- if (((cmp_lock->start <= smb_lock->start &&
- cmp_lock->end > smb_lock->start) ||
- (cmp_lock->start < smb_lock->end &&
- cmp_lock->end >= smb_lock->end)) &&
+ if (cmp_lock->start <= smb_lock->end &&
+ smb_lock->start <= cmp_lock->end &&
!cmp_lock->zero_len && !smb_lock->zero_len) {
spin_unlock(&conn->llist_lock);
up_read(&conn_list_lock);
--
2.53.0
^ permalink raw reply related [flat|nested] 23+ messages in thread