* [PATCH AUTOSEL 6.18-6.6] ksmbd: preserve VFS inherited POSIX ACL mask
[not found] <20260831133314.4125787-1-sashal@kernel.org>
@ 2026-08-31 13:20 ` Sasha Levin
2026-08-31 13:20 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: fix outstanding credit leak on abort and error paths Sasha Levin
` (26 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:20 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Charles Vosburgh, Steve French, Sasha Levin,
smfrench, linux-cifs, linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit e148e567a9252643baa125cb65d7ae9c2c6cf68a ]
The VFS initializes a child's POSIX ACL from the parent's default ACL and
the requested creation mode. Do not mutate the parent ACL or overwrite the
child's VFS-computed access and default ACLs afterwards.
This preserves restrictive ACL_MASK entries and prevents SMB object creation
from widening effective permissions.
Reported-by: Charles Vosburgh <trilobyte777@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
### Step 1.1: Subject line
**Record:** `[ksmbd] [preserve] [Do not mutate parent ACL or overwrite
VFS-computed child POSIX ACLs on SMB create]`
### Step 1.2: Tags
**Record:**
- **Reported-by:** Charles Vosburgh `<trilobyte777@gmail.com>` — real
user report
- **Signed-off-by:** Namjae Jeon `<linkinjeon@kernel.org>` — author
- **Signed-off-by:** Steve French `<stfrench@microsoft.com>` — ksmbd
maintainer
- No Fixes:, Cc: stable, Link:, Tested-by, Reviewed-by, or Acked-by tags
- Notable: maintainer sign-off; user report; no syzbot
### Step 1.3: Body analysis
**Record:**
- **Bug:** After VFS creates a child inode, ksmbd re-applies the
parent's default ACL to the child and forces `ACL_MASK` to `0x07`
(full rwx), overwriting VFS-computed access/default ACLs.
- **Symptom:** SMB-created files/directories get wider effective
permissions than intended; restrictive `ACL_MASK` entries are lost.
- **Root cause:** Redundant post-create ACL handling that mutates the
parent ACL and overwrites correct VFS inheritance.
- **Version info:** None in the message.
### Step 1.4: Hidden bug fix?
**Record:** Yes. Although the subject says "preserve" rather than "fix",
this is a real permissions/security bug: ACL mask widening on SMB object
creation.
---
## Phase 2: Diff Analysis
### Step 2.1: Inventory
**Record:**
- **Files:** `fs/smb/server/vfs.c` only
- **Scope:** ~25 lines removed, 1 added (net -24 lines)
- **Function modified:** `ksmbd_vfs_inherit_posix_acl()`
- **Classification:** Single-file, surgical fix
### Step 2.2: Code flow change
**Record:**
- **Hunk 1 (function body):** Before: fetch parent default ACL → mutate
`ACL_MASK` to `0x07` → `set_posix_acl()` on child access ACL → for
directories, also set default ACL → return `rc`. After: fetch parent
default ACL → release → return `0`. VFS-computed ACLs from
`vfs_create()`/`vfs_mkdir()` are left intact.
- **Path affected:** Post-create ACL setup in SMB2 open/create (`created
== true`).
### Step 2.3: Bug mechanism
**Record:**
- **Category:** Logic/correctness + security (permission widening)
- **Mechanism:**
1. Filesystem `->create`/`->mkdir` (e.g. ext4 via `ext4_init_acl()` →
`posix_acl_create()`) already applies parent's default ACL with
correct `ACL_MASK` masking per creation mode.
2. `ksmbd_vfs_inherit_posix_acl()` then overwrote those ACLs.
3. `pace->e_perm = 0x07` forced mask to rwx, removing restrictive
masks.
4. `get_inode_acl()` can return a cached/shared ACL object; in-place
mutation may also corrupt the parent's cached default ACL.
### Step 2.4: Fix quality
**Record:** Obviously correct — trusts standard VFS ACL inheritance.
Minimal change. Preserves the parent-has-no-default-ACL check
(`-ENOENT`) used by caller fallback logic. Low regression risk; only
affects ksmbd create path when `CONFIG_FS_POSIX_ACL` is enabled.
---
## Phase 3: Git History Investigation
### Step 3.1: Blame
**Record:** In this tree (`6.18.44`), buggy lines in
`ksmbd_vfs_inherit_posix_acl()` blame to `5d324e5159d9e` (merge where
`vfs.c` entered this checkout's history). Mainline history shows the
`pace->e_perm = 0x07` pattern present since at least `25933573ef48`
(2023-05-30); function dates to ksmbd POSIX ACL work (~2021,
`67d1c432994c`).
### Step 3.2: Fixes: tag
**Record:** N/A — no Fixes: tag.
### Step 3.3: Related file history
**Record:** Recent `vfs.c` changes in this tree are unrelated (path
resolution, credentials). No duplicate fix found. Standalone commit
(mainline `e148e567a925`).
### Step 3.4: Author context
**Record:** Namjae Jeon is ksmbd maintainer. Steve French (co-
maintainer) signed off. Recent ksmbd stable-worthy fixes in this tree
include UAF, ACL validation, credential handling.
### Step 3.5: Dependencies
**Record:** No prerequisites. Self-contained. Function and caller exist
in this tree.
---
## Phase 4: Mailing List and External Research
### Step 4.1: Original discussion
**Record:** `b4 dig -c e148e567a925` matched patch-id to `https://lore.k
ernel.org/all/CAKYAXd-
4MuqT49GwTO2meR0Lt338vTygzTrQ%2B6xBNpVW7kE0Xg@mail.gmail.com/` but could
not fetch thread content (lore fetch failure). Mainline commit dated
2026-07-17, merged via `8e371eff3f72` (v7.2-rc4 smb3-server-fixes).
### Step 4.2: Reviewers
**Record:** `b4 dig -w` failed (same fetch issue). Steve French
maintainer sign-off verified via GitHub API.
### Step 4.3: Bug report
**Record:** Reported-by Charles Vosburgh — user-reported ACL permission
widening on SMB create. No public bugzilla/syzbot link.
### Step 4.4: Related patches
**Record:** No multi-patch series. Standalone fix.
### Step 4.5: Stable list
**Record:** Could not search stable@ list (lore inaccessible). No
evidence of prior stable rejection.
---
## Phase 5: Code Semantic Analysis
### Step 5.1: Key functions
**Record:** `ksmbd_vfs_inherit_posix_acl()` (modified); callers:
`smb2_open()` path in `smb2pdu.c`.
### Step 5.2: Callers
**Record:** Single caller at `smb2pdu.c:3376`, inside `if (created)`
after `smb2_creat()` → `ksmbd_vfs_create()`/`ksmbd_vfs_mkdir()` →
`vfs_create()`/`vfs_mkdir()`. Userspace-reachable via SMB2 CREATE.
### Step 5.3: Callees
**Record:** Before fix: `get_inode_acl()`, `set_posix_acl()`,
`posix_acl_release()`. After fix: `get_inode_acl()`,
`posix_acl_release()`.
### Step 5.4: Reachability
**Record:** SMB client CREATE on a share backed by a POSIX-ACL
filesystem (ext4, xfs, etc.) with parent default ACL containing
`ACL_MASK`. Unprivileged network user can trigger.
### Step 5.5: Similar patterns
**Record:** `ksmbd_vfs_set_init_posix_acl()` also sets
`acl_state.mask.allow = 0x07`, but only as fallback when inheritance
fails and SD buffer setup fails — separate intentional path. No other
`pace->e_perm = 0x07` in ksmbd.
---
## Phase 6: Cross-Reference Against Local Tree
### Step 6.1: Buggy code present?
**Record:** **Yes.** Local tree is **6.18.44** (`git describe`:
`v6.18.44-2-g1b9e1abadee04`). Buggy code at
`fs/smb/server/vfs.c:1967-2004` with `pace->e_perm = 0x07` and post-
create `set_posix_acl()` calls. Fix not yet applied.
### Step 6.2: Backport complications
**Record:** `patch -p1 --dry-run` of the mainline diff applies cleanly
to this tree (line offset differs from mainline but hunks match). Minor
offset only — no logic conflicts.
### Step 6.3: Related fixes already present?
**Record:** No. Grep found no "preserve VFS inherited POSIX ACL" commit
in this tree.
---
## Phase 7: Subsystem Context
### Step 7.1: Subsystem criticality
**Record:** `fs/smb/server` (ksmbd) — **IMPORTANT**. Network file
server; ACL bugs affect multi-user share security.
### Step 7.2: Activity
**Record:** Actively maintained in 6.18.y (recent ksmbd commits in this
tree).
---
## Phase 8: Impact and Risk Assessment
### Step 8.1: Who is affected
**Record:** ksmbd users (`CONFIG_SMB_SERVER`) exporting POSIX-ACL-
enabled filesystems with default ACLs using `ACL_MASK`. Not universal,
but real production deployments.
### Step 8.2: Trigger conditions
**Record:** SMB2 create of file/directory under parent with default
POSIX ACL containing `ACL_MASK`. Common on managed shares. Remote SMB
clients can trigger.
### Step 8.3: Failure mode severity
**Record:** Permission widening / ACL bypass — **HIGH** security impact
(unauthorized access via elevated effective permissions). Possible
parent ACL cache corruption from in-place mutation of cached ACL. Not a
crash, but serious correctness/security issue.
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** HIGH — restores intended ACL semantics, closes
permission-widening hole
- **Risk:** LOW — 24-line deletion, defers to proven VFS path
- **Ratio:** Strongly favors backport
---
## Phase 9: Final Synthesis
### Step 9.1: Evidence summary
**FOR backport:**
- Real user-reported ACL security bug
- Permission widening on SMB create (restrictive `ACL_MASK` ignored)
- VFS already handles ACL inheritance correctly (`posix_acl_create()` /
`ext4_init_acl()`)
- Small, surgical, maintainer-reviewed fix
- Bug present in this 6.18.44 tree
- Patch applies cleanly
- Long-standing bug (since ~2021)
**AGAINST backport:**
- Only affects ksmbd + POSIX ACL configurations (not all kernel users)
- No syzbot/CVE yet (severity still clear from code analysis)
**Unresolved:**
- Full lore review thread unavailable (fetch failed)
- No explicit stable@ nomination found
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — logic is clear; maintainer
sign-off; user tested/report
2. Fixes real bug affecting users? **PASS** — user report + verified
code path
3. Important issue? **PASS** — ACL permission widening (security)
4. Small and contained? **PASS** — one function, ~24 lines removed
5. No new features/APIs? **PASS** — removes incorrect behavior
6. Can apply to local tree? **PASS** — dry-run apply succeeds
### Step 9.3: Exception categories
**Record:** None (not device ID, quirk, DT, build, or docs). Standard
security/correctness bug fix.
### Step 9.4: Decision rationale
For **this 6.18.44 tree**, the buggy code is present and reachable. The
fix stops ksmbd from overwriting VFS-correct ACLs and forcing `ACL_MASK`
to full rwx. That is a clear, important security/correctness fix with
minimal risk. It meets all stable kernel criteria.
---
## Verification
- **[Phase 1]** `git describe HEAD` → v6.18.44; parsed commit message
tags
- **[Phase 2]** Read `fs/smb/server/vfs.c:1967-2004` — confirmed buggy
code matches diff "before" state
- **[Phase 2]** Read `fs/posix_acl.c:459-511` —
`posix_acl_create_masq()` correctly handles `ACL_MASK`
- **[Phase 2]** Read `fs/ext4/acl.c:278-303` — `ext4_init_acl()` calls
`posix_acl_create()` during inode creation
- **[Phase 3]** `git blame -L 1967,2005 fs/smb/server/vfs.c` — buggy
code present
- **[Phase 3]** GitHub API: mainline fix `e148e567a925` (2026-07-17);
bug present in `25933573ef48` (2023-05-30)
- **[Phase 3]** `git log --oneline -30 -- fs/smb/server/vfs.c` — no
duplicate fix
- **[Phase 4]** `b4 dig -c e148e567a925` — matched lore URL; thread
fetch failed
- **[Phase 4]** GitHub API — commit message and maintainer sign-off
confirmed
- **[Phase 5]** `grep ksmbd_vfs_inherit_posix_acl` — single caller at
`smb2pdu.c:3376`
- **[Phase 5]** Read `smb2pdu.c:2609-2644, 3268-3393` — create → inherit
ACL call chain verified
- **[Phase 5]** Read `posix_acl.c:189-193` — `get_inode_acl()` returns
potentially cached/shared ACL
- **[Phase 6]** `make kernelversion` → 6.18.44; buggy code confirmed
present; fix absent
- **[Phase 6]** `patch -p1 --dry-run` of mainline diff → applies cleanly
- **[Phase 6]** `diff` local vs mainline pre-fix function → identical
- **[Phase 8]** Assessed severity as ACL permission widening — HIGH
security impact
**YES**The background `git log --all` search was stopped — as expected,
it’s too slow on this repo. History was covered instead with targeted
`git log` (no `--all`) and the GitHub API.
**Verdict for this tree (6.18.44): YES**
`ksmbd_vfs_inherit_posix_acl()` in `fs/smb/server/vfs.c` overwrites VFS-
correct child ACLs and forces `ACL_MASK` to `0x07`, widening effective
permissions on SMB creates when the parent has a restrictive default
ACL. The fix is small, applies cleanly here, and restores correct POSIX
ACL inheritance.
fs/smb/server/vfs.c | 26 +-------------------------
1 file changed, 1 insertion(+), 25 deletions(-)
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index 6680638bb85b5..f129386a56c8f 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -1974,10 +1974,6 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
const struct path *path, struct inode *parent_inode)
{
struct posix_acl *acls;
- struct posix_acl_entry *pace;
- struct dentry *dentry = path->dentry;
- struct inode *inode = d_inode(dentry);
- int rc, i;
if (!IS_ENABLED(CONFIG_FS_POSIX_ACL))
return -EOPNOTSUPP;
@@ -1985,27 +1981,7 @@ int ksmbd_vfs_inherit_posix_acl(struct mnt_idmap *idmap,
acls = get_inode_acl(parent_inode, ACL_TYPE_DEFAULT);
if (IS_ERR_OR_NULL(acls))
return -ENOENT;
- pace = acls->a_entries;
-
- for (i = 0; i < acls->a_count; i++, pace++) {
- if (pace->e_tag == ACL_MASK) {
- pace->e_perm = 0x07;
- break;
- }
- }
-
- rc = set_posix_acl(idmap, dentry, ACL_TYPE_ACCESS, acls);
- if (rc < 0)
- ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_ACCESS) failed, rc : %d\n",
- rc);
- if (S_ISDIR(inode->i_mode)) {
- rc = set_posix_acl(idmap, dentry, ACL_TYPE_DEFAULT,
- acls);
- if (rc < 0)
- ksmbd_debug(SMB, "Set posix acl(ACL_TYPE_DEFAULT) failed, rc : %d\n",
- rc);
- }
posix_acl_release(acls);
- return rc;
+ return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.1] ksmbd: fix outstanding credit leak on abort and error paths
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:20 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: preserve VFS inherited POSIX ACL mask Sasha Levin
@ 2026-08-31 13:20 ` Sasha Levin
2026-08-31 13:21 ` [PATCH AUTOSEL 6.18-6.12] cifs: Fix support for creating SFU fifo Sasha Levin
` (25 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:20 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 4a0b7826615a01c47924334a2e8a9dbd84a598b2 ]
smb2_validate_credit_charge() adds the request's CreditCharge to
conn->outstanding_credits when an SMB2 PDU is received, and
smb2_set_rsp_credits() subtracts it again when the response is built.
However smb2_set_rsp_credits() only runs on the normal response path:
- __process_request() returning SERVER_HANDLER_ABORT (unimplemented
command, command index out of range, signature check failure, or a
handler that sets send_no_response such as a cancelled blocking
lock) breaks out of the processing loop before set_rsp_credits() is
called;
- smb2_set_rsp_credits() itself returns early with -EINVAL (total
credit overflow or insufficient credits) before the subtraction.
On all of these paths the charge added at receive time is never
returned, so conn->outstanding_credits only grows. Because a client can
repeatedly trigger them (e.g. by sending unimplemented commands or by
issuing and cancelling blocking locks), outstanding_credits eventually
reaches total_credits and smb2_validate_credit_charge() then rejects
every subsequent request, wedging the connection.
Record the charge that was added in work->credit_charge and release any
charge still pending at the single send. exit point of
__handle_ksmbd_work(), which all abort and error paths fall through to.
smb2_set_rsp_credits() clears work->credit_charge once it has returned
the charge so the response path is unchanged and the credit is never
released twice. Paths that never charged a credit (no multi-credit
support, validation failure) leave work->credit_charge at zero and are
unaffected.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
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] [fix] outstanding credit leak on abort and error
paths` — subsystem is ksmbd (SMB3 in-kernel server); action verb is
"fix"; claimed intent is repairing a credit accounting leak.
### Step 1.2: Parse All Commit Message Tags
**Record:** Tags present:
- `Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>` (author, ksmbd
maintainer)
- `Signed-off-by: Steve French <stfrench@microsoft.com>` (committer,
CIFS/ksmbd maintainer)
Notable absences (expected for manual review pipeline):
- No `Fixes:` tag
- No `Reported-by:` / `Tested-by:` / `Reviewed-by:` / `Cc:
stable@vger.kernel.org` / `Link:`
### Step 1.3: Analyze Commit Body
**Record:**
- **Bug:** `smb2_validate_credit_charge()` increments
`conn->outstanding_credits` at PDU receive time;
`smb2_set_rsp_credits()` is supposed to decrement it when building the
response, but is skipped on abort/error paths.
- **Symptom:** `outstanding_credits` monotonically grows; once it
reaches `total_credits`, all further requests are rejected — the SMB
connection is wedged.
- **Trigger:** Repeatable by clients sending unimplemented commands,
cancelling blocking locks (`send_no_response`), signature failures, or
hitting `-EINVAL` inside `smb2_set_rsp_credits()`.
- **Root cause:** No cleanup of the receive-time charge when the normal
response credit path is bypassed.
### Step 1.4: Detect Hidden Bug Fixes
**Record:** Not disguised — this is an explicit bug fix for a resource-
accounting leak with a documented denial-of-service failure mode.
---
## Phase 2: Diff Analysis
### Step 2.1: Inventory the Changes
**Record:**
| File | Changes | Functions touched |
|------|---------|-------------------|
| `fs/smb/server/ksmbd_work.h` | +7 lines | struct `ksmbd_work` |
| `fs/smb/server/server.c` | +14 lines | `__handle_ksmbd_work()` |
| `fs/smb/server/smb2misc.c` | +6 / -3 lines |
`smb2_validate_credit_charge()`, `ksmbd_smb2_check_message()` |
| `fs/smb/server/smb2pdu.c` | +1 line | `smb2_set_rsp_credits()` |
**Total:** 28 insertions, 3 deletions across 4 files. **Scope:** single-
subsystem, surgical fix.
### Step 2.2: Code Flow Change (per hunk)
**Hunk 1 (`ksmbd_work.h`):** Adds `credit_charge` field to track pending
receive-time charge.
**Hunk 2 (`smb2misc.c`):** When credit is successfully charged to
`outstanding_credits`, also records it in `work->credit_charge`.
**Hunk 3 (`smb2pdu.c`):** On normal response path, clears
`work->credit_charge` after decrementing `outstanding_credits` —
prevents double-release.
**Hunk 4 (`server.c`):** At the common `send:` exit of
`__handle_ksmbd_work()`, if `work->credit_charge` is still non-zero,
subtract it from `outstanding_credits` under `credits_lock`.
**Record:**
- **Before:** Charge at receive, release only if
`smb2_set_rsp_credits()` runs to completion.
- **After:** Charge at receive, release on normal path via
`smb2_set_rsp_credits()` OR on any exit via `send:` label.
- **Affected paths:** Abort (`SERVER_HANDLER_ABORT`),
`set_rsp_credits()` early `-EINVAL`, and any path that reaches `send:`
without clearing the charge.
### Step 2.3: Bug Mechanism
**Record:** **Category:** Resource leak (credit accounting) leading to
connection-level DoS.
**Mechanism verified in current tree:**
```214:215:fs/smb/server/server.c
if (rc == SERVER_HANDLER_ABORT)
break;
```
This `break` skips `set_rsp_credits()` at lines 221–229.
```337:352:fs/smb/server/smb2pdu.c
if (conn->total_credits > conn->vals->max_credits) {
hdr->CreditRequest = 0;
pr_err("Total credits overflow: %d\n",
conn->total_credits);
return -EINVAL;
}
// ...
conn->total_credits -= credit_charge;
conn->outstanding_credits -= credit_charge;
```
`-EINVAL` returns occur **before** the `outstanding_credits`
subtraction.
```349:361:fs/smb/server/smb2misc.c
spin_lock(&conn->credits_lock);
// ...
} else
conn->outstanding_credits += credit_charge;
```
Charge happens at receive with no corresponding guaranteed release.
### Step 2.4: Fix Quality Assessment
**Record:**
- **Obviously correct:** Yes — classic "track pending resource, release
at unified exit" pattern.
- **Minimal:** Yes — 28 lines, no refactoring.
- **Regression risk:** Very low. `kmem_cache_zalloc()` zero-initializes
work structs; paths that never charge leave `credit_charge == 0`;
normal path clears the field in `smb2_set_rsp_credits()` before
reaching `send:`.
- **Locking:** Uses existing `credits_lock`, consistent with surrounding
credit code.
---
## Phase 3: Git History Investigation
### Step 3.1: Blame the Changed Lines
**Record:** `outstanding_credits += credit_charge` in `smb2misc.c`
(lines 356–361) blames to merge commit `5d324e5159d9e` (v6.18-rc8,
2025-11-28). The credit validation logic is present in this 6.18.44
tree. Fix commit `4a0b7826615a0` is **not** an ancestor of HEAD.
### Step 3.2: Follow Fixes: Tag
**Record:** N/A — no `Fixes:` tag in commit message.
### Step 3.3: File History for Related Changes
**Record:** Recent ksmbd fixes in this tree include UAF fixes, session
handling, and validation hardening (`9be4a66f019ea`, `a60b5da05e318`,
etc.). Prior related fix: `85bf0a73831cc` ("smb: server: fix last send
credit problem causing disconnects"). **Standalone** — not part of a
multi-patch series.
### Step 3.4: Author's Other Commits
**Record:** Namjae Jeon is the primary ksmbd maintainer with numerous
recent fixes in `fs/smb/server/`. Steve French committed the patch. High
subsystem trust.
### Step 3.5: Dependent/Prerequisite Commits
**Record:** No dependencies. `git show 4a0b7826615a0 -- . | git apply
--check` succeeds on current HEAD — patch applies cleanly with no
prerequisites.
---
## Phase 4: Mailing List and External Research
### Step 4.1: Original Patch Discussion
**Record:** `b4 dig -c 4a0b7826615a0` returned no match on
lore.kernel.org. `b4 dig -a` and `b4 dig -w` also failed. Likely
committed directly via maintainer tree (`Merge tag
'v7.2-rc1-smb3-server-fixes'`). Lore search blocked by bot protection.
### Step 4.2: Reviewers
**Record:** UNVERIFIED from lore — commit signed off by author and
committed by subsystem maintainer (Steve French).
### Step 4.3: Bug Report
**Record:** No external bug report referenced. Bug mechanism is
explained in detail in the commit message and verifiable from code.
### Step 4.4: Related Patches/Series
**Record:** Standalone fix, not part of a series.
### Step 4.5: Stable Mailing List History
**Record:** UNVERIFIED — lore search unavailable; no stable-list
discussion found.
---
## Phase 5: Code Semantic Analysis
### Step 5.1: Key Functions
**Record:** `smb2_validate_credit_charge()`, `smb2_set_rsp_credits()`,
`__handle_ksmbd_work()`, `__process_request()`,
`ksmbd_smb2_check_message()`, `ksmbd_verify_smb_message()`.
### Step 5.2: Trace Callers
**Record:**
- `ksmbd_smb2_check_message()` ← `ksmbd_verify_smb_message()` ←
`__process_request()` ← `__handle_ksmbd_work()` ←
`handle_ksmbd_work()` (kworker)
- Every incoming SMB2 work item on connections with
`SMB2_GLOBAL_CAP_LARGE_MTU` goes through this path.
- `SMB2_GLOBAL_CAP_LARGE_MTU` is set for all SMB 2.1+ protocol versions
in `fs/smb/server/smb2ops.c`.
### Step 5.3: Key Callees
**Record:** Credit paths use `spin_lock(&conn->credits_lock)` around
`outstanding_credits` / `total_credits` mutations.
### Step 5.4: Call Chain / Reachability
**Record:** Any networked SMB client that can send SMB2 requests to
ksmbd can trigger abort paths (unimplemented commands, signature
failures, cancelled blocking locks). **Reachable from remote clients**
on any ksmbd-enabled system (`CONFIG_SMB_SERVER`).
### Step 5.5: Similar Patterns
**Record:** Prior credit accounting bug fixed in `85bf0a73831cc` (SMB
Direct send credits). Same subsystem, same class of problem.
---
## Phase 6: Cross-Referencing Against Local Tree
### Step 6.1: Does the Buggy Code Exist?
**Record:** **Yes.** Local tree is **Linux 6.18.44** (`git describe
HEAD` → `v6.18.44-1-g2736c32da98b9`). Buggy code confirmed at
`smb2misc.c:361`, `server.c:214-215`, `smb2pdu.c:337-352`. No
`credit_charge` field in `ksmbd_work.h`. Fix commit `4a0b7826615a0` is
**not** in HEAD.
### Step 6.2: Backport Complications
**Record:** **Clean apply** — `git apply --check` passes without
modification. No `compress_response` code in this 6.18 tree (present in
newer mainline context lines of the patch), so the `send:` hunk applies
against the simpler local `server.c`.
### Step 6.3: Related Fixes Already Present?
**Record:** No equivalent fix found. `git log --grep="outstanding credit
leak"` returns nothing on this branch.
---
## Phase 7: Subsystem and Maintainer Context
### Step 7.1: Subsystem Criticality
**Record:** **Subsystem:** `fs/smb/server` (ksmbd /
`CONFIG_SMB_SERVER`). **Criticality:** IMPORTANT — optional but
production-relevant for users running the in-kernel SMB3 server; not
core kernel, but file-server availability is business-critical for those
deployments.
### Step 7.2: Subsystem Activity
**Record:** Actively maintained — multiple ksmbd fixes landed in this
6.18.y tree in 2026.
---
## Phase 8: Impact and Risk Assessment
### Step 8.1: Who Is Affected
**Record:** Users with `CONFIG_SMB_SERVER` enabled (module `ksmbd` or
built-in), using SMB 2.1+ (LARGE_MTU). Not universal, but affects all
ksmbd server deployments.
### Step 8.2: Trigger Conditions
**Record:**
- Client sends requests that hit `SERVER_HANDLER_ABORT` (unimplemented
command, bad signature, `send_no_response`, command index out of
range).
- Or `smb2_set_rsp_credits()` returns `-EINVAL`.
- Repeated triggers exhaust the credit window.
- **Likelihood:** Moderate — unimplemented commands and lock cancel are
normal SMB client behaviors; a buggy or malicious client can wedge the
connection deliberately.
### Step 8.3: Failure Mode Severity
**Record:** Connection wedge — all subsequent SMB requests rejected once
credits exhaust. **Severity: HIGH** for affected deployments (complete
loss of SMB service on that connection; requires reconnect/restart). Not
a kernel oops/panic, but a reproducible availability failure.
### Step 8.4: Risk-Benefit Ratio
**Record:**
- **Benefit:** HIGH for ksmbd users — prevents progressive credit leak
and connection DoS.
- **Risk:** VERY LOW — 28-line, obviously correct accounting fix using
existing locks; applies cleanly.
- **Ratio:** Strongly favors backport.
---
## Phase 9: Final Synthesis
### Step 9.1: Evidence Summary
**FOR backport:**
- Real, verifiable resource leak in credit accounting
- Leads to connection wedge (availability DoS)
- Triggerable by remote SMB clients
- Small, surgical, maintainer-authored fix
- Applies cleanly to 6.18.44
- Buggy code present; fix not yet applied
- Prior similar credit fixes exist in this subsystem
**AGAINST backport:**
- Only affects `CONFIG_SMB_SERVER` users (optional, default disabled)
- No kernel crash/panic — connection-level rather than system-level
failure
- No external bug report or syzbot finding
**Unresolved:** Lore discussion and stable-list nomination not found (b4
dig failed; lore blocked).
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — logic is clear; committed by
subsystem maintainer (testing implied by maintainer merge, but no
explicit Tested-by).
2. Fixes a real bug affecting users? **PASS** — credit leak wedges SMB
connections.
3. Important issue? **PASS** — connection-level DoS for file server
users (HIGH severity for that subsystem).
4. Small and contained? **PASS** — 4 files, 28 lines.
5. No new features or APIs? **PASS** — internal accounting field only.
6. Can apply to local tree? **PASS** — clean `git apply --check`.
### Step 9.3: Exception Categories
**Record:** N/A — standard bug fix, not device ID/quirk/build/doc
exception.
### Step 9.4: Decision Rationale
This commit fixes a genuine credit accounting leak in ksmbd that allows
remote clients to progressively exhaust `outstanding_credits` and wedge
the SMB connection. The bug exists in Linux 6.18.44, the fix is minimal
and applies cleanly, and the failure mode is a complete loss of SMB
service on the affected connection. While ksmbd is optional, stable
trees routinely accept such fixes for optional but production-used
server subsystems — especially when the fix is this small and the
mechanism is clearly correct.
---
## Verification
- [Phase 1] Parsed commit `4a0b7826615a0` message: fix for credit leak
on abort/error paths; SOBs from Namjae Jeon and Steve French only
- [Phase 2] Read current `server.c:214-215` — `SERVER_HANDLER_ABORT`
breaks before `set_rsp_credits()`
- [Phase 2] Read current `smb2pdu.c:337-352` — `-EINVAL` returns before
`outstanding_credits` decrement
- [Phase 2] Read current `smb2misc.c:349-361` — charge added at receive
without guaranteed release
- [Phase 2] Read `ksmbd_work.c:21` — `kmem_cache_zalloc()` confirms
zero-init of new `credit_charge` field
- [Phase 3] `git describe HEAD` → v6.18.44; Makefile confirms 6.18.44
- [Phase 3] `git merge-base --is-ancestor 4a0b7826615a0 HEAD` → fix NOT
in HEAD
- [Phase 3] `git blame smb2misc.c:356-361` → credit code present since
6.18-rc8 merge
- [Phase 3] `git show 4a0b7826615a0 -- . | git apply --check` → applies
cleanly
- [Phase 4] `b4 dig -c/-a/-w 4a0b7826615a0` → no lore match found
- [Phase 5] Grep `SMB2_GLOBAL_CAP_LARGE_MTU` in
`fs/smb/server/smb2ops.c` → all SMB2.1+ server versions use LARGE_MTU
- [Phase 5] Traced `__process_request()` abort paths at
`server.c:118-159` — signature failure, unimplemented command,
`send_no_response`
- [Phase 6] Grep `credit_charge` in tree → field absent (bug present,
fix absent)
- [Phase 6] Read `fs/smb/server/Kconfig` → `CONFIG_SMB_SERVER` (ksmbd),
default `n`
- [Phase 7] `git log --author=Namjae -- fs/smb/server/` → active
maintainer with recent fixes
- [Phase 8] Confirmed failure mode: `outstanding_credits` exhaustion
blocks all further requests per commit message and
`smb2_validate_credit_charge()` logic at lines 356-359
- [UNVERIFIED] Lore/stable-list reviewer discussion (b4 dig and web
fetch unavailable)
- [UNVERIFIED] Explicit runtime testing evidence (no Tested-by tag)
**YES**The background check finished: commit `4a0b7826615a0` is **not**
in this tree (Linux **6.18.44**), and the buggy credit-accounting code
is still present.
**Verdict: YES** — backport this fix. It’s a small, clean patch that
stops a credit leak on abort/error paths, which can wedge ksmbd SMB
connections until they’re restarted. It applies cleanly to the current
checkout.
fs/smb/server/ksmbd_work.h | 7 +++++++
fs/smb/server/server.c | 14 ++++++++++++++
fs/smb/server/smb2misc.c | 9 ++++++---
fs/smb/server/smb2pdu.c | 1 +
4 files changed, 28 insertions(+), 3 deletions(-)
diff --git a/fs/smb/server/ksmbd_work.h b/fs/smb/server/ksmbd_work.h
index 45eea779bd962..ffac059306966 100644
--- a/fs/smb/server/ksmbd_work.h
+++ b/fs/smb/server/ksmbd_work.h
@@ -64,6 +64,13 @@ struct ksmbd_work {
/* Number of granted credits */
unsigned int credits_granted;
+ /*
+ * Credit charge added to conn->outstanding_credits at receive time
+ * for the SMB2 PDU currently being processed, pending release. Zero
+ * once the charge has been returned (on the response or error path).
+ */
+ unsigned short credit_charge;
+
/* response smb header size */
unsigned int response_sz;
diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c
index b78126bb23711..c729d47f9932b 100644
--- a/fs/smb/server/server.c
+++ b/fs/smb/server/server.c
@@ -238,6 +238,20 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
} while (is_chained == true);
send:
+ /*
+ * Release any credit charge still outstanding for this request. On
+ * the normal path smb2_set_rsp_credits() already returned it, but the
+ * abort, error and send-no-response paths skip that call, so the
+ * charge would otherwise leak and eventually exhaust the connection's
+ * outstanding credit window.
+ */
+ if (work->credit_charge) {
+ spin_lock(&conn->credits_lock);
+ conn->outstanding_credits -= work->credit_charge;
+ work->credit_charge = 0;
+ spin_unlock(&conn->credits_lock);
+ }
+
if (work->tcon)
ksmbd_tree_connect_put(work->tcon);
smb3_preauth_hash_rsp(work);
diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c
index b11d854d3fcfb..d8913d2008748 100644
--- a/fs/smb/server/smb2misc.c
+++ b/fs/smb/server/smb2misc.c
@@ -298,9 +298,10 @@ static inline int smb2_ioctl_resp_len(struct smb2_ioctl_req *h)
le32_to_cpu(h->MaxOutputResponse);
}
-static int smb2_validate_credit_charge(struct ksmbd_conn *conn,
+static int smb2_validate_credit_charge(struct ksmbd_work *work,
struct smb2_hdr *hdr)
{
+ struct ksmbd_conn *conn = work->conn;
unsigned int req_len = 0, expect_resp_len = 0, calc_credit_num, max_len;
unsigned short credit_charge = le16_to_cpu(hdr->CreditCharge);
void *__hdr = hdr;
@@ -357,8 +358,10 @@ static int smb2_validate_credit_charge(struct ksmbd_conn *conn,
ksmbd_debug(SMB, "Limits exceeding the maximum allowable outstanding requests, given : %u, pending : %u\n",
credit_charge, conn->outstanding_credits);
ret = 1;
- } else
+ } else {
conn->outstanding_credits += credit_charge;
+ work->credit_charge = credit_charge;
+ }
spin_unlock(&conn->credits_lock);
@@ -466,7 +469,7 @@ int ksmbd_smb2_check_message(struct ksmbd_work *work)
validate_credit:
if ((work->conn->vals->req_capabilities & SMB2_GLOBAL_CAP_LARGE_MTU) &&
- smb2_validate_credit_charge(work->conn, hdr))
+ smb2_validate_credit_charge(work, hdr))
return 1;
return 0;
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index da114b2b39ea3..55ac0ee338dae 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -350,6 +350,7 @@ int smb2_set_rsp_credits(struct ksmbd_work *work)
conn->total_credits -= credit_charge;
conn->outstanding_credits -= credit_charge;
+ work->credit_charge = 0;
credits_requested = max_t(unsigned short,
le16_to_cpu(req_hdr->CreditRequest), 1);
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.12] cifs: Fix support for creating SFU fifo
[not found] <20260831133314.4125787-1-sashal@kernel.org>
2026-08-31 13:20 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: preserve VFS inherited POSIX ACL mask Sasha Levin
2026-08-31 13:20 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: fix outstanding credit leak on abort and error paths Sasha Levin
@ 2026-08-31 13:21 ` Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: find bound sessions during reauthentication Sasha Levin
` (24 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:21 UTC (permalink / raw)
To: patches, stable
Cc: Pali Rohár, Paulo Alcantara (Red Hat), Steve French,
Sasha Levin, linkinjeon, linux-cifs, samba-technical,
linux-kernel
From: Pali Rohár <pali@kernel.org>
[ Upstream commit 608362facd2d0f2667f68b7f42207707d59a0071 ]
SFU fifos are natively supported (created and recognized) at least by:
- Microsoft POSIX subsystem
- OpenNT/Interix subsystem
- Microsoft SFU (Windows Services for UNIX)
- Microsoft SUA (Subsystem for UNIX-based Applications)
- Windows NFS server (up to the Windows Server 2008 R2)
Windows NFS server since Windows Server 2012 uses new reparse point format
for storing new fifos, but still can recognize this old format (also in the
latest Windows Server 2022 version).
SFU-style fifo is empty regular file which has system attribute set.
These SFU-style fifos are already recognized by Linux SMB client.
But Linux SMB client is currently creating new SFU fifos in different
format which is not compatible with all those SFU-style consumers. Fix this
by creating new fifos in correct SFU format which would be recognized by
all those applications and also by existing Linux SMB clients.
This change affects only creating new fifos when mount option -o sfu is used.
Signed-off-by: Pali Rohár <pali@kernel.org>
Acked-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The buggy commit `72bc63f5e23a` ("smb3: fix creating FIFOs when mounting
with sfu mount option") is in the repo and present on several
development branches (`all-next`, `cluster-next`, etc.). The `LnxFIFO`
creation code it introduced is still in the current `v6.18.44` tree at
`smb2ops.c:5290–5294`.
The fix commit `63e4ae114ea69` is **not** in `HEAD` — it only shows up
on the `autosel` branch. That confirms the fix hasn't landed in
`6.18.44` yet and remains a valid backport candidate; the prior **YES**
stands.
fs/smb/client/smb2ops.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 43eaad8fd0ad4..618e36f4d838e 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -5288,10 +5288,8 @@ int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
type[0] = '\0';
break;
case S_IFIFO:
- type_len = 8;
- strscpy(type, "LnxFIFO");
- data = (u8 *)&pdev;
- data_len = sizeof(pdev);
+ /* SFU fifo is system file which is empty */
+ type_len = 0;
break;
default:
rc = -EPERM;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: find bound sessions during reauthentication
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (2 preceding siblings ...)
2026-08-31 13:21 ` [PATCH AUTOSEL 6.18-6.12] cifs: Fix support for creating SFU fifo Sasha Levin
@ 2026-08-31 13:22 ` Sasha Levin
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18] ksmbd: propagate failed command status in related compounds Sasha Levin
` (23 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:22 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit faf8578c77f3d846aca9cd882c293e03eafcc6df ]
A session bound to an additional connection is stored in the session
channel list, but it is not added to that connection's local session table.
After the binding exchange completes, conn->binding is cleared.
A later SESSION_SETUP reauthentication on the bound channel only searches
the local session table. It fails to find the session and returns
STATUS_USER_SESSION_DELETED instead of processing authentication and
returning STATUS_LOGON_FAILURE for invalid credentials.
If the local lookup fails, look up the session globally and accept it only
when the current connection is registered in its channel list. This keeps
unbound connections from using the session while allowing reauthentication
on an established channel.
This fixes smb2.session.bind_invalid_auth.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The background `git branch -a --contains` check hung and was killed; it
didn’t change the backport analysis.
A quick rerun confirmed the SMB3 multichannel commit object exists in
this repo and the binding code landed via the 6.18-rc8 merge. The
verdict for **linux-6.18.y** stands: **YES** — a small, low-risk fix for
broken SMB3 multichannel reauthentication on bound channels.
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 55ac0ee338dae..9394fd2605f3d 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -1863,6 +1863,13 @@ int smb2_sess_setup(struct ksmbd_work *work)
} else {
sess = ksmbd_session_lookup(conn,
le64_to_cpu(req->hdr.SessionId));
+ if (!sess) {
+ sess = ksmbd_session_lookup_slowpath(le64_to_cpu(req->hdr.SessionId));
+ if (sess && !lookup_chann_list(sess, conn)) {
+ ksmbd_user_session_put(sess);
+ sess = NULL;
+ }
+ }
if (!sess) {
rc = -ENOENT;
goto out_err;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18] ksmbd: propagate failed command status in related compounds
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (3 preceding siblings ...)
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: find bound sessions during reauthentication Sasha Levin
@ 2026-08-31 13:22 ` Sasha Levin
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: treat read-control opens as stat opens only for leases Sasha Levin
` (22 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:22 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 3f67e624e591747c2b2c9c607a76d79f7ffdcabc ]
In a related compound request, later commands can refer to the file handle
from an earlier command using the related FID value. If the earlier
command fails without producing a valid compound FID, the later related
commands must fail with the same status instead of operating on an invalid
or stale handle.
smb2.compound.related4 sends CREATE followed by IOCTL, CLOSE and SET_INFO.
The CREATE is expected to fail with STATUS_ACCESS_DENIED, and the remaining
related commands are expected to return STATUS_ACCESS_DENIED as well. ksmbd
only stored the compound FID on successful CREATE and did not remember
failed compound statuses.
Store the failed status in the work item and make related handle-based
requests fail immediately with that status only when the compound FID is
invalid. Also preserve and consume the related FID across successful
FLUSH, READ and WRITE requests whose responses do not carry a file id. Keep
a valid compound FID across non-close failures so later related commands
can continue to use the handle.
When extracting the FID from a successful READ, WRITE or FLUSH request, use
the request structure matching the SMB2 command: READ and WRITE place
PersistentFileId and VolatileFileId at a different offset than FLUSH, so a
single smb2_flush_req cast can save the wrong value as compound_fid and
make the following related request fail with STATUS_FILE_CLOSED
(smb2.compound_async.write_write after smb2.compound_async.flush_flush).
Only update the saved compound FID when the request carries a valid
volatile FID. otherwise an all-ones related FID would overwrite the CREATE
FID and break smb2.compound.related6.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
**Step 1.1 — Subject line**
Record: `[ksmbd]` `[propagate]` — propagate failed SMB2 compound-command
status to later related operations in a compound chain.
**Step 1.2 — Tags**
Record:
- `Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>` (author, ksmbd
maintainer)
- `Signed-off-by: Steve French <stfrench@microsoft.com>` (cifs/ksmbd
maintainer)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Cc:
stable@vger.kernel.org`, or `Link:` tags
- Notable: maintainer authorship and sign-off only; no fuzzer or user
bug reports
**Step 1.3 — Body analysis**
Record:
- **Bug:** In SMB2 related compound requests, later commands use a
“related” file ID from an earlier command. If an earlier command
(especially CREATE) fails without producing a valid compound FID,
later related commands must return the same NTSTATUS instead of
proceeding with an invalid/stale handle.
- **Symptom:** Wrong NTSTATUS codes (e.g. `STATUS_INVALID_HANDLE`
instead of `STATUS_ACCESS_DENIED`); broken compound sequences such as
`smb2.compound.related4` (CREATE + IOCTL + CLOSE + SET_INFO) and
`smb2.compound_async.flush_flush` / `write_write`.
- **Root cause:** ksmbd only stored `compound_fid` on successful CREATE;
failed statuses were not remembered; READ/WRITE/FLUSH FIDs were not
preserved across compound steps; wrong structure casts could corrupt
saved FIDs.
- **Version info:** None in the message.
**Step 1.4 — Hidden bug fix?**
Record: **Yes.** Although framed as protocol propagation, this is a real
functional bug fix: wrong error propagation, missing compound-FID
handling in several command handlers, and incorrect FID extraction
across FLUSH/READ/WRITE compound steps.
---
## Phase 2: Diff Analysis
**Step 2.1 — Inventory**
Record:
- `fs/smb/server/ksmbd_work.h`: +1 line (`compound_status`)
- `fs/smb/server/smb2pdu.c`: +156 / -4 lines
- Functions modified/added: `init_chained_smb2_rsp()`, new
`smb2_compound_has_failed()`, `smb2_query_dir()`, `smb2_query_info()`,
`smb2_close()`, `smb2_set_info()`, `smb2_read()`, `smb2_write()`,
`smb2_flush()`, `smb2_lock()`, `smb2_ioctl()`, `smb2_notify()`
- Scope: two-file, single-subsystem fix; moderate size but focused
**Step 2.2 — Code flow changes**
Record:
- **`init_chained_smb2_rsp()` before:** Only saved `compound_fid` on
successful CREATE; cleared FIDs when related flag absent.
- **After:** Tracks `compound_status`; preserves FIDs across successful
FLUSH/READ/WRITE using command-specific request structures; records
failed CREATE status; propagates failed status from related commands;
resets status on unrelated commands.
- **`smb2_compound_has_failed()` (new):** If in a compound chain, no
valid `compound_fid`, and a prior failed status exists, immediately
returns that NTSTATUS.
- **Command handlers before:** Several handlers (`smb2_write`,
`smb2_flush`, `smb2_lock`, `smb2_query_dir`) did not substitute
`work->compound_fid` for related FIDs; none checked prior compound
failure.
- **After:** All affected handlers check `smb2_compound_has_failed()`
and use `compound_fid`/`compound_pfid` when request FID is invalid.
**Step 2.3 — Bug mechanism**
Record:
- **Category:** Logic / protocol correctness; partial compound-FID
handling; incorrect structure casting.
- **Mechanism:** Related compound commands with `VolatileFileId ==
UINT64_MAX` require propagated FID/status from earlier commands.
Without status tracking, later commands proceed incorrectly. Without
FID substitution in WRITE/FLUSH/LOCK/QUERY_DIR, related compounds fail
or misbehave. Wrong `smb2_flush_req` cast for READ/WRITE would save
garbage FIDs.
**Step 2.4 — Fix quality**
Record: Fix is logically sound, follows existing compound-FID patterns
already used in `smb2_read()`/`smb2_set_info()`, and is careful to only
propagate failure from related commands
(`SMB2_FLAGS_RELATED_OPERATIONS`). Low regression risk; new field is
zero-initialized via `kmem_cache_zalloc()`.
---
## Phase 3: Git History Investigation
**Step 3.1 — Blame**
Record: Core compound-FID logic introduced in 2021 (`e2f34481b24db`) and
extended 2022 (`2d004c6cae567e`). Bug present since compound support
landed; long-standing in this tree.
**Step 3.2 — Fixes: tag**
Record: Not applicable — no `Fixes:` tag.
**Step 3.3 — Related file history**
Record: Multiple prior compound fixes in this tree, e.g. `7cad3ceaf679c`
(reject invalid session in compound), `075ea208c648c` (OOB in QUERY_INFO
for compounds), `f0e337e7db67c` (validate compound size),
`be0f89d4419dc` (wrong error response status). This fix is in the same
problem area and is standalone.
**Step 3.4 — Author context**
Record: Namjae Jeon is the ksmbd maintainer. Recent stable-tree ksmbd
fixes from this author include UAF and validation fixes.
**Step 3.5 — Dependencies**
Record: Patch is `[09/29]` in a larger series on lore, but `git apply
--check` succeeds cleanly on v6.18.44 without earlier series patches.
**Standalone for this tree.**
---
## Phase 4: Mailing List and External Research
**Step 4.1 — Original discussion**
Record: `b4 dig -c 3f67e624e5917` found `[PATCH 09/29]` at
https://patch.msgid.link/20260621124844.6235-9-linkinjeon@kernel.org.
Lore page content could not be fetched (Anubis bot wall). Reviewer
feedback and stable nominations: **UNVERIFIED**.
**Step 4.2 — Reviewers**
Record: `b4 dig -w` shows CC to `linux-cifs@vger.kernel.org`,
`smfrench@gmail.com`, `senozhatsky@chromium.org`, `tom@talpey.com`,
`atteh.mailbox@gmail.com`.
**Step 4.3 — Bug reports**
Record: Not applicable — no `Reported-by:` or `Link:` tags. Commit
references Samba test cases (`smb2.compound.related4`,
`smb2.compound_async.flush_flush`, `smb2.compound.related6`) as
validation scenarios.
**Step 4.4 — Series context**
Record: Part of 29-patch ksmbd series (v1, 2026-06-21), but applies
independently to 6.18.44.
**Step 4.5 — Stable list history**
Record: **UNVERIFIED** — could not search lore stable archives due to
fetch failure.
---
## Phase 5: Code Semantic Analysis
**Step 5.1 — Key functions**
Record: `init_chained_smb2_rsp`, `smb2_compound_has_failed`,
`smb2_query_dir`, `smb2_query_info`, `smb2_close`, `smb2_set_info`,
`smb2_read`, `smb2_write`, `smb2_flush`, `smb2_lock`, `smb2_ioctl`,
`smb2_notify`.
**Step 5.2 — Callers**
Record: All modified handlers are SMB2 command dispatch entry points,
reached from userspace SMB clients over network connections through
ksmbd’s request processing path. High relevance for any ksmbd
deployment.
**Step 5.3 — Callees**
Record: `has_file_id()`, `ksmbd_lookup_fd_slow()`, `ksmbd_vfs_fsync()`,
`smb2_set_err_rsp()`, `ksmbd_req_buf_next()` / `ksmbd_resp_buf_next()`.
**Step 5.4 — Reachability**
Record: **Userspace-reachable** — any SMB2 client sending compound
related requests triggers this code. Windows and Samba clients commonly
use compound requests.
**Step 5.5 — Similar patterns**
Record: `smb2_read()` and `smb2_set_info()` already had partial
compound-FID substitution in v6.18.44; `smb2_write()`, `smb2_flush()`,
`smb2_lock()`, and `smb2_query_dir()` did not — confirming
inconsistent/incomplete compound handling in the current tree.
---
## Phase 6: Cross-Reference Against Local Tree
**Step 6.1 — Buggy code present?**
Record: **Yes.** Local tree is `v6.18.44-1-g2736c32da98b9` (6.18.y
stable). `init_chained_smb2_rsp()` at lines 402–406 only saves FID on
successful CREATE; no `compound_status`;
`smb2_write()`/`smb2_flush()`/`smb2_lock()`/`smb2_query_dir()` lack
compound-FID substitution. Commit `3f67e624e5917` is on `master` but
**not** in HEAD.
**Step 6.2 — Backport complications**
Record: `git apply --check` on the commit patch succeeds with no
conflicts. Expected apply: **clean**.
**Step 6.3 — Related fixes already present?**
Record: No equivalent fix found. `compound_status` and
`smb2_compound_has_failed` are absent from this tree.
---
## Phase 7: Subsystem and Maintainer Context
**Step 7.1 — Subsystem**
Record: `fs/smb/server` (ksmbd SMB server). Criticality: **IMPORTANT**
for ksmbd users; not universal core kernel, but file-server correctness
affects data-serving workloads.
**Step 7.2 — Activity**
Record: ksmbd in 6.18.y is actively maintained with recent stable fixes
(UAF, validation, compound-related patches).
---
## Phase 8: Impact and Risk Assessment
**Step 8.1 — Who is affected**
Record: Users running `CONFIG_SMB_SERVER` / ksmbd, especially with
Windows or Samba clients using SMB2 compound related requests.
**Step 8.2 — Trigger conditions**
Record: Common client behavior — compound CREATE+IOCTL/CLOSE/SET_INFO,
or compound FLUSH+WRITE sequences. Not obscure; standard SMB2 usage.
Unprivileged network clients can trigger.
**Step 8.3 — Failure mode severity**
Record:
- Wrong NTSTATUS propagation → client interoperability failures, broken
file operations
- Missing compound FID in WRITE/FLUSH/LOCK/QUERY_DIR → compound
operations fail incorrectly
- Stale/invalid handle risk explicitly called out by author
- **Severity: MEDIUM-HIGH** for ksmbd users (functional correctness, not
kernel oops, but can break real file-server workflows)
**Step 8.4 — Risk-benefit**
Record:
- **Benefit:** HIGH for ksmbd deployments; restores correct SMB2
compound semantics
- **Risk:** LOW — contained change, maintainer-authored, applies
cleanly, follows existing patterns
- **Ratio:** Favorable for backport
---
## Phase 9: Final Synthesis
**Step 9.1 — Evidence summary**
FOR:
- Real, reproducible SMB2 compound bugs (test cases named in commit
message)
- Incomplete compound handling verified in current 6.18.44 code
- Maintainer-authored and signed
- Applies cleanly to this tree
- Similar compound/error-status fixes already present in stable history
- Affects common client request patterns
AGAINST:
- No crash/UAF/CVE reported
- ~160 lines (moderate, not tiny)
- Part of larger 29-patch series (though standalone here)
- Lore review/stable nomination details unverified
UNRESOLVED:
- Whether reviewers explicitly nominated for stable on lore
**Step 9.2 — Stable rules checklist**
1. Obviously correct and tested? **PASS** — clear logic, Samba test
references, maintainer sign-off
2. Fixes a real bug affecting users? **PASS** — compound SMB2 handling
broken for multiple commands
3. Important issue? **PASS** — functional file-server correctness; wrong
handle/status behavior on common client paths (MEDIUM-HIGH for ksmbd)
4. Small and contained? **PASS** — 2 files, single subsystem
5. No new features/APIs? **PASS** — internal state only
6. Can apply to local tree? **PASS** — `git apply --check` succeeds on
v6.18.44
**Step 9.3 — Exception categories**
Record: None (not device ID, quirk, DT, build, or docs fix).
**Step 9.4 — Decision rationale**
This commit fixes genuine SMB2 compound-request bugs in ksmbd that are
present in the local 6.18.y tree. The buggy code mishandles related
compound operations that Windows and Samba clients routinely send:
failed CREATE statuses are not propagated, several command handlers lack
compound-FID substitution, and FID preservation across FLUSH/READ/WRITE
is wrong or missing. While not a kernel crash fix, it is an important
correctness fix for a network file server shipped in stable kernels,
with low backport risk and clean applicability to this tree.
---
## Verification
- [Phase 1] Parsed subject, tags, and body from provided commit message
and `git show 3f67e624e5917`
- [Phase 2] Diff analysis: 2 files, +156/-4; new `compound_status`,
`smb2_compound_has_failed()`, handler updates confirmed
- [Phase 3] `git blame -L 402,406 fs/smb/server/smb2pdu.c`: compound
logic from 2021/2022
- [Phase 3] `git log --oneline -20 -- fs/smb/server/smb2pdu.c`: prior
compound fixes in tree
- [Phase 3] `git apply --check` on commit patch: succeeds cleanly
- [Phase 3] `git merge-base --is-ancestor 3f67e624e5917 HEAD`: commit
NOT in HEAD
- [Phase 4] `b4 dig -c 3f67e624e5917`: found PATCH 09/29 lore link
- [Phase 4] `b4 dig -c 3f67e624e5917 -a`: v1 series, 29 patches
- [Phase 4] `b4 dig -c 3f67e624e5917 -w`: CC list retrieved
- [Phase 4] WebFetch lore URL: **FAILED** (bot protection) — review
discussion UNVERIFIED
- [Phase 5] Read `smb2_write()`, `smb2_flush()`, `smb2_lock()`,
`smb2_query_dir()`, `smb2_read()` in tree: confirmed missing compound
handling in write/flush/lock/query_dir
- [Phase 5] `has_file_id()` / `KSMBD_NO_FID` in `vfs_cache.h`: related
FID `UINT64_MAX` treated as invalid
- [Phase 6] `git describe HEAD`: v6.18.44-1; `Makefile`: 6.18.44
- [Phase 6] Grep: no `compound_status` or `smb2_compound_has_failed` in
tree
- [Phase 6] Read `init_chained_smb2_rsp()` lines 386–448: buggy code
confirmed present
- [Phase 6] `ksmbd_alloc_work_struct()` initializes `compound_fid` to
`KSMBD_NO_FID`
- [Phase 8] Failure mode: wrong NTSTATUS / broken compound file ops;
severity MEDIUM-HIGH for ksmbd users
**YES**Those background lookups finished and matched what the analysis
already used:
- **Compound-fix search** — The tree has earlier ksmbd compound fixes
(session validation, OOB in QUERY_INFO, size checks), but not this
specific status-propagation fix.
- **`b4 dig`** — Found the submission as **[PATCH 09/29]** in Namjae
Jeon’s June 2026 series:
https://patch.msgid.link/20260621124844.6235-9-linkinjeon@kernel.org
- **Master search** — The commit is `3f67e624e5917` on `master`; it is
not in the local `v6.18.44` tree, and the patch applies cleanly there.
**Verdict for this tree: YES** — backport-worthy ksmbd SMB2 compound
correctness fix with low risk.
fs/smb/server/ksmbd_work.h | 1 +
fs/smb/server/smb2pdu.c | 159 ++++++++++++++++++++++++++++++++++++-
2 files changed, 156 insertions(+), 4 deletions(-)
diff --git a/fs/smb/server/ksmbd_work.h b/fs/smb/server/ksmbd_work.h
index d36393ff8310c..45eea779bd962 100644
--- a/fs/smb/server/ksmbd_work.h
+++ b/fs/smb/server/ksmbd_work.h
@@ -57,6 +57,7 @@ struct ksmbd_work {
u64 compound_fid;
u64 compound_pfid;
u64 compound_sid;
+ __le32 compound_status;
const struct cred *saved_cred;
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index da0e02b760f8e..0f8194fc17776 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -403,6 +403,59 @@ static void init_chained_smb2_rsp(struct ksmbd_work *work)
work->compound_fid = ((struct smb2_create_rsp *)rsp)->VolatileFileId;
work->compound_pfid = ((struct smb2_create_rsp *)rsp)->PersistentFileId;
work->compound_sid = le64_to_cpu(rsp->SessionId);
+ work->compound_status = STATUS_SUCCESS;
+ } else if ((req->Command == SMB2_FLUSH ||
+ req->Command == SMB2_READ ||
+ req->Command == SMB2_WRITE) &&
+ rsp->Status == STATUS_SUCCESS) {
+ u64 volatile_id = KSMBD_NO_FID;
+ u64 persistent_id = KSMBD_NO_FID;
+
+ if (req->Command == SMB2_FLUSH) {
+ struct smb2_flush_req *flush_req =
+ (struct smb2_flush_req *)req;
+
+ volatile_id = flush_req->VolatileFileId;
+ persistent_id = flush_req->PersistentFileId;
+ } else if (req->Command == SMB2_READ) {
+ struct smb2_read_req *read_req =
+ (struct smb2_read_req *)req;
+
+ volatile_id = read_req->VolatileFileId;
+ persistent_id = read_req->PersistentFileId;
+ } else {
+ struct smb2_write_req *write_req =
+ (struct smb2_write_req *)req;
+
+ volatile_id = write_req->VolatileFileId;
+ persistent_id = write_req->PersistentFileId;
+ }
+
+ if (has_file_id(volatile_id)) {
+ work->compound_fid = volatile_id;
+ work->compound_pfid = persistent_id;
+ work->compound_sid = le64_to_cpu(rsp->SessionId);
+ work->compound_status = STATUS_SUCCESS;
+ }
+ } else if (req->Command == SMB2_CREATE) {
+ work->compound_fid = KSMBD_NO_FID;
+ work->compound_pfid = KSMBD_NO_FID;
+ work->compound_sid = le64_to_cpu(rsp->SessionId);
+ work->compound_status = rsp->Status;
+ } else if (rsp->Status != STATUS_SUCCESS) {
+ work->compound_sid = le64_to_cpu(rsp->SessionId);
+ /*
+ * Only carry the failed status forward when the failing command
+ * was itself part of the related chain. An unrelated command
+ * that fails (e.g. a standalone request with a bad session id)
+ * must not seed the status for a following related command,
+ * which has to be evaluated on its own (and may legitimately
+ * fail with a different status such as INVALID_PARAMETER). The
+ * compound session id is still tracked so a following related
+ * command can validate it.
+ */
+ if (req->Flags & SMB2_FLAGS_RELATED_OPERATIONS)
+ work->compound_status = rsp->Status;
}
len = get_rfc1002_len(work->response_buf) - work->next_smb2_rsp_hdr_off;
@@ -428,6 +481,7 @@ static void init_chained_smb2_rsp(struct ksmbd_work *work)
ksmbd_debug(SMB, "related flag should be set\n");
work->compound_fid = KSMBD_NO_FID;
work->compound_pfid = KSMBD_NO_FID;
+ work->compound_status = STATUS_SUCCESS;
}
memset((char *)rsp_hdr, 0, sizeof(struct smb2_hdr) + 2);
rsp_hdr->ProtocolId = SMB2_PROTO_NUMBER;
@@ -447,6 +501,19 @@ static void init_chained_smb2_rsp(struct ksmbd_work *work)
memcpy(rsp_hdr->Signature, rcv_hdr->Signature, 16);
}
+static bool smb2_compound_has_failed(struct ksmbd_work *work,
+ struct smb2_hdr *rsp)
+{
+ if (!work->next_smb2_rcv_hdr_off ||
+ has_file_id(work->compound_fid) ||
+ work->compound_status == STATUS_SUCCESS)
+ return false;
+
+ rsp->Status = work->compound_status;
+ smb2_set_err_rsp(work);
+ return true;
+}
+
/**
* is_chained_smb2_message() - check for chained command
* @work: smb work containing smb request buffer
@@ -4429,11 +4496,28 @@ int smb2_query_dir(struct ksmbd_work *work)
unsigned char srch_flag;
int buffer_sz;
struct smb2_query_dir_private query_dir_private = {NULL, };
+ unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
ksmbd_debug(SMB, "Received smb2 query directory request\n");
WORK_BUFFERS(work, req, rsp);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
+ if (work->next_smb2_rcv_hdr_off &&
+ !has_file_id(req->VolatileFileId)) {
+ ksmbd_debug(SMB, "Compound request set FID = %llu\n",
+ work->compound_fid);
+ id = work->compound_fid;
+ pid = work->compound_pfid;
+ }
+
+ if (!has_file_id(id)) {
+ id = req->VolatileFileId;
+ pid = req->PersistentFileId;
+ }
+
if (ksmbd_override_fsids(work)) {
rsp->hdr.Status = STATUS_NO_MEMORY;
smb2_set_err_rsp(work);
@@ -4446,7 +4530,7 @@ int smb2_query_dir(struct ksmbd_work *work)
goto err_out2;
}
- dir_fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId);
+ dir_fp = ksmbd_lookup_fd_slow(work, id, pid);
if (!dir_fp) {
rc = -EBADF;
goto err_out2;
@@ -5896,6 +5980,9 @@ int smb2_query_info(struct ksmbd_work *work)
WORK_BUFFERS(work, req, rsp);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
if (ksmbd_override_fsids(work)) {
rc = -ENOMEM;
goto err_out;
@@ -6000,6 +6087,9 @@ int smb2_close(struct ksmbd_work *work)
WORK_BUFFERS(work, req, rsp);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
if (test_share_config_flag(work->tcon->share_conf,
KSMBD_SHARE_FLAG_PIPE)) {
ksmbd_debug(SMB, "IPC pipe close request\n");
@@ -6683,6 +6773,8 @@ int smb2_set_info(struct ksmbd_work *work)
if (work->next_smb2_rcv_hdr_off) {
req = ksmbd_req_buf_next(work);
rsp = ksmbd_resp_buf_next(work);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
if (!has_file_id(req->VolatileFileId)) {
ksmbd_debug(SMB, "Compound request set FID = %llu\n",
work->compound_fid);
@@ -6912,6 +7004,8 @@ int smb2_read(struct ksmbd_work *work)
if (work->next_smb2_rcv_hdr_off) {
req = ksmbd_req_buf_next(work);
rsp = ksmbd_resp_buf_next(work);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
if (!has_file_id(req->VolatileFileId)) {
ksmbd_debug(SMB, "Compound request set FID = %llu\n",
work->compound_fid);
@@ -7176,11 +7270,28 @@ int smb2_write(struct ksmbd_work *work)
bool writethrough = false, is_rdma_channel = false;
int err = 0;
unsigned int max_write_size = work->conn->vals->max_write_size;
+ unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
ksmbd_debug(SMB, "Received smb2 write request\n");
WORK_BUFFERS(work, req, rsp);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
+ if (work->next_smb2_rcv_hdr_off &&
+ !has_file_id(req->VolatileFileId)) {
+ ksmbd_debug(SMB, "Compound request set FID = %llu\n",
+ work->compound_fid);
+ id = work->compound_fid;
+ pid = work->compound_pfid;
+ }
+
+ if (!has_file_id(id)) {
+ id = req->VolatileFileId;
+ pid = req->PersistentFileId;
+ }
+
if (test_share_config_flag(work->tcon->share_conf, KSMBD_SHARE_FLAG_PIPE)) {
ksmbd_debug(SMB, "IPC pipe write request\n");
return smb2_write_pipe(work);
@@ -7225,7 +7336,7 @@ int smb2_write(struct ksmbd_work *work)
goto out;
}
- fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId);
+ fp = ksmbd_lookup_fd_slow(work, id, pid);
if (!fp) {
err = -ENOENT;
goto out;
@@ -7319,13 +7430,30 @@ int smb2_flush(struct ksmbd_work *work)
{
struct smb2_flush_req *req;
struct smb2_flush_rsp *rsp;
+ u64 id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
int err;
WORK_BUFFERS(work, req, rsp);
ksmbd_debug(SMB, "Received smb2 flush request(fid : %llu)\n", req->VolatileFileId);
- err = ksmbd_vfs_fsync(work, req->VolatileFileId, req->PersistentFileId);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
+ if (work->next_smb2_rcv_hdr_off &&
+ !has_file_id(req->VolatileFileId)) {
+ ksmbd_debug(SMB, "Compound request set FID = %llu\n",
+ work->compound_fid);
+ id = work->compound_fid;
+ pid = work->compound_pfid;
+ }
+
+ if (!has_file_id(id)) {
+ id = req->VolatileFileId;
+ pid = req->PersistentFileId;
+ }
+
+ err = ksmbd_vfs_fsync(work, id, pid);
if (err)
goto out;
@@ -7543,11 +7671,29 @@ int smb2_lock(struct ksmbd_work *work)
LIST_HEAD(lock_list);
LIST_HEAD(rollback_list);
int prior_lock = 0, bkt;
+ unsigned int id = KSMBD_NO_FID, pid = KSMBD_NO_FID;
WORK_BUFFERS(work, req, rsp);
ksmbd_debug(SMB, "Received smb2 lock request\n");
- fp = ksmbd_lookup_fd_slow(work, req->VolatileFileId, req->PersistentFileId);
+
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
+ if (work->next_smb2_rcv_hdr_off &&
+ !has_file_id(req->VolatileFileId)) {
+ ksmbd_debug(SMB, "Compound request set FID = %llu\n",
+ work->compound_fid);
+ id = work->compound_fid;
+ pid = work->compound_pfid;
+ }
+
+ if (!has_file_id(id)) {
+ id = req->VolatileFileId;
+ pid = req->PersistentFileId;
+ }
+
+ fp = ksmbd_lookup_fd_slow(work, id, pid);
if (!fp) {
ksmbd_debug(SMB, "Invalid file id for lock : %llu\n", req->VolatileFileId);
err = -ENOENT;
@@ -8348,6 +8494,8 @@ int smb2_ioctl(struct ksmbd_work *work)
if (work->next_smb2_rcv_hdr_off) {
req = ksmbd_req_buf_next(work);
rsp = ksmbd_resp_buf_next(work);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
if (!has_file_id(req->VolatileFileId)) {
ksmbd_debug(SMB, "Compound request set FID = %llu\n",
work->compound_fid);
@@ -8955,6 +9103,9 @@ int smb2_notify(struct ksmbd_work *work)
WORK_BUFFERS(work, req, rsp);
+ if (smb2_compound_has_failed(work, &rsp->hdr))
+ return -EACCES;
+
if (work->next_smb2_rcv_hdr_off && req->hdr.NextCommand) {
rsp->hdr.Status = STATUS_INTERNAL_ERROR;
smb2_set_err_rsp(work);
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.6] ksmbd: treat read-control opens as stat opens only for leases
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (4 preceding siblings ...)
2026-08-31 13:22 ` [PATCH AUTOSEL 6.18] ksmbd: propagate failed command status in related compounds Sasha Levin
@ 2026-08-31 13:23 ` Sasha Levin
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: mark invalid session responses as signed Sasha Levin
` (21 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:23 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit be939e11c4724d1de3650e8bafd4c3583d9684b2 ]
A second open that requests only metadata-level access must not break
the existing caching state. ksmbd already skips the break for such opens
via fp->attrib_only (FILE_READ_ATTRIBUTES,
FILE_WRITE_ATTRIBUTES and FILE_SYNCHRONIZE).
An open requesting only READ_CONTROL (reading the security descriptor)
must be treated differently depending on the existing caching state.
smbtorture smb2.lease.statopen4 expects a read-control open NOT to break
a caching lease, while smb2.oplock.statopen1 expects the same open to
break a batch oplock. So READ_CONTROL is a stat open for leases but not
for oplocks.
Extend the stat-open break-skip in smb_grant_oplock() to also cover a
read-control-only open, but only when the existing holder is a lease.
The global fp->attrib_only flag (used for share-mode, rename and truncate
decisions) is left unchanged so oplock behaviour is preserved.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `ksmbd: treat read-control opens as stat
opens only for leases`
**Local tree:** `v6.18.44` (`linux-6.18.y` stable, `HEAD` detached at
`2736c32da98b9`)
**Candidate commit (mainline):** `be939e11c4724` (on `master`, not yet
in this tree)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1 – Subject line**
Record: `[ksmbd] [treat] READ_CONTROL-only opens should be treated as
stat opens for leases (but not oplocks)`
**Step 1.2 – Tags**
Record:
- `Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>` (author)
- `Signed-off-by: Steve French <stfrench@microsoft.com>`
(committer/maintainer)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Acked-
by:`, `Link:`, or `Cc: stable@vger.kernel.org`
- Notable absence: no user report or syzbot; verification cited is Samba
torture tests
**Step 1.3 – Body analysis**
Record:
- **Bug:** A second open requesting only `READ_CONTROL` (security-
descriptor read) incorrectly breaks an existing SMB2 caching lease.
- **Symptom:** Spurious lease break when a metadata-only open should
leave caching state intact; fails `smbtorture smb2.lease.statopen4`.
- **Expected behavior:** `READ_CONTROL` is a stat open for leases (no
break) but not for oplocks (`smb2.oplock.statopen1` expects break).
- **Root cause:** `fp->attrib_only` covers `FILE_READ_ATTRIBUTES`,
`FILE_WRITE_ATTRIBUTES`, and `FILE_SYNCHRONIZE` but not
`READ_CONTROL`; the stat-open skip in `smb_grant_oplock()` therefore
does not apply.
- **Fix approach:** Extend the stat-open break-skip for
`READ_CONTROL`-only opens, but only when the existing holder is a
lease; leave `fp->attrib_only` unchanged so oplock behavior is
preserved.
**Step 1.4 – Hidden bug fix?**
Record: **Yes.** Despite no "fix" in the subject, this is a protocol-
correctness bug in lease/oplock handling, not cosmetic cleanup.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1 – Inventory**
Record:
- **Files:** `fs/smb/server/oplock.c` only (+27 / −3 lines)
- **Functions modified:** new `ksmbd_inode_has_lease()`; modified
`smb_grant_oplock()`
- **Scope:** Single-file, surgical fix
**Step 2.2 – Code flow per hunk**
*Hunk 1 – `ksmbd_inode_has_lease()`:*
Record: **Before:** no way to distinguish lease vs oplock holder in the
stat-open path. **After:** peek at first `opinfo` on inode list, return
`is_lease`, with proper refcount via `opinfo_get_list()` /
`opinfo_put()`.
*Hunk 2 – `smb_grant_oplock()` stat-open skip:*
Record: **Before:** only `fp->attrib_only` opens skip the break path
(set `req_op_level = NONE`, `goto set_lev`). **After:** also skip when
open requests only stat/metadata access including `READ_CONTROL` **and**
`ksmbd_inode_has_lease(ci)` is true. Truncating dispositions
(`FILE_OVERWRITE_*`, `FILE_SUPERSEDE`) still force a break.
**Step 2.3 – Bug mechanism**
Record:
- **Category:** Logic / protocol correctness (lease vs oplock semantics)
- **Mechanism:** `READ_CONTROL`-only open has `fp->attrib_only == false`
(set in `smb2pdu.c:3461-3462`), so code falls through to
`opinfo_get_list()` and `oplock_break()` even when the existing holder
is a caching lease. Fix short-circuits that path for lease holders.
**Step 2.4 – Fix quality**
Record:
- Fix is minimal and mirrors existing `attrib_only` logic.
- Deliberately preserves oplock break behavior by gating on
`ksmbd_inode_has_lease()`.
- Uses existing `fp->daccess` (already set at `smb2pdu.c:3367` before
`smb_grant_oplock()` at line 3523).
- Low regression risk; same `opinfo_get_list()` pattern already used
later in `smb_grant_oplock()`.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1 – Blame**
Record: Stat-open skip introduced in `849fbc549d4cca` (2021-06-29,
"ksmbd: opencode to remove ATTR_FP macro"). Bug has existed since
`attrib_only` was introduced. Present in this 6.18.y tree.
**Step 3.2 – Fixes: tag**
Record: N/A – no `Fixes:` tag.
**Step 3.3 – Related file history**
Record: Recent `oplock.c` changes in 6.18.y are mostly UAF/NULL-
deref/refcount fixes. Mainline has ~27 additional lease/oplock commits
not in 6.18.y (series starting `a04159d96c27f`). This patch is **patch
26/29** of that series but **`git apply --check` succeeds cleanly** on
6.18.y without the other 25 patches.
**Step 3.4 – Author context**
Record: Namjae Jeon is ksmbd maintainer; Steve French is SMB/CIFS
maintainer. Both signed off.
**Step 3.5 – Dependencies**
Record: **Standalone.** No prerequisite commits required; all symbols
(`opinfo_get_list`, `fp->daccess`, `FILE_READ_CONTROL_LE`, `is_lease`)
exist in 6.18.y.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1 – Original discussion**
Record:
- `b4 dig -c be939e11c4724`:
https://patch.msgid.link/20260621124844.6235-26-linkinjeon@kernel.org
- Part of v1 series `[PATCH 01/29]` through `[PATCH 29/29]`, dated
2026-06-21
**Step 4.2 – Reviewers**
Record: `b4 dig -w` CC'd `linux-cifs@vger.kernel.org`,
`smfrench@gmail.com`, `senozhatsky@chromium.org`, `tom@talpey.com`,
`atteh.mailbox@gmail.com`. No `Reviewed-by`/`Acked-by` on the committed
patch.
**Step 4.3 – Bug report**
Record: No external bug report. Verification is internal Samba torture
references (`smb2.lease.statopen4`, `smb2.oplock.statopen1`).
**Step 4.4 – Series context**
Record: Patch 26/29 in a large lease-improvement series. Earlier patches
(e.g. `889d2e38943ad` "break conflicting-open leases only as far as
needed") address related lease-break issues but are **not**
prerequisites for this patch on 6.18.y.
**Step 4.5 – Stable list history**
Record: No `Cc: stable@vger.kernel.org` found in the lore thread (`rg`
over downloaded mbox). No stable-specific discussion found.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1 – Key functions**
Record: `ksmbd_inode_has_lease()`, `smb_grant_oplock()`, helpers
`opinfo_get_list()`, `opinfo_put()`, `opinfo_count()`
**Step 5.2 – Callers**
Record: `smb_grant_oplock()` called from `smb2pdu.c:3523` during SMB2
CREATE handling — common file-server path reachable by remote SMB
clients on every open with oplock/lease request.
**Step 5.3 – Callees**
Record: `opinfo_get_list()` acquires `ci->m_lock` read lock and bumps
refcount; `oplock_break()` (avoided by fix) sends break notifications to
clients.
**Step 5.4 – Reachability**
Record: **Yes, remotely triggerable.** Any SMB client opening a file
with only `READ_CONTROL` (+ stat bits) while another client holds a
lease hits this path. ACL/security-descriptor reads are routine Windows
operations.
**Step 5.5 – Similar patterns**
Record: `smb2pdu.c:3303` already treats `FILE_READ_CONTROL` as non-
conflicting for inode permission checks. `fp->attrib_only` definition at
`smb2pdu.c:3461-3462` intentionally excludes `READ_CONTROL` because
oplocks must still break — confirming the fix must be lease-specific,
not a global `attrib_only` change.
---
## PHASE 6: CROSS-REFERENCING AGAINST LOCAL TREE (6.18.y)
**Step 6.1 – Buggy code present?**
Record: **Yes.** Current tree at `oplock.c:1237-1243`:
```1237:1243:fs/smb/server/oplock.c
/* grant none-oplock if second open is trunc */
if (fp->attrib_only && fp->cdoption != FILE_OVERWRITE_IF_LE &&
fp->cdoption != FILE_OVERWRITE_LE &&
fp->cdoption != FILE_SUPERSEDE_LE) {
req_op_level = SMB2_OPLOCK_LEVEL_NONE;
goto set_lev;
}
```
Bug present since 2021 (`849fbc549d4cca`).
**Step 6.2 – Backport complications**
Record: **`git format-patch -1 be939e11c4724 | git apply --check` →
clean apply.** No conflicts expected.
**Step 6.3 – Related fixes already present?**
Record: No equivalent fix in 6.18.y (`git log -S
'ksmbd_inode_has_lease'` returns nothing on this tree).
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1 – Subsystem**
Record: `fs/smb/server` (ksmbd / `CONFIG_SMB_SERVER`) — **IMPORTANT**
for SMB file-server deployments; not core kernel, but critical for that
use case.
**Step 7.2 – Activity**
Record: Actively maintained in 6.18.y with frequent security and
protocol fixes (e.g. `a60b5da05e318` negotiate rejection,
`213b4568f6e5d` deferred-close status).
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1 – Who is affected**
Record: Users running `CONFIG_SMB_SERVER` (module `ksmbd`) with
oplocks/leases enabled — SMB/NAS/file-server deployments.
**Step 8.2 – Trigger conditions**
Record: Second client opens a file requesting only `READ_CONTROL` (+
optional stat bits) while a caching lease is held. **Common** for
ACL/security-descriptor access. Unprivileged remote SMB clients can
trigger.
**Step 8.3 – Failure mode severity**
Record: Spurious lease break → unnecessary client cache invalidation,
extra break/ack round-trips, degraded I/O performance. **Not** crash,
corruption, deadlock, or security exploit. Severity: **MEDIUM**
(protocol/interoperability + performance).
**Step 8.4 – Risk-benefit**
Record:
- **Benefit:** Correct SMB2 lease semantics; passes
`smb2.lease.statopen4`; prevents unnecessary cache churn on routine
ACL reads.
- **Risk:** Very low — 27 lines, one file, clean apply, mirrors existing
logic.
- **Ratio:** Favorable for SMB server users; conservative but justified.
---
## PHASE 9: FINAL SYNTHESIS
**Step 9.1 – Evidence compile**
*FOR backport:*
- Real, long-standing protocol bug (since 2021)
- Remotely triggerable on common SMB server path
- Small, obviously correct, maintainer-authored fix
- Applies cleanly to 6.18.y without series dependencies
- In mainline (`be939e11c4724` on `master`)
- Precedent: 6.18.y already backports ksmbd protocol/interop fixes
(`a60b5da`, `213b4568f6e5d`)
- Samba torture test provides concrete verification
*AGAINST backport:*
- No crash, corruption, security issue, or hang
- No user `Reported-by`, no `Cc: stable`, no distro-maintainer
nomination
- `CONFIG_SMB_SERVER` defaults to `n` — narrower audience
- Performance/interop issue rather than hard failure
- Part of a larger 29-patch lease series (though standalone applicable)
*Unresolved:* No end-user production bug reports found; impact
quantified only via torture tests.
**Step 9.2 – Stable rules checklist**
1. Obviously correct and tested? **PASS** — logic is clear; torture-test
references; maintainer sign-off.
2. Fixes a real bug affecting users? **PASS** — incorrect lease breaks
on ACL reads affect SMB server clients.
3. Important issue? **PASS (borderline)** — not crash/corruption, but
protocol non-compliance causing spurious lease breaks and measurable
cache/performance impact on a file server.
4. Small and contained? **PASS** — 27 lines, one file.
5. No new features/APIs? **PASS** — behavior correction only.
6. Can apply to local tree? **PASS** — verified clean apply.
**Step 9.3 – Exception categories**
Record: None (not device ID, quirk, DT, build fix, or docs). Qualifies
as protocol correctness fix for existing `CONFIG_SMB_SERVER`
functionality.
**Step 9.4 – Problem summary for stable users**
Without this fix, ksmbd incorrectly breaks caching leases when a client
opens a file solely to read its security descriptor (`READ_CONTROL`).
Windows and Samba clients routinely perform such opens (Explorer
properties, ACL tools, backup software). Each spurious break forces
clients to flush caches and complete break acknowledgments, degrading
performance and violating SMB2 lease semantics that Samba and Windows
implement correctly. The fix is surgical, self-contained, and applies
cleanly to 6.18.y.
---
## Verification
- **[Phase 1]** Parsed commit message from user query and `git show
be939e11c4724`; tags recorded.
- **[Phase 2]** Analyzed diff; confirmed `fp->daccess` field in
`vfs_cache.h:94`; confirmed `daccess` set before `smb_grant_oplock()`
at `smb2pdu.c:3367`/`3523`.
- **[Phase 3]** `git describe HEAD` → `v6.18.44`; `git blame` → bug
since `849fbc549d4cca` (2021); `git log HEAD..master --
fs/smb/server/oplock.c` → 15+ commits including candidate; `git apply
--check` → clean.
- **[Phase 4]** `b4 dig -c be939e11c4724` → lore URL found; `b4 dig -a`
→ patch 26/29; `b4 dig -w` → recipients listed; mbox downloaded; no
`Cc: stable` or NAKs found.
- **[Phase 5]** `grep smb_grant_oplock` → caller in `smb2pdu.c`; traced
`attrib_only` definition at `smb2pdu.c:3461-3462`.
- **[Phase 6]** Confirmed buggy code at `oplock.c:1237-1243`;
`ksmbd_inode_has_lease` absent; `git apply --check` passes.
- **[Phase 7]** `CONFIG_SMB_SERVER` in `fs/smb/server/Kconfig`; recent
ksmbd stable commits reviewed.
- **[Phase 8]** Assessed trigger (remote READ_CONTROL open) and severity
(spurious lease break, MEDIUM).
- **[Phase 9]** Stable rules checklist completed; decision synthesized.
**YES**The background `git log` searches timed out, but that didn’t
block the analysis — the commit was found on `master` as
`be939e11c4724`, and the rest of the investigation (clean apply to
6.18.y, lore thread, code review) completed normally.
**Verdict for 6.18.y: YES** — this is a real SMB2 lease protocol bug
(spurious lease breaks on `READ_CONTROL`-only opens) with a small, self-
contained fix that applies cleanly.
fs/smb/server/oplock.c | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
index b6705a07c6ebe..f700ee48c54c0 100644
--- a/fs/smb/server/oplock.c
+++ b/fs/smb/server/oplock.c
@@ -208,6 +208,18 @@ void opinfo_put(struct oplock_info *opinfo)
free_opinfo(opinfo);
}
+static bool ksmbd_inode_has_lease(struct ksmbd_inode *ci)
+{
+ struct oplock_info *opinfo = opinfo_get_list(ci);
+ bool is_lease;
+
+ if (!opinfo)
+ return false;
+ is_lease = opinfo->is_lease;
+ opinfo_put(opinfo);
+ return is_lease;
+}
+
static void opinfo_add(struct oplock_info *opinfo, struct ksmbd_file *fp)
{
struct ksmbd_inode *ci = fp->f_ci;
@@ -1251,10 +1263,22 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,
if (!opinfo_count(fp))
goto set_lev;
- /* grant none-oplock if second open is trunc */
- if (fp->attrib_only && fp->cdoption != FILE_OVERWRITE_IF_LE &&
+ /*
+ * A stat open that only requests metadata access must not break the
+ * existing caching state. READ_CONTROL (reading the security
+ * descriptor) does not conflict with a lease, but it does conflict
+ * with an oplock, so only treat a read-control-only open as a stat
+ * open when the existing holder is a lease.
+ */
+ if (fp->cdoption != FILE_OVERWRITE_IF_LE &&
fp->cdoption != FILE_OVERWRITE_LE &&
- fp->cdoption != FILE_SUPERSEDE_LE) {
+ fp->cdoption != FILE_SUPERSEDE_LE &&
+ (fp->attrib_only ||
+ (!(fp->daccess & ~(FILE_READ_ATTRIBUTES_LE |
+ FILE_WRITE_ATTRIBUTES_LE |
+ FILE_SYNCHRONIZE_LE |
+ FILE_READ_CONTROL_LE)) &&
+ ksmbd_inode_has_lease(ci)))) {
req_op_level = SMB2_OPLOCK_LEVEL_NONE;
goto set_lev;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: mark invalid session responses as signed
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (5 preceding siblings ...)
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: treat read-control opens as stat opens only for leases Sasha Levin
@ 2026-08-31 13:23 ` Sasha Levin
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: Fix acl.sd_buf memory leak and invalid sd_size error handling Sasha Levin
` (20 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:23 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 9e8ad620ddfde5a5f4ef58372e3805e9388cb0f4 ]
When a signed request uses a session that is not registered on the
connection, ksmbd returns STATUS_USER_SESSION_DELETED before reaching the
normal response signing path. The response therefore lacks
SMB2_FLAGS_SIGNED.
Clients that require signing check this flag before handling
STATUS_USER_SESSION_DELETED and replace the server status with
STATUS_ACCESS_DENIED when it is absent. The protocol permits this error
response to skip signature verification because the connection has no
matching session key.
Preserve SMB2_FLAGS_SIGNED on the early error response when the request was
signed. This lets the client propagate STATUS_USER_SESSION_DELETED.
It fixes smb2.session.bind2.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
### Step 1.1: Subject line
**Record:** `[ksmbd] [mark] invalid session responses as signed` — sets
`SMB2_FLAGS_SIGNED` on early session-validation error responses when the
request was signed.
### Step 1.2: Tags
**Record:**
- **Signed-off-by:** Namjae Jeon `<linkinjeon@kernel.org>` (author)
- **Signed-off-by:** Steve French `<stfrench@microsoft.com>` (cifs/ksmbd
maintainer)
- No Fixes:, Reported-by:, Tested-by:, Reviewed-by:, Acked-by:, Link:,
or Cc: stable tags (expected for manual review)
### Step 1.3: Body analysis
**Record:**
- **Bug:** Signed request references a session not registered on the
connection; `smb2_check_user_session()` fails early; server returns
`STATUS_USER_SESSION_DELETED` without `SMB2_FLAGS_SIGNED`.
- **Symptom:** Signing-required clients check `SMB2_FLAGS_SIGNED` before
honoring that status; missing flag → client reports
`STATUS_ACCESS_DENIED` instead of the server’s real status.
- **Root cause:** Early `goto send` bypasses the normal signing path
(`work->sess` is NULL, so `set_sign_rsp()` is never called).
- **Fix approach:** Set only `SMB2_FLAGS_SIGNED` (no signature bytes);
protocol allows skipping verification when no session key exists on
the connection.
- **Test reference:** `smb2.session.bind2` (Samba protocol test suite).
### Step 1.4: Hidden bug fix?
**Record:** Yes — described as marking responses signed, but it fixes a
real SMB protocol/interoperability bug: wrong client-visible error on
signed session-binding paths.
---
## Phase 2: Diff Analysis
### Step 2.1: Inventory
**Record:**
- **Files:** `fs/smb/server/server.c` (+6 / -0)
- **Function:** `__handle_ksmbd_work()`
- **Scope:** Single-file, surgical fix in one error path
### Step 2.2: Code flow change
**Record:**
- **Hunk (session check failure, `rc < 0`):**
- **Before:** Set `STATUS_INVALID_PARAMETER` or
`STATUS_USER_SESSION_DELETED`, `goto send` with unsigned response.
- **After:** If `is_sign_req(work, get_cmd_val(work))`, set
`SMB2_FLAGS_SIGNED` on current response header via
`ksmbd_resp_buf_curr()`, then `goto send`.
- **Path affected:** Early error path before `__process_request()` and
before the `work->sess && ... set_sign_rsp()` block (lines 234–237).
### Step 2.3: Bug mechanism
**Record:** **Category:** Logic / protocol correctness on error path.
- Normal signing requires `work->sess` (lines 234–237).
- Invalid session → `work->sess` stays NULL → flag never set.
- Fix sets the flag without signing when the request was signed and no
session key is available.
### Step 2.4: Fix quality
**Record:**
- Minimal, matches existing pattern in related ksmbd signing fixes (e.g.
`1f12738`, `3e67423` on mainline).
- Low regression risk: only touches error path; only sets a flag when
request was signed.
- Uses `get_cmd_val(work)` (reads request header directly), not
uninitialized local `command` (still 0 at this point).
---
## Phase 3: Git History Investigation
### Step 3.1: Blame
**Record:** Session-check early-exit block dates to merge
`5d324e5159d9e` (v6.18-rc8 era, Nov 2025). Bug has been present since
this code structure landed in this tree.
### Step 3.2: Fixes: tag
**Record:** N/A — no Fixes: tag.
### Step 3.3: Related file history
**Record:** Recent `server.c` changes are crypto-library refactors and
leak/loop fixes (`74c2f0f`, `51c5f7e`, `71b5e7c`, `6a37bc4`). Related
binding fixes exist in tree (`a897064a45705` “do not expire session on
binding failure”, `9feb2d1bf86d9`). July 2026 signing series (`1f12738`,
`3e67423`, `4b70636`, `9e8ad620`) is **not** in this tree yet. This
commit is standalone for its code path.
### Step 3.4: Author context
**Record:** Namjae Jeon is ksmbd maintainer; Steve French is cifs
maintainer. Prior stable-nominated ksmbd fix in this tree:
`8cabcb4dd3dc` (refcount leak on invalid session lookup, `Cc:
stable@vger.kernel.org`).
### Step 3.5: Dependencies
**Record:** No series/prerequisite commits required. Uses existing APIs:
`is_sign_req`, `get_cmd_val`, `ksmbd_resp_buf_curr`,
`SMB2_FLAGS_SIGNED`. Patch applies cleanly (`git apply --check` on
GitHub `.patch` succeeded).
---
## Phase 4: Mailing List and External Research
### Step 4.1: Original discussion
**Record:** `b4 dig -c 9e8ad620ddfde5a5f4ef58372e3805e9388cb0f4` — no
lore match found. GitHub commit page confirms message and diff.
### Step 4.2: Reviewers
**Record:** `b4 dig -w` — no lore data. Committer is subsystem
maintainer (Steve French).
### Step 4.3: Bug report
**Record:** No external bug report; validation reference is Samba test
`smb2.session.bind2`. Related mainline commits from same author/date
document the same signing-flag pattern for binding errors.
### Step 4.4: Related patches
**Record:** Part of a broader July 2026 ksmbd multichannel/signing fix
set on mainline, but this patch is self-contained for the `server.c`
early-session-check path.
### Step 4.5: Stable list history
**Record:** Lore blocked by bot protection; no stable-list discussion
found. Precedent: other ksmbd session/binding fixes backported to stable
in this tree.
---
## Phase 5: Code Semantic Analysis
### Step 5.1: Key functions
**Record:** `__handle_ksmbd_work()`, `smb2_check_user_session()`,
`smb2_is_sign_req()`, `get_smb2_cmd_val()`, `ksmbd_resp_buf_curr()`.
### Step 5.2: Callers
**Record:** `__handle_ksmbd_work()` ← `handle_ksmbd_work()` ← workqueue
processing of incoming SMB requests (network I/O path for all ksmbd
clients).
### Step 5.3: Callees
**Record:** On failure: `check_user_session()` →
`ksmbd_session_lookup_all()`; fix calls `is_sign_req()` and sets
response header flags.
### Step 5.4: Reachability
**Record:** Triggered by any signed SMB2/3 request with a session ID not
registered on the connection — reachable from remote SMB clients
(session binding / multichannel scenarios).
### Step 5.5: Similar patterns
**Record:** Same `Flags |= SMB2_FLAGS_SIGNED` without full signing in
mainline binding-error fixes (`3e67423`, `1f12738`). Normal signing
still done via `set_sign_rsp()` when `work->sess` is valid (lines
234–237).
---
## Phase 6: Cross-Reference Against Local Tree
### Step 6.1: Buggy code present?
**Record:** **Yes.** Local tree is **6.18.44** (`git describe HEAD` →
`v6.18.44-1-g2736c32da98b9`). Buggy code at
`fs/smb/server/server.c:189-198` — early `goto send` without setting
signed flag. Commit `9e8ad620ddfde` is **not** an ancestor of HEAD.
### Step 6.2: Backport complications
**Record:** **Clean apply** verified. No structural conflicts expected.
### Step 6.3: Related fixes already present?
**Record:** Binding-related fixes present (`a897064a45705`,
`9feb2d1bf86d9`). This specific signed-flag-on-early-session-error fix
is **not** present.
---
## Phase 7: Subsystem and Maintainer Context
### Step 7.1: Subsystem criticality
**Record:** **fs/smb/server (ksmbd)** — IMPORTANT. Network file server;
affects remote SMB clients, especially with mandatory signing.
### Step 7.2: Activity
**Record:** Actively maintained in 6.18.y (recent ksmbd security and
binding fixes in this tree).
---
## Phase 8: Impact and Risk Assessment
### Step 8.1: Who is affected
**Record:** ksmbd users (`CONFIG_SMB_SERVER`) with SMB signing required
and session binding/multichannel — enterprise and Windows-client
environments.
### Step 8.2: Trigger conditions
**Record:** Signed request with session ID unknown on current connection
(common in SMB multichannel binding). Remote-triggerable; not timing-
dependent.
### Step 8.3: Failure mode severity
**Record:** Wrong error status (`STATUS_ACCESS_DENIED` vs
`STATUS_USER_SESSION_DELETED`) → session binding failures, multichannel
setup breakage, client disconnects. **Severity: MEDIUM**
(functional/protocol, not kernel oops/corruption).
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** MEDIUM-HIGH for ksmbd + signing + multichannel users
- **Risk:** VERY LOW (+6 lines, error path only, flag-only change)
- **Ratio:** Favorable for stable
---
## Phase 9: Final Synthesis
### Step 9.1: Evidence summary
**FOR:**
- Real, reproducible protocol bug (Samba test `smb2.session.bind2`)
- Buggy code confirmed in 6.18.44 tree
- Small, obviously correct, applies cleanly
- Maintainer-authored and maintainer-committed
- Same signing-flag pattern as other accepted ksmbd stable fixes
- Affects remote SMB clients on a production server subsystem
- Precedent: ksmbd binding/session fixes already in this stable series
**AGAINST:**
- Not crash/security/data-corruption class
- Full `smb2.session.bind2` pass may also need other mainline signing
commits not yet in tree
- No lore review trail found via b4
**UNRESOLVED:**
- No mailing-list review thread found
- Exact production user reports not verified beyond Samba test reference
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — logic is clear; Samba test
cited; maintainer sign-off
2. Fixes real bug affecting users? **PASS** — wrong SMB status on signed
requests
3. Important issue? **PASS (borderline)** — MEDIUM severity
protocol/interop bug breaking session binding with signing
4. Small and contained? **PASS** — 6 lines, one file
5. No new features/APIs? **PASS** — flag on existing error path only
6. Can apply to local tree? **PASS** — verified clean apply
### Step 9.3: Exception categories
**Record:** None (not device ID, quirk, DT, build, or docs). Qualifies
as protocol correctness bug fix.
### Step 9.4: Decision rationale
For **this 6.18.44 tree**, ksmbd is present with multichannel/binding
support, the buggy early-exit path exists, and the fix is minimal and
low-risk. Wrong `STATUS_ACCESS_DENIED` on signed session-binding errors
breaks real SMB client interoperability — the same class of issue other
ksmbd binding fixes have addressed in stable. Benefit outweighs risk.
---
## Verification
- [Phase 1] Parsed subject, tags, body from provided commit message and
GitHub `9e8ad620ddfde`
- [Phase 2] Read diff and `fs/smb/server/server.c:163-254`; traced
signing path at lines 234-237
- [Phase 2] Read `smb2_check_user_session()` at `smb2pdu.c:581-629` —
returns `-ENOENT` when session not found
- [Phase 2] Read `smb2_is_sign_req()` at `smb2pdu.c:9018-9028`
- [Phase 3] `git blame -L 188,238 fs/smb/server/server.c` — block from
`5d324e5159d9e`
- [Phase 3] `git merge-base --is-ancestor 9e8ad620ddfde HEAD` → exit 1
(not in tree)
- [Phase 3] Related commits `1f12738`, `3e67423`, `4b70636` — all NOT in
tree
- [Phase 3] `git log --grep="Cc: stable" -- fs/smb/server/` — found
`8cabcb4dd3dc` precedent
- [Phase 4] `b4 dig -c 9e8ad620ddfde` — no lore match
- [Phase 4] GitHub API/commit page — confirmed author, message, +6/-0
- [Phase 5] `get_smb2_cmd_val()` at `smb2pdu.c:227-236` reads from
request buffer
- [Phase 5] Header chain: `server.c` → `connection.h` → `ksmbd_work.h`
(`ksmbd_resp_buf_curr`); `smb_common.h` → `common/smb2pdu.h`
(`SMB2_FLAGS_SIGNED`, `struct smb2_hdr`)
- [Phase 6] `git describe HEAD` → v6.18.44; `make kernelversion` →
6.18.44
- [Phase 6] Buggy code present at lines 189-198 (no signed flag on early
error)
- [Phase 6] `curl .../9e8ad620....patch | git apply --check` → success
- [Phase 7] Multichannel binding code present in `smb2pdu.c:1734+`
- [Phase 8] Failure mode: wrong SMB status, session binding breakage —
MEDIUM severity
**YES**The background check finished: none of the related July 2026
ksmbd signing/binding commits are in this **6.18.44** tree yet:
- `9e8ad620ddfde` — mark invalid session responses as signed (the
candidate)
- `1f12738b0ed7` — sign rejected SMB2.1 session binding responses
- `3e67423336f0` — mark rejected cross-dialect bindings as signed
- `4b706360ffb7` — fix multichannel binding and enforce channel limit
The buggy early-exit path in `fs/smb/server/server.c` is still present
here, and the candidate patch applies cleanly. That supports backporting
**`9e8ad620`** on its own; passing `smb2.session.bind2` end-to-end may
still need the other three mainline fixes.
fs/smb/server/server.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c
index c729d47f9932b..e70ea8ef1deb8 100644
--- a/fs/smb/server/server.c
+++ b/fs/smb/server/server.c
@@ -195,6 +195,12 @@ static void __handle_ksmbd_work(struct ksmbd_work *work,
else
conn->ops->set_rsp_status(work,
STATUS_USER_SESSION_DELETED);
+ if (conn->ops->is_sign_req(work, conn->ops->get_cmd_val(work))) {
+ struct smb2_hdr *rsp_hdr;
+
+ rsp_hdr = ksmbd_resp_buf_curr(work);
+ rsp_hdr->Flags |= SMB2_FLAGS_SIGNED;
+ }
goto send;
} else if (rc > 0) {
rc = conn->ops->get_ksmbd_tcon(work);
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: Fix acl.sd_buf memory leak and invalid sd_size error handling
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (6 preceding siblings ...)
2026-08-31 13:23 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: mark invalid session responses as signed Sasha Levin
@ 2026-08-31 13:24 ` Sasha Levin
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: start file id allocation at 1 Sasha Levin
` (19 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:24 UTC (permalink / raw)
To: patches, stable
Cc: Qiang Liu, ChenXiaoSong, Namjae Jeon, Steve French, Sasha Levin,
smfrench, linux-cifs, linux-kernel
From: Qiang Liu <liuqiang@kylinos.cn>
[ Upstream commit d708a36634bb7b6f94d0e76d587d2ec50b2b93b5 ]
1. When ndr_decode_v4_ntacl() fails, the code jumped to free_n_data
which only freed n.data, skipping kfree(acl.sd_buf) and leaking
the buffer. Zero-initialize struct xattr_ntacl acl, reorder error
labels to out_free to release acl.sd_buf on all error paths.
2. if (acl.sd_size < sizeof(struct smb_ntsd)) is true, original code
returned success without freeing sd_buf and left stale *pntsd.
Set rc = -EINVAL before jumping to out_free to return error code and
free buffer.
Signed-off-by: Qiang Liu <liuqiang@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
**Step 1.1 — Subject line**
Record: `[ksmbd] [Fix] acl.sd_buf memory leak and invalid sd_size error
handling in ksmbd_vfs_get_sd_xattr()`
**Step 1.2 — Tags**
Record:
- `Signed-off-by: Qiang Liu <liuqiang@kylinos.cn>` (author)
- `Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>`
- `Acked-by: Namjae Jeon <linkinjeon@kernel.org>` (ksmbd maintainer)
- `Signed-off-by: Steve French <stfrench@microsoft.com>` (SMB
maintainer)
- No `Fixes:`, `Reported-by:`, `Cc: stable@vger.kernel.org`, or `Link:`
tags
- Mainline commit: `d708a36634bb7`
**Step 1.3 — Body analysis**
Record:
- **Bug 1:** On `ndr_decode_v4_ntacl()` failure, control jumps to
`free_n_data`, which frees only `n.data` and skips
`kfree(acl.sd_buf)`, leaking the security-descriptor buffer.
- **Bug 2:** When `acl.sd_size < sizeof(struct smb_ntsd)`, the function
returns success (`rc` still 0) without freeing `sd_buf`, leaving a
stale `*pntsd`.
- **Symptom:** Memory leaks on ACL/security-descriptor xattr error
paths; incorrect success return on malformed data.
- **Root cause:** Misordered cleanup labels (`free_n_data` vs
`out_free`) and missing `rc = -EINVAL` on the invalid-size path.
**Step 1.4 — Hidden bug fix?**
Record: No — this is an explicit bug fix (memory leak + incorrect error
handling), not disguised cleanup.
---
## Phase 2: Diff Analysis
**Step 2.1 — Inventory**
Record:
- File: `fs/smb/server/vfs.c` (+3 / -4 lines)
- Function: `ksmbd_vfs_get_sd_xattr()`
- Scope: Single-file, surgical fix
**Step 2.2 — Code flow changes**
Record:
- **Hunk 1:** `struct xattr_ntacl acl` → `struct xattr_ntacl acl = {0}`
— ensures `acl.sd_buf` is NULL when decode fails before allocation.
- **Hunk 2:** `goto free_n_data` → `goto out_free` on
`ndr_decode_v4_ntacl()` failure — routes through the path that frees
`acl.sd_buf` when `rc < 0`.
- **Hunk 3:** Adds `rc = -EINVAL` before `goto out_free` on invalid
`sd_size` — ensures error return and buffer cleanup.
- **Hunk 4:** Removes separate `free_n_data:` label; `kfree(n.data)` now
always runs after `out_free` cleanup.
**Step 2.3 — Bug mechanism**
Record:
- **Category:** Resource leak (memory) + logic/correctness bug (wrong
return code)
- **Mechanism 1:** `ndr_decode_v4_ntacl()` allocates `acl->sd_buf` at
line 508 of `ndr.c` and can fail on the final `ndr_read_bytes()` at
line 512. The old `goto free_n_data` bypassed `out_free`'s
`kfree(acl.sd_buf)`.
- **Mechanism 2:** On invalid `sd_size`, `rc` remained 0 (from
successful `ndr_encode_posix_acl()`), so `if (rc < 0)` in `out_free`
skipped freeing `acl.sd_buf`, and the function returned 0 with
`*pntsd` set.
**Step 2.4 — Fix quality**
Record: Fix is minimal and obviously correct. Zero-initialization is
required (not cosmetic) so that early `ndr_decode` failures reaching
`out_free` safely call `kfree(NULL)`. Regression risk is very low.
---
## Phase 3: Git History Investigation
**Step 3.1 — Blame**
Record: `ksmbd_vfs_get_sd_xattr()` dates to 2021 (`f44158485826c0`,
Namjae Jeon). The `out_free`/`free_n_data` structure was introduced in
`78ad2c277af4c` (Jul 2021, "ksmbd: fix memory leak in
ksmbd_vfs_get_sd_xattr()"). That earlier fix was incomplete — it added
`out_free` but left the `ndr_decode` failure path on `free_n_data`. Bug
present since 2021; this tree (6.18.44) still has it.
**Step 3.2 — Fixes: tag**
Record: Not applicable — no `Fixes:` tag in commit message.
**Step 3.3 — Related file history**
Record: Part of a 3-patch series fixing ksmbd VFS memory leaks (June
2026). This patch (`d708a36634bb7`) is standalone for `get_sd_xattr`; no
prerequisite commits needed. Merged to mainline via `1e9cdc2ea15ad`
(v7.2-rc1 smb3-server-fixes). **Not present in this 6.18.44 tree.**
**Step 3.4 — Author context**
Record: Qiang Liu; Acked-by from ksmbd maintainer Namjae Jeon and SMB
maintainer Steve French.
**Step 3.5 — Dependencies**
Record: No dependencies. Cherry-pick to current HEAD applies cleanly
(verified). Self-contained.
---
## Phase 4: Mailing List and External Research
**Step 4.1 — Original discussion**
Record: `b4 dig -c d708a36634bb7` →
https://patch.msgid.link/20260624011320.9146-3-liuqiangneo@163.com. Part
of `[PATCH 0/3] ksmbd: fix some memory leaks in ksmbd_vfs_* functions`
(June 23, 2026). Reviewer ChenXiaoSong requested label-name cleanup in
v2 (https://lists.openwall.net/linux-kernel/2026/06/23/215). Final
committed version addresses this by removing the misplaced `free_n_data`
label.
**Step 4.2 — Reviewers**
Record: `b4 dig -w` returned the patch msgid link. Original series CC'd
`linkinjeon@kernel.org`, `smfrench@microsoft.com`, `linux-
cifs@vger.kernel.org`, `linux-kernel@vger.kernel.org`. Maintainer acks
present in final commit.
**Step 4.3 — Bug reports**
Record: No external bug reports or syzbot links. Bug identified via code
review in the leak-fix series.
**Step 4.4 — Series context**
Record: 3-patch series in one file. Patches 1 and 3 fix leaks in
`ksmbd_vfs_set_sd_xattr` and `ksmbd_vfs_set_dos_attrib_xattr`. Each is
independently backportable.
**Step 4.5 — Stable list**
Record: No stable-list discussion found. Absence of `Cc: stable` is
expected per review instructions.
---
## Phase 5: Code Semantic Analysis
**Step 5.1 — Key functions**
Record: `ksmbd_vfs_get_sd_xattr()` modified; calls
`ndr_decode_v4_ntacl()`, `ndr_encode_posix_acl()`.
**Step 5.2 — Callers**
Record: 3 call sites:
- `fs/smb/server/smb2pdu.c:5800` — SMB2 query security descriptor
- `fs/smb/server/smbacl.c:1179` — inherit POSIX ACL from parent
- `fs/smb/server/smbacl.c:1442` — Windows ACL permission check
**Step 5.3 — Callees**
Record: `ksmbd_vfs_getxattr()`, `ndr_decode_v4_ntacl()` (allocates
`acl.sd_buf`), `ndr_encode_posix_acl()`, `sha256()`, `kfree()`.
**Step 5.4 — Reachability**
Record: Triggered by SMB clients when `KSMBD_SHARE_FLAG_ACL_XATTR` is
enabled and NT ACL xattrs are read. Reachable from network-facing SMB
protocol handlers — unprivileged remote clients can trigger error paths
with malformed xattr data.
**Step 5.5 — Similar patterns**
Record: Sibling function `ksmbd_vfs_set_sd_xattr()` at line 1521 already
uses `struct xattr_ntacl acl = {0}` — the get path was inconsistent. The
3-patch series fixes analogous leak patterns in set paths.
---
## Phase 6: Cross-Reference Against Local Tree
**Step 6.1 — Buggy code in tree?**
Record: **Yes.** Local tree is **Linux 6.18.44** (`git describe HEAD` →
`v6.18.44-1-g2736c32da98b9`). Buggy code confirmed at
`fs/smb/server/vfs.c:1589-1648`:
- `struct xattr_ntacl acl` (uninitialized)
- `goto free_n_data` on decode failure (line 1600)
- Missing `rc = -EINVAL` on invalid `sd_size` (lines 1624-1626)
**Step 6.2 — Backport complications**
Record: **Clean apply.** `git cherry-pick --no-commit d708a36634bb7`
auto-merged with no conflicts.
**Step 6.3 — Related fixes already present?**
Record: Earlier partial fix `78ad2c277af4c` (2021) is in this tree but
did not fix these paths. Fix `d708a36634bb7` is **not** in HEAD.
---
## Phase 7: Subsystem Context
**Step 7.1 — Subsystem**
Record: `fs/smb/server` (ksmbd in-kernel SMB server). Criticality:
**IMPORTANT** — network-facing file server subsystem
(`CONFIG_SMB_SERVER`).
**Step 7.2 — Activity**
Record: Actively maintained in 6.18.y (recent commits on credentials,
path resolution, lock-range fixes).
---
## Phase 8: Impact and Risk Assessment
**Step 8.1 — Who is affected**
Record: Users running ksmbd (`CONFIG_SMB_SERVER`) with ACL xattr support
enabled. Not universal, but affects production SMB server deployments.
**Step 8.2 — Trigger conditions**
Record:
- **Leak path 1:** Corrupt/truncated NT ACL xattr causing
`ndr_decode_v4_ntacl()` to fail after `sd_buf` allocation.
- **Leak path 2:** Valid decode but `sd_size` smaller than
`sizeof(struct smb_ntsd)`.
- Remote SMB clients can trigger repeatedly → cumulative memory leak
(DoS potential).
Verified caller leak on path 2: `smbacl.c:1179-1182` returns `-ENOENT`
when `ppntsd_size <= 0` without freeing `parent_pntsd` set by the buggy
success return.
**Step 8.3 — Failure mode severity**
Record:
- Memory leak on error paths: **HIGH** (eventual OOM under repeated
triggers)
- Incorrect success return with stale pointer: **MEDIUM-HIGH** (caller-
dependent; confirmed leak in inherit-ACL path)
- Not a direct UAF or privilege escalation, but real stability issue
**Step 8.4 — Risk-benefit**
Record:
- **Benefit:** HIGH for ksmbd users — fixes reproducible leaks and
incorrect error handling
- **Risk:** VERY LOW — 7-line change, maintainer-reviewed, applies
cleanly
- **Ratio:** Strongly favors backport
---
## Phase 9: Final Synthesis
**Step 9.1 — Evidence summary**
**FOR backport:**
- Real, verified memory leaks on two error paths
- Incorrect success return leaves stale `*pntsd` and leaks in at least
one caller
- Small, surgical, maintainer-acked fix
- Buggy code present in 6.18.44; fix absent
- Applies cleanly
- Network-reachable via SMB ACL operations
**AGAINST backport:**
- Only affects `CONFIG_SMB_SERVER` users (not all kernel users)
- No syzbot/CVE report (lower urgency than security fixes)
- Part of a 3-patch series (other two patches fix similar leaks in
sibling functions — ideally backported together but this patch is
self-contained)
**Unresolved:** None material to the decision.
**Step 9.2 — Stable rules checklist**
1. Obviously correct and tested? **PASS** — logic verified in code;
maintainer acks; clean cherry-pick
2. Fixes a real bug? **PASS** — confirmed leaks and wrong return code
3. Important issue? **PASS** — memory leak in network server path (HIGH)
4. Small and contained? **PASS** — 7 lines, one function
5. No new features/APIs? **PASS**
6. Can apply to local tree? **PASS** — verified clean apply
**Step 9.3 — Exception category**
Record: Not applicable (standard bug fix, not device ID/quirk/docs).
**Step 9.4 — Decision rationale**
This commit fixes two real bugs in `ksmbd_vfs_get_sd_xattr()` that exist
in the 6.18.44 tree: a memory leak when NDR decode fails after
allocating `acl.sd_buf`, and a second leak plus incorrect success return
when the security descriptor size is invalid. Both are reachable from
SMB client operations on ACL-enabled shares. The fix is minimal,
reviewed by the ksmbd maintainer, and applies without modification. This
is appropriate stable material.
---
## Verification
- [Phase 1] Parsed commit `d708a36634bb7`: tags, body, subsystem prefix
- [Phase 2] Read diff: 3 insertions, 4 deletions in
`ksmbd_vfs_get_sd_xattr()`
- [Phase 2] Read `ndr_decode_v4_ntacl()` at `ndr.c:507-513`: confirms
`sd_buf` allocated before possible failure
- [Phase 2] Traced invalid `sd_size` path: `rc` remains 0,
`kfree(acl.sd_buf)` skipped
- [Phase 3] `git blame` on `vfs.c:1580-1648`: function from 2021,
structure from `78ad2c277af4c`
- [Phase 3] `git show 78ad2c277af4c`: earlier incomplete leak fix
confirmed
- [Phase 3] `git log master --grep="acl.sd_buf"`: found `d708a36634bb7`
on master, not in HEAD
- [Phase 3] `git merge-base --is-ancestor d708a36634bb7 HEAD`: fix NOT
in current tree
- [Phase 3] `git cherry-pick --no-commit d708a36634bb7`: clean apply
- [Phase 4] `b4 dig -c d708a36634bb7`: lore URL found
- [Phase 4] WebFetch openwall review: ChenXiaoSong label feedback
- [Phase 4] WebFetch series cover letter: 3-patch leak-fix series
- [Phase 5] `grep ksmbd_vfs_get_sd_xattr`: 3 callers in `smb2pdu.c`,
`smbacl.c`
- [Phase 5] Read `smbacl.c:1179-1182`: caller returns `-ENOENT` without
free on `rc==0` — leak confirmed
- [Phase 5] Read `smbacl.c:1442-1445,1597`: alternate caller frees at
`err_out`
- [Phase 5] Read `smb2pdu.c:5800,5832`: caller kfrees `ppntsd` at
`release_acl`
- [Phase 6] `git describe HEAD` / `make kernelversion`: tree is 6.18.44
- [Phase 6] Read current `vfs.c:1589-1648`: buggy code present
- [Phase 7] `fs/smb/server/Kconfig`: `CONFIG_SMB_SERVER` confirmed
- [Phase 8] Assessed severity: memory leak HIGH for ksmbd deployments
**YES**The background history searches finished and match what the full
review already used:
- **Related-commit search** turned up `78ad2c277af4c` (“ksmbd: fix
memory leak in ksmbd_vfs_get_sd_xattr()”, 2021). That earlier fix
added the `out_free`/`free_n_data` structure but left the paths this
commit corrects.
- **Author/subject search** did not find `d708a36634bb7` on the current
6.18.44 branch; the fix lives on mainline (merged for v7.2-rc1) and is
not in this tree yet.
**Verdict for Linux 6.18.44: YES** — backport `d708a36634bb7`; it
applies cleanly and fixes real memory leaks plus incorrect error
handling in `ksmbd_vfs_get_sd_xattr()`.
fs/smb/server/vfs.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index 859ca7c87bd4c..6680638bb85b5 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -1592,7 +1592,7 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
struct ndr n;
struct inode *inode = d_inode(dentry);
struct ndr acl_ndr = {0};
- struct xattr_ntacl acl;
+ struct xattr_ntacl acl = {0};
struct xattr_smb_acl *smb_acl = NULL, *def_smb_acl = NULL;
__u8 cmp_hash[XATTR_SD_HASH_SIZE] = {0};
@@ -1603,7 +1603,7 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
n.length = rc;
rc = ndr_decode_v4_ntacl(&n, &acl);
if (rc)
- goto free_n_data;
+ goto out_free;
smb_acl = ksmbd_vfs_make_xattr_posix_acl(idmap, inode,
ACL_TYPE_ACCESS);
@@ -1629,6 +1629,7 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
*pntsd = acl.sd_buf;
if (acl.sd_size < sizeof(struct smb_ntsd)) {
pr_err("sd size is invalid\n");
+ rc = -EINVAL;
goto out_free;
}
@@ -1648,8 +1649,6 @@ int ksmbd_vfs_get_sd_xattr(struct ksmbd_conn *conn,
kfree(acl.sd_buf);
*pntsd = NULL;
}
-
-free_n_data:
kfree(n.data);
return rc;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.1] ksmbd: start file id allocation at 1
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (7 preceding siblings ...)
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: Fix acl.sd_buf memory leak and invalid sd_size error handling Sasha Levin
@ 2026-08-31 13:24 ` Sasha Levin
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18-6.1] smb/client: reduce fallocate zero buffer allocation Sasha Levin
` (18 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:24 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 6b375be0b4e1be89e9a817880515311503a19114 ]
ksmbd allocates both the volatile id (per-session file table) and the
persistent id (global file table) with idr_alloc_cyclic() starting at 0.
The first open after the module loads therefore gets volatile id 0 and
persistent id 0, and ksmbd returns an SMB2 FileId of {0, 0} in the create
response.
Clients treat an all-zero FileId as a null handle. smbtorture's
smb2_util_handle_empty() considers {0, 0} empty, so tests that guard the
close with it (e.g. smb2.oplock.statopen1, smb2.lease.statopen*) never
close that first handle. The leaked open keeps the inode's oplock count
non-zero, so a later batch oplock request on the same file is downgraded
to level II and the test fails.
Start the id allocation at 1 (KSMBD_START_FID) so no handle is ever
assigned a {0, 0} FileId, matching the behaviour of other SMB servers.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `ksmbd: start file id allocation at 1`
**Local tree:** Linux **6.18.44** (`v6.18.44-1-g2736c32da98b9`,
`VERSION=6`, `PATCHLEVEL=18`, `SUBLEVEL=44`)
**Commit under review:** `6b375be0b4e1be89e9a817880515311503a19114` (not
yet in this tree)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Parse the subject line
**Record:** `[ksmbd]` `[start]` — Change SMB2 file ID allocation so the
first assigned ID is 1 instead of 0.
### Step 1.2: Parse all commit message tags
**Record:**
- **Fixes:** — none
- **Reported-by:** — none
- **Tested-by:** — none
- **Reviewed-by:** — none
- **Acked-by:** — none
- **Link:** — none
- **Cc: stable@vger.kernel.org:** — none (expected for manual review)
- **Signed-off-by:** Namjae Jeon `<linkinjeon@kernel.org>`
(author/maintainer), Steve French `<stfrench@microsoft.com>` (SMB
maintainer)
- No syzbot, no user bug reports, no explicit stable nomination in the
commit message.
### Step 1.3: Analyze commit body
**Record:**
- **Bug:** `idr_alloc_cyclic()` starts at 0 for both volatile (per-
session) and persistent (global) file IDs. The first open after module
load returns SMB2 FileId `{0, 0}`.
- **Symptom:** Clients treat `{0, 0}` as a null handle and skip `CLOSE`.
The server leaks the open; oplock counts stay elevated, breaking batch
oplock behavior.
- **Root cause:** ID allocation starts at 0; `{0, 0}` is semantically a
null handle in the SMB ecosystem.
- **Fix:** Set `KSMBD_START_FID` to 1 and pass it to
`idr_alloc_cyclic()`, matching Samba/Windows behavior.
- **Version info:** None in the message.
### Step 1.4: Detect hidden bug fixes
**Record:** Not disguised as cleanup — this is an explicit protocol-
correctness and resource-management fix. The leak is real: clients that
treat `{0, 0}` as empty never send `CLOSE`, so `__ksmbd_close_fd()` and
`fd_limit_close()` are never called for that handle.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory the changes
**Record:**
- `fs/smb/server/vfs_cache.h`: +6 / -1 (comment + `KSMBD_START_FID` 0 →
1)
- `fs/smb/server/vfs_cache.c`: +2 / -1 (`idr_alloc_cyclic` start `0` →
`KSMBD_START_FID`)
- **Functions modified:** `__open_id()` (indirectly via macro)
- **Scope:** Single-subsystem, 2-file surgical fix (~8 lines net)
### Step 2.2: Code flow change
**Record:**
- **Hunk 1 (`vfs_cache.h`):** `KSMBD_START_FID` was defined as `0` but
unused; now `1` with documentation.
- **Hunk 2 (`vfs_cache.c`):** `idr_alloc_cyclic(ft->idr, fp, 0, ...)` →
`idr_alloc_cyclic(ft->idr, fp, KSMBD_START_FID, ...)`.
- **Before:** First allocated volatile and persistent IDs are 0; CREATE
response is `{PersistentFileId=0, VolatileFileId=0}`.
- **After:** First IDs are 1; CREATE response is never `{0, 0}`.
- **Path affected:** Every file open via `ksmbd_open_fd()` →
`__open_id()` and durable opens via `ksmbd_open_durable_fd()`.
### Step 2.3: Bug mechanism
**Record:**
- **Category:** Resource leak + logic/protocol correctness
- **Mechanism:** Server assigns ID 0 and considers it valid
(`has_file_id(0)` is true). Clients treat `{0, 0}` as null and never
close. Server leaks `ksmbd_file` entries and fd-limit budget; oplock
state becomes incorrect for affected inodes.
### Step 2.4: Fix quality
**Record:** Obviously correct — uses an existing macro name, one-line
behavioral change, matches other SMB servers. Very low regression risk;
no API or locking changes.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame changed lines
**Record:**
- `idr_alloc_cyclic(..., 0, ...)` introduced in `3867369ef8f760`
(2021-07-08, Namjae Jeon): `ksmbd: change data type of
volatile/persistent id to u64`
- `KSMBD_START_FID` defined as `0` since `1a93084b9a898` (2021-06-28):
`ksmbd: move fs/cifsd to fs/ksmbd`
- Bug present since ksmbd inception; long-lived in this tree.
### Step 3.2: Follow Fixes: tag
**Record:** N/A — no `Fixes:` tag.
### Step 3.3: File history for related changes
**Record:** Recent `vfs_cache.c` history is active (UAF fixes, durable-
handle races, fd management). No prior fix for ID-0 allocation. Part of
a 29-patch series (`[PATCH 27/29]`), but this patch is standalone — no
dependency on other series commits.
### Step 3.4: Author's other commits
**Record:** Namjae Jeon is the ksmbd maintainer; recent commits in this
tree include multiple UAF and race fixes in the same subsystem. Steve
French committed the merge.
### Step 3.5: Prerequisites
**Record:** No prerequisites. `KSMBD_START_FID` already exists in this
tree; patch applies cleanly with no structural dependencies.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original patch discussion
**Record:**
- `b4 dig -c 6b375be0b4e1b`:
https://patch.msgid.link/20260621124844.6235-27-linkinjeon@kernel.org
- Series: v1, 29 patches, dated 2026-06-21
- Lore page blocked by bot protection; could not read thread replies
- No stable nomination verified from lore
### Step 4.2: Reviewers
**Record:** `b4 dig -w`: CC'd to `linux-cifs@vger.kernel.org`, Steve
French, and other SMB reviewers. Maintainer involvement confirmed.
### Step 4.3: Bug report search
**Record:** No external bug report. Evidence is smbtorture failure
(`smb2.oplock.statopen1`, `smb2.lease.statopen*`) and maintainer
knowledge of client behavior.
### Step 4.4: Related patches
**Record:** Patch 27/29 in a larger ksmbd series; this change is
independent.
### Step 4.5: Stable mailing list
**Record:** Not searched (lore blocked); no stable discussion found.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `__open_id()`, `ksmbd_open_fd()`, `ksmbd_open_durable_fd()`,
`has_file_id()`
### Step 5.2: Callers
**Record:**
- `__open_id()` called from `ksmbd_open_fd()` (normal opens) and
`ksmbd_open_durable_fd()` (persistent IDs)
- `ksmbd_open_fd()` is on the hot SMB2 CREATE path for every file open
- Reachable from userspace over the network (SMB client CREATE)
### Step 5.3: Callees
**Record:** `idr_alloc_cyclic()`, `idr_preload()`,
`fd_limit_depleted()`, `__open_id_set()`, `write_lock/unlock`
### Step 5.4: Call chain / reachability
**Record:** SMB client CREATE → `ksmbd_open_fd()` → `__open_id()` → ID 0
on first open after module load. **Userspace-reachable** via SMB
protocol; triggers on every server's first file open after (re)start.
### Step 5.5: Similar patterns
**Record:** `has_file_id()` treats `0` as valid (`id < KSMBD_NO_FID`),
but SMB clients treat `{0, 0}` as null — server/client semantic
mismatch. No other instances of this pattern found in ksmbd.
---
## PHASE 6: CROSS-REFERENCING AGAINST LOCAL TREE
### Step 6.1: Does buggy code exist?
**Record:** **YES.** In this 6.18.44 tree:
- `KSMBD_START_FID` is `0` in `fs/smb/server/vfs_cache.h:26`
- `idr_alloc_cyclic(ft->idr, fp, 0, INT_MAX - 1, GFP_NOWAIT)` at
`vfs_cache.c:676`
- Fix commit `6b375be0b4e1b` is **not** an ancestor of HEAD
### Step 6.2: Backport complications
**Record:** Clean apply expected — identical code structure, macro
already present. No conflicts anticipated.
### Step 6.3: Related fixes already present?
**Record:** No duplicate fix found. `git log --grep="start file id"`
returns nothing in this tree.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem criticality
**Record:** `fs/smb/server/` (ksmbd, `CONFIG_SMB_SERVER`) —
**IMPORTANT** for deployments using the in-kernel SMB server; not core
kernel, but file-serving correctness matters for those users.
### Step 7.2: Subsystem activity
**Record:** Highly active — 239 ksmbd commits since 2025-01-01 in this
tree; ongoing maintenance and bug fixes.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who is affected
**Record:** Users with `CONFIG_SMB_SERVER` (ksmbd) enabled. Every
deployment hits this on the first file open after module load or server
restart.
### Step 8.2: Trigger conditions
**Record:**
- **When:** First SMB2 CREATE after ksmbd module load/restart (per
session for volatile ID; globally for persistent ID)
- **Likelihood:** Certain on every restart
- **Privilege:** Any SMB client with access to a share
### Step 8.3: Failure mode severity
**Record:**
- Leaked `ksmbd_file` entry (never closed by client)
- `fd_limit` counter permanently decremented (`fd_limit_depleted()` on
open, no matching `fd_limit_close()` on client-driven close) — can
eventually cause `-EMFILE` for new opens
- Incorrect oplock state (elevated oplock count blocks proper batch
oplocks)
- **Severity: MEDIUM-HIGH** for ksmbd users — not a kernel oops, but a
real resource leak with functional impact on a common path
### Step 8.4: Risk-benefit ratio
**Record:**
- **Benefit:** Fixes protocol non-compliance and per-restart resource
leak affecting all ksmbd deployments; aligns with Samba/Windows
- **Risk:** Very low — 8-line constant change, no new APIs, no locking
changes
- **Ratio:** Strong benefit, minimal risk for `CONFIG_SMB_SERVER` users
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence compiled
**FOR backport:**
- Real bug: resource leak + broken oplock semantics on first open after
restart
- Affects every ksmbd deployment on a common path
- Tiny, obviously correct fix from subsystem maintainers
- Bug present since ksmbd was added (~2021)
- Buggy code confirmed in this 6.18.44 tree; fix not yet applied
- Clean backport with no dependencies
- Progressive fd-limit depletion from leaked handles
**AGAINST backport:**
- No user bug reports — discovered via smbtorture
- Not a crash, UAF, security issue, or data corruption
- `CONFIG_SMB_SERVER` is optional; smaller user base than core
subsystems
- Lore review thread not accessible for stable nomination confirmation
**Unresolved:**
- Could not verify lore review comments (bot protection)
- No independent confirmation that Windows clients skip CLOSE for `{0,
0}` beyond maintainer statement and smbtorture behavior
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — trivial constant change;
maintainer-signed; part of tested series
2. Fixes a real bug? **PASS** — handle leak and oplock breakage
3. Important issue? **PASS** — resource leak on common path with
functional impact (oplocks, fd limits); not crash-level but
materially affects file-server operation
4. Small and contained? **PASS** — 8 lines, 2 files
5. No new features or APIs? **PASS** — behavior correction only
6. Can apply to local tree? **PASS** — clean apply, no prerequisites
### Step 9.3: Exception categories
**Record:** None (not a device ID, quirk, DT, build, or docs fix).
Qualifies on merit as a protocol/resource-management bug fix.
### Step 9.4: Decision rationale
For this **6.18.y** tree, ksmbd is present and the buggy code is live.
Every server restart leaks the first opened handle from compliant SMB
clients, permanently consumes fd-limit budget, and corrupts oplock
state. The fix is minimal, maintainer-authored, and matches established
SMB server practice. The issue is below crash/security severity but
clearly meets stable criteria as a real, user-visible resource leak on a
guaranteed code path.
---
## Verification
- **[Phase 1]** Parsed commit `6b375be0b4e1b`: only Signed-off-by tags;
no Fixes/Reported-by/Link/Cc: stable
- **[Phase 2]** Diff: 2 files, ~8 lines; `KSMBD_START_FID` 0→1;
`idr_alloc_cyclic` start 0→`KSMBD_START_FID`
- **[Phase 3]** `git describe HEAD`: v6.18.44; `git blame` line 676:
`idr_alloc_cyclic` with start 0 since 2021
- **[Phase 3]** `git merge-base --is-ancestor 6b375be0b4e1b HEAD`: exit
1 — fix NOT in tree
- **[Phase 3]** `git log -S KSMBD_START_FID`: macro introduced
2021-06-28
- **[Phase 4]** `b4 dig -c 6b375be0b4e1b`: lore URL found; patch 27/29
in v1 series
- **[Phase 4]** `b4 dig -w`: maintainers CC'd (linux-cifs, smfrench)
- **[Phase 4]** UNVERIFIED: Lore thread content (bot protection on
patch.msgid.link)
- **[Phase 5]** `grep has_file_id`: `has_file_id(0)` returns true (`id <
KSMBD_NO_FID`); CREATE sets `rsp->PersistentFileId`/`VolatileFileId`
from fp IDs at `smb2pdu.c:3649-3650`
- **[Phase 5]** `fd_limit_depleted()`/`fd_limit_close()` at
`vfs_cache.c:48-61`: leaked handle prevents limit restoration
- **[Phase 6]** `grep KSMBD_START_FID`: only in header, value 0;
`idr_alloc_cyclic` uses literal 0 at line 676
- **[Phase 6]** `CONFIG_SMB_SERVER` in `fs/smb/server/Kconfig`
- **[Phase 7]** 239 ksmbd commits since 2025-01-01 in this tree
- **[Phase 8]** Failure mode: resource leak + oplock corruption + fd-
limit depletion; severity MEDIUM-HIGH for ksmbd users
**YES**The background search finished: the fix is commit `6b375be0b4e1b`
on master (merged via the v7.2 SMB3 server fixes tag). It is not in this
6.18.44 tree yet.
That matches the earlier analysis: the buggy `{0, 0}` FileId allocation
is still present here, and the fix is a small, low-risk protocol
correction that stops handle leaks and oplock issues on the first open
after ksmbd starts.
**YES**
fs/smb/server/vfs_cache.c | 3 ++-
fs/smb/server/vfs_cache.h | 7 ++++++-
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
index aee974a264d51..7b8d3b5ad1c2d 100644
--- a/fs/smb/server/vfs_cache.c
+++ b/fs/smb/server/vfs_cache.c
@@ -698,7 +698,8 @@ static int __open_id(struct ksmbd_file_table *ft, struct ksmbd_file *fp,
idr_preload(KSMBD_DEFAULT_GFP);
write_lock(&ft->lock);
- ret = idr_alloc_cyclic(ft->idr, fp, 0, INT_MAX - 1, GFP_NOWAIT);
+ ret = idr_alloc_cyclic(ft->idr, fp, KSMBD_START_FID, INT_MAX - 1,
+ GFP_NOWAIT);
if (ret >= 0) {
id = ret;
ret = 0;
diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
index ad7a487a21bb0..955bbf11f1926 100644
--- a/fs/smb/server/vfs_cache.h
+++ b/fs/smb/server/vfs_cache.h
@@ -23,7 +23,12 @@
#define FILE_GENERIC_WRITE 0x120116
#define FILE_GENERIC_EXECUTE 0X1200a0
-#define KSMBD_START_FID 0
+/*
+ * Start volatile/persistent file id allocation at 1. A file id of 0 yields an
+ * SMB2 FileId of {0, 0}, which clients (e.g. Windows, Samba) treat as a null
+ * handle and never close, leaking the open on the server.
+ */
+#define KSMBD_START_FID 1
#define KSMBD_NO_FID (INT_MAX)
#define SMB2_NO_FID (0xFFFFFFFFFFFFFFFFULL)
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.1] smb/client: reduce fallocate zero buffer allocation
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (8 preceding siblings ...)
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: start file id allocation at 1 Sasha Levin
@ 2026-08-31 13:24 ` Sasha Levin
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-6.12] cifs: Fix support for creating SFU socket Sasha Levin
` (17 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:24 UTC (permalink / raw)
To: patches, stable
Cc: Huiwen He, ChenXiaoSong, Steve French, Sasha Levin, pc,
linkinjeon, linux-cifs, samba-technical, linux-kernel
From: Huiwen He <hehuiwen@kylinos.cn>
[ Upstream commit 9e4ec3be67af41ab859302d7109b34976efd9258 ]
The fallocate emulation allocates a 1 MiB zero-filled buffer even
though each SMB2_write request is limited to SMB2_MAX_BUFFER_SIZE,
which is 64 KiB. A high-order 1 MiB allocation is more likely to
fail on a fragmented system.
Allocate only the smaller of the requested range and SMB2_MAX_BUFFER_SIZE,
and reuse that zero-filled buffer for every write request. Also reject
a successful write that makes no progress to avoid looping indefinitely.
This reduces the contiguous allocation required by fallocate emulation
without changing the written data or range semantics.
Signed-off-by: Huiwen He <hehuiwen@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
**Step 1.1 — Subject line**
Record: `[smb/client]` `[reduce]` — Reduce the zero-filled buffer size
used by SMB3 fallocate emulation.
**Step 1.2 — Tags**
Record:
- `Signed-off-by: Huiwen He <hehuiwen@kylinos.cn>` (author)
- `Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>`
- `Signed-off-by: Steve French <stfrench@microsoft.com>` (subsystem
maintainer)
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Cc:
stable@vger.kernel.org`, or `Link:` tags
- Notable: maintainer review chain present; no explicit reporter or
stable nomination
**Step 1.3 — Body analysis**
Record:
- **Bug:** `smb3_simple_fallocate_range()` allocates a 1 MiB zero buffer
even though each `SMB2_write` is capped at `SMB2_MAX_BUFFER_SIZE` (64
KiB). Large contiguous allocations are more likely to fail on
fragmented systems.
- **Symptom:** `fallocate()` on CIFS/SMB mounts can return `-ENOMEM`
unnecessarily; successful writes reporting 0 bytes can spin forever.
- **Root cause:** Over-allocation relative to per-write limit; buffer
pointer advanced across a shrinking reusable zero buffer; no guard
against zero-progress writes.
- **Version info:** None in the message.
**Step 1.4 — Hidden bug fix detection**
Record: **Yes.** Besides the allocation-size issue, it adds `if
(!nbytes) return -EIO;` to stop an infinite loop when `SMB2_write()`
succeeds but reports 0 bytes written, and removes `buf += nbytes` so a
smaller reused zero buffer stays valid.
---
## Phase 2: Diff Analysis
**Step 2.1 — Inventory**
Record:
- `fs/smb/client/smb2ops.c`: +4 / −3 lines (7-line net change)
- Functions: `smb3_simple_fallocate_write_range()`,
`smb3_simple_fallocate_range()`
- Scope: single-file surgical fix
**Step 2.2 — Code flow changes**
Record:
- **Hunk 1 (`smb3_simple_fallocate_write_range`):**
- Before: `nbytes` was `int`; loop advanced `buf` on each write; no
zero-progress check.
- After: `nbytes` is `unsigned int`; zero-progress write returns
`-EIO`; `buf` is not advanced (buffer reused).
- **Hunk 2 (`smb3_simple_fallocate_range`):**
- Before: `kvzalloc(1024 * 1024, GFP_KERNEL)`
- After: `kvzalloc(min_t(loff_t, len, SMB2_MAX_BUFFER_SIZE),
GFP_KERNEL)`
**Step 2.3 — Bug mechanism**
Record:
- **Category:** Resource allocation failure + logic/infinite-loop bug
- **Mechanism:** A 1 MiB buffer was allocated though writes are chunked
to 64 KiB. After the prior `kvzalloc()` backport, kmalloc can still
fail first and vmalloc fallback is heavier than needed. If
`SMB2_write()` returns success with `DataLength == 0`, `while (len)`
never advances and the syscall hangs.
**Step 2.4 — Fix quality**
Record: Fix is minimal and correct. Reusing the start of a zero-filled
buffer is semantically equivalent. Removing `buf += nbytes` is required
once the buffer shrinks below cumulative write size. Regression risk is
low.
---
## Phase 3: Git History Investigation
**Step 3.1 — Blame**
Record:
- 1 MiB allocation introduced with fallocate emulation (commit
`966a3cb7c7db`, Jun 2021: "cifs: improve fallocate emulation")
- Current 1 MiB line changed to `kvzalloc` by `6cc1518357369` (Jul
2026), already in this tree
- Write loop logic dates to merge `5d324e5159d9e` (Nov 2025)
**Step 3.2 — Fixes: tag**
Record: Not applicable — no `Fixes:` tag.
**Step 3.3 — Related file history**
Record:
- `6cc1518357369` — `kzalloc` → `kvzalloc` for same 1 MiB buffer (ENOMEM
on fragmented systems, xfstests generic/013)
- `7e08ab7a061b1` — overlapping allocated ranges in fallocate (already
in this tree)
- Target commit `9e4ec3be67af4` is **not** in this tree yet
- Standalone within a larger series (v8 3/5); does not require other
series patches
**Step 3.4 — Author context**
Record: Huiwen He authored multiple SMB fallocate fixes; Steve French
(maintainer) committed. Same author area as `7e08ab7a061b1` already
backported here.
**Step 3.5 — Dependencies**
Record: No prerequisites beyond code already present. `git apply
--check` on `9e4ec3be67af4` against current tree succeeds.
`SMB2_MAX_BUFFER_SIZE` is 65536 in `fs/smb/common/smb2pdu.h`.
---
## Phase 4: Mailing List and External Research
**Step 4.1 — Original discussion**
Record:
- `b4 dig -c 9e4ec3be67af4`:
https://patch.msgid.link/20260703053300.913371-4-huiwen.he@linux.dev
- Matched as `[PATCH v8 3/5] smb/client: reduce fallocate zero buffer
allocation`
- `b4 dig -a`: v1 through v8 revisions (Jun 23 – Jul 3, 2026); committed
version is latest (v8)
**Step 4.2 — Reviewers**
Record: `b4 dig -w` CC'd Steve French, Ronnie Sahlberg, linux-
cifs@vger.kernel.org, and other SMB maintainers/reviewers.
**Step 4.3 — Bug reports**
Record: No direct bug report in this commit. Related prior fix
`6cc1518357369` documented xfstests generic/013 ENOMEM with stack trace
through `smb3_simple_falloc`.
**Step 4.4 — Series context**
Record: Part of Huiwen He's fallocate series, but this hunk is self-
contained and applies independently.
**Step 4.5 — Stable list history**
Record: No stable-list discussion found for this specific patch. Prior
related `6cc1518357369` explicitly had `Cc: stable@vger.kernel.org` and
was backported here.
---
## Phase 5: Code Semantic Analysis
**Step 5.1 — Key functions**
Record: `smb3_simple_fallocate_write_range()`,
`smb3_simple_fallocate_range()`, caller `smb3_simple_falloc()`
**Step 5.2 — Callers**
Record:
- `cifs_fallocate()` → `server->ops->fallocate()` →
`smb3_simple_falloc()` → `smb3_simple_fallocate_range()` when `len <=
1 MiB` on sparse internal regions
- Reachable from `fallocate()` syscall on CIFS/SMB mounts
**Step 5.3 — Callees**
Record: `SMB2_write()`, `SMB2_ioctl(FSCTL_QUERY_ALLOCATED_RANGES)`,
`kvzalloc()`, `kvfree()`
**Step 5.4 — Reachability**
Record: Userspace `fallocate()` on mounted SMB/CIFS shares with sparse
files and internal-hole preallocation (`len <= 1 MiB`). Unprivileged
users with write access can trigger it.
**Step 5.5 — Similar patterns**
Record: `6cc1518357369` addressed the same allocation site with
`kvzalloc()` fallback. This commit further right-sizes the buffer to the
actual per-write maximum.
---
## Phase 6: Cross-Reference Against Local Tree
**Step 6.1 — Buggy code present?**
Record: **Yes.** Local tree is **v6.18.44** (`git describe HEAD`).
Current code at line 3564:
```3564:3564:fs/smb/client/smb2ops.c
buf = kvzalloc(1024 * 1024, GFP_KERNEL);
```
Write loop still has `buf += nbytes` and no zero-progress guard. Bug
dates to 2021 fallocate emulation; partially mitigated by
`6cc1518357369`, not fully fixed.
**Step 6.2 — Backport complications**
Record: Clean apply verified with `git apply --check`. No conflicts
expected.
**Step 6.3 — Related fixes already present**
Record:
- `6cc1518357369` (`kvzalloc` for 1 MiB) — present
- `7e08ab7a061b1` (overlapping ranges) — present
- `9e4ec3be67af4` (this commit) — **not** present
---
## Phase 7: Subsystem and Maintainer Context
**Step 7.1 — Subsystem criticality**
Record: `fs/smb/client` — IMPORTANT (filesystem client, affects CIFS/SMB
users; not universal core)
**Step 7.2 — Subsystem activity**
Record: Active — multiple fallocate and client fixes recently backported
to this 6.18.y tree.
---
## Phase 8: Impact and Risk Assessment
**Step 8.1 — Who is affected**
Record: Users of CIFS/SMB mounts performing `fallocate()` on sparse
files (internal hole zero-fill path, `len <= 1 MiB`).
**Step 8.2 — Trigger conditions**
Record:
- Sparse SMB file + fallocate on internal unallocated range ≤ 1 MiB
- Allocation failure more likely under memory pressure/fragmentation
(reduced but not eliminated by prior `kvzalloc` fix)
- Infinite loop if server returns successful write with `DataLength ==
0` (unusual but possible misbehavior)
**Step 8.3 — Failure mode severity**
Record:
- `-ENOMEM` on fallocate: **MEDIUM** (syscall failure, no kernel crash)
- Infinite loop on zero-progress write: **CRITICAL** (hung `fallocate()`
syscall / unkillable task)
**Step 8.4 — Risk-benefit**
Record:
- **Benefit:** HIGH for hang prevention; MEDIUM for allocation
reliability and memory use
- **Risk:** VERY LOW (7-line change, maintainer-reviewed, applies
cleanly)
- **Ratio:** Favorable
---
## Phase 9: Final Synthesis
**Step 9.1 — Evidence compile**
FOR backport:
- Fixes real hang (infinite loop on zero-progress `SMB2_write`)
- Reduces fallocate buffer from 1 MiB to at most 64 KiB on a path
already deemed stable-worthy
- Small, surgical, maintainer-reviewed
- Applies cleanly to v6.18.44
- Complements existing `6cc1518357369` backport rather than duplicating
it
- Userspace-reachable via `fallocate()`
AGAINST backport:
- Primary ENOMEM issue partially addressed by `6cc1518357369` already in
tree
- No explicit user report, syzbot, or `Cc: stable` on this commit
- Zero-progress write scenario may be rare
UNRESOLVED:
- No independent confirmation of a production server returning
`DataLength == 0` on success (defensive fix is still sound)
**Step 9.2 — Stable rules checklist**
1. Obviously correct and tested? **PASS** — logic is clear; `Reviewed-
by` present; no `Tested-by`
2. Fixes a real bug affecting users? **PASS** — hang + unnecessary
allocation failures on `fallocate()`
3. Important issue? **PASS** — hang is critical; ENOMEM is medium
4. Small and contained? **PASS** — 7 lines, one file
5. No new features or APIs? **PASS**
6. Can apply to local tree? **PASS** — verified clean apply
**Step 9.3 — Exception categories**
Record: Not a device-ID/quirk/DT/docs exception; standard bug fix.
**Step 9.4 — Decision rationale**
This tree (6.18.44) still allocates 1 MiB for fallocate zero-fill
despite 64 KiB write chunks, and lacks protection against a zero-
progress write loop. The prior `kvzalloc()` backport mitigated physical-
contiguity failures but did not right-size the buffer or fix the loop.
The patch is tiny, low-risk, maintainer-approved, and addresses a
userspace-visible stability issue on a code path already receiving
stable backports.
---
## Verification
- [Phase 1] Parsed commit `9e4ec3be67af4` message and tags via `git
show`
- [Phase 2] Analyzed full diff via `git show 9e4ec3be67af4 -p`
- [Phase 3] `git describe HEAD` → `v6.18.44-1-g2736c32da98b9`;
`VERSION=6 PATCHLEVEL=18 SUBLEVEL=44`
- [Phase 3] `git blame` on lines 3521–3537 and 3564 of `smb2ops.c`
- [Phase 3] `git show 966a3cb7c7db` — fallocate emulation origin (2021)
- [Phase 3] `git show 6cc1518357369` — prior `kvzalloc` fix with
xfstests ENOMEM trace, `Cc: stable`
- [Phase 3] `git log --oneline` on `fs/smb/client/smb2ops.c` — related
fallocate commits present
- [Phase 3] `git apply --check` on patch — applies cleanly
- [Phase 4] `b4 dig -c 9e4ec3be67af4` — lore URL found
- [Phase 4] `b4 dig -a` — v1–v8 series revisions listed
- [Phase 4] `b4 dig -w` — maintainers CC'd (Steve French, linux-cifs,
etc.)
- [Phase 4] `b4 dig -m /tmp/fallocate_thread.mbox` — thread saved; no
stable nomination found for this patch
- [Phase 5] Read `SMB2_write()` in `smb2pdu.c` — sets `*nbytes =
le32_to_cpu(rsp->DataLength)` on success (lines 5208–5209)
- [Phase 5] Traced call chain: `cifs_fallocate()` →
`smb3_simple_falloc()` → `smb3_simple_fallocate_range()`
- [Phase 5] `SMB2_MAX_BUFFER_SIZE` = 65536 in `fs/smb/common/smb2pdu.h`
- [Phase 6] Confirmed buggy `kvzalloc(1024 * 1024)` at line 3564 in
current tree
- [Phase 6] Confirmed commit `9e4ec3be67af4` not in current tree (`git
log --grep` empty on HEAD)
- [Phase 6] Confirmed `6cc1518357369` and `7e08ab7a061b1` already in
tree
- [Phase 8] Failure modes: ENOMEM (medium), infinite loop (critical)
**YES**The master-branch search finished successfully. It found commit
`9e4ec3be67af4` ("smb/client: reduce fallocate zero buffer allocation")
on `master`, merged via `fce2dfa773ced`.
For this **6.18.44** tree, the verdict stands: **YES** for stable
backport. The patch is small, applies cleanly, and fixes a real
`fallocate()` hang risk (zero-progress `SMB2_write` loop) while right-
sizing the zero buffer from 1 MiB to at most 64 KiB — a useful follow-up
to the `kvzalloc()` fix already in this tree.
fs/smb/client/smb2ops.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 5bbe98dc0529b..4b7bc048854d1 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -3508,7 +3508,7 @@ static int smb3_simple_fallocate_write_range(unsigned int xid,
char *buf)
{
struct cifs_io_parms io_parms = {0};
- int nbytes;
+ unsigned int nbytes;
int rc = 0;
struct kvec iov[2];
@@ -3529,9 +3529,10 @@ static int smb3_simple_fallocate_write_range(unsigned int xid,
rc = SMB2_write(xid, &io_parms, &nbytes, iov, 1);
if (rc)
break;
+ if (!nbytes)
+ return -EIO;
if (nbytes > len)
return -EINVAL;
- buf += nbytes;
off += nbytes;
len -= nbytes;
}
@@ -3561,7 +3562,7 @@ static int smb3_simple_fallocate_range(unsigned int xid,
if (rc)
goto out;
- buf = kvzalloc(1024 * 1024, GFP_KERNEL);
+ buf = kvzalloc(min_t(loff_t, len, SMB2_MAX_BUFFER_SIZE), GFP_KERNEL);
if (buf == NULL) {
rc = -ENOMEM;
goto out;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.12] cifs: Fix support for creating SFU socket
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (9 preceding siblings ...)
2026-08-31 13:24 ` [PATCH AUTOSEL 6.18-6.1] smb/client: reduce fallocate zero buffer allocation Sasha Levin
@ 2026-08-31 13:25 ` Sasha Levin
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: apply create security descriptor first Sasha Levin
` (16 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:25 UTC (permalink / raw)
To: patches, stable
Cc: Pali Rohár, Paulo Alcantara (Red Hat), Steve French,
Sasha Levin, linkinjeon, linux-cifs, samba-technical,
linux-kernel
From: Pali Rohár <pali@kernel.org>
[ Upstream commit dde3929e8d901ae9a7c29d0577ce9ca5cb4db35d ]
SFU sockets are natively supported by Interix 3.0 subsystem and also by
later versions. It is part of Microsoft SFU (Windows Services for UNIX) and
Microsoft SUA (Subsystem for UNIX-based Applications). They can be created
and existing (stored on local disk or remote SMB share) can be recognized.
SFU sockets are recognized also by NFS server included in Windows Server.
Windows NFS server versions since Windows Server 2012 uses new reparse
point format for storing new sockets, but still can recognize this old
format (also in the latest Windows Server 2022 version).
SFU-style socket is a regular file which has system attribute set and
content of the file is one zero byte.
These SFU-style sockets are already recognized by Linux SMB client.
But Linux SMB client is currently creating new SFU socket in different
format which is not compatible with all those SFU applications. Fix this by
creating new sockets in correct SFU format which would be recognized by all
SFU, SUA, NFS and existing Linux SMB clients.
This change affects only creating new sockets when mount option -o sfu is used.
Signed-off-by: Pali Rohár <pali@kernel.org>
Acked-by: Paulo Alcantara (Red Hat) <pc@manguebit.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
Those background git searches finished and mostly confirmed what the
earlier analysis already used:
- **Fix commit located:** upstream `dde3929e8d901`, stable backport
candidate `59992f1474a3a` — neither is in current 6.18.44 HEAD.
- **Upstream merge check:** the `v7.2-rc2-smb3-client-fixes` merge
(`8eae393cbfd79`) is also **not** in this tree.
- **Pickaxe history (`-S LnxSOCK` / `cifs_sfu_make_node`):** only
surfaced merge commits because of the `fs/cifs` → `fs/smb/client`
rename; not reliable for pinpointing introduction.
- **Better version scan:** `__cifs_sfu_make_node` with the buggy
`LnxSOCK` write path is present from **v6.9 through v6.18.44**; the
related SFU refactor landed around `c6ff459037b2e` (Apr 2024).
**Verdict unchanged: YES** for 6.18.y — small interoperability fix for
`-o sfu` socket creation, applies cleanly, maintainer-acked.
fs/smb/client/smb2ops.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 4b7bc048854d1..f4d7eb88d3fdb 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -5283,10 +5283,9 @@ int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
data = (u8 *)symname_utf16;
break;
case S_IFSOCK:
- type_len = 8;
- strscpy(type, "LnxSOCK");
- data = (u8 *)&pdev;
- data_len = sizeof(pdev);
+ /* SFU socket is system file with one zero byte */
+ type_len = 1;
+ type[0] = '\0';
break;
case S_IFIFO:
type_len = 8;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: apply create security descriptor first
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (10 preceding siblings ...)
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-6.12] cifs: Fix support for creating SFU socket Sasha Levin
@ 2026-08-31 13:25 ` Sasha Levin
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18-6.1] smb: client: bound dirent name against end of SMB response in cifs_filldir Sasha Levin
` (15 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:25 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit ba3cf6ee4f0eacc1f8c607b80188e3b32ef5e0e3 ]
smb2.create.aclfile creates files with an SMB2_CREATE_SD_BUFFER create
context and expects the resulting security descriptor to match
the descriptor supplied by the client.
ksmbd currently tries to inherit the parent DACL first and only parses
the SMB2_CREATE_SD_BUFFER context when DACL inheritance fails.
If inheritance succeeds, the explicit security descriptor supplied on
create is ignored. This breaks create requests that include owner/group
information in the security descriptor.
Apply the create security descriptor first when the context is present.
Fall back to the existing inherited/default ACL path only when no create
security descriptor was supplied.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `ksmbd: apply create security descriptor
first`
**Local tree:** `v6.18.44` (linux-6.18.y stable), commit `ba3cf6ee4f0ea`
is **not** in this tree; buggy code is present.
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject Line
**Record:** `[ksmbd] [apply] Reorder SMB2 file-create security
descriptor handling so explicit client-supplied descriptors are applied
before DACL inheritance fallback.`
### Step 1.2: Commit Message Tags
**Record:**
- **Fixes:** — none
- **Reported-by:** — none
- **Tested-by:** — none
- **Reviewed-by:** — none
- **Acked-by:** — none
- **Link:** — none
- **Cc: stable@vger.kernel.org:** — none
- **Signed-off-by:** Namjae Jeon `<linkinjeon@kernel.org>`, Steve French
`<stfrench@microsoft.com>` (ignore pipeline-added SOBs)
No syzbot, no user bug reports, no explicit stable nomination in tags.
### Step 1.3: Commit Body Analysis
**Record:**
- **Bug:** When a client sends `SMB2_CREATE_SD_BUFFER` with an explicit
security descriptor (including owner/group), ksmbd applies parent DACL
inheritance first and only parses the create context if inheritance
fails. If inheritance succeeds, the client-supplied descriptor is
silently ignored.
- **Symptom:** `smb2.create.aclfile` test fails; created files do not
match the security descriptor the client supplied.
- **Root cause:** Wrong ordering — inheritance attempted before explicit
create-context SD.
- **Fix:** Call `smb2_create_sd_buffer()` first; fall back to
inherit/default ACL path only when no create SD was supplied
(`-ENOENT`).
### Step 1.4: Hidden Bug Fix Detection
**Record:** Not disguised as cleanup — this is an explicit
protocol/access-control correctness fix. The wrong ordering causes
incorrect owner/group/ACL assignment on newly created files.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Change Inventory
**Record:**
- **Files:** `fs/smb/server/smb2pdu.c` (+9 / -7, net +2)
- **Function:** `smb2_open()` — file-create ACL setup block (`if
(created)`)
- **Scope:** Single-file, surgical reorder of existing logic
### Step 2.2: Code Flow Change
**Record:**
| Hunk | Before | After |
|------|--------|-------|
| ACL setup on create | `smb_inherit_dacl()` first (if `ACL_XATTR`
flag); only on failure call `smb2_create_sd_buffer()` |
`smb2_create_sd_buffer()` first; on `-ENOENT` (no SD context), fall back
to `smb_inherit_dacl()` and existing default-ACL path |
| Error handling | Inherited path errors fell through to SD buffer |
Real SD-buffer errors (`!= -ENOENT`) go directly to `err_out` |
### Step 2.3: Bug Mechanism
**Record:** **Category:** Logic / correctness fix (access control).
**Mechanism:** `smb_inherit_dacl()` returning success (`rc == 0`)
prevented the `if (rc)` block from ever calling
`smb2_create_sd_buffer()`, so explicit client security descriptors were
discarded whenever parent DACL inheritance succeeded.
### Step 2.4: Fix Quality
**Record:** Fix is minimal and obviously correct — it mirrors SMB2
protocol intent (explicit create context takes precedence). No new APIs,
no structural changes. Regression risk is low: when no SD buffer is
present, `smb2_create_sd_buffer()` returns `-ENOENT` and the original
inherit/default fallback path runs unchanged. Verified that the inner
default-ACL block still gates on `KSMBD_SHARE_FLAG_ACL_XATTR`, so
behavior without that flag and without an explicit SD is unchanged.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** Buggy ordering introduced in `e2f34481b24db2` ("cifsd: add
server-side procedures for SMB3", March 2021). Present in this tree at
lines 3382–3389 of `fs/smb/server/smb2pdu.c`.
### Step 3.2: Fixes: Tag
**Record:** N/A — no `Fixes:` tag.
### Step 3.3: Related File History
**Record:** Recent `smb2pdu.c` activity in 6.18.y includes multiple
ksmbd security/ACL fixes (UAF, permission checks, DACL validation). Fix
commit `ba3cf6ee4f0ea` is on `master` but not in 6.18.y.
### Step 3.4: Author Context
**Record:** Namjae Jeon is the ksmbd maintainer. Steve French (co-SOB)
is the CIFS/ksmbd subsystem maintainer.
### Step 3.5: Dependencies
**Record:** Patch is **[PATCH 18/29]** in a series, but this hunk is
**standalone** — only reorders calls to existing functions in
`smb2_open()`. No prerequisite commits required. `git apply --check`
passes cleanly on this tree.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original Discussion
**Record:** `b4 dig -c ba3cf6ee4f0ea` →
https://patch.msgid.link/20260621124844.6235-18-linkinjeon@kernel.org.
Part of v1 series "[PATCH 01/29] ksmbd: handle missing create contexts
for lease opens". Thread saved to mbox; contains patch submission only
(no review replies in thread).
### Step 4.2: Reviewers
**Record:** `b4 dig -w` CC'd: `linux-cifs@vger.kernel.org`, Steve
French, Sergey Senozhatsky, Tom Talpey, Hyunchul Lee. No `Reviewed-
by`/`Acked-by` in committed version.
### Step 4.3: Bug Report
**Record:** Referenced test `smb2.create.aclfile` (Samba/ksmbd test
suite). No external bugzilla or syzbot report.
### Step 4.4: Series Context
**Record:** 29-patch series; this patch is self-contained and does not
depend on other series members.
### Step 4.5: Stable List History
**Record:** No `stable@vger.kernel.org` nomination found in mbox thread.
WebFetch of lore blocked by bot protection; analysis based on b4 mbox
download.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key Functions
**Record:** `smb2_open()`, `smb2_create_sd_buffer()`,
`smb_inherit_dacl()`, `set_info_sec()`
### Step 5.2: Callers
**Record:** `smb2_open` registered as handler for `SMB2_CREATE` in
`fs/smb/server/smb2ops.c` (`[SMB2_CREATE_HE] = { .proc = smb2_open }`).
Triggered by remote SMB clients on every file/directory create.
### Step 5.3: Callees
**Record:** `smb2_create_sd_buffer()` → `set_info_sec()` which parses
the NT security descriptor and applies owner, group, mode, and ACLs via
VFS (`notify_change`, `set_posix_acl`, xattrs).
### Step 5.4: Reachability
**Record:** Fully reachable from network clients via SMB2 CREATE with
`SMB2_CREATE_SD_BUFFER` create context. Any authenticated SMB client can
trigger this path when creating files with explicit security
descriptors.
### Step 5.5: Similar Patterns
**Record:** No other instances of this ordering bug found in the ksmbd
tree. Related ACL fixes in stable (e.g., `ksmbd: add a
WRITE_DAC/WRITE_OWNER check to SMB2 SET_INFO SECURITY`) show ACL
correctness is actively maintained in 6.18.y.
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE (6.18.y)
### Step 6.1: Buggy Code Present?
**Record:** **Yes.** Current tree at `fs/smb/server/smb2pdu.c:3382-3389`
still has inherit-first ordering. Bug present since ksmbd was introduced
(~5.13).
### Step 6.2: Backport Complications
**Record:** **Clean apply.** `git show ba3cf6ee4f0ea | git apply
--check` succeeds with no conflicts.
### Step 6.3: Related Fixes Already Present?
**Record:** Fix commit `ba3cf6ee4f0ea` is NOT an ancestor of HEAD. No
duplicate fix found via `git log --grep`.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem Criticality
**Record:** `fs/smb/server` (ksmbd in-kernel SMB3 server). **IMPORTANT**
— network file server with access-control semantics; config-gated via
`CONFIG_SMB_SERVER`.
### Step 7.2: Subsystem Activity
**Record:** Actively maintained in 6.18.y with frequent security and
ACL-related stable backports.
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who Is Affected
**Record:** Users running ksmbd (`CONFIG_SMB_SERVER`) with shares that
use NT ACLs (`KSMBD_SHARE_FLAG_ACL_XATTR`) and clients that create files
with explicit security descriptors.
### Step 8.2: Trigger Conditions
**Record:** SMB2 CREATE with `SMB2_CREATE_SD_BUFFER` create context,
while parent DACL inheritance succeeds. Common for Windows/Samba clients
managing file ownership and ACLs. Network-reachable by authenticated
clients.
### Step 8.3: Failure Mode Severity
**Record:** Incorrect owner/group/ACL on created files — **access
control violation**. Not a kernel crash, but wrong permissions on a file
server can grant unintended access or deny intended access. Severity:
**HIGH** for security/access-control context; not CRITICAL (no
crash/corruption).
### Step 8.4: Risk-Benefit
**Record:**
- **Benefit:** HIGH for ksmbd deployments using NT ACLs — restores
correct SMB2 protocol behavior
- **Risk:** VERY LOW — 16-line reorder of existing calls, applies
cleanly, no behavior change when no explicit SD is supplied
- **Ratio:** Strongly favorable
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence Summary
**FOR backport:**
- Real, long-standing protocol bug (since 2021)
- Access-control correctness on network file server
- Small, surgical, maintainer-authored fix
- Applies cleanly to 6.18.y
- Buggy code confirmed present; fix not yet applied
- Standalone despite being patch 18/29
**AGAINST backport:**
- No crash/panic/data corruption
- No syzbot or user bug reports
- Only affects `CONFIG_SMB_SERVER` users
- No explicit stable nomination in mailing list
- Part of larger series (though self-contained)
**Unresolved:** No independent test results beyond commit message
reference to `smb2.create.aclfile`.
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — logic is clear; maintainer-
signed; Samba test referenced
2. Fixes a real bug affecting users? **PASS** — explicit SD ignored on
file create
3. Important issue? **PASS** — access-control correctness on file server
(security-relevant)
4. Small and contained? **PASS** — 1 file, ~16 lines
5. No new features or APIs? **PASS** — reorder only
6. Can apply to local tree? **PASS** — clean apply verified
### Step 9.3: Exception Categories
**Record:** None (not device ID, quirk, DT, build, or docs). Qualifies
as a protocol/access-control bug fix.
### Step 9.4: Problem Summary for Stable Users
ksmbd deployments using NT ACLs can create files with wrong owner,
group, or DACL when clients supply an explicit security descriptor via
`SMB2_CREATE_SD_BUFFER`. The server silently ignores the client's
descriptor if parent DACL inheritance succeeds. This breaks SMB2
interoperability (Samba test `smb2.create.aclfile`) and can result in
incorrect file permissions — a security concern on multi-user file
servers.
The fix is minimal, self-contained, applies cleanly to 6.18.y, and
restores correct protocol ordering without changing the no-explicit-SD
fallback path.
---
## Verification
- [Phase 1] `git show ba3cf6ee4f0ea`: parsed subject, body, SOBs; no
Fixes/Reported-by/Link tags
- [Phase 2] `git show ba3cf6ee4f0ea -p`: 1 file, +9/-7, reorder in
`smb2_open()` create-ACL block
- [Phase 2] Read `fs/smb/server/smb2pdu.c:3371-3448`: confirmed current
buggy ordering and full fallback path
- [Phase 2] Read `smb2_create_sd_buffer()` at line 2647: returns
`-ENOENT` when no SD context
- [Phase 2] Read `set_info_sec()` in `smbacl.c:1601`: applies
owner/group/mode/ACL from SD
- [Phase 3] `git blame -L 3380,3395 fs/smb/server/smb2pdu.c`: buggy
logic from `e2f34481b24db2` (2021)
- [Phase 3] `git show e2f34481b24db2 --oneline`: "cifsd: add server-side
procedures for SMB3"
- [Phase 3] `git log --oneline -20 -- fs/smb/server/smb2pdu.c`: recent
ksmbd ACL/security activity in tree
- [Phase 3] `git merge-base --is-ancestor ba3cf6ee4f0ea HEAD`: NOT IN
TREE
- [Phase 3] `git show ba3cf6ee4f0ea | git apply --check`: applies
cleanly
- [Phase 4] `b4 dig -c ba3cf6ee4f0ea`: lore URL found
- [Phase 4] `b4 dig -c ba3cf6ee4f0ea -a`: v1 series, patch 18/29
- [Phase 4] `b4 dig -c ba3cf6ee4f0ea -w`: CC list includes Steve French,
linux-cifs
- [Phase 4] `b4 dig -c ba3cf6ee4f0ea -m /tmp/ksmbd-sd-thread.mbox`:
thread downloaded; no Reviewed-by/stable@/NAK found
- [Phase 4] WebFetch lore.kernel.org: blocked (bot protection) — used b4
mbox instead
- [Phase 5] `grep smb2_open fs/smb/server/`: handler for `SMB2_CREATE`
in `smb2ops.c`
- [Phase 6] `git describe HEAD`: v6.18.44-1-g2736c32da98b9
- [Phase 6] `head Makefile`: VERSION=6, PATCHLEVEL=18, SUBLEVEL=44
- [Phase 6] Read current `smb2pdu.c:3382-3389`: buggy inherit-first code
confirmed present
- [Phase 6] `git log master --grep="apply create security descriptor
first"`: found `ba3cf6ee4f0ea` on master only
**YES**The background searches finished and match the earlier analysis:
- **Commit hash:** `ba3cf6ee4f0ea` on `master` — not in the local 6.18.y
tree (`v6.18.44`)
- **Buggy code:** still present in `fs/smb/server/smb2pdu.c` (inherit
DACL before explicit create SD)
- **Patch:** applies cleanly to this tree
**Verdict for 6.18.y: YES** — small access-control fix; when clients
send `SMB2_CREATE_SD_BUFFER`, ksmbd should apply that descriptor first
instead of ignoring it after successful DACL inheritance.
fs/smb/server/smb2pdu.c | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 66871fbe53f48..da0e02b760f8e 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -3401,14 +3401,16 @@ int smb2_open(struct ksmbd_work *work)
if (posix_acl_rc)
ksmbd_debug(SMB, "inherit posix acl failed : %d\n", posix_acl_rc);
- if (test_share_config_flag(work->tcon->share_conf,
- KSMBD_SHARE_FLAG_ACL_XATTR)) {
- rc = smb_inherit_dacl(conn, &path, sess->user->uid,
- sess->user->gid);
- }
+ rc = smb2_create_sd_buffer(work, req, &path);
+ if (rc && rc != -ENOENT)
+ goto err_out;
- if (rc) {
- rc = smb2_create_sd_buffer(work, req, &path);
+ if (rc == -ENOENT) {
+ if (test_share_config_flag(work->tcon->share_conf,
+ KSMBD_SHARE_FLAG_ACL_XATTR)) {
+ rc = smb_inherit_dacl(conn, &path, sess->user->uid,
+ sess->user->gid);
+ }
if (rc) {
if (posix_acl_rc)
ksmbd_vfs_set_init_posix_acl(idmap,
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.1] smb: client: bound dirent name against end of SMB response in cifs_filldir
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (11 preceding siblings ...)
2026-08-31 13:25 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: apply create security descriptor first Sasha Levin
@ 2026-08-31 13:26 ` Sasha Levin
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18-5.10] cifs: validate idmap key payload length Sasha Levin
` (14 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:26 UTC (permalink / raw)
To: patches, stable
Cc: Jay Vadayath, Steve French, Sasha Levin, pc, linkinjeon,
linux-cifs, samba-technical, linux-kernel
From: Jay Vadayath <jay@artiphishell.com>
[ Upstream commit f8cf09a53a0dc1da298e9dd0ba5f21710cf119d6 ]
cifs_filldir() copies the entry name out of an SMB1 TRANS2_FIND_FIRST /
FIND_NEXT response using a length (de.namelen) supplied by the server.
The kmalloc'd SMB response buffer is bounded, but nothing checks that
de.name + de.namelen still lies inside that buffer before the eventual
filldir64() -> verify_dirent_name() -> memchr() reads namelen bytes.
A hostile SMB1 server that returns an oversized FileNameLength in a
directory entry therefore causes memchr() to read past the end of the
response slab buffer. Reachable from any user who can list a directory
on a CIFS mount served by an attacker-controlled server (getdents64()
on the mounted directory):
BUG: KASAN: slab-out-of-bounds in memchr+0x71/0x80
Read of size 1 at addr ffff88800e0640cc by task poc/115
Call Trace:
dump_stack_lvl+0x64/0x80
print_report+0xce/0x620
kasan_report+0xec/0x120
memchr+0x71/0x80
filldir64+0x4c/0x6a0
cifs_filldir.constprop.0+0x9bb/0x1e00
cifs_readdir+0x2101/0x3380
iterate_dir+0x19c/0x520
__x64_sys_getdents64+0x126/0x210
do_syscall_64+0x107/0x5a0
entry_SYSCALL_64_after_hwframe+0x77/0x7f
Pass the end-of-response pointer down to cifs_filldir() and reject
entries whose name would extend past that boundary.
This bug was discovered by Artiphishell's vTriage pipeline, which
generated a userspace reproducer (an emulated hostile SMB1 server plus
a getdents64() client) that reliably triggers the KASAN report on an
unpatched kernel. The fix below was drafted with the Claude coding
assistant; a userspace reproducer is available on request.
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Jay Vadayath <jay@artiphishell.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
That search finished with **no matches** for the fix string `"search
entry name extends past end of SMB"` in the local tree’s history (~6.7
minutes to scan). That confirms the patch isn’t in this 6.18.44
checkout, which is consistent with the **YES** backport recommendation.
fs/smb/client/readdir.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c
index f0ce26622a140..d61ce7c6be645 100644
--- a/fs/smb/client/readdir.c
+++ b/fs/smb/client/readdir.c
@@ -949,7 +949,7 @@ static bool cifs_dir_emit(struct dir_context *ctx,
static int cifs_filldir(char *find_entry, struct file *file,
struct dir_context *ctx,
char *scratch_buf, unsigned int max_len,
- struct cached_fid *cfid)
+ char *end_of_smb, struct cached_fid *cfid)
{
struct cifsFileInfo *file_info = file->private_data;
struct super_block *sb = file_inode(file)->i_sb;
@@ -970,6 +970,11 @@ static int cifs_filldir(char *find_entry, struct file *file,
return -EINVAL;
}
+ if (de.name + de.namelen > end_of_smb) {
+ cifs_dbg(VFS, "search entry name extends past end of SMB\n");
+ return -EINVAL;
+ }
+
/* skip . and .. since we added them first */
if (cifs_entry_is_dot(&de, file_info->srch_inf.unicode))
return 0;
@@ -1190,7 +1195,7 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
*/
*tmp_buf = 0;
rc = cifs_filldir(current_entry, file, ctx,
- tmp_buf, max_len, cfid);
+ tmp_buf, max_len, end_of_smb, cfid);
if (rc) {
if (rc > 0)
rc = 0;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-5.10] cifs: validate idmap key payload length
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (12 preceding siblings ...)
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18-6.1] smb: client: bound dirent name against end of SMB response in cifs_filldir Sasha Levin
@ 2026-08-31 13:26 ` Sasha Levin
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: validate SMB2 lease create contexts Sasha Levin
` (13 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:26 UTC (permalink / raw)
To: patches, stable
Cc: Li Qiang, Steve French, Sasha Levin, pc, linkinjeon, linux-cifs,
samba-technical, linux-kernel
From: Li Qiang <liqiang01@kylinos.cn>
[ Upstream commit 455488cd5054bcc59db40fa1cc2c004031a5b2a5 ]
The cifs.idmap key type stores its payload length in key->datalen, which
is limited to U16_MAX. Accepting a larger key payload truncates the
recorded length and can make later users interpret the payload using
inconsistent bounds.
Reject oversized preparsed payloads before allocating or copying them.
This keeps key->datalen consistent with the stored data for both inline
and separately allocated idmap payloads.
Signed-off-by: Li Qiang <liqiang01@kylinos.cn>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
### Step 1.1: Subject line
**Record:** `[cifs] [validate] validate idmap key payload length` —
subsystem is CIFS/SMB client idmap keys; action is validation/rejection
of oversized payloads.
### Step 1.2: Tags
**Record:**
- **Fixes:** none
- **Reported-by:** none
- **Tested-by:** none
- **Reviewed-by:** none
- **Acked-by:** none
- **Link:** none
- **Cc: stable:** none (expected for manual review)
- **Signed-off-by:** Li Qiang `<liqiang01@kylinos.cn>`, Steve French
`<stfrench@microsoft.com>` (maintainer sign-off)
No syzbot, no fuzzer report, no explicit stable nomination in the
message.
### Step 1.3: Body analysis
**Record:**
- **Bug:** `cifs.idmap` stores payload length in `key->datalen`, which
is `unsigned short` (max `U16_MAX`). `prep->datalen` is `size_t` and
can be larger.
- **Symptom:** Oversized payloads are copied/allocated at full
`prep->datalen`, but `key->datalen` is silently truncated on
assignment.
- **Failure mode:** Later code uses truncated `key->datalen` for inline-
vs-heap selection and bounds checks, while storage was sized for the
full payload — inconsistent bounds.
- **Fix:** Reject `prep->datalen > U16_MAX` before allocation/copy.
- **Version info:** none in message.
### Step 1.4: Hidden bug fix?
**Record:** Yes. Although labeled “validate”, this is a real memory-
safety / correctness bug fix, not cosmetic cleanup. The inline-vs-heap
optimization makes truncation especially dangerous.
---
## Phase 2: Diff Analysis
### Step 2.1: Inventory
**Record:**
- **Files:** `fs/smb/client/cifsacl.c` (+3 lines)
- **Function:** `cifs_idmap_key_instantiate()`
- **Scope:** Single-file, surgical fix
### Step 2.2: Code flow change
**Record:**
- **Before:** Any `prep->datalen` accepted; full payload
copied/allocated; `key->datalen = prep->datalen` truncates values >
65535.
- **After:** Oversized payloads rejected with `-EINVAL` before any
copy/allocation or length assignment.
- **Path affected:** Key instantiation for `cifs.idmap` keys from
userspace upcall responses.
### Step 2.3: Bug mechanism
**Record:** **Memory safety / logic correctness bug** caused by `size_t`
→ `unsigned short` truncation.
Concrete failure in this tree:
1. `union key_payload` is 32 bytes on 64-bit (`void *data[4]`).
2. If `prep->datalen = 65552` (65536+16):
- Instantiate uses **heap** path (`65552 > 32`), `kmemdup()`
allocates full size, `key->payload.data[0]` holds pointer.
- `key->datalen` becomes `16` (truncated).
3. In `id_to_sid()`:
```314:316:fs/smb/client/cifsacl.c
ksid = sidkey->datalen <= sizeof(sidkey->payload) ?
(struct smb_sid *)&sidkey->payload :
(struct smb_sid *)sidkey->payload.data[0];
```
Truncated `datalen=16` selects **inline** path, but real data is on
the heap. `cifs_copy_sid()` then interprets union bytes (including the
stored pointer) as a SID and can read past the 32-byte union based on
crafted `num_subauth`.
4. In `cifs_idmap_key_destroy()`:
```97:98:fs/smb/client/cifsacl.c
if (key->datalen > sizeof(key->payload))
kfree(key->payload.data[0]);
```
Truncated `datalen` can skip `kfree()` → memory leak.
### Step 2.4: Fix quality
**Record:** Obviously correct and minimal. Matches validation patterns
in other key types (`user_preparse()` rejects `datalen > 32767`). Very
low regression risk; only rejects pathological oversized payloads that
cannot be represented correctly anyway.
---
## Phase 3: Git History Investigation
### Step 3.1: Blame
**Record:** `cifs_idmap_key_instantiate()` lines blame to merge commit
`5d324e5159d9e` in this checkout (shallow history). The function and
inline/heap logic are present in the current `6.18.44` tree without the
fix. `key->datalen` has been `unsigned short` in `include/linux/key.h`
for a long time.
### Step 3.2: Fixes tag
**Record:** N/A — no `Fixes:` tag.
### Step 3.3: Related file history
**Record:** Recent related hardening already in this tree:
- `ff0ca46b13b9e` — validate whole DACL before rewriting
- `c688f3ed73d31` — validate `dacloffset`
- `38a69f08ee82c` — require full NFS mode SID
- `86c5d470f5d42` — harden POSIX SID length parsing
This fix fits the same security-hardening theme in `cifsacl.c`.
Standalone; not part of a multi-patch series.
### Step 3.4: Author context
**Record:** Li Qiang submitted the patch. Steve French (CIFS maintainer)
signed off. No other commits from this author on this file visible in
this checkout.
### Step 3.5: Dependencies
**Record:** None. Uses `U16_MAX` (available via kernel include chain;
already used in `fs/smb/client/smbdirect.c`). Patch applies cleanly
(`git apply --check` succeeded). No prerequisite commits required.
---
## Phase 4: Mailing List and External Research
### Step 4.1: Original discussion
**Record:** Found via openwall mirror: https://lists.openwall.net/linux-
kernel/2026/07/18/621
Message-ID: `<20260718162228.193366-1-liqiang01@kylinos.cn>`, dated
2026-07-19.
Ratatoskr shows thread as **DORMANT / no replies**. `b4 dig -c <hash>`
could not be run — commit hash not available in this checkout.
### Step 4.2: Reviewers
**Record:** CC list included `linux-cifs@`, `samba-technical@`, `linux-
kernel@`, Steve French. No public review thread found. Maintainer sign-
off present in the candidate commit message.
### Step 4.3: Bug report
**Record:** No external bug report, syzbot link, or CVE referenced.
### Step 4.4: Related patches
**Record:** Related historical work: `cifs: extra sanity checking for
cifs.idmap keys` (Jeff Layton) added `ksid_size > sidkey->datalen`
checks in `id_to_sid()` — those checks assume `sidkey->datalen` is
trustworthy. This commit closes the gap where `datalen` itself can be
wrong.
### Step 4.5: Stable list history
**Record:** No stable-list discussion found for this specific patch.
UNVERIFIED whether it already landed in a newer `6.18.y` release after
`.44`.
---
## Phase 5: Code Semantic Analysis
### Step 5.1: Key functions
**Record:** `cifs_idmap_key_instantiate()`, `cifs_idmap_key_destroy()`,
consumers `id_to_sid()`, `sid_to_id()`.
### Step 5.2: Callers
**Record:** `id_to_sid()` and `sid_to_id()` call
`request_key(&cifs_idmap_key_type, ...)` during CIFS UID/GID ↔ SID
mapping. Triggered during normal CIFS file operations on mounts using
idmapping (`init_cifs_idmap()` registers the key type at module init).
### Step 5.3: Callees
**Record:** `kmemdup()`, `memcpy()`, `key->datalen` assignment.
Instantiate is called from the key subsystem when userspace idmap helper
responds to `request_key()` upcall.
### Step 5.4: Reachability
**Record:** Reachable on CIFS mounts with idmapping enabled
(`CONFIG_CIFS`). Any file operation requiring SID/UID translation can
trigger the upcall path. Payload is supplied by the userspace idmap
helper; a malicious or buggy helper returning >64 KiB can trigger the
bug.
### Step 5.5: Similar patterns
**Record:** Other key types validate payload size in `preparse()`
(`user_preparse`: max 32767; `trusted_core`: max 32767; `big_key`: max 1
MiB). `cifs.idmap` lacked any upper bound check.
---
## Phase 6: Cross-Reference Against Local Tree (6.18.44)
### Step 6.1: Buggy code present?
**Record:** **Yes.** Local tree is `v6.18.44` (`VERSION=6`,
`PATCHLEVEL=18`, `SUBLEVEL=44`). `cifs_idmap_key_instantiate()` at lines
67–91 lacks the `U16_MAX` check. `key->datalen` is `unsigned short` per
`include/linux/key.h:217`.
### Step 6.2: Backport complications
**Record:** **Clean apply** to `fs/smb/client/cifsacl.c`. This tree uses
the `fs/smb/client/` path (not legacy `fs/cifs/`). No conflicts
expected.
### Step 6.3: Related fixes already present?
**Record:** Related SID/DACL validation fixes are present; this specific
`U16_MAX` validation is **not** present.
---
## Phase 7: Subsystem Context
### Step 7.1: Subsystem criticality
**Record:** **IMPORTANT** — SMB/CIFS client (`fs/smb/client`),
filesystem driver used in enterprise/embedded deployments with network
file access.
### Step 7.2: Activity
**Record:** Actively maintained; multiple recent security hardening
commits in `cifsacl.c` in this tree.
---
## Phase 8: Impact and Risk Assessment
### Step 8.1: Who is affected
**Record:** Users of `CONFIG_CIFS` mounts with UID/GID idmapping
(userspace `cifs.idmap` upcall). Not universal, but real production
configuration.
### Step 8.2: Trigger conditions
**Record:** Userspace idmap helper instantiates a `cifs.idmap` key with
`prep->datalen > 65535`. Unusual but possible from a compromised/buggy
helper. Not a typical remote network attack by itself, but kernel must
not trust oversized helper input.
### Step 8.3: Failure mode severity
**Record:**
- Wrong inline/heap selection → misinterpreted SID data, potential out-
of-bounds read in `cifs_copy_sid()` — **HIGH**
- Skipped `kfree()` in destroy → memory leak — **MEDIUM**
- Inconsistent bounds checks undermining prior `id_to_sid()` validation
— **HIGH**
Overall: **HIGH** for a kernel memory-safety issue in a trust-boundary
path (kernel ↔ userspace key payload).
### Step 8.4: Risk vs benefit
**Record:**
- **Benefit:** HIGH — closes a real truncation bug at the trust
boundary; complements existing SID validation.
- **Risk:** VERY LOW — 3-line bounds check, rejects only invalid inputs.
- **Ratio:** Strongly favors backport.
---
## Phase 9: Final Synthesis
### Step 9.1: Evidence summary
**FOR backport:**
- Real bug: `size_t` payload length truncated into `unsigned short
key->datalen`
- Causes inline/heap mismatch, broken bounds logic, and memory leak
- Small, obviously correct, maintainer-signed
- Applies cleanly to this `6.18.44` tree
- Consistent with other key-type validation and recent CIFS hardening in
same file
- Fixes trust-boundary input validation gap
**AGAINST backport:**
- No syzbot/CVE/user report
- Requires unusual >64 KiB idmap payload from userspace helper
- No public review discussion found (DORMANT thread)
**UNRESOLVED:**
- Exact mainline commit hash not in this checkout
- Whether a later `6.18.y` release already contains it (not in `.44`)
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — trivial validation;
maintainer SOB; no Tested-by but logic is self-evident.
2. Fixes a real bug affecting users? **PASS** — truncation with concrete
failure modes on CIFS idmap mounts.
3. Important issue? **PASS** — kernel memory-safety / inconsistent
bounds at userspace trust boundary (HIGH).
4. Small and contained? **PASS** — 3 lines, one function.
5. No new features/APIs? **PASS** — input validation only.
6. Can apply to local tree? **PASS** — verified with `git apply
--check`.
### Step 9.3: Exception category
**Record:** None of the hardware-quirk/build-fix exceptions apply. This
is a standard security/correctness bug fix.
### Step 9.4: Decision rationale
This commit should be backported to **this** `6.18.44` tree. The buggy
code is present, the failure mode is serious (truncated length breaks
inline/heap selection and destroy logic), the fix is minimal and matches
established key-subsystem practice, and it fits the ongoing CIFS ACL/SID
hardening already landing in stable.
---
## Verification
- **[Phase 1]** Parsed commit message and tags from user-provided
candidate; cross-checked openwall mirror.
- **[Phase 2]** Read `cifs_idmap_key_instantiate()`,
`cifs_idmap_key_destroy()`, `id_to_sid()` in
`fs/smb/client/cifsacl.c`.
- **[Phase 2]** Verified `key->datalen` is `unsigned short` in
`include/linux/key.h:217`.
- **[Phase 2]** Verified `prep->datalen` is `size_t` in
`include/linux/key-type.h:36`.
- **[Phase 2]** Verified `union key_payload` is `void *data[4]` (32
bytes on 64-bit) in `include/linux/key.h:134-137`.
- **[Phase 3]** `git describe HEAD` → `v6.18.44-2-g1b9e1abadee04`.
- **[Phase 3]** `git blame` on `cifs_idmap_key_instantiate()` — function
present without fix.
- **[Phase 3]** Found related hardening commits: `ff0ca46b13b9e`,
`c688f3ed73d31`, `38a69f08ee82c`, `86c5d470f5d42`.
- **[Phase 3]** `git apply --check` — patch applies cleanly.
- **[Phase 4]** WebFetch openwall: https://lists.openwall.net/linux-
kernel/2026/07/18/621 — original submission found.
- **[Phase 4]** WebFetch ratatoskr — thread DORMANT, no replies.
- **[Phase 4]** `b4 dig -c <hash>` — **UNVERIFIED** (commit hash
unavailable in checkout).
- **[Phase 5]** Grep callers: `request_key(&cifs_idmap_key_type)` in
`id_to_sid()` / `sid_to_id()`.
- **[Phase 5]** Compared with `user_preparse()` size validation in
`security/keys/user_defined.c:64`.
- **[Phase 6]** Confirmed fix absent in current tree; `U16_MAX` defined
in `include/linux/limits.h:18`, used elsewhere in
`fs/smb/client/smbdirect.c`.
- **[Phase 6]** Confirmed `cifs_idmap_key_instantiate()` does not call
`key_payload_reserve()`.
- **[Phase 8]** Traced inline/heap mismatch scenario with
`prep->datalen=65552`, truncated `datalen=16`.
**YES**
fs/smb/client/cifsacl.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/fs/smb/client/cifsacl.c b/fs/smb/client/cifsacl.c
index 92ee03cd01b39..50cf6345975e3 100644
--- a/fs/smb/client/cifsacl.c
+++ b/fs/smb/client/cifsacl.c
@@ -69,6 +69,9 @@ cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
{
char *payload;
+ if (prep->datalen > U16_MAX)
+ return -EINVAL;
+
/*
* If the payload is less than or equal to the size of a pointer, then
* an allocation here is wasteful. Just copy the data directly to the
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.6] ksmbd: validate SMB2 lease create contexts
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (13 preceding siblings ...)
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18-5.10] cifs: validate idmap key payload length Sasha Levin
@ 2026-08-31 13:26 ` Sasha Levin
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: fix credit charge calculation for SMB2 QUERY_INFO Sasha Levin
` (12 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:26 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit b69be2c58615950ee7353b61a21acdf8508c0cbb ]
Validate SMB2 lease context lengths, requested lease state bits, and v2
flags before using the context. Return errors via ERR_PTR so CREATE can
distinguish a missing lease context from a malformed one.
Also ignore lease v2 contexts for SMB 2.1, where they are not valid.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The background `git log --grep` searches finished. They confirm the
commit **is not in this tree**:
- `--grep="validate SMB2 lease"` — no matches
- `--grep="lease create context"` — only `bb05367a66a99` (“set v2 lease
version on lease upgrade”), not the validation patch
That lines up with the earlier analysis: the buggy `parse_lease_state()`
code is present in **6.18.44**, and the fix exists only on Namjae Jeon’s
ksmbd fork (`e9d6231`), not in kernel.org git here.
**Verdict remains YES** for backport to this tree.
fs/smb/server/oplock.c | 33 ++++++++++++++++++++++++++++-----
fs/smb/server/smb2pdu.c | 24 +++++++++++++++++++++++-
2 files changed, 51 insertions(+), 6 deletions(-)
diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
index d7ba8a01f2c68..c12b2b2857667 100644
--- a/fs/smb/server/oplock.c
+++ b/fs/smb/server/oplock.c
@@ -5,6 +5,7 @@
*/
#include <linux/moduleparam.h>
+#include <linux/err.h>
#include "glob.h"
#include "oplock.h"
@@ -19,6 +20,20 @@
static LIST_HEAD(lease_table_list);
static DEFINE_RWLOCK(lease_list_lock);
+#define SMB2_LEASE_STATE_MASK_LE (SMB2_LEASE_READ_CACHING_LE | \
+ SMB2_LEASE_HANDLE_CACHING_LE | \
+ SMB2_LEASE_WRITE_CACHING_LE)
+
+static bool lease_state_valid(__le32 state)
+{
+ return !(state & ~SMB2_LEASE_STATE_MASK_LE);
+}
+
+static bool lease_v2_flags_valid(__le32 flags)
+{
+ return !(flags & ~SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE);
+}
+
/**
* alloc_opinfo() - allocate a new opinfo object for oplock info
* @work: smb work
@@ -1531,12 +1546,14 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
struct lease_ctx_info *lreq;
cc = smb2_find_context_vals(req, SMB2_CREATE_REQUEST_LEASE, 4);
- if (IS_ERR_OR_NULL(cc))
+ if (IS_ERR(cc))
+ return ERR_CAST(cc);
+ if (!cc)
return NULL;
lreq = kzalloc(sizeof(struct lease_ctx_info), KSMBD_DEFAULT_GFP);
if (!lreq)
- return NULL;
+ return ERR_PTR(-ENOMEM);
if (sizeof(struct lease_context_v2) == le32_to_cpu(cc->DataLength)) {
struct create_lease_v2 *lc = (struct create_lease_v2 *)cc;
@@ -1550,11 +1567,14 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
lreq->flags = lc->lcontext.LeaseFlags;
lreq->epoch = lc->lcontext.Epoch;
lreq->duration = lc->lcontext.LeaseDuration;
+ if (!lease_state_valid(lreq->req_state) ||
+ !lease_v2_flags_valid(lreq->flags))
+ goto err_out;
if (lreq->flags == SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET_LE)
memcpy(lreq->parent_lease_key, lc->lcontext.ParentLeaseKey,
SMB2_LEASE_KEY_SIZE);
lreq->version = 2;
- } else {
+ } else if (sizeof(struct lease_context) == le32_to_cpu(cc->DataLength)) {
struct create_lease *lc = (struct create_lease *)cc;
if (le16_to_cpu(cc->DataOffset) + le32_to_cpu(cc->DataLength) <
@@ -1565,12 +1585,15 @@ struct lease_ctx_info *parse_lease_state(void *open_req)
lreq->req_state = lc->lcontext.LeaseState;
lreq->flags = lc->lcontext.LeaseFlags;
lreq->duration = lc->lcontext.LeaseDuration;
+ if (!lease_state_valid(lreq->req_state))
+ goto err_out;
lreq->version = 1;
- }
+ } else
+ goto err_out;
return lreq;
err_out:
kfree(lreq);
- return NULL;
+ return ERR_PTR(-EINVAL);
}
/**
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index b16e1c156ee5f..1921a87e20855 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -3005,6 +3005,17 @@ int smb2_open(struct ksmbd_work *work)
if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE &&
req->CreateContextsOffset) {
lc = parse_lease_state(req);
+ if (IS_ERR(lc)) {
+ rc = PTR_ERR(lc);
+ lc = NULL;
+ goto err_out2;
+ }
+ if (lc && lc->version == 2 && conn->dialect < SMB30_PROT_ID) {
+ kfree(lc);
+ lc = NULL;
+ if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE)
+ req_op_level = SMB2_OPLOCK_LEVEL_NONE;
+ }
rc = parse_durable_handle_context(work, req, lc, &dh_info);
if (rc) {
ksmbd_debug(SMB, "error parsing durable handle context\n");
@@ -3036,8 +3047,19 @@ int smb2_open(struct ksmbd_work *work)
goto reconnected_fp;
}
- } else if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE)
+ } else if (req_op_level == SMB2_OPLOCK_LEVEL_LEASE) {
lc = parse_lease_state(req);
+ if (IS_ERR(lc)) {
+ rc = PTR_ERR(lc);
+ lc = NULL;
+ goto err_out2;
+ }
+ if (lc && lc->version == 2 && conn->dialect < SMB30_PROT_ID) {
+ kfree(lc);
+ lc = NULL;
+ req_op_level = SMB2_OPLOCK_LEVEL_NONE;
+ }
+ }
if (le32_to_cpu(req->ImpersonationLevel) > le32_to_cpu(IL_DELEGATE)) {
pr_err("Invalid impersonationlevel : 0x%x\n",
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: fix credit charge calculation for SMB2 QUERY_INFO
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (14 preceding siblings ...)
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: validate SMB2 lease create contexts Sasha Levin
@ 2026-08-31 13:26 ` Sasha Levin
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: validate SID namespace before mapping IDs Sasha Levin
` (11 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:26 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 284dc80ff529a0b454f11b6c2fea0d5daf6f315f ]
smb2_validate_credit_charge() computes the credit charge a request is
allowed to consume from the payload size:
CreditCharge = (max(SendPayloadSize, ResponsePayloadSize) - 1)/65536 + 1
For SMB2 QUERY_INFO, the server must validate CreditCharge based on the
*maximum* of InputBufferLength and OutputBufferLength. ksmbd instead
summed the two lengths, which overestimates the required charge.
As a result a single-credit QUERY_INFO whose InputBufferLength and
OutputBufferLength each fit in 64KB but whose sum exceeds 64KB is
rejected with STATUS_INVALID_PARAMETER, even though it is a valid
request. IOCTL already uses max() of the request and response sizes;
make QUERY_INFO consistent by feeding InputBufferLength as the request
length and OutputBufferLength as the expected response length so that
smb2_validate_credit_charge() takes their maximum.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The `git log -S "smb2_query_info_resp_len"` search finished with no
results — that helper from the fix commit isn’t in this tree’s history,
which confirms the patch hasn’t landed on this branch yet. That’s
consistent with the earlier **YES** backport recommendation for 6.18.44.
fs/smb/server/smb2misc.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/fs/smb/server/smb2misc.c b/fs/smb/server/smb2misc.c
index d8913d2008748..efbbf7ea48094 100644
--- a/fs/smb/server/smb2misc.c
+++ b/fs/smb/server/smb2misc.c
@@ -262,8 +262,12 @@ static int smb2_calc_size(void *buf, unsigned int *len)
static inline int smb2_query_info_req_len(struct smb2_query_info_req *h)
{
- return le32_to_cpu(h->InputBufferLength) +
- le32_to_cpu(h->OutputBufferLength);
+ return le32_to_cpu(h->InputBufferLength);
+}
+
+static inline int smb2_query_info_resp_len(struct smb2_query_info_req *h)
+{
+ return le32_to_cpu(h->OutputBufferLength);
}
static inline int smb2_set_info_req_len(struct smb2_set_info_req *h)
@@ -310,6 +314,7 @@ static int smb2_validate_credit_charge(struct ksmbd_work *work,
switch (hdr->Command) {
case SMB2_QUERY_INFO:
req_len = smb2_query_info_req_len(__hdr);
+ expect_resp_len = smb2_query_info_resp_len(__hdr);
break;
case SMB2_SET_INFO:
req_len = smb2_set_info_req_len(__hdr);
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: validate SID namespace before mapping IDs
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (15 preceding siblings ...)
2026-08-31 13:26 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: fix credit charge calculation for SMB2 QUERY_INFO Sasha Levin
@ 2026-08-31 13:27 ` Sasha Levin
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18-6.12] smb/client: zero-initialize stack-allocated cifs_open_info_data Sasha Levin
` (10 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:27 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit fbe0bb2b75eb3c61e8464486506253d1b471240b ]
sid_to_id() currently treats the last subauthority of any owner or group
SID as a Unix uid or gid. For example, this maps Everyone (S-1-1-0) to
uid 0 and BUILTIN\Users (S-1-5-32-545) to gid 545.
When an SMB2 CREATE security descriptor contains those SIDs, ksmbd
attempts to change the newly created file to the bogus Unix ownership.
notify_change() then returns -EPERM, which makes smb2.create.aclfile fail
with NT_STATUS_SHARING_VIOLATION.
Validate the SID prefix before extracting its RID. Only server-domain
owner SIDs and S-1-22-2 Unix group SIDs have local ID representations.
Treat other valid Windows SIDs as unmapped so their original values can
still be preserved in the NT ACL xattr.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `ksmbd: validate SID namespace before
mapping IDs`
**Local tree:** Linux 6.18.44 (`v6.18.44-1-g2736c32da98b9`)
**Candidate commit:** `fbe0bb2b75eb3` (mainline 7.2-rc2; **not** in
current HEAD history)
**Bug status in this tree:** Present — `sid_to_id()` lacks SID prefix
validation
---
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1 — Subject line**
Record: `[ksmbd] [validate] validate SID namespace before mapping IDs` —
ACL/SID correctness fix in the SMB server.
**Step 1.2 — Tags**
Record:
- `Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>` (ksmbd
maintainer)
- `Signed-off-by: Steve French <stfrench@microsoft.com>` (CIFS/SMB
maintainer)
- No `Fixes:`, `Reported-by:`, `Cc: stable`, `Link:`, `Tested-by:`, or
`Reviewed-by:` tags
**Step 1.3 — Body analysis**
Record:
- **Bug:** `sid_to_id()` treats the last subauthority of *any*
owner/group SID as a Unix uid/gid.
- **Examples:** Everyone (`S-1-1-0`) → uid 0; `BUILTIN\Users`
(`S-1-5-32-545`) → gid 545.
- **Symptom:** SMB2 CREATE with such security descriptors causes bogus
ownership change; `notify_change()` returns `-EPERM`; CREATE fails
with `NT_STATUS_SHARING_VIOLATION`.
- **Root cause:** No validation that the SID belongs to the server
domain (owner) or `S-1-22-2` Unix group namespace (group) before RID
extraction.
- **Fix approach:** Validate SID prefix; only map domain owner SIDs and
`S-1-22-2-*` group SIDs; treat other valid Windows SIDs as unmapped so
NT ACL xattrs are preserved.
**Step 1.4 — Hidden bug fix?**
Record: **Yes.** Although titled “validate,” this is a functional
correctness bug — incorrect ID mapping breaks SMB2 CREATE with security
descriptors and can attempt root ownership for `Everyone`.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1 — Inventory**
Record:
- **File:** `fs/smb/server/smbacl.c` (+17 / -4 lines)
- **Functions:** `sid_to_id()`, `parse_sec_desc()`
- **Scope:** Single-file surgical fix
**Step 2.2 — Code flow changes**
| Hunk | Before | After |
|------|--------|-------|
| `sid_to_id()` owner path | Extract last subauthority as uid
unconditionally | Require `psid` to match `server_conf.domain_sid`
prefix + exactly one RID |
| `sid_to_id()` group path | Extract last subauthority as gid
unconditionally | Require `psid` to match `sid_unix_groups` (`S-1-22-2`)
prefix + one RID |
| `parse_sec_desc()` error handling | `pr_err()` on mapping failure |
`ksmbd_debug()` + `rc = 0` for unmapped (non-fatal) SIDs |
**Step 2.3 — Bug mechanism**
Record: **Logic/correctness fix.** `sid_to_id()` is the inverse of
`id_to_sid()` but lacked the corresponding namespace checks. Well-known
Windows SIDs were misinterpreted as Unix IDs.
**Step 2.4 — Fix quality**
Record:
- **Obviously correct:** Mirrors `id_to_sid()` which uses
`server_conf.domain_sid` for `SIDOWNER` and `sid_unix_groups` for
groups.
- **Minimal:** Uses existing `compare_sids()`.
- **Low regression risk:** Only rejects SIDs that were never valid Unix
ID mappings.
- **Note:** `parse_sec_desc()` already ends with `return 0`; the `rc =
0` reset is defensive/cosmetic but the `sid_to_id()` validation is the
substantive fix.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1 — Blame**
Record: Buggy `sid_to_id()` logic present at HEAD in lines 278–300,
introduced with ksmbd in this tree (blame points to merge
`5d324e5159d9e`).
**Step 3.2 — Fixes: tag**
Record: N/A — no `Fixes:` tag.
**Step 3.3 — Related file history**
Record: Recent 6.18.y ksmbd ACL hardening commits in same file:
- `337022d9dfac4` — validate ACE size against SID sub-authorities
- `18d8db24b0a5b` — validate SID in parent security descriptor during
ACL inheritance
- Multiple DACL/OOB validation fixes
This fix fits the same ACL correctness pattern already being backported.
**Step 3.4 — Author context**
Record: Namjae Jeon is the ksmbd maintainer; Steve French committed.
Both are authoritative for this subsystem.
**Step 3.5 — Dependencies**
Record: **Standalone.** Requires only symbols present in 6.18.44:
- `compare_sids()` — exists
- `server_conf.domain_sid` — exists
- `sid_unix_groups` — exists (`S-1-22-2` constant at line 43)
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1 — Original discussion**
Record: `b4 dig -c fbe0bb2b75eb3` found **no matching lore thread**
(patch-id `dfb14c6056968734ff03c9e2be7c62bc06662d79`). Manual lore
search blocked by bot protection.
**Step 4.2 — Reviewers**
Record: `b4 dig -w` returned nothing (no thread found).
**Step 4.3 — Bug reports**
Record: N/A — no `Reported-by:` or `Link:` tags. Bug described only in
commit message.
**Step 4.4 — Related patches**
Record: Standalone; not part of a numbered series.
**Step 4.5 — Stable list**
Record: No stable-list discussion found (b4/lore unavailable for this
commit).
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1 — Key functions**
Record: `sid_to_id()`, `parse_sec_desc()`, `set_info_sec()`,
`smb2_create_sd_buffer()`
**Step 5.2 — Callers**
| Function | Callers | Context |
|----------|---------|---------|
| `sid_to_id()` | `parse_sec_desc()` (owner/group), DACL ACE parsing
(~line 509) | Security descriptor processing |
| `parse_sec_desc()` | `set_info_sec()` | SMB2 SET_INFO / CREATE SD
buffer |
| `set_info_sec()` | `smb2_create_sd_buffer()`, `smb2_set_info_sec()` |
SMB2 CREATE/SET_INFO from network clients |
| `smb2_create_sd_buffer()` | `smb2_open()` CREATE path (~line 3389) |
File creation with `SMB2_CREATE_SD_BUFFER` |
**Step 5.3 — Callees**
Record: `compare_sids()`, `from_vfsuid()`/`from_vfsgid()`,
`notify_change()` (downstream in `set_info_sec()`)
**Step 5.4 — Reachability**
Record: **Reachable from SMB clients** via SMB2 CREATE with security-
descriptor create context. Triggered when Windows clients send SDs
containing well-known SIDs (`Everyone`, `BUILTIN\Users`, etc.) — common
in Windows ACLs.
**Step 5.5 — Similar patterns**
Record: `id_to_sid()` already restricts mapping to
`server_conf.domain_sid` / `sid_unix_groups`; `sid_to_id()` was the
missing inverse validation.
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE (6.18.44)
**Step 6.1 — Buggy code present?**
Record: **YES.** Current `sid_to_id()` at lines 257–303 extracts RID
without prefix check. Fix commit `fbe0bb2b75eb3` is **not** an ancestor
of HEAD.
**Step 6.2 — Backport difficulty**
Record: **Clean apply** — `git apply --check` on `fbe0bb2b75eb3` patch
succeeded with no conflicts.
**Step 6.3 — Duplicate fix?**
Record: **No** — grep shows no SID prefix validation in current
`sid_to_id()`.
---
## PHASE 7: SUBSYSTEM CONTEXT
**Step 7.1 — Subsystem**
Record: `fs/smb/server/` (ksmbd SMB server). **Criticality: IMPORTANT**
— network file server, config-dependent (`CONFIG_SMB_SERVER`).
**Step 7.2 — Activity**
Record: Actively maintained in 6.18.y with recent security and ACL fixes
(UAF, OOB, ACL validation).
---
## PHASE 8: IMPACT AND RISK
**Step 8.1 — Who is affected**
Record: Users running ksmbd (`CONFIG_SMB_SERVER`) with ACL/security-
descriptor features, especially Windows SMB clients creating files with
SD buffers.
**Step 8.2 — Trigger conditions**
Record: SMB2 CREATE (or SET_INFO) carrying a security descriptor whose
owner/group SID is a well-known Windows SID (e.g. `S-1-1-0`,
`S-1-5-32-545`). **Common** in Windows environments. Triggerable by
remote SMB clients (authenticated).
**Step 8.3 — Failure mode**
Record:
- **Primary:** CREATE fails with `NT_STATUS_SHARING_VIOLATION` after
`-EPERM` from `notify_change()` — **functional breakage**
- **Secondary:** Incorrect mapping of `Everyone` → uid 0; if chown were
permitted, file would get root ownership — **correctness/security
concern**
- **Severity: MEDIUM-HIGH** for ksmbd deployments (not kernel panic, but
breaks interoperability)
**Step 8.4 — Risk/benefit**
Record:
- **Benefit:** Restores SMB2 CREATE with Windows security descriptors;
prevents bogus uid/gid assignment
- **Risk:** Very low — 21-line change, uses existing helpers, only
rejects invalid mappings
- **Ratio:** Favorable for ksmbd users
---
## PHASE 9: FINAL SYNTHESIS
**Evidence FOR backport:**
- Real, reproducible functional bug on common Windows SID patterns
- Small, surgical, applies cleanly to 6.18.44
- Obviously correct — mirrors `id_to_sid()` inverse logic
- Signed by ksmbd and SMB maintainers
- Same subsystem already receives similar ACL fixes in 6.18.y
- Remote SMB clients can trigger the bug path
**Evidence AGAINST:**
- No syzbot report or user `Reported-by:` tags
- Not a kernel crash/UAF/OOB — operational failure
- Only affects `CONFIG_SMB_SERVER` users
- No mailing-list review traceable via b4
**Stable rules checklist:**
1. Obviously correct and tested? **PASS** (logic mirrors existing
`id_to_sid()`; maintainer SOBs)
2. Fixes real bug? **PASS**
3. Important issue? **PASS** (SMB interoperability breakage; potential
incorrect root ownership)
4. Small and contained? **PASS** (21 lines, 1 file)
5. No new features/APIs? **PASS**
6. Can apply to local tree? **PASS** (verified clean apply)
**Exception category:** N/A (not device ID, quirk, DT, build, or docs)
**Problem summary for stable users:** Windows SMB clients sending
security descriptors with well-known SIDs (e.g. `Everyone`,
`BUILTIN\Users`) cause ksmbd to mis-map them to Unix uid/gid, attempt
invalid ownership changes, and fail file creation. The fix restricts ID
mapping to the same SID namespaces `id_to_sid()` already uses.
---
## Verification
- [Phase 1] `git show fbe0bb2b75eb3 --format=fuller`: parsed subject,
body, SOB tags
- [Phase 2] `git show fbe0bb2b75eb3`: full diff reviewed; 17 insertions,
4 deletions
- [Phase 2] Read `fs/smb/server/smbacl.c` lines 257–303, 871–958,
1601–1654: confirmed buggy code and call chain
- [Phase 3] `git describe HEAD`: v6.18.44-1-g2736c32da98b9; Makefile
VERSION=6 PATCHLEVEL=18 SUBLEVEL=44
- [Phase 3] `git merge-base --is-ancestor fbe0bb2b75eb3 HEAD`: commit
NOT in HEAD history
- [Phase 3] `git blame -L 278,300 fs/smb/server/smbacl.c`: buggy lines
present at HEAD
- [Phase 3] `git log --oneline -15 -- fs/smb/server/`: related ACL fixes
in tree
- [Phase 4] `b4 dig -c fbe0bb2b75eb3 -C`: no lore match found
- [Phase 4] WebFetch lore.kernel.org: blocked by bot protection
- [Phase 5] `grep` for `parse_sec_desc`, `set_info_sec`,
`smb2_create_sd_buffer`: traced SMB2 CREATE path
- [Phase 5] Read `compare_sids()` lines 71–114: prefix comparison
behavior verified
- [Phase 5] Read `id_to_sid()` lines 221–231: inverse mapping namespaces
confirmed
- [Phase 6] Read current `sid_to_id()`: no prefix validation present
- [Phase 6] `git apply --check` on patch: applies cleanly
- [Phase 6] `grep domain_sid`, `sid_unix_groups`: all dependencies exist
- [Phase 8] Read `smb2pdu.c` lines 2647–2672, 3388–3389: CREATE SD
buffer path confirmed
**YES**The background check finished: commit `fbe0bb2b75eb3` (“ksmbd:
validate SID namespace before mapping IDs”) is on the **7.2-rc2** line,
not in your current **6.18.44** tree — which matches the earlier finding
that the buggy `sid_to_id()` logic is still present locally and the
patch applies cleanly.
**Backport recommendation remains YES** for 6.18.y: it’s a small, self-
contained fix for a real ksmbd interoperability bug where common Windows
SIDs (e.g. `Everyone`, `BUILTIN\Users`) get mis-mapped to Unix IDs and
SMB2 CREATE with security descriptors fails.
fs/smb/server/smbacl.c | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/fs/smb/server/smbacl.c b/fs/smb/server/smbacl.c
index d3d0a22620f96..0b55c77e64562 100644
--- a/fs/smb/server/smbacl.c
+++ b/fs/smb/server/smbacl.c
@@ -258,6 +258,7 @@ static int sid_to_id(struct mnt_idmap *idmap,
struct smb_sid *psid, uint sidtype,
struct smb_fattr *fattr)
{
+ const struct smb_sid *sid_prefix;
int rc = -EINVAL;
/*
@@ -279,6 +280,12 @@ static int sid_to_id(struct mnt_idmap *idmap,
kuid_t uid;
uid_t id;
+ /* Only the server domain RID has a local uid representation. */
+ sid_prefix = &server_conf.domain_sid;
+ if (psid->num_subauth != sid_prefix->num_subauth + 1 ||
+ compare_sids(psid, sid_prefix))
+ return -EINVAL;
+
id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
uid = KUIDT_INIT(id);
uid = from_vfsuid(idmap, &init_user_ns, VFSUIDT_INIT(uid));
@@ -290,6 +297,12 @@ static int sid_to_id(struct mnt_idmap *idmap,
kgid_t gid;
gid_t id;
+ /* Local gids are represented by S-1-22-2-<gid>. */
+ sid_prefix = &sid_unix_groups;
+ if (psid->num_subauth != sid_prefix->num_subauth + 1 ||
+ compare_sids(psid, sid_prefix))
+ return -EINVAL;
+
id = le32_to_cpu(psid->sub_auth[psid->num_subauth - 1]);
gid = KGIDT_INIT(id);
gid = from_vfsgid(idmap, &init_user_ns, VFSGIDT_INIT(gid));
@@ -916,9 +929,9 @@ int parse_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
rc = sid_to_id(idmap, owner_sid_ptr, SIDOWNER, fattr);
if (rc) {
- pr_err("%s: Error %d mapping Owner SID to uid\n",
- __func__, rc);
+ ksmbd_debug(SMB, "Owner SID has no Unix uid mapping\n");
owner_sid_ptr = NULL;
+ rc = 0;
}
}
@@ -934,9 +947,9 @@ int parse_sec_desc(struct mnt_idmap *idmap, struct smb_ntsd *pntsd,
}
rc = sid_to_id(idmap, group_sid_ptr, SIDUNIX_GROUP, fattr);
if (rc) {
- pr_err("%s: Error %d mapping Group SID to gid\n",
- __func__, rc);
+ ksmbd_debug(SMB, "Group SID has no Unix gid mapping\n");
group_sid_ptr = NULL;
+ rc = 0;
}
}
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.12] smb/client: zero-initialize stack-allocated cifs_open_info_data
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (16 preceding siblings ...)
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: validate SID namespace before mapping IDs Sasha Levin
@ 2026-08-31 13:27 ` Sasha Levin
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: break RH leases before delete-on-close Sasha Levin
` (9 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:27 UTC (permalink / raw)
To: patches, stable
Cc: ChenXiaoSong, Steve French, Sasha Levin, pc, linkinjeon,
linux-cifs, samba-technical, linux-kernel
From: ChenXiaoSong <chenxiaosong@kylinos.cn>
[ Upstream commit 8fce4cf4369c766a3293a05419500cbfde72e60d ]
Stack-allocated cifs_open_info_data may contain random data.
This can make some fields have wrong value if they are not set later.
Signed-off-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
The background checks finished. Summary:
**Series commits in 6.18.44:** None of the related commits are in your
tree — `fc8789bb57e62`, `1f551e407bb49`, and `8fce4cf4369c7` (the zero-
init fix) all return exit 1 from `git merge-base --is-ancestor`.
**Nlink fix:** The main fstat/nlink fix in the series is `9dd1964ac59d2`
("smb/client: fix incorrect nlink returned by fstat()"), merged via
`8eae393cbfd79` — also not in 6.18.44.
**Backport verdict:** The zero-init patch still applies cleanly to the
three uninitialized `cifs_open_info_data` sites in this tree. It's a
small, correct uninitialized-memory fix in the SMB client, though
immediate impact at those call sites is limited without the sibling
series commits. For 6.18.44:
**YES**
fs/smb/client/link.c | 2 +-
fs/smb/client/smb1ops.c | 2 +-
fs/smb/client/smb2ops.c | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/smb/client/link.c b/fs/smb/client/link.c
index 70f3c0c67eebd..0b8cf3dd65d97 100644
--- a/fs/smb/client/link.c
+++ b/fs/smb/client/link.c
@@ -234,7 +234,7 @@ cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon,
struct cifs_open_parms oparms;
struct cifs_io_parms io_parms = {0};
int buf_type = CIFS_NO_BUFFER;
- struct cifs_open_info_data query_data;
+ struct cifs_open_info_data query_data = {};
oparms = (struct cifs_open_parms) {
.tcon = tcon,
diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c
index ca8f3dd7ff63b..209bcf0fab4be 100644
--- a/fs/smb/client/smb1ops.c
+++ b/fs/smb/client/smb1ops.c
@@ -962,7 +962,7 @@ smb_set_file_info(struct inode *inode, const char *full_path,
struct cifs_open_parms oparms;
struct cifsFileInfo *open_file;
FILE_BASIC_INFO new_buf;
- struct cifs_open_info_data query_data;
+ struct cifs_open_info_data query_data = {};
__le64 write_time = buf->LastWriteTime;
struct cifsInodeInfo *cinode = CIFS_I(inode);
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index f4d7eb88d3fdb..43eaad8fd0ad4 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -5234,7 +5234,7 @@ int __cifs_sfu_make_node(unsigned int xid, struct inode *inode,
{
struct TCP_Server_Info *server = tcon->ses->server;
struct cifs_open_parms oparms;
- struct cifs_open_info_data idata;
+ struct cifs_open_info_data idata = {};
struct cifs_io_parms io_parms = {};
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
struct cifs_fid fid;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: break RH leases before delete-on-close
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (17 preceding siblings ...)
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18-6.12] smb/client: zero-initialize stack-allocated cifs_open_info_data Sasha Levin
@ 2026-08-31 13:27 ` Sasha Levin
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18] smb/client: emulate small EOF-extending mode 0 fallocate ranges Sasha Levin
` (8 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:27 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 1f1083c36fa11c5d9011451c7b9ab380545c72ea ]
The delete paths only marked the opened file delete pending or
delete-on-close. When another client still held a read/handle lease, no
lease break was sent before the delete state changed.
smb2.lease.unlink uses a create request with FILE_DELETE_ON_CLOSE and
expects the second client's unlink to break the first client's RH lease to
R with ACK_REQUIRED set. SetInfo(FileDispositionInformation) has the same
lease-breaking requirement.
Break level-II/read-handle leases before setting delete pending or
delete-on-close so clients are notified before the file is removed.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
### Step 1.1: Subject Line
**Record:** `[ksmbd]` `[break]` — Break read/handle (RH) SMB2 leases
before marking files delete-pending or delete-on-close.
### Step 1.2: Tags
**Record:** Tags present:
- `Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>` (author)
- `Signed-off-by: Steve French <stfrench@microsoft.com>` (ksmbd
maintainer)
Not present (expected for this review pipeline): `Fixes:`, `Reported-
by:`, `Tested-by:`, `Reviewed-by:`, `Acked-by:`, `Cc:
stable@vger.kernel.org`, `Link:`
Notable: Maintainer sign-off from Steve French; no syzbot or user bug
reports.
### Step 1.3: Body Analysis
**Record:**
- **Bug:** Delete paths (`FILE_DELETE_ON_CLOSE` on CREATE,
`SetInfo(FileDispositionInformation)`) set delete state without
sending lease-break notifications to clients holding RH (read+handle)
leases.
- **Symptom:** SMB2 clients are not notified before delete;
`smb2.lease.unlink` smbtorture test expects RH lease break to `R` with
`ACK_REQUIRED` on second-client unlink.
- **Root cause:** Delete handlers called
`ksmbd_fd_set_delete_on_close()` / `ksmbd_set_inode_pending_delete()`
directly, skipping `smb_break_all_levII_oplock()`.
- **Version info:** None in message.
### Step 1.4: Hidden Bug Fix?
**Record:** No — this is an explicit protocol-conformance / lease-
coherency bug fix, not disguised cleanup.
---
## Phase 2: Diff Analysis
### Step 2.1: Inventory
**Record:**
- **Files:** `fs/smb/server/smb2pdu.c` only (+7 / −3 lines)
- **Functions modified:** `smb2_open()`, `set_file_disposition_info()`,
`smb2_set_info_file()`
- **Scope:** Single-file surgical fix
### Step 2.2: Code Flow Changes
**Record:**
1. **`smb2_open()` hunk:** Before → if `FILE_DELETE_ON_CLOSE`, only
`ksmbd_fd_set_delete_on_close()`. After → call
`smb_break_all_levII_oplock(work, fp, 0)` first, then set delete-on-
close.
2. **`set_file_disposition_info()` hunk:** Signature gains `struct
ksmbd_work *work`. Before → on `DeletePending`, only
`ksmbd_set_inode_pending_delete()`. After → break level-II/RH leases
first.
3. **`smb2_set_info_file()` hunk:** Passes `work` into
`set_file_disposition_info()`.
All affected paths are normal SMB2 request handling (CREATE with delete-
on-close, SET_INFO disposition).
### Step 2.3: Bug Mechanism
**Record:** **Category:** Logic / protocol correctness (lease
coherency).
**Mechanism:** SMB2 requires breaking conflicting RH leases before
delete state changes. The server skipped notification, leaving clients
with active read/handle caches on files being deleted. Fix mirrors the
existing rename path pattern (`smb_break_all_levII_oplock(work, fp, 0)`
at line 6169 after successful rename).
### Step 2.4: Fix Quality
**Record:**
- **Obviously correct:** Yes — identical pattern to rename and other
ksmbd lease-break call sites.
- **Minimal:** Yes — two call sites + signature plumbing.
- **Regression risk:** Very low — only adds lease breaks before delete;
`smb_break_all_levII_oplock()` already guards on
`KSMBD_SHARE_FLAG_OPLOCKS` and skips non-level-II/non-RH leases.
- **Red flags:** None.
---
## Phase 3: Git History Investigation
### Step 3.1: Blame
**Record:**
- Delete-on-close in `smb2_open()` introduced in `e2f34481b24db`
(2021-05-10, "cifsd: add server-side procedures for SMB3").
- `set_file_disposition_info()` delete-pending path same origin
(`e2f34481b24db`); directory-empty check from `64b39f4a2fd293`
(2021-03-30).
- Bug has existed since ksmbd SMB3 support landed; present throughout
6.18.y.
### Step 3.2: Fixes: Tag
**Record:** N/A — no `Fixes:` tag.
### Step 3.3: Related File History
**Record:**
- Precedent: `3fc74c65b3674` ("ksmbd: send lease break notification on
FILE_RENAME_INFORMATION", 2024-01-09) — same class of fix, already
**in** this 6.18.44 tree.
- Target commit `1f1083c36fa11` is **not** in this tree (`merge-base
--is-ancestor` returns not ancestor).
- Part of 14-patch series (patch 12/14) on master; this specific hunk is
self-contained.
### Step 3.4: Author Context
**Record:** Namjae Jeon is primary ksmbd author/maintainer. Recent
6.18.y ksmbd work includes security/correctness fixes (UAF, negotiate
races, permission checks).
### Step 3.5: Dependencies
**Record:** No prerequisites required for this tree:
- `smb_break_all_levII_oplock()` exists in `fs/smb/server/oplock.c`
(since before 6.18).
- `struct ksmbd_work *work` is available at all call sites.
- Cherry-pick to current HEAD applies cleanly (verified: 7 insertions, 3
deletions, no conflicts).
---
## Phase 4: Mailing List and External Research
### Step 4.1: Original Discussion
**Record:**
- `b4 dig -c 1f1083c36fa11`:
https://patch.msgid.link/20260618141739.9029-12-linkinjeon@kernel.org
- Series: v1 only (no v2/v3 revisions found for this patch).
- Lore web fetch blocked by Anubis bot protection — could not read
inline review thread.
### Step 4.2: Reviewers
**Record:** `b4 dig -w` CC list: `linux-cifs@vger.kernel.org`, Steve
French (`smfrench@gmail.com`), Sergey Senozhatsky, Tom Talpey, Metze,
Atte Jääskeläinen. Appropriate subsystem coverage.
### Step 4.3: Bug Report
**Record:** No external bug report. Failure mode documented via
`smb2.lease.unlink` smbtorture expectation in commit message. No
syzbot/KASAN report.
### Step 4.4: Related Patches
**Record:** Patch 12/14 of "ksmbd: validate SMB2 lease create contexts"
series. Patches 13–14 address v2 lease-break routing; patch 12 is
independently applicable and matches the rename-path approach already in
6.18.y.
### Step 4.5: Stable List History
**Record:** Not searched (lore blocked). No stable nomination found in
available sources.
---
## Phase 5: Code Semantic Analysis
### Step 5.1: Key Functions
**Record:** `smb2_open()`, `set_file_disposition_info()`,
`smb_break_all_levII_oplock()`, `ksmbd_fd_set_delete_on_close()`,
`ksmbd_set_inode_pending_delete()`.
### Step 5.2: Callers
**Record:**
- `smb2_open()` — SMB2 CREATE handler (common file-server path).
- `set_file_disposition_info()` — called only from
`smb2_set_info_file()` on `FILE_DISPOSITION_INFORMATION`.
- `smb2_set_info_file()` — SMB2 SET_INFO handler.
All reachable from authenticated SMB clients when `CONFIG_SMB_SERVER`
(ksmbd) is enabled with oplocks/leases.
### Step 5.3: Callees
**Record:** `smb_break_all_levII_oplock()` iterates inode oplock list,
calls `oplock_break()` to send SMB2 lease-break notifications to clients
with level-II or RH leases.
### Step 5.4: Reachability
**Record:** Triggered by any SMB client issuing CREATE with
`FILE_DELETE_ON_CLOSE` or SET_INFO `FileDispositionInformation` with
`DeletePending=TRUE` on a share with oplocks enabled. Multi-client lease
scenarios are the intended ksmbd use case. Userspace-reachable via SMB
protocol.
### Step 5.5: Similar Patterns
**Record:** Same `smb_break_all_levII_oplock(work, fp, 0)` already used
after rename (`smb2_rename` success at line 6169) and in vfs paths.
Delete was the missing symmetric case.
---
## Phase 6: Cross-Reference Against Local Tree
### Step 6.1: Buggy Code Present?
**Record:** **Yes** in linux-6.18.44 (`v6.18.44-1-g2736c32da98b9`):
- Lines 3531–3532: delete-on-close without lease break.
- Lines 6458–6462: disposition delete-pending without lease break.
Bug present since ~2021; not introduced after 6.18 branch.
### Step 6.2: Backport Complications
**Record:** **Clean apply** — cherry-pick of `1f1083c36fa11` auto-merges
with no conflicts. Minor line-number offset from master (e.g., `-EINVAL`
vs `-EMSGSIZE` in nearby code) does not affect the fix hunks.
### Step 6.3: Related Fixes Already Present?
**Record:** Rename lease-break fix (`3fc74c65b3674`) is already in
6.18.y. This delete-path fix is the complementary missing piece. No
duplicate fix found.
---
## Phase 7: Subsystem Context
### Step 7.1: Subsystem / Criticality
**Record:** `fs/smb/server` (ksmbd in-kernel SMB server). **IMPORTANT**
for deployments using ksmbd; peripheral for kernels built without
`CONFIG_SMB_SERVER`.
### Step 7.2: Activity
**Record:** Actively maintained in 6.18.y — recent commits include UAF
fixes, negotiate hardening, permission enforcement.
---
## Phase 8: Impact and Risk
### Step 8.1: Who Is Affected
**Record:** ksmbd users with SMB2 oplocks/leases enabled on multi-client
shares. Config-specific (`CONFIG_SMB_SERVER`), not universal.
### Step 8.2: Trigger Conditions
**Record:** Client A holds RH lease; Client B deletes same file via
CREATE+`FILE_DELETE_ON_CLOSE` or SET_INFO disposition. Requires oplocks
enabled on share. Realistic in enterprise/embedded NAS scenarios.
Authenticated SMB clients can trigger.
### Step 8.3: Failure Severity
**Record:** **MEDIUM-HIGH** for affected deployments:
- Not a kernel oops/panic.
- SMB2 protocol violation; `smb2.lease.unlink` conformance failure.
- Clients may retain stale read/handle caches after another client
deletes the file — user-visible coherency/correctness issue on a file
server.
- Does not corrupt server-side filesystem data, but can cause incorrect
client behavior.
### Step 8.4: Risk-Benefit
**Record:**
- **Benefit:** MEDIUM-HIGH for ksmbd+lease users — restores spec-
compliant lease breaks on delete, matching rename behavior already in
tree.
- **Risk:** VERY LOW — 10-line change using established helper,
maintainer-reviewed.
- **Ratio:** Favorable for backport to this tree.
---
## Phase 9: Final Synthesis
### Step 9.1: Evidence Summary
**FOR backport:**
- Real, long-standing protocol bug in code present in 6.18.44
- Direct precedent: rename lease-break fix already in 6.18.y
- Small, surgical, applies cleanly
- Maintainer sign-off (Steve French)
- smbtorture-documented expectation (`smb2.lease.unlink`)
- Multi-client cache coherency impact
**AGAINST backport:**
- Not a kernel crash, security CVE, or server-side data corruption
- Only affects `CONFIG_SMB_SERVER` + oplocks/leases
- Part of larger series (though this patch is standalone)
- No explicit stable nomination or user bug reports found
**Unresolved:** Full lore review thread unavailable (Anubis block).
### Step 9.2: Stable Rules Checklist
1. Obviously correct and tested? **PASS** — mirrors rename path;
smbtorture case cited; maintainer SOB.
2. Fixes real bug affecting users? **PASS** — SMB2 lease-break omission
on delete paths.
3. Important issue? **PASS (MEDIUM-HIGH)** — protocol/coherency bug for
multi-client file servers; not kernel crash but materially affects
ksmbd correctness.
4. Small and contained? **PASS** — 1 file, 10 lines.
5. No new features/APIs? **PASS** — uses existing
`smb_break_all_levII_oplock()`.
6. Can apply to local tree? **PASS** — verified clean cherry-pick.
### Step 9.3: Exception Categories
**Record:** None (not device ID, quirk, DT, build, or docs). Standard
bug fix.
### Step 9.4: Decision Rationale
For **linux-6.18.y (v6.18.44)**, this commit should be backported. The
buggy delete paths have existed since ksmbd SMB3 support and are present
in this tree. The fix is minimal, follows an established in-tree pattern
(rename already breaks RH leases via the same helper), applies without
dependencies, and corrects a real SMB2 lease-coherency defect that
affects multi-client file-server deployments — the primary use case for
ksmbd with leases enabled.
---
## Verification
- [Phase 1] Parsed commit `1f1083c36fa11`: only author + maintainer
Signed-off-by tags
- [Phase 2] Diff: 7+/3− in `fs/smb/server/smb2pdu.c`; two
`smb_break_all_levII_oplock()` additions
- [Phase 3] `git blame`: delete paths from `e2f34481b24db` (2021-05-10)
- [Phase 3] `git show 3fc74c65b3674`: rename lease-break precedent;
confirmed ancestor of HEAD
- [Phase 3] `merge-base --is-ancestor 1f1083c36fa11 HEAD`: commit NOT in
6.18.44 tree
- [Phase 3] Cherry-pick test: applies cleanly (7 insertions, 3
deletions, no conflicts)
- [Phase 4] `b4 dig -c 1f1083c36fa11`: lore URL found
- [Phase 4] `b4 dig -a`: v1 only, patch 12/14
- [Phase 4] `b4 dig -w`: linux-cifs + Steve French CC'd
- [Phase 4] WebFetch lore: **FAILED** (Anubis bot wall)
- [Phase 5] `grep smb_break_all_levII_oplock`: helper exists; rename
uses same call at line 6169
- [Phase 5] `grep set_file_disposition_info`: single caller in
`smb2_set_info_file()`
- [Phase 6] `git describe HEAD`: v6.18.44-1-g2736c32da98b9
(linux-6.18.y)
- [Phase 6] Read lines 3531–3532, 6458–6462: buggy code confirmed
present
- [Phase 6] Read `smb_break_all_levII_oplock()` at oplock.c:1380:
function fully implemented
- [Phase 7] `fs/smb/server/Kconfig`: `CONFIG_SMB_SERVER` controls ksmbd
- [Phase 8] Failure mode: client lease coherency / protocol non-
compliance, not kernel crash
**YES**
fs/smb/server/smb2pdu.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 0f8194fc17776..da114b2b39ea3 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -3619,8 +3619,10 @@ int smb2_open(struct ksmbd_work *work)
goto err_out1;
}
- if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE)
+ if (req->CreateOptions & FILE_DELETE_ON_CLOSE_LE) {
+ smb_break_all_levII_oplock(work, fp, 0);
ksmbd_fd_set_delete_on_close(fp, file_info);
+ }
if (need_truncate) {
rc = smb2_create_truncate(&fp->filp->f_path);
@@ -6558,7 +6560,8 @@ static int set_rename_info(struct ksmbd_work *work, struct ksmbd_file *fp,
return smb2_rename(work, fp, rename_info, work->conn->local_nls);
}
-static int set_file_disposition_info(struct ksmbd_file *fp,
+static int set_file_disposition_info(struct ksmbd_work *work,
+ struct ksmbd_file *fp,
struct smb2_file_disposition_info *file_info)
{
struct inode *inode;
@@ -6573,6 +6576,7 @@ static int set_file_disposition_info(struct ksmbd_file *fp,
if (S_ISDIR(inode->i_mode) &&
ksmbd_vfs_empty_dir(fp) == -ENOTEMPTY)
return -EBUSY;
+ smb_break_all_levII_oplock(work, fp, 0);
ksmbd_set_inode_pending_delete(fp);
} else {
ksmbd_clear_inode_pending_delete(fp);
@@ -6702,7 +6706,7 @@ static int smb2_set_info_file(struct ksmbd_work *work, struct ksmbd_file *fp,
if (buf_len < sizeof(struct smb2_file_disposition_info))
return -EINVAL;
- return set_file_disposition_info(fp,
+ return set_file_disposition_info(work, fp,
(struct smb2_file_disposition_info *)buffer);
}
case FILE_FULL_EA_INFORMATION:
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18] smb/client: emulate small EOF-extending mode 0 fallocate ranges
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (18 preceding siblings ...)
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: break RH leases before delete-on-close Sasha Levin
@ 2026-08-31 13:27 ` Sasha Levin
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18] smb/client: do not account EOF extension as allocation Sasha Levin
` (7 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:27 UTC (permalink / raw)
To: patches, stable
Cc: Huiwen He, ChenXiaoSong, Steve French, Sasha Levin, pc,
linkinjeon, linux-cifs, samba-technical, linux-kernel
From: Huiwen He <hehuiwen@kylinos.cn>
[ Upstream commit 7a06d3b816d73448b4e38b83d65049f090b7b201 ]
When a mode 0 fallocate extends EOF from 1G to 2G + 1M, the client
currently sends SetEOF for 2G + 1M. This can make fallocate return
success without allocating the requested range, or allocate extra
space before that range.
For example, on a fresh file:
xfs_io -f \
-c "falloc 0 1G" \
-c "falloc 2G 1M" \
-c "truncate 3G" test
The second fallocate should allocate [2G, 2G + 1M), leaving [1G, 2G)
as a hole.
Before this change, the result depended on the server allocation policy.
With Samba "strict allocate = no", SetEOF could return success without
allocating [2G, 2G + 1M). With "strict allocate = yes":
# filefrag -v test
[0, 1G) allocated
[1G, 2G) allocated unexpectedly
[2G, 2G + 1M) allocated
SMB cannot allocate that arbitrary range, so write zeroes to small
EOF-extending ranges instead. Limit this to 1 MiB to bound the
client-side I/O cost.
With "strict allocate = no", the requested range [2G, 2G + 1M) is
allocated by the writes. With "strict allocate = yes":
# filefrag -v test
[0, 1G) allocated
[1G, 2G) hole
[2G, 2G + 1M) allocated
This fixes the small EOF-extending range case exercised by generic/213.
Signed-off-by: Huiwen He <hehuiwen@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## PHASE 1: COMMIT MESSAGE FORENSICS
**Step 1.1 — Subject line**
Record: `[smb/client] [emulate] small EOF-extending mode 0 fallocate
ranges — fix incorrect SetEOF-based allocation for small ranges beyond
EOF`
**Step 1.2 — Tags**
Record:
- Signed-off-by: Huiwen He, Steve French
- Reviewed-by: ChenXiaoSong
- No Fixes:, Reported-by:, Link:, Cc: stable@vger.kernel.org, Tested-
by:, or syzbot tags
- Notable: Reviewed-by present; no explicit stable nomination in commit
message
**Step 1.3 — Body analysis**
Record:
- **Bug:** Mode-0 fallocate extending EOF with a gap (e.g., allocate
[2G, 2G+1M) when EOF is 1G) uses `SMB2_set_eof()` instead of
allocating the specific range.
- **Symptoms:**
- With Samba `strict allocate = no`: fallocate can return success
without allocating [2G, 2G+1M)
- With `strict allocate = yes`: may allocate [1G, 2G) unexpectedly
instead of leaving a hole
- **Fix:** For small (≤1 MiB) EOF-extending ranges at or beyond EOF,
write zeroes via `smb3_simple_fallocate_range()` instead of SetEOF;
refresh `i_blocks` from server `AllocationSize`.
- **Test reference:** xfstests `generic/213`
- **Root cause:** SMB has no true fallocate; SetEOF cannot allocate an
arbitrary non-contiguous range.
**Step 1.4 — Hidden bug fix?**
Record: Yes. Subject says "emulate" but this is a correctness fix for
POSIX fallocate semantics on CIFS/SMB mounts, not a feature addition.
---
## PHASE 2: DIFF ANALYSIS
**Step 2.1 — Inventory**
Record:
- **File:** `fs/smb/client/smb2ops.c` (+60 / -9 lines)
- **Functions modified:** `smb3_simple_fallocate_range()`,
`smb3_simple_falloc()`
- **Scope:** Single-file, surgical fix in SMB3 fallocate emulation path
**Step 2.2 — Code flow changes**
Record:
- **`smb3_simple_fallocate_range()`:** Buffer allocation moved earlier;
new fast path when `off >= i_size_read(inode)` skips
`FSCTL_QUERY_ALLOCATED_RANGES` and directly zero-writes the range
(correct for beyond-EOF allocation).
- **`smb3_simple_falloc()`:** Before SetEOF for EOF-extending mode-0
fallocate, detects small ranges at/beyond EOF (`off > old_eof`, or
`off == old_eof` on sparse non-empty files) and routes through zero-
write path; updates size and queries server for real `AllocationSize`
to set `i_blocks`.
**Step 2.3 — Bug mechanism**
Record:
- **Category:** Logic/correctness fix (filesystem semantics)
- **Mechanism:** SetEOF extends file size but cannot allocate a specific
distant range or preserve an intervening hole; zero-writes allocate
exactly the requested range on the server.
**Step 2.4 — Fix quality**
Record:
- Fix is logically sound and minimal for the described case.
- 1 MiB cap bounds client I/O cost (consistent with existing internal-
range fallocate limit).
- **Minor regression risk:** Low; only affects small EOF-extending
mode-0 fallocate on SMB mounts.
- **Note:** Diff includes `min_t(loff_t, len, SMB2_MAX_BUFFER_SIZE)`
buffer sizing from sibling commit `9e4ec3be67af4` (not yet in this
tree); backport may need minor adjustment to existing `kvzalloc(1024 *
1024)` line.
---
## PHASE 3: GIT HISTORY INVESTIGATION
**Step 3.1 — Blame**
Record: EOF-extending SetEOF path in `smb3_simple_falloc()` dates to
merge base `5d324e5159d9e` (v6.18); underlying fallocate emulation
introduced in `966a3cb7c7db` ("cifs: improve fallocate emulation",
2021). Bug has been present since SetEOF was used for EOF extension.
**Step 3.2 — Fixes: tag**
Record: Not applicable — no Fixes: tag in commit message.
**Step 3.3 — Related file history**
Record:
- `7e08ab7a061b1` — "handle overlapping allocated ranges in fallocate" —
**already in this tree**
- `6cc1518357369` — kvzalloc for fallocate buffer — **already in this
tree**
- `9e4ec3be67af4` — reduce fallocate buffer to `min_t(len,
SMB2_MAX_BUFFER_SIZE)` — on master, **not in this tree**
- `5bd1d3dcc25a5` — refresh allocation after EOF-extending fallocate
(SetEOF path) — on master, **not in this tree**
- Part of v8 series "fix fallocate and allocation accounting" (patch
4/5), but this specific patch is largely standalone for the small-gap
EOF case.
**Step 3.4 — Author context**
Record: Huiwen He authored multiple CIFS fallocate/accounting fixes;
`7e08ab7a061b1` from same author is already backported to this 6.18.y
tree.
**Step 3.5 — Dependencies**
Record:
- **Hard dependency met:** `7e08ab7a061b1` (overlapping ranges fix) is
in tree.
- **Soft dependency:** `9e4ec3be67af4` (buffer size) makes the diff
apply cleanly; without it, one hunk needs minor adaptation (use
existing 1 MiB buffer or include `9e4ec3` alongside).
- **Not required:** `5906d0e82e8e0` (duplicate extents), `5bd1d3dcc25a5`
(SetEOF allocation refresh) — separate concerns.
- Can apply standalone with at most minor buffer-allocation adjustment.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
**Step 4.1 — Original discussion**
Record:
- `b4 dig -c 7a06d3b816d73`: [PATCH v8 4/5] at
https://patch.msgid.link/20260703053300.913371-5-huiwen.he@linux.dev
- Series revisions v4–v8 found; committed version is latest (v8).
- No explicit Cc: stable in thread headers found.
**Step 4.2 — Reviewers**
Record: `b4 dig -w` shows CC to Steve French (maintainer), linux-
cifs@vger.kernel.org, and core CIFS reviewers. Reviewed-by: ChenXiaoSong
on all revisions.
**Step 4.3 — Bug report**
Record: No external bug report or syzbot link. Validation is via
xfstests `generic/213` (referenced in commit message and series cover
letters).
**Step 4.4 — Series context**
Record: v8 series covers fallocate + allocation accounting (5 patches).
Patch 4/5 (this commit) fixes small EOF-extending mode-0 case; patch 5/5
(`5bd1d3dcc25a5`) addresses SetEOF-path allocation refresh for other
generic/213/generic/701 scenarios. This patch stands alone for its
specific bug class.
**Step 4.5 — Stable list**
Record: No stable@vger.kernel.org discussion found for this specific
patch.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
**Step 5.1 — Key functions**
Record: `smb3_simple_falloc()`, `smb3_simple_fallocate_range()`,
`smb3_simple_fallocate_write_range()`, `cifs_fallocate()` (caller in
`cifsfs.c`)
**Step 5.2 — Callers**
Record: `cifs_fallocate()` → `server->ops->fallocate()` →
`smb3_fallocate()` → `smb3_simple_falloc(file, tcon, off, len, false)`
for mode 0. Reachable from `fallocate(2)` syscall on CIFS/SMB mounts.
**Step 5.3 — Callees**
Record: `SMB2_write()` (zero-fill), `SMB2_query_info()` (allocation
refresh), `SMB2_ioctl(FSCTL_QUERY_ALLOCATED_RANGES)`,
`netfs_resize_file()`, `cifs_setsize()`. All exist in this tree.
**Step 5.4 — Reachability**
Record: Userspace `fallocate()` on SMB-mounted files with mode 0 and EOF
extension — common for preallocation tools (`xfs_io`, databases, etc.).
Unprivileged users can trigger on writable mounts.
**Step 5.5 — Similar patterns**
Record: Existing code already uses `smb3_simple_fallocate_range()` for
internal sparse-file holes (len ≤ 1 MiB at lines 3726–3728 in current
tree). This commit extends the same pattern to EOF-extending cases.
---
## PHASE 6: CROSS-REFERENCING AGAINST LOCAL TREE
**Step 6.1 — Buggy code exists?**
Record: **YES.** Local tree is **v6.18.44** (`git describe HEAD`).
Current `smb3_simple_falloc()` at lines 3665–3680 still uses SetEOF for
all EOF-extending mode-0 fallocate without the small-range zero-write
path. Bug present since 2021 fallocate emulation.
**Step 6.2 — Backport complications**
Record: **Minor adaptation expected.** Stable tree uses `kvzalloc(1024 *
1024)` at line 3564; upstream commit expects `kvzalloc(min_t(loff_t,
len, SMB2_MAX_BUFFER_SIZE))` from `9e4ec3be67af4`. Core logic applies
cleanly; buffer line is a one-line adjustment or companion pick of
`9e4ec3`.
**Step 6.3 — Related fixes already present?**
Record: `7e08ab7a061b1` (overlapping allocated ranges) already
backported. This specific EOF-extending small-range fix is **not**
present. No duplicate fix found.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
**Step 7.1 — Subsystem**
Record: **fs/smb/client** (CIFS/SMB client) — **IMPORTANT** subsystem
for enterprise/consumer network filesystem mounts.
**Step 7.2 — Activity**
Record: Actively maintained; multiple fallocate fixes landed in 6.18.y
cycle including `7e08ab7a061b1`, `6cc1518357369`, `f4e35576da439`
(i_blocks/generic/694).
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
**Step 8.1 — Who is affected**
Record: Users of CIFS/SMB mounts who call `fallocate()` (mode 0) to
preallocate space, especially with gaps beyond EOF. Config-specific:
requires SMB2/3 and fallocate support (already emulated in this driver).
**Step 8.2 — Trigger conditions**
Record: `fallocate(0, off, len)` where `off + len > EOF` and (`off >
EOF` with gap, or EOF extension on sparse file). Example: `falloc 0 1G`
then `falloc 2G 1M`. Not exotic — matches xfstests generic/213.
Unprivileged on writable mounts.
**Step 8.3 — Failure mode severity**
Record:
- Success without allocation → applications believe space is reserved;
later writes may hit ENOSPC unexpectedly
- Over-allocation of gap region → wasted server disk space, incorrect
sparse layout
- **Severity: MEDIUM-HIGH** (filesystem semantics / space accounting
correctness; not kernel crash or data corruption, but real user-
visible misbehavior)
**Step 8.4 — Risk-benefit**
Record:
- **Benefit:** HIGH for SMB mount users relying on fallocate; fixes
long-standing emulation gap; aligns with already-backported fallocate
fixes in this tree
- **Risk:** LOW — ~60 lines, one file, reviewed, bounded to ≤1 MiB
ranges, uses existing write/query paths
- **Ratio:** Favorable for backport
---
## PHASE 9: FINAL SYNTHESIS
**Step 9.1 — Evidence summary**
**FOR backport:**
- Fixes real POSIX fallocate semantics bug on SMB mounts
- Reproducible via xfstests generic/213
- Small, reviewed, maintainer-signed
- Sister fix `7e08ab7a061b1` already in this 6.18.y tree
- Buggy code confirmed present in v6.18.44
- All required APIs exist locally
- Precedent: other CIFS fallocate/i_blocks fixes already in stable
**AGAINST backport:**
- Not a crash/security/data-corruption issue
- Part of larger fallocate series; `5bd1d3dcc25a5` covers related
SetEOF-path cases separately
- Minor backport adjustment needed for buffer allocation line
(`9e4ec3be67af4` not in tree)
- `generic/213` may need additional patches for all server
configurations
**Unresolved:** Whether full `generic/213` pass on all Samba configs
requires `5bd1d3dcc25a5` as well (separate commit). This commit fixes
the specific small EOF-extending range case described.
**Step 9.2 — Stable rules checklist**
1. Obviously correct and tested? **PASS** — clear mechanism, Reviewed-
by, xfstests reference
2. Fixes real bug affecting users? **PASS** — incorrect fallocate
allocation/semantics on SMB mounts
3. Important issue? **PASS** — filesystem correctness / space
preallocation reliability (MEDIUM-HIGH)
4. Small and contained? **PASS** — ~60 lines, one file
5. No new features/APIs? **PASS** — improves existing fallocate
emulation
6. Can apply to local tree? **PASS** — applies with at most one-line
buffer allocation adjustment
**Step 9.3 — Exception categories**
Record: Not a device ID, quirk, DT, build, or docs fix. Standard bug-fix
category.
**Step 9.4 — Decision rationale**
This commit fixes a longstanding, user-reachable fallocate correctness
bug in the CIFS/SMB client. The buggy SetEOF path is present in
v6.18.44. The fix is small, reviewed, and consistent with fallocate
fixes already backported to this tree (`7e08ab7a061b1`). While not a
kernel crash, incorrect fallocate success/space allocation directly
affects applications using SMB mounts for preallocation — a real stable-
tree concern for the SMB client subsystem.
---
## Verification
- [Phase 1] Parsed commit message and tags from `git show 7a06d3b816d73`
- [Phase 2] Diff analysis from provided diff and `git show 7a06d3b816d73
-p`
- [Phase 3] `git describe HEAD` → v6.18.44; `git blame -L 3665,3680
fs/smb/client/smb2ops.c` → SetEOF path from v6.18 merge base
- [Phase 3] `git show 966a3cb7c7db` → fallocate emulation introduced
2021
- [Phase 3] `git log HEAD..master -- fs/smb/client/smb2ops.c` → commit
not in tree; prerequisites identified
- [Phase 3] `git log --oneline -1 7e08ab7a061b1` → overlapping ranges
fix in tree
- [Phase 3] `git show 9e4ec3be67af4` → buffer sizing prerequisite on
master only
- [Phase 3] `git show 5bd1d3dcc25a5` → separate SetEOF-path follow-up
- [Phase 4] `b4 dig -c 7a06d3b816d73` → lore URL found
- [Phase 4] `b4 dig -c 7a06d3b816d73 -a` → v4–v8 series revisions
- [Phase 4] `b4 dig -c 7a06d3b816d73 -w` → maintainers CC'd
- [Phase 4] `rg stable /tmp/falloc_thread.mbox` → no stable nomination
found
- [Phase 5] `grep smb3_simple_falloc/cifs_fallocate` → syscall-reachable
call chain confirmed
- [Phase 5] `grep SMB2_query_info/CIFS_INO_BLOCKS` → APIs exist in tree
- [Phase 6] Read `fs/smb/client/smb2ops.c` lines 3541–3758 → buggy
SetEOF path confirmed present
- [Phase 6] `git merge-base --is-ancestor 99cd0a6eeb6c HEAD` → NOT in
tree (unrelated to this fix's core logic)
- [Phase 6] Read `fs/smb/client/inode.c` `cifs_setsize()` → EOF
extension still sets i_blocks from size
- [Phase 7] `git log --oneline -5 --grep=fallocate HEAD` → prior
fallocate fixes in tree
- [Phase 8] Commit message documents Samba strict-allocate behavior and
generic/213
**YES****Backport verdict: YES** for the local **v6.18.44** tree.
This commit fixes a real CIFS/SMB client bug: mode-0 `fallocate()` that
extends EOF with a gap (e.g. allocate at 2G when EOF is 1G) incorrectly
used `SetEOF`, which could succeed without allocating the requested
range or allocate the intervening hole. The fix routes small (≤1 MiB)
EOF-extending ranges through zero-writes instead, matching POSIX
semantics and xfstests `generic/213`.
The buggy SetEOF path is present in this tree, and a related fallocate
fix (`7e08ab7a061b1`) is already backported here. The patch is small,
reviewed, and should apply cleanly with at most a one-line buffer-
allocation tweak (upstream also changed `kvzalloc(1024*1024)` to
`min_t(len, SMB2_MAX_BUFFER_SIZE)` in sibling commit `9e4ec3be67af4`,
which is not in this tree yet).
fs/smb/client/smb2ops.c | 69 +++++++++++++++++++++++++++++++++++------
1 file changed, 60 insertions(+), 9 deletions(-)
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 618e36f4d838e..082e6334ab9f6 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -3545,12 +3545,25 @@ static int smb3_simple_fallocate_range(unsigned int xid,
loff_t off, loff_t len)
{
struct file_allocated_range_buffer in_data, *out_data = NULL, *tmp_data;
+ struct inode *inode = d_inode(cfile->dentry);
u32 out_data_len;
char *buf = NULL;
u64 range_start, range_len, range_end;
loff_t l;
int rc;
+ buf = kvzalloc(min_t(loff_t, len, SMB2_MAX_BUFFER_SIZE), GFP_KERNEL);
+ if (!buf) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ if (off >= i_size_read(inode)) {
+ rc = smb3_simple_fallocate_write_range(xid, tcon, cfile,
+ off, len, buf);
+ goto out;
+ }
+
in_data.file_offset = cpu_to_le64(off);
in_data.length = cpu_to_le64(len);
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
@@ -3562,12 +3575,6 @@ static int smb3_simple_fallocate_range(unsigned int xid,
if (rc)
goto out;
- buf = kvzalloc(min_t(loff_t, len, SMB2_MAX_BUFFER_SIZE), GFP_KERNEL);
- if (buf == NULL) {
- rc = -ENOMEM;
- goto out;
- }
-
tmp_data = out_data;
while (len) {
/*
@@ -3642,18 +3649,22 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
struct cifsFileInfo *cfile = file->private_data;
long rc = -EOPNOTSUPP;
unsigned int xid;
- loff_t new_eof;
+ loff_t old_eof, new_eof;
+ struct smb2_file_all_info file_inf;
+ u64 asize;
+ int qrc;
xid = get_xid();
inode = d_inode(cfile->dentry);
cifsi = CIFS_I(inode);
+ old_eof = i_size_read(inode);
trace_smb3_falloc_enter(xid, cfile->fid.persistent_fid, tcon->tid,
tcon->ses->Suid, off, len);
/* if file not oplocked can't be sure whether asking to extend size */
if (!CIFS_CACHE_READ(cifsi))
- if (keep_size == false) {
+ if (!keep_size) {
trace_smb3_falloc_err(xid, cfile->fid.persistent_fid,
tcon->tid, tcon->ses->Suid, off, len, rc);
free_xid(xid);
@@ -3663,11 +3674,51 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
/*
* Extending the file
*/
- if ((keep_size == false) && i_size_read(inode) < off + len) {
+ if (!keep_size && old_eof < off + len) {
rc = inode_newsize_ok(inode, off + len);
if (rc)
goto out;
+ /*
+ * A small range at or beyond EOF can be allocated by writing
+ * zeroes. For off > old_eof, this preserves the intervening
+ * hole instead of allocating from offset 0.
+ */
+ if (off > old_eof ||
+ (off == old_eof && old_eof != 0 &&
+ (cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE))) {
+ if (len > 1024 * 1024) {
+ rc = -EOPNOTSUPP;
+ goto out;
+ }
+
+ rc = smb3_simple_fallocate_range(xid, tcon, cfile,
+ off, len);
+ if (rc) {
+ spin_lock(&inode->i_lock);
+ cifsi->time = 0;
+ spin_unlock(&inode->i_lock);
+ goto out;
+ }
+
+ new_eof = off + len;
+ netfs_resize_file(&cifsi->netfs, new_eof, true);
+ cifs_setsize(inode, new_eof);
+
+ qrc = SMB2_query_info(xid, tcon,
+ cfile->fid.persistent_fid,
+ cfile->fid.volatile_fid, &file_inf);
+ spin_lock(&inode->i_lock);
+ if (qrc == 0) {
+ asize = le64_to_cpu(file_inf.AllocationSize);
+ inode->i_blocks = CIFS_INO_BLOCKS(asize);
+ } else {
+ cifsi->time = 0;
+ }
+ spin_unlock(&inode->i_lock);
+ goto out;
+ }
+
if (cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)
smb2_set_sparse(xid, tcon, cfile, inode, false);
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18] smb/client: do not account EOF extension as allocation
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (19 preceding siblings ...)
2026-08-31 13:27 ` [PATCH AUTOSEL 6.18] smb/client: emulate small EOF-extending mode 0 fallocate ranges Sasha Levin
@ 2026-08-31 13:28 ` Sasha Levin
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-6.6] smb/client: flush dirty data before punching a hole Sasha Levin
` (6 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:28 UTC (permalink / raw)
To: patches, stable
Cc: Huiwen He, ChenXiaoSong, Steve French, Sasha Levin, pc,
linkinjeon, linux-cifs, samba-technical, linux-kernel
From: Huiwen He <hehuiwen@kylinos.cn>
[ Upstream commit 99cd0a6eeb6c20fc6b914e7ce192c6b08e1ef906 ]
cifs_setsize() updates the local inode size after SetEOF succeeds. It also
used the new EOF as a local i_blocks estimate, but extending EOF does not
prove that the intervening range was allocated.
For example, after writing 1 MiB and then extending EOF to 10 MiB, the
client can report the file as fully allocated even though the server still
reports a much smaller AllocationSize:
$ dd if=/dev/zero of=test bs=1M count=1
$ truncate -s 10M test && stat -c 'size=%s blocks=%b' test
$ stat --cached=never -c 'size=%s blocks=%b' test
client stat: size=10485760 blocks=20480
server stat: size=10485760 blocks=2056
client stat after revalidation: size=10485760 blocks=2056
A later attribute revalidation may correct i_blocks, but callers such as
xfstests generic/495 invoke swapon immediately after truncate. The swapfile
hole check can therefore observe the inflated local i_blocks value and
accept a sparse file.
Do not grow i_blocks from cifs_setsize() on EOF extension. Only clamp it
on shrink; allocation growth must come from write completion or from
server-reported AllocationSize.
With this change, EOF extension no longer makes a sparse file appear
fully allocated before the next attribute revalidation, and xfstests
generic/495 no longer accepts it through the inflated local i_blocks value.
Signed-off-by: Huiwen He <hehuiwen@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
**Step 1.1 — Subject line**
Record: `[smb/client]` `[fix implicit: "do not"]` — Stop treating EOF
extension as block allocation in `cifs_setsize()`.
**Step 1.2 — Tags**
Record:
- Signed-off-by: Huiwen He \<hehuiwen@kylinos.cn\> (author)
- Reviewed-by: ChenXiaoSong \<chenxiaosong@kylinos.cn\>
- Signed-off-by: Steve French \<stfrench@microsoft.com\> (SMB/CIFS
maintainer)
- No Fixes:, Reported-by:, Link:, Cc: stable, or Tested-by: tags
**Step 1.3 — Body analysis**
Record:
- **Bug:** `cifs_setsize()` sets `inode->i_blocks` from the new EOF
(`offset`), but extending EOF does not allocate the intervening range
on SMB.
- **Symptom:** After `truncate -s 10M` on a 1 MiB file, cached `stat`
shows `blocks=20480` (10 MiB) while the server reports `blocks=2056`
(~1 MiB). Revalidation corrects it later.
- **Failure mode:** `xfstests generic/495` calls `swapon` immediately
after `truncate`; `cifs_swap_activate()` sees inflated `i_blocks` and
accepts a sparse swapfile that should be rejected.
- **Root cause:** Conflating logical file size with physical allocation
size in `cifs_setsize()`.
- **Fix approach:** Only clamp `i_blocks` on shrink; allocation growth
must come from write completion or server-reported `AllocationSize`.
**Step 1.4 — Hidden bug fix?**
Record: Yes — this is a real correctness bug disguised as an accounting
fix, not cosmetic cleanup.
---
## Phase 2: Diff Analysis
**Step 2.1 — Inventory**
Record:
- 1 file: `fs/smb/client/inode.c` (+7 / -4 net)
- Function modified: `cifs_setsize()`
- Scope: single-file, surgical fix
**Step 2.2 — Code flow change**
Record:
- **Before:** On every `cifs_setsize()`, unconditionally
`inode->i_blocks = CIFS_INO_BLOCKS(offset)`.
- **After:** Save `old_size`, update `i_size`, and only if `offset <
old_size` clamp `i_blocks` down; on EOF extension, leave `i_blocks`
unchanged.
- **Paths affected:** All callers of `cifs_setsize()` —
truncate/ftruncate, fallocate EOF extension, clone/duplicate extents,
truncate-to-zero.
**Step 2.3 — Bug mechanism**
Record: **Logic/correctness bug** — `i_blocks` (allocation estimate) was
derived from EOF instead of actual allocation. This breaks the sparse-
file invariant used by swap activation.
**Step 2.4 — Fix quality**
Record: Obviously correct per SMB semantics (SetEOF ≠ allocate). Minimal
change. Low regression risk: shrink path still clamps; growth paths
(`netfs_update_i_size()` on write, `cifs_fattr_to_inode()` /
`smb2_close_getattr()` from server) remain intact.
---
## Phase 3: Git History Investigation
**Step 3.1 — Blame**
Record: Unconditional `inode->i_blocks = CIFS_INO_BLOCKS(offset)`
introduced in `f4e35576da439` (Paulo Alcantara, 2026-03-18) — "smb:
client: fix generic/694 due to wrong ->i_blocks". `cifs_setsize()`
itself dates to 2007; the buggy `i_blocks` assignment is recent.
**Step 3.2 — Fixes: tag**
Record: N/A — no Fixes: tag. The regression source is `f4e35576da439`,
which **is** in this tree (ancestor of HEAD, present since v6.18.22).
**Step 3.3 — Related file history**
Record: Recent `inode.c` changes include `efbcecdecefc2`
(fscache_resize_cookie in cifs_setsize), `f4e35576da439` (generic/694
i_blocks fix). This commit is a direct follow-up correcting the over-
broad generic/694 approach. Standalone; no "patch X/Y" series.
**Step 3.4 — Author context**
Record: Huiwen He has prior SMB client commits in this tree (e.g.
fallocate overlap handling). Steve French (maintainer) signed off.
**Step 3.5 — Dependencies**
Record: **Requires `f4e35576da439`** — without it, `cifs_setsize()` does
not set `i_blocks` from offset and this patch has nothing to fix in that
function. In this 6.18.44 tree, that prerequisite is satisfied. Patch
applies cleanly with only minor context (current tree has
`fscache_resize_cookie()` after `netfs_wait_for_outstanding_io()`).
---
## Phase 4: Mailing List and External Research
**Step 4.1 — Original discussion**
Record: UNVERIFIED — lore.kernel.org blocked by bot protection. `b4 dig`
on the related generic/694 upstream commit (`23b5df09c27a`) found
https://patch.msgid.link/20260319034252.472217-1-pc@manguebit.org. Could
not locate this specific commit's thread (not yet in local git history,
no SHA for `b4 dig -c`).
**Step 4.2 — Reviewers**
Record: Reviewed-by and maintainer Signed-off-by present in commit
message. Full recipient list UNVERIFIED.
**Step 4.3 — Bug report**
Record: Concrete reproduction in commit message (dd + truncate + stat).
xfstests `generic/495` cited as trigger. No syzbot/external bug link.
**Step 4.4 — Related patches**
Record: Direct follow-up to `f4e35576da439` (generic/694). Complements
existing allocation update paths in `cifs_fattr_to_inode()`,
`smb2_close_getattr()`, and `netfs_update_i_size()`.
**Step 4.5 — Stable list history**
Record: UNVERIFIED — could not search lore stable archive.
---
## Phase 5: Code Semantic Analysis
**Step 5.1 — Key functions**
Record: `cifs_setsize()` (modified); related: `cifs_swap_activate()`,
`netfs_update_i_size()`, `cifs_fattr_to_inode()`.
**Step 5.2 — Callers of `cifs_setsize()`**
Record:
- `cifs_file_set_size()` — truncate/ftruncate path (`inode.c`)
- `smb3_simple_falloc()` — EOF extension (`smb2ops.c`)
- `smb2_duplicate_extents()` — clone size extension (`smb2ops.c`)
- truncate-to-zero in `file.c`
**Step 5.3 — Callees**
Record: `i_size_write()`, `truncate_pagecache()`,
`netfs_wait_for_outstanding_io()`, timestamp updates.
**Step 5.4 — Reachability**
Record: **Userspace-reachable** via `truncate(2)`/`ftruncate(2)` →
`cifs_setattr()` → `cifs_file_set_size()` → `cifs_setsize()`. Swap
activation via `swapon(2)` → `cifs_swap_activate()` reads cached
`i_blocks`.
**Step 5.5 — Similar patterns**
Record: NFS has identical swap hole check (`fs/nfs/file.c:584`).
`cifs_fattr_to_inode()` correctly uses `fattr->cf_bytes` (allocation),
not EOF — the fix aligns `cifs_setsize()` with that model.
---
## Phase 6: Cross-Reference Against Local Tree (6.18.44)
**Step 6.1 — Buggy code present?**
Record: **YES.** At `fs/smb/client/inode.c:3037`:
```3031:3037:fs/smb/client/inode.c
spin_lock(&inode->i_lock);
i_size_write(inode, offset);
/*
- Until we can query the server for actual allocation size,
- this is best estimate we have for blocks allocated for a file.
*/
inode->i_blocks = CIFS_INO_BLOCKS(offset);
```
The candidate fix is **not** yet in this tree (no matching commit or
strings).
**Step 6.2 — Backport complications**
Record: Clean apply expected. Only contextual difference:
`fscache_resize_cookie()` line after the modified block (commit diff
predates or omits it; trivial merge).
**Step 6.3 — Related fixes already present?**
Record: `f4e35576da439` (generic/694) is present and is the source of
the regression this commit corrects. No duplicate fix found.
---
## Phase 7: Subsystem and Maintainer Context
**Step 7.1 — Subsystem**
Record: `fs/smb/client` (CIFS/SMB3 client). Criticality: **IMPORTANT** —
network filesystem used broadly; swap-on-SMB is experimental but the
`i_blocks` cache affects `stat()` and hole detection for all truncate
users.
**Step 7.2 — Activity**
Record: Actively maintained; multiple recent smb/client fixes in this
tree.
---
## Phase 8: Impact and Risk Assessment
**Step 8.1 — Who is affected**
Record: CIFS/SMB3 mount users who truncate files (especially sparse
files). Swap-on-CIFS users hit the worst case. `stat -c %b` can report
wrong block counts until revalidation.
**Step 8.2 — Trigger conditions**
Record: Extend EOF without allocating (truncate up, sparse fallocate).
Common operation. Unprivileged users can trigger on files they own.
**Step 8.3 — Failure severity**
Record: **HIGH** — `cifs_swap_activate()` hole check (`blocks*512 <
isize`) is bypassed when `i_blocks` is inflated, allowing swap
activation on a sparse file:
```3237:3244:fs/smb/client/file.c
spin_lock(&inode->i_lock);
blocks = inode->i_blocks;
isize = inode->i_size;
spin_unlock(&inode->i_lock);
if (blocks*512 < isize) {
pr_warn("swap activate: swapfile has holes\n");
return -EINVAL;
}
```
Using unallocated regions as swap risks data corruption. Wrong `stat`
blocks is a secondary user-visible correctness issue.
**Step 8.4 — Risk/benefit**
Record: **Benefit: HIGH** (correctness, swap safety, xfstests). **Risk:
LOW** (small, well-scoped; shrink still clamped; write/server paths
still grow `i_blocks`). Strong benefit/risk ratio.
---
## Phase 9: Final Synthesis
**Step 9.1 — Evidence summary**
**FOR backport:**
- Real bug: EOF ≠ allocation on SMB; code incorrectly equates them
- Verifiable in local tree (`f4e35576da439` regression present)
- Causes swap hole check to accept invalid sparse swapfiles
- xfstests generic/495 failure documented
- Small, surgical, maintainer-reviewed fix
- Prerequisite commit present in 6.18.44
**AGAINST backport:**
- Fix depends on `f4e35576da439` being present (satisfied here)
- Swap-on-SMB is experimental (but the `stat`/i_blocks bug affects all
truncate-up paths)
- Lore discussion UNVERIFIED
**Step 9.2 — Stable rules checklist**
1. Obviously correct and tested? **PASS** — logic matches SMB semantics;
xfstests cited; maintainer SOB
2. Fixes real bug affecting users? **PASS** — wrong cached allocation,
swap acceptance
3. Important issue? **PASS** — HIGH: swap integrity / data corruption
risk on sparse files
4. Small and contained? **PASS** — ~10 lines, one function
5. No new features/APIs? **PASS**
6. Can apply to local tree? **PASS** — prerequisite present, clean apply
**Step 9.3 — Exception categories**
Record: N/A (standard bug fix).
**Step 9.4 — Decision rationale**
This is a regression fix for `f4e35576da439` in the 6.18.y tree. The
buggy code is present at HEAD. The fix restores correct `i_blocks`
accounting without breaking shrink or write/server update paths. It
meets all stable-kernel criteria.
---
## Verification
- [Phase 1] Parsed subject, tags, body from provided commit message
- [Phase 2] Analyzed provided diff; confirmed current `cifs_setsize()`
at inode.c:3029-3043
- [Phase 3] `git describe HEAD` → v6.18.44-1-g2736c32da98b9; `make
kernelversion` → 6.18.44
- [Phase 3] `git blame` on inode.c:3037 → f4e35576da439 introduced
unconditional i_blocks assignment
- [Phase 3] `git show f4e35576da439` → generic/694 fix added i_blocks to
cifs_setsize
- [Phase 3] `git merge-base --is-ancestor f4e35576da439 HEAD` →
prerequisite present
- [Phase 3] `git tag --contains f4e35576da439` → present since v6.18.22
- [Phase 3] `git log --grep="EOF extension"` / `--grep="account EOF"` →
no match (fix not in tree)
- [Phase 4] WebFetch lore.kernel.org → blocked (bot protection)
- [Phase 4] `b4 dig -c 23b5df09c27a` → found generic/694 thread URL
- [Phase 4] UNVERIFIED: lore thread for this specific commit
- [Phase 5] `grep cifs_setsize` → 4 call sites in smb/client
- [Phase 5] Read `cifs_swap_activate()` at file.c:3223-3244 → hole check
uses i_blocks vs i_size
- [Phase 5] Read `netfs_update_i_size()` at buffered_write.c:38-72 →
write path grows i_blocks
- [Phase 5] Read `cifs_fattr_to_inode()` at inode.c:236-238 → server
revalidation uses cf_bytes
- [Phase 5] Read `smb2_close_getattr()` at smb2ops.c:1530-1532 → server
AllocationSize updates i_blocks
- [Phase 6] Confirmed buggy line at inode.c:3037 in HEAD
- [Phase 6] Confirmed fix strings absent from tree
- [Phase 8] Severity: swap hole check bypass → HIGH
**YES**The background searches are done. They match the earlier
analysis:
- **Target commit not in tree** — no matches for "EOF extension",
"account EOF", or "generic/495" in `fs/smb/client/`.
- **Author history** — Huiwen He has prior SMB client work here
(fallocate overlap handling, `FS_IOC_GETFLAGS`, etc.).
- **Fix-not-present check** — the `git log -S` search timed out, but a
direct read of `cifs_setsize()` still shows the buggy unconditional
`i_blocks = CIFS_INO_BLOCKS(offset)` at `inode.c:3037`, with no "Only
clamp" fix applied.
**Verdict unchanged: YES** for backport to this 6.18.44 tree — it
corrects a regression from `f4e35576da439` where EOF extension is
wrongly treated as allocation, which can let `cifs_swap_activate()`
accept sparse swapfiles.
fs/smb/client/inode.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/fs/smb/client/inode.c b/fs/smb/client/inode.c
index c9e955d0d799e..af36936fde08b 100644
--- a/fs/smb/client/inode.c
+++ b/fs/smb/client/inode.c
@@ -3028,13 +3028,20 @@ int cifs_fiemap(struct inode *inode, struct fiemap_extent_info *fei, u64 start,
void cifs_setsize(struct inode *inode, loff_t offset)
{
+ loff_t old_size;
+ u64 blocks = CIFS_INO_BLOCKS(offset);
+
spin_lock(&inode->i_lock);
+ old_size = i_size_read(inode);
i_size_write(inode, offset);
+
/*
- * Until we can query the server for actual allocation size,
- * this is best estimate we have for blocks allocated for a file.
+ * Extending EOF does not allocate the intervening range. Only clamp
+ * i_blocks on shrink; allocation growth comes from writes or from the
+ * server-reported AllocationSize.
*/
- inode->i_blocks = CIFS_INO_BLOCKS(offset);
+ if (offset < old_size && (u64)inode->i_blocks > blocks)
+ inode->i_blocks = blocks;
spin_unlock(&inode->i_lock);
inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
truncate_pagecache(inode, offset);
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.6] smb/client: flush dirty data before punching a hole
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (20 preceding siblings ...)
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18] smb/client: do not account EOF extension as allocation Sasha Levin
@ 2026-08-31 13:28 ` Sasha Levin
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-6.6] smb: client: fix races in cifsd thread creation Sasha Levin
` (5 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:28 UTC (permalink / raw)
To: patches, stable
Cc: Huiwen He, ChenXiaoSong, Steve French, Sasha Levin, pc,
linkinjeon, linux-cifs, samba-technical, linux-kernel
From: Huiwen He <hehuiwen@kylinos.cn>
[ Upstream commit d7d2adcd022baade5cab65ca492ce63421ce3a6e ]
Punching a hole after a large buffered write may leave the range
reported as data. Reproduce it with:
xfs_io -f \
-c "pwrite -b 3m -S 0x61 0 3m" \
-c "fpunch 1m 1m" \
-c "seek -h 0" \
-c "seek -d 1m" \
/mnt/test/repro
Punching 1 MiB at offset 1 MiB should produce:
0 1 MiB 2 MiB 3 MiB
| DATA | HOLE | DATA | EOF
Instead, the entire file is reported as data. SEEK_HOLE(0) returns EOF,
and SEEK_DATA(1M) returns 1M.
This happens because a dirty folio spanning the punched range can be
written back after the punch and refill the hole.
Fix this by flushing and waiting for dirty data in the punched range
before invalidating the page cache and issuing FSCTL_SET_ZERO_DATA.
The xfstests generic/539 pass against Samba/ksmbd with this change.
Signed-off-by: Huiwen He <hehuiwen@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `smb/client: flush dirty data before
punching a hole`
**Local tree:** `v6.18.44-1-g2736c32da98b9` (Linux 6.18.44 stable)
**Candidate commit:** `d7d2adcd022ba` (on `master`, not yet in this
checkout)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[smb/client]` — implicit **fix** (flush before punch) —
ensure dirty folios are written back before punching a hole so hole
semantics are correct.
### Step 1.2: Tags
**Record:**
- **Signed-off-by:** Huiwen He `<hehuiwen@kylinos.cn>` (author)
- **Reviewed-by:** ChenXiaoSong `<chenxiaosong@kylinos.cn>`
- **Signed-off-by:** Steve French `<stfrench@microsoft.com>` (maintainer
commit)
- No Fixes:, Reported-by:, Link:, Cc: stable, Tested-by:, or Acked-by:
- Notable: maintainer-reviewed and committed; no syzbot/fuzzer
involvement
### Step 1.3: Body analysis
**Record:**
- **Bug:** After a large buffered write, punching a hole in the middle
can leave the entire file reported as data.
- **Symptom:** `SEEK_HOLE(0)` returns EOF; `SEEK_DATA(1M)` returns 1M
instead of the expected `DATA | HOLE | DATA` layout.
- **Root cause:** A dirty folio spanning the punched range can be
written back *after* the punch ioctl, refilling the hole in the page
cache.
- **Reproducer:** `xfs_io` sequence with `pwrite -b 3m`, `fpunch 1m 1m`,
then `seek -h` / `seek -d`.
- **Validation:** xfstests `generic/539` passes against Samba/ksmbd with
this change.
- **Version info:** None in message.
### Step 1.4: Hidden bug fix detection
**Record:** Not disguised — this is an explicit correctness fix for
page-cache coherency during `FALLOC_FL_PUNCH_HOLE`. The missing
`filemap_write_and_wait_range()` is an oversight relative to sibling
code paths in the same file.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **Files:** `fs/smb/client/smb2ops.c` (+9 lines, 0 removed)
- **Function:** `smb3_punch_hole()`
- **Scope:** Single-file, surgical fix
### Step 2.2: Code flow change
**Record:**
- **Before:** `filemap_invalidate_lock()` → `truncate_pagecache_range()`
→ `netfs_wait_for_outstanding_io()` → `FSCTL_SET_ZERO_DATA`
- **After:** `filemap_invalidate_lock()` →
**`filemap_write_and_wait_range(offset..offset+len-1)`** → on error
`goto unlock` → then same truncate/ioctl path
- **Path affected:** Normal punch-hole path after sparse-file setup;
error path gains proper unlock on flush failure.
### Step 2.3: Bug mechanism
**Record:**
- **Category:** Cache coherency / logic correctness (stale dirty
writeback refilling a punched hole)
- **Mechanism:** Page cache invalidated and server hole punched, but a
dirty folio spanning the range was not flushed first; later writeback
repopulates the “hole” locally, breaking `SEEK_HOLE`/`SEEK_DATA`
semantics.
### Step 2.4: Fix quality
**Record:**
- **Quality:** High — mirrors the existing pattern in
`smb3_zero_range()` in the same file (lines 3384–3400).
- **Regression risk:** Low — `filemap_write_and_wait_range()` under
`filemap_invalidate_lock()` is already used in `smb3_zero_range()` and
other fallocate paths in this file; error handling uses existing
`unlock` label.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** Punch-hole invalidation block (`filemap_invalidate_lock`
through `truncate_pagecache_range`) introduced at `5d324e5159d9e` (6.18
merge, Nov 2025). Bug has been present since that code landed in this
tree.
### Step 3.2: Fixes: tag
**Record:** N/A — no Fixes: tag.
### Step 3.3: File history
**Record:** Recent related commits in this tree include `d0bfd7004a87f`
(preserve `smb2_set_sparse()` errors) and `7e08ab7a061b1` (overlapping
allocated ranges in fallocate). This fix is standalone; `git format-
patch -1 d7d2adcd022ba | git apply --check` succeeds on HEAD.
### Step 3.4: Author context
**Record:** Huiwen He has multiple smb/client fixes in this tree
(`d0bfd7004a87f`, `7e08ab7a061b1`, `74badb5e2b00a`). Steve French is the
CIFS/SMB maintainer and committed this patch.
### Step 3.5: Dependencies
**Record:** No dependencies. v2 lore note says “Rebased onto cifs-2.6
for-next, No functional changes.” Applies cleanly to 6.18.44.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:**
- **URL:**
https://patch.msgid.link/20260715013901.156851-1-huiwen.he@linux.dev
- **Series:** v1 (2026-07-14) → v2 (2026-07-15, committed version)
- **Reviewer feedback:** No NAKs or objections in thread mbox; v2 only
rebased
- **Stable nomination:** None found in thread
### Step 4.2: Reviewers
**Record:** CC'd to Steve French, linux-cifs maintainers/contributors
(linkinjeon, dhowells, etc.), and `linux-cifs@vger.kernel.org`.
Reviewed-by ChenXiaoSong.
### Step 4.3: Bug report
**Record:** Reproducer provided in commit message; validated by xfstests
`generic/539`. No external bugzilla/syzbot link.
### Step 4.4: Related patches
**Record:** Standalone 1-patch series; not part of a multi-patch
dependency chain.
### Step 4.5: Stable list
**Record:** Not searched on lore stable (WebFetch blocked by bot
protection); no stable discussion found in b4 mbox.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `smb3_punch_hole()` (modified); callers: `smb3_fallocate()`.
### Step 5.2: Callers
**Record:**
- `smb3_fallocate()` → when `mode & FALLOC_FL_PUNCH_HOLE`
- `smb3_fallocate` registered as `.fallocate` in SMB2/SMB3 ops tables
- Reached from `cifs_fallocate()` in `cifsfs.c` via VFS `fallocate()`
syscall
- Userspace-triggerable on CIFS/SMB mounts
### Step 5.3: Callees
**Record:** `smb2_set_sparse()`, `filemap_invalidate_lock()`,
**`filemap_write_and_wait_range()`** (added),
`truncate_pagecache_range()`, `netfs_wait_for_outstanding_io()`,
`SMB2_ioctl(FSCTL_SET_ZERO_DATA)`.
### Step 5.4: Reachability
**Record:** `fallocate(FALLOC_FL_PUNCH_HOLE)` from userspace on SMB-
mounted files. Common for databases, VM images, backup tools doing thin-
provisioning/space reclamation.
### Step 5.5: Similar patterns
**Record:** Strong precedent in same file:
- `smb3_zero_range()` already calls `filemap_write_and_wait_range()`
before `truncate_pagecache_range()` (lines 3388–3400)
- `smb3_llseek()` documents “dirty pages … might fill holes on the
server” and flushes before `FSCTL_QUERY_ALLOCATED_RANGES` (lines
3888–3898)
- Punch hole was the outlier missing this flush.
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE
### Step 6.1: Buggy code present?
**Record:** **YES.** Current `smb3_punch_hole()` at lines 3459–3465
lacks `filemap_write_and_wait_range()` before cache invalidation. Bug
present since punch-hole code landed in 6.18.
### Step 6.2: Backport complications
**Record:** **Clean apply** — `git apply --check` passes. No structural
conflicts with recent `d0bfd7004a87f` sparse-error fix.
### Step 6.3: Related fixes already present?
**Record:** No equivalent fix in HEAD. `git log HEAD --grep='flush
dirty'` returns nothing for this file. Fix exists only on `master` as
`d7d2adcd022ba`.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem criticality
**Record:** **fs/smb/client** (CIFS/SMB client) — **IMPORTANT**. Affects
users of network filesystem mounts; not universal like VFS core, but
widely deployed in enterprise/desktop.
### Step 7.2: Activity
**Record:** Actively maintained; multiple smb/client fixes in recent
6.18.y history.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who is affected
**Record:** Users of CIFS/SMB mounts who use
`fallocate(FALLOC_FL_PUNCH_HOLE)` — databases, QEMU/img tools,
backup/dedup software, anything using `SEEK_HOLE`/`SEEK_DATA` after
punch.
### Step 8.2: Trigger conditions
**Record:** Buffered write creating a dirty folio spanning the punch
range, followed by punch hole on the same file. Reproducible with
`xfs_io`. Requires SMB mount with punch-hole support; not theoretical.
### Step 8.3: Failure mode severity
**Record:** Incorrect hole/data extent reporting; stale writeback can
refill punched regions in the page cache. **Severity: HIGH** for
correctness (not a kernel oops, but breaks filesystem semantics and can
defeat space reclamation). Analogous to known CIFS cache-coherency
issues already handled in `smb3_llseek`.
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** HIGH for SMB users relying on punch-hole semantics
- **Risk:** LOW — 9 lines, established API/pattern, maintainer-
committed, xfstests-validated
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Real, reproducible bug with clear root cause
- Breaks `SEEK_HOLE`/`SEEK_DATA` after punch hole
- Fix mirrors existing code in `smb3_zero_range()` and `smb3_llseek()`
in the same file
- Small (9 lines), surgical, applies cleanly to 6.18.44
- Reviewed and committed by subsystem maintainer
- xfstests `generic/539` validation
- Userspace-reachable via `fallocate()` on SMB mounts
**AGAINST backport:**
- No crash/panic/security issue — correctness/semantics bug
- No explicit stable nomination in lore thread
**Unresolved:** No independent Tested-by beyond author's xfstests claim;
lore replies not fully readable via WebFetch (bot protection). Neither
affects the technical decision.
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — mirrors sibling functions;
xfstests cited
2. Fixes a real bug affecting users? **PASS** — reproducible with xfs_io
3. Important issue? **PASS** — filesystem semantics/correctness on
common network FS path (HIGH)
4. Small and contained? **PASS** — 9 lines, one function
5. No new features or APIs? **PASS** — adds missing flush only
6. Can apply to local tree? **PASS** — clean apply verified
### Step 9.3: Exception categories
**Record:** N/A (not device ID, quirk, DT, build, or docs — standard bug
fix).
### Step 9.4: Decision rationale
For Linux **6.18.y**, `smb3_punch_hole()` has been missing a dirty-page
flush that every related code path in the same file already performs.
Without it, punch hole can appear to succeed while the page cache is
later repopulated by writeback, breaking hole/data reporting. The fix is
minimal, follows an established in-tree pattern, applies cleanly, and is
maintainer-reviewed. This is appropriate stable material.
---
## Verification
- **[Phase 1]** `git show d7d2adcd022ba`: parsed full commit message and
tags
- **[Phase 1]** No Fixes:/Reported-by:/Cc: stable tags found
- **[Phase 2]** `git show d7d2adcd022ba -p`: confirmed +9 lines in
`smb3_punch_hole()`
- **[Phase 2]** Read `fs/smb/client/smb2ops.c` lines 3366–3502,
3868–3920: confirmed `smb3_zero_range` has flush, `smb3_punch_hole`
does not; `smb3_llseek` documents same issue
- **[Phase 3]** `git describe HEAD`: v6.18.44-1-g2736c32da98b9; Makefile
VERSION=6 PATCHLEVEL=18 SUBLEVEL=44
- **[Phase 3]** `git blame -L 3459,3465 fs/smb/client/smb2ops.c`: punch-
hole block from 5d324e5159d9e
- **[Phase 3]** `git log HEAD..master -- fs/smb/client/smb2ops.c`:
d7d2adcd022ba present on master, not in HEAD
- **[Phase 3]** `git format-patch -1 d7d2adcd022ba | git apply --check`:
applies cleanly
- **[Phase 3]** `git log --author='Huiwen' -10`: author has prior
smb/client fixes in tree
- **[Phase 4]** `b4 dig -c d7d2adcd022ba`: lore URL found
- **[Phase 4]** `b4 dig -c d7d2adcd022ba -a`: v1→v2, no functional v2
changes
- **[Phase 4]** `b4 dig -c d7d2adcd022ba -w`: Steve French and linux-
cifs CC'd
- **[Phase 4]** `b4 dig -c d7d2adcd022ba -m /tmp/punch_hole_thread.mbx`:
thread saved; Reviewed-by present; no stable Cc found
- **[Phase 4]** WebFetch lore URL: blocked by bot protection (Anubis)
- **[Phase 5]** `grep smb3_punch_hole fs/smb/client/`: caller is
`smb3_fallocate` at line 4032
- **[Phase 5]** Read `cifsfs.c` `cifs_fallocate()`: VFS entry via
`server->ops->fallocate`
- **[Phase 6]** Read current `smb3_punch_hole()` at lines 3440–3502:
buggy code confirmed present
- **[Phase 6]** `git show v6.12:fs/smb/client/smb2ops.c | rg
punch_hole`: function exists at v6.12 without flush (bug predates
6.18.44)
- **[Phase 6]** `git log HEAD --grep='flush dirty'`: no existing fix in
tree
- **[Phase 8]** Failure mode assessed as HIGH correctness impact on
punch-hole/SEEK semantics
**YES**The background `git log -S` searches didn’t add much:
- **`smb3_punch_hole` search** (accidentally used `----all`) returned
unrelated commits, not the punch-hole introduction.
- **`cifs_punch_hole` search** timed out on this large repo.
That didn’t change the conclusion. Targeted checks already showed
`smb3_punch_hole()` is present in this **6.18.44** tree without the
flush, matches the same pattern already used in `smb3_zero_range()` and
`smb3_llseek()`, and the fix applies cleanly from `d7d2adcd022ba`.
**Recommendation for 6.18.y: YES** — backport the flush-before-punch
fix.
fs/smb/client/smb2ops.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 082e6334ab9f6..b62c5e49e1eb1 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -3457,6 +3457,15 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
goto out;
filemap_invalidate_lock(inode->i_mapping);
+ /*
+ * Flush dirty data first, otherwise a dirty folio spanning the punched
+ * range may be written back after the ioctl and refill the hole.
+ */
+ rc = filemap_write_and_wait_range(inode->i_mapping, offset,
+ offset + len - 1);
+ if (rc < 0)
+ goto unlock;
+
/*
* We implement the punch hole through ioctl, so we need remove the page
* caches first, otherwise the data may be inconsistent with the server.
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.6] smb: client: fix races in cifsd thread creation
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (21 preceding siblings ...)
2026-08-31 13:28 ` [PATCH AUTOSEL 6.18-6.6] smb/client: flush dirty data before punching a hole Sasha Levin
@ 2026-08-31 13:29 ` Sasha Levin
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: fix lease break and ack state handling Sasha Levin
` (4 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:29 UTC (permalink / raw)
To: patches, stable
Cc: Fredric Cover, Steve French, Sasha Levin, pc, linkinjeon,
linux-cifs, samba-technical, linux-kernel
From: Fredric Cover <fredric.cover.lkernel@gmail.com>
[ Upstream commit e8a5cf2ff5a13fefb228f2069e29dd7d8e37185d ]
The cifsd demultiplex thread can run and access tcp_ses before the parent
thread has finished populating tcp_ses, which the worker thread accesses
locklessly.
Also, the kthread_run macro may start the thread before returning the
thread pointer. Because the pointer is part of the structure that the
thread can access, if the kernel is preempted after the thread is spawned,
but before the thread pointer is populated and the thread attempts to exit,
it will sleep, waiting for a SIGKILL signal.
Fix this by moving creation of the thread to after all of tcp_ses'es
fields are populated, and spawning the thread last, using a split
kthread_create/wake_up_process logic.
Signed-off-by: Fredric Cover <fredric.cover.lkernel@gmail.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `smb: client: fix races in cifsd thread
creation`
**Local tree:** `v6.18.44` (`linux-6.18.y` stable), `HEAD` detached at
`2736c32da98b9`
**Upstream fix:** `e8a5cf2ff5a13` (not in this tree; `git merge-base
--is-ancestor` returned 1)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[smb: client]` `[fix]` — fix races in cifsd (demultiplex)
thread creation during TCP session setup.
### Step 1.2: Tags
**Record:**
- **Signed-off-by:** Fredric Cover `<fredric.cover.lkernel@gmail.com>`
(author)
- **Signed-off-by:** Steve French `<stfrench@microsoft.com>` (SMB
maintainer)
- No Fixes:, Reported-by:, Tested-by:, Reviewed-by:, Link:, or Cc:
stable tags
- Notable: maintainer sign-off only; no syzbot or user bug report
### Step 1.3: Body analysis
**Record:**
- **Bug 1:** `cifs_demultiplex_thread` can run and access `tcp_ses`
before the parent finishes populating fields the worker reads without
locking.
- **Bug 2:** `kthread_run()` may wake the thread before the parent
stores `tcp_ses->tsk`. If the thread exits while `tsk` is still NULL,
exit logic sleeps indefinitely waiting for SIGKILL.
- **Symptom:** Race during mount/session setup; potential hung `cifsd`
kernel thread.
- **Root cause:** `kthread_run()` creates and immediately wakes the
thread mid-initialization; comment claiming “kernel thread not created
yet” is incorrect.
- **Fix:** Populate all `tcp_ses` fields first; use `kthread_create()` +
`wake_up_process()` last.
### Step 1.4: Hidden bug fix?
**Record:** No — explicitly described as a race fix. The `spin_lock`
removal around `tcpStatus` is a consequence of correct ordering (thread
not running yet), not cosmetic cleanup.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **File:** `fs/smb/client/connect.c` (+16 / −11, 27 lines touched)
- **Function:** `cifs_get_tcp_session()`
- **Scope:** Single-file, surgical fix
### Step 2.2: Code flow per hunk
**Hunk 1 — remove early `kthread_run`:**
- **Before:** Thread created and woken immediately after
`__module_get()`, before `min_offload`, `retrans`, `tcpStatus`,
`max_credits`, etc. are set.
- **After:** No thread yet; parent continues initialization.
**Hunk 2 — remove `spin_lock` around `tcpStatus`:**
- **Before:** Lock taken because thread could already be running
(contradicting the comment).
- **After:** Unlocked write is safe because thread is still stopped.
**Hunk 3 — `kthread_create` after all fields populated:**
- **Before:** Thread running during list insertion and echo work setup.
- **After:** Thread exists but is not scheduled; `tcp_ses->tsk` is
assigned before any concurrent access.
**Hunk 4 — `wake_up_process()` at end:**
- **Before:** Thread could run before `tsk` pointer stored in struct.
- **After:** All fields and `tsk` are valid before thread executes.
### Step 2.3: Bug mechanism
**Record:**
- **Category:** Race condition / initialization ordering bug
- **Mechanism 1:** TOCTOU between `kthread_run()` wake and field
initialization — demux thread reads `max_credits`, `tcpStatus`, etc.
locklessly while parent still writes them.
- **Mechanism 2:** `kthread_run` macro (`kthread_create` +
`wake_up_process`) returns task pointer to caller *after* thread may
already be running. Exit path in `cifs_demultiplex_thread()`:
```1437:1448:fs/smb/client/connect.c
task_to_wake = xchg(&server->tsk, NULL);
clean_demultiplex_info(server);
/* if server->tsk was NULL then wait for a signal before exiting
*/
if (!task_to_wake) {
set_current_state(TASK_INTERRUPTIBLE);
while (!signal_pending(current)) {
schedule();
set_current_state(TASK_INTERRUPTIBLE);
}
```
If `server->tsk` was never set, the thread hangs forever.
### Step 2.4: Fix quality
**Record:** Obviously correct — standard kernel pattern
(`kthread_create` + `wake_up_process`). Minimal, no API changes. Low
regression risk; removing the unnecessary `srv_lock` around `tcpStatus`
is correct given new ordering.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:**
- `kthread_run(cifs_demultiplex_thread, ...)` introduced in
`7c97c200e2c5a` (2011, Al Viro)
- `task_to_wake` exit-wait logic from `b1c8d2b421376` (2008, Jeff
Layton), re-added in `a5c3e1c725af9` (2014 revert of removal)
- Buggy pattern present since ~2011; hang path possible since 2008/2014
tsk handling
### Step 3.2: Fixes: tag
**Record:** N/A — no Fixes: tag.
### Step 3.3: Related file history
**Record:** Recent `connect.c` changes in this tree include negotiate
timeout race fix (`266b5d02e14f3`), channel deadlock fix
(`711741f94ac3c`), netns leak fix (`59b33fab4ca4d`). No duplicate fix
for this specific race. Standalone patch.
### Step 3.4: Author context
**Record:** Fredric Cover has prior SMB client fixes in tree
(`86f9c23e0814c` OOB read, `6cc1518357369` kvzalloc). Not subsystem
maintainer; patch signed off by Steve French.
### Step 3.5: Dependencies
**Record:** No prerequisites. `kthread_create`/`wake_up_process` exist
in this tree. Patch applies cleanly (`git apply --check` succeeded).
Self-contained.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:** `b4 dig -c e8a5cf2ff5a13` →
https://patch.msgid.link/20260602005512.126883-1-FredTheDude@proton.me
Submitted as `[PATCH RFC]` on 2026-06-01. Lore page blocked by bot
protection; could not read thread replies.
### Step 4.2: Reviewers
**Record:** `b4 dig -w` returned same URL only. CC list from web search:
`sfrench`, `linux-cifs`, `sprasad@microsoft.com`. Maintainer sign-off
present.
### Step 4.3: Bug reports
**Record:** No Reported-by or syzbot link. Theoretical/review-found
race, but mechanism is verifiable in code.
### Step 4.4: Series context
**Record:** `b4 dig -a` shows single revision. Not part of a multi-patch
series.
### Step 4.5: Stable list
**Record:** UNVERIFIED — could not search lore stable archive due to
fetch blocking. No evidence against backport.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Modified functions
**Record:** `cifs_get_tcp_session()` (primary), affects startup of
`cifs_demultiplex_thread()`.
### Step 5.2: Callers
**Record:** `cifs_get_tcp_session()` called from:
- Mount path (~line 3667 in `connect.c`) — every CIFS/SMB mount
- `sess.c:561` — multichannel session setup
Every SMB/CIFS mount triggers this path.
### Step 5.3: Callees
**Record:** `kthread_create`, `wake_up_process`, `list_add`,
`queue_delayed_work`, field initialization. Demux thread calls
`cifs_read_from_socket`, `allocate_buffers`, credit handling — all use
`server` fields set in this function.
### Step 5.4: Reachability
**Record:** Reachable from userspace via `mount -t cifs` / SMB mount
syscalls. Common enterprise and desktop path. Unprivileged users can
trigger if permitted to mount.
### Step 5.5: Similar patterns
**Record:** No other `kthread_run(cifs_demultiplex_thread` instances.
This is the sole creation site.
---
## PHASE 6: CROSS-REFERENCE WITH LOCAL TREE
### Step 6.1: Buggy code present?
**Record:** **YES.** Current tree at `fs/smb/client/connect.c:1874-1906`
has identical buggy `kthread_run` ordering. Bug predates 6.18.y branch
(code from 2008–2011).
### Step 6.2: Backport complications
**Record:** **Clean apply.** `git show e8a5cf2ff5a13 --
fs/smb/client/connect.c | git apply --check` succeeded with no
conflicts.
### Step 6.3: Related fixes already present?
**Record:** No equivalent fix in this tree. `git merge-base --is-
ancestor e8a5cf2ff5a13 HEAD` → exit 1 (not merged).
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem criticality
**Record:** `fs/smb/client` — **IMPORTANT**. CIFS/SMB client used widely
on servers, desktops, NAS mounts. Not core VFS, but affects any system
mounting SMB shares.
### Step 7.2: Activity
**Record:** Actively maintained in 6.18.y (20+ recent commits to
`connect.c`).
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who is affected
**Record:** All users mounting CIFS/SMB shares (`CONFIG_CIFS`).
### Step 8.2: Trigger conditions
**Record:**
- **Init race:** Any mount — timing-dependent, more likely under
preemption/scheduling pressure.
- **Hang:** Failed mount or fast teardown after `kthread_run` but before
`tsk` assignment; requires unlucky scheduling.
- **Unprivileged trigger:** Yes, if user can mount SMB shares.
### Step 8.3: Failure severity
**Record:**
- Init race: incorrect credit/state handling, unpredictable behavior,
potential protocol errors — **HIGH**
- Hung `cifsd` thread: stuck kernel thread, module unload failure,
resource leak — **CRITICAL**
- Overall: **HIGH to CRITICAL**
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** HIGH — prevents mount-path races and potential hung
threads on common filesystem
- **Risk:** LOW — 27-line ordering fix, well-established pattern,
applies cleanly
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Fixes real, verifiable race in mount hot path
- Can cause hung kernel thread (indefinite sleep in exit path)
- Small, surgical, maintainer-approved
- Applies cleanly to v6.18.44
- Buggy code confirmed present in this tree since long before branch
- No dependencies or new APIs
**AGAINST backport:**
- No user bug report or syzbot reproduction (theoretical timing race)
- RFC submission — may have had review comments we could not read
**UNRESOLVED:**
- Full lore review thread content (bot-blocked)
- Whether any reviewer explicitly nominated for stable
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — logic is sound; maintainer
SOB; no Tested-by
2. Fixes real bug affecting users? **PASS** — mount-path race with
verifiable hang mechanism
3. Important issue? **PASS** — hung task / mount failures (**CRITICAL**)
4. Small and contained? **PASS** — 1 file, 27 lines
5. No new features/APIs? **PASS**
6. Can apply to local tree? **PASS** — clean apply verified
### Step 9.3: Exception categories
**Record:** None (not device ID, quirk, DT, build, or docs fix —
standard bug fix).
### Step 9.4: Decision rationale
This fix addresses two concrete problems in `cifs_get_tcp_session()`:
the demux thread running before `tcp_ses` is fully initialized, and the
`tsk` pointer race that can leave `cifsd` sleeping forever on exit. The
buggy code is present in v6.18.44, the patch is minimal and applies
cleanly, and the failure modes (hung thread, mount instability) are
serious enough for stable. The absence of a public bug report does not
diminish the technical merit — the race is structurally present in code
that has been wrong since `kthread_run` was adopted here.
---
## Verification
- **[Phase 1]** Parsed subject, tags, body from provided commit message
and `git show e8a5cf2ff5a13`
- **[Phase 2]** Analyzed diff; read `cifs_demultiplex_thread` exit path
at lines 1437–1448; read `kthread_run` macro in
`include/linux/kthread.h:69–76`
- **[Phase 3]** `git blame -L 1870,1910 fs/smb/client/connect.c` —
kthread_run from 2011
- **[Phase 3]** `git log -S 'kthread_run(cifs_demultiplex_thread'` —
introduced 7c97c200e2c5a
- **[Phase 3]** `git log -S 'if (!task_to_wake)'` — tsk exit wait from
b1c8d2b421376, re-added a5c3e1c725af9
- **[Phase 3]** `git log --oneline -20 -- fs/smb/client/connect.c` — no
duplicate fix
- **[Phase 3]** `git log --author="Fredric Cover" -- fs/smb/client/` — 2
prior fixes
- **[Phase 4]** `b4 dig -c e8a5cf2ff5a13` → lore URL found; `b4 dig -a`
→ single revision
- **[Phase 4]** Lore fetch blocked (bot protection) — review comments
UNVERIFIED
- **[Phase 5]** `grep cifs_get_tcp_session` — callers at connect.c:3667,
sess.c:561
- **[Phase 5]** Read `cifs_demultiplex_thread` startup loop (lines
1251–1285)
- **[Phase 6]** `git describe HEAD` → v6.18.44; buggy code at
connect.c:1874–1906 confirmed
- **[Phase 6]** `git merge-base --is-ancestor e8a5cf2ff5a13 HEAD` → exit
1 (fix not in tree)
- **[Phase 6]** `git show e8a5cf2ff5a13 -- fs/smb/client/connect.c | git
apply --check` → clean apply
- **[Phase 8]** Failure modes: init race (HIGH), hung cifsd thread
(CRITICAL)
**YES**
fs/smb/client/connect.c | 27 ++++++++++++++++-----------
1 file changed, 16 insertions(+), 11 deletions(-)
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 2ee2199d2a6a2..e8bf3e8868d70 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -1871,14 +1871,6 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
* this will succeed. No need for try_module_get().
*/
__module_get(THIS_MODULE);
- tcp_ses->tsk = kthread_run(cifs_demultiplex_thread,
- tcp_ses, "cifsd");
- if (IS_ERR(tcp_ses->tsk)) {
- rc = PTR_ERR(tcp_ses->tsk);
- cifs_dbg(VFS, "error %d create cifsd thread\n", rc);
- module_put(THIS_MODULE);
- goto out_err_crypto_release;
- }
tcp_ses->min_offload = ctx->min_offload;
tcp_ses->retrans = ctx->retrans;
/*
@@ -1886,9 +1878,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
* to the struct since the kernel thread not created yet
* no need to spinlock this update of tcpStatus
*/
- spin_lock(&tcp_ses->srv_lock);
tcp_ses->tcpStatus = CifsNeedNegotiate;
- spin_unlock(&tcp_ses->srv_lock);
if ((ctx->max_credits < 20) || (ctx->max_credits > 60000))
tcp_ses->max_credits = SMB2_MAX_CREDITS_AVAILABLE;
@@ -1897,7 +1887,16 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
tcp_ses->nr_targets = 1;
tcp_ses->ignore_signature = ctx->ignore_signature;
- /* thread spawned, put it on the list */
+
+ tcp_ses->tsk = kthread_create(cifs_demultiplex_thread,
+ tcp_ses, "cifsd");
+ if (IS_ERR(tcp_ses->tsk)) {
+ rc = PTR_ERR(tcp_ses->tsk);
+ cifs_dbg(VFS, "error %d create cifsd thread\n", rc);
+ module_put(THIS_MODULE);
+ goto out_err_crypto_release;
+ }
+ /* thread created, put it on the list */
spin_lock(&cifs_tcp_ses_lock);
list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
spin_unlock(&cifs_tcp_ses_lock);
@@ -1905,6 +1904,12 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
/* queue echo request delayed work */
queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval);
+ /*
+ * Use split create/wake logic to ensure that tcp_ses is fully populated
+ * and tcp_ses->tsk is valid
+ */
+ wake_up_process(tcp_ses->tsk);
+
return tcp_ses;
out_err_crypto_release:
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.6] ksmbd: fix lease break and ack state handling
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (22 preceding siblings ...)
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-6.6] smb: client: fix races in cifsd thread creation Sasha Levin
@ 2026-08-31 13:29 ` Sasha Levin
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: fix n.data memory leak in ksmbd_vfs_set_dos_attrib_xattr Sasha Levin
` (3 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:29 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 5015191096db311759fef98769270336cd8b1324 ]
Do not skip valid lease states containing WRITE_CACHING when breaking
level-II/read leases for writes and truncates.
Handle lease break acknowledgments according to the SMB2 rule that the
acknowledged state must be a subset of the server's break target. Apply
the acknowledged state directly and keep the break pending on failed ACKs.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `ksmbd: fix lease break and ack state
handling`
**Local tree:** `v6.18.44` (`VERSION = 6`, `PATCHLEVEL = 18`, `SUBLEVEL
= 44`)
**Commit under review:** `5015191096db3` (on `master`, not yet in this
checkout)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[ksmbd]` `[fix]` — Correct SMB2 lease-break dispatch and
lease-break-ACK handling in the in-kernel SMB server.
### Step 1.2: Tags
**Record:**
- `Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>` — author
- `Signed-off-by: Steve French <stfrench@microsoft.com>` — subsystem
maintainer
- No `Fixes:`, `Reported-by:`, `Cc: stable@vger.kernel.org`, `Link:`,
`Tested-by:`, or `Reviewed-by:` tags
Notable: maintainer sign-off only; no explicit reporter or stable
nomination.
### Step 1.3: Body analysis
**Record:**
- **Bug:** Level-II/read lease breaks for writes/truncates incorrectly
skip leases that still have `WRITE_CACHING`. Lease-break ACK handling
does not follow the SMB2 rule that the acknowledged state must be a
subset of the server’s break target.
- **Symptom:** Missed lease breaks and incorrect ACK completion; clients
can retain stale caches.
- **Root cause (author):** Overly strict lease-state filter in
`smb_break_all_levII_oplock()`; ACK path applies wrong/complex state
transitions instead of validating subset and applying acknowledged
state directly; failed ACKs should leave the break pending.
- **Version info:** None in message.
### Step 1.4: Hidden bug fix?
**Record:** No — explicitly described as a protocol-correctness bug fix,
not disguised cleanup.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
| File | Change |
|------|--------|
| `fs/smb/server/oplock.c` | ~24 lines changed (net reduction) |
| `fs/smb/server/smb2pdu.c` | ~106 lines changed (large net reduction) |
**Functions modified:**
- `smb_break_all_levII_oplock()`
- `smb2_map_lease_to_oplock()`
- `check_lease_state()` (+ new `smb2_lease_state_valid()`)
- `smb21_lease_break_ack()`
**Scope:** Two-file, surgical SMB server oplock/lease fix.
### Step 2.2: Code flow changes
**Hunk 1 — `smb_break_all_levII_oplock()`**
- **Before:** Rejects any lease whose state includes `WRITE_CACHING`
(treated as “unexpected”), then requires level-II oplock for non-
leases.
- **After:** Only validates oplock level for non-lease entries; leases
with `WRITE_CACHING` are no longer skipped.
- **Path:** Write/truncate/rename/create conflict paths that break
level-II/read leases.
**Hunk 2 — `smb2_map_lease_to_oplock()`**
- **Before:** Exact-match batch mapping; exclusive mapping fails when
`HANDLE` is set without `READ`.
- **After:** Batch = `WRITE`+`HANDLE`; exclusive = any `WRITE`; level-II
= `READ` or `HANDLE`.
- **Path:** Lease open and post-ACK level updates.
**Hunk 3 — `smb21_lease_break_ack()` / `check_lease_state()`**
- **Before:** Narrow ACK validation; large `lease_change_type` switch;
on many error paths falls through to success cleanup (`op_state =
NONE`, `breaking_cnt--`).
- **After:** Validates `req_state` is legal and `req_state ⊆
lease->new_state`; applies `req->LeaseState` directly; success and
error paths are fully separated — failed ACKs keep break pending.
- **Path:** Client SMB2 lease-break ACK handling.
### Step 2.3: Bug mechanism
**Record:**
- **Category:** Logic / protocol correctness (cache coherency)
- **Mechanism 1:** `state & ~(READ|HANDLE)` flags `WRITE_CACHING` as
invalid → lease breaks skipped during writes/truncates → stale client
caches.
- **Mechanism 2:** ACK handler does not implement subset semantics;
incorrect state transitions and wrong `opinfo->level`.
- **Mechanism 3:** `goto err_out` in current tree still falls through to
unconditional break completion after `smb2_set_err_rsp()`.
### Step 2.4: Fix quality
**Record:**
- Fix is obviously correct against SMB2 lease semantics.
- Net -62 lines; removes overcomplicated ACK logic.
- Low regression risk: narrower validation is more permissive only where
protocol allows (subset ACKs); stricter about illegal states via
`smb2_lease_state_valid()`.
- No public API changes.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:**
- Buggy `smb_break_all_levII_oplock()` filter: `e2f34481b24db` (Namjae
Jeon, 2021-03-16) — original ksmbd server import.
- Buggy `check_lease_state()`: same commit; RH special-case added in
`64b39f4a2fd293` (2021-03-30).
- Bug present since ksmbd introduction in this form; long-lived in
6.18.y.
### Step 3.2: Fixes: tag
**Record:** N/A — no `Fixes:` tag.
### Step 3.3: Related file history
**Record:** Many ksmbd oplock/lease commits on `master` since
`v6.18.44`, including `cd80ce7e68f16` (“don't update ->op_state as
OPLOCK_STATE_NONE on error”, 2023) — partial fix only; current tree
still has fall-through bug on failed ACKs. This commit is patch 3/14 of
a June 2026 series but is logically standalone.
### Step 3.4: Author context
**Record:** Namjae Jeon is primary ksmbd maintainer; Steve French is SMB
maintainer. Both signed off.
### Step 3.5: Dependencies
**Record:** `git cherry-pick --no-commit 5015191096db3` applies cleanly
to current `HEAD` (exit 0). No hard dependency on other series patches
for this diff.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:** `b4 dig -c 5015191096db3` →
https://patch.msgid.link/20260618141739.9029-3-linkinjeon@kernel.org —
`[PATCH 03/14] ksmbd: fix lease break and ack state handling`.
### Step 4.2: Reviewers
**Record:** `b4 dig -w` CC'd: `linux-cifs@vger.kernel.org`,
`smfrench@gmail.com`, `senozhatsky@chromium.org`, `tom@talpey.com`,
`metze@samba.org`, `atteh.mailbox@gmail.com`.
### Step 4.3: Bug reports
**Record:** No external bug report in commit message. Prior related fix
`cd80ce7e68f16` mentions `smb2.lease.breaking2` test failure for a
narrower issue.
### Step 4.4: Series context
**Record:** Part of 14-patch ksmbd lease series (starts with “validate
SMB2 lease create contexts”). This patch applies standalone to 6.18.44;
earlier series patches are not required for this diff to build/apply.
### Step 4.5: Stable list
**Record:** UNVERIFIED — lore.kernel.org blocked automated fetch (Anubis
bot protection). No stable-list discussion found via other means.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `smb_break_all_levII_oplock`, `smb2_map_lease_to_oplock`,
`check_lease_state`, `smb21_lease_break_ack`, `smb2_oplock_break`.
### Step 5.2: Callers of `smb_break_all_levII_oplock`
**Record:**
- `fs/smb/server/vfs.c` — write, truncate, setattr paths (e.g. line 535
on write)
- `fs/smb/server/smb2pdu.c` — create, rename, set-info
- `fs/smb/server/oplock.c` — `smb_break_all_oplock()`
Common hot paths for multi-client file server workloads.
### Step 5.3: Callees
**Record:** `oplock_break()` → `smb2_lease_break_noti()`; ACK path uses
`lookup_lease_in_table()`, `ksmbd_iov_pin_rsp()`.
### Step 5.4: Reachability
**Record:** Triggered by remote SMB2 clients during writes, truncates,
renames, and conflicting opens when `CONFIG_SMB_SERVER` and
oplocks/leases are enabled. Network-reachable, normal file-server
operations.
### Step 5.5: Similar patterns
**Record:** Multiple prior ksmbd stable-worthy oplock/lease fixes in
this tree (`50f930db22365` UAF in break ack, `e735dbd489e3e` NULL-deref
in break notifiers, `cd80ce7e68f16` partial ACK error handling). Same
subsystem, same concern area.
---
## PHASE 6: CROSS-REFERENCE WITH LOCAL TREE
### Step 6.1: Buggy code present?
**Record:** YES. Current tree at `v6.18.44` contains all three buggy
patterns:
- `oplock.c:1407-1418` — WRITE_CACHING rejection
- `oplock.c:1464-1477` — old `smb2_map_lease_to_oplock()` logic
- `smb2pdu.c:8806-8950` — old ACK handling with fall-through cleanup
### Step 6.2: Backport difficulty
**Record:** Clean apply verified via test cherry-pick. No rework needed.
### Step 6.3: Related fixes already present?
**Record:** `cd80ce7e68f16` partially addressed ACK error handling but
did not fix fall-through after `goto err_out`, subset ACK semantics,
WRITE_CACHING skip, or lease-to-oplock mapping. This fix is not
redundant.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem and criticality
**Record:** `fs/smb/server` (ksmbd in-kernel SMB server). **IMPORTANT**
— affects all ksmbd users; not core kernel, but file-server data
integrity is critical for deployments using it.
### Step 7.2: Activity
**Record:** Actively maintained; many ksmbd commits between `v6.18.44`
and `master`.
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who is affected
**Record:** Users of `CONFIG_SMB_SERVER` with oplocks/leases enabled —
enterprise/embedded Samba-alternative file serving, multi-client SMB
workloads.
### Step 8.2: Trigger conditions
**Record:**
- Multiple clients with leases on the same file
- Write, truncate, rename, or conflicting open
- Client sends lease-break ACK (including partial/subset ACKs)
- Common in real SMB deployments; not exotic
### Step 8.3: Failure mode severity
**Record:**
- **Failure mode:** Stale client-side read/write caches; incorrect lease
state after ACK; break prematurely marked complete on failed ACK
- **Severity:** **CRITICAL** for data coherency — can cause silent data
corruption across SMB clients (not a kernel oops, but a serious
correctness bug for a file server)
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** HIGH — fixes long-standing protocol bugs on common multi-
client paths
- **Risk:** LOW — small, localized, maintainer-authored, verified clean
apply
- **Ratio:** Strongly favors backport
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Fixes real SMB2 lease coherency bugs present since 2021
- Can cause stale caches / data corruption with multiple clients
- Small, surgical (-62 lines net), maintainer-reviewed
- Applies cleanly to 6.18.44
- No new APIs or features
- Failed ACK handling properly keeps break pending
**AGAINST backport:**
- Only affects `CONFIG_SMB_SERVER` users (subset of kernel users)
- Part of a 14-patch series (but standalone-applicable)
- No syzbot/user bug report in commit message
**Unresolved:** Lore thread content and stable-list discussion
(UNVERIFIED).
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — protocol-aligned logic,
maintainer SOBs; no explicit Tested-by
2. Fixes a real bug affecting users? **PASS** — multi-client lease
coherency
3. Important issue? **PASS** — data coherency / potential corruption
(CRITICAL for file server)
4. Small and contained? **PASS** — 2 files, ~130 lines touched, -62 net
5. No new features or APIs? **PASS**
6. Can apply to local tree? **PASS** — clean cherry-pick verified
### Step 9.3: Exception categories
**Record:** None (not device ID, quirk, DT, build, or docs).
### Step 9.4: Decision rationale
For **this** tree (`6.18.44`), the buggy code is present, the fix is
self-contained, applies cleanly, and addresses important SMB2 lease
coherency bugs that can lead to stale client caches and data corruption.
This meets stable kernel criteria.
---
## Verification
- [Phase 1] Parsed subject, tags (Namjae Jeon + Steve French SOBs only),
body
- [Phase 2] Read full diff from `git show 5015191096db3`; analyzed all 4
function changes
- [Phase 2] Confirmed `goto err_out` fall-through bug in current
`smb2pdu.c:8859-8950`
- [Phase 3] `git blame` on `oplock.c:1407-1418` and
`smb2pdu.c:8806-8818` → `e2f34481b24db` (2021)
- [Phase 3] `git show cd80ce7e68f16` — partial prior fix, insufficient
- [Phase 3] `git merge-base --is-ancestor 5015191096db3 HEAD` → exit 1
(not in tree)
- [Phase 3] `git cherry-pick --no-commit 5015191096db3` → exit 0 (clean
apply)
- [Phase 4] `b4 dig -c 5015191096db3` → lore URL found
- [Phase 4] `b4 dig -a` → patch 03/14 of series
- [Phase 4] `b4 dig -w` → linux-cifs, smfrench CC'd
- [Phase 4] UNVERIFIED: lore thread content (Anubis blocked WebFetch)
- [Phase 5] `grep smb_break_all_levII_oplock` → callers in vfs.c,
smb2pdu.c, oplock.c
- [Phase 5] Read `oplock_break()` lease break logic in
`oplock.c:893-958`
- [Phase 6] `git describe HEAD` → `v6.18.44`; buggy code confirmed
present
- [Phase 6] `git log v6.18.44..master -- fs/smb/server/oplock.c` — many
intervening commits; patch still applies cleanly
- [Phase 7] `fs/smb/server/Kconfig` — `CONFIG_SMB_SERVER` exists
- [Phase 8] Failure mode: cache coherency / data corruption risk,
severity CRITICAL for SMB server use
**YES**The background checks finished and match the earlier analysis:
- **Master:** commit `5015191096db3` (`ksmbd: fix lease break and ack
state handling`) is on `master`.
- **This tree (`v6.18.44`):** that commit is **not** present yet.
So the lease-break/ACK bugs are still in your checkout, and the fix is
available on `master` and applies cleanly here. The backport
recommendation remains **YES**.
fs/smb/server/oplock.c | 24 +++------
fs/smb/server/smb2pdu.c | 106 ++++++++++------------------------------
2 files changed, 34 insertions(+), 96 deletions(-)
diff --git a/fs/smb/server/oplock.c b/fs/smb/server/oplock.c
index ff0dbf3f8cbf4..d7ba8a01f2c68 100644
--- a/fs/smb/server/oplock.c
+++ b/fs/smb/server/oplock.c
@@ -1404,14 +1404,8 @@ void smb_break_all_levII_oplock(struct ksmbd_work *work, struct ksmbd_file *fp,
continue;
}
- if (brk_op->is_lease && (brk_op->o_lease->state &
- (~(SMB2_LEASE_READ_CACHING_LE |
- SMB2_LEASE_HANDLE_CACHING_LE)))) {
- ksmbd_debug(OPLOCK, "unexpected lease state(0x%x)\n",
- brk_op->o_lease->state);
- goto next;
- } else if (brk_op->level !=
- SMB2_OPLOCK_LEVEL_II) {
+ if (!brk_op->is_lease &&
+ brk_op->level != SMB2_OPLOCK_LEVEL_II) {
ksmbd_debug(OPLOCK, "unexpected oplock(0x%x)\n",
brk_op->level);
goto next;
@@ -1463,15 +1457,13 @@ void smb_break_all_oplock(struct ksmbd_work *work, struct ksmbd_file *fp)
*/
__u8 smb2_map_lease_to_oplock(__le32 lease_state)
{
- if (lease_state == (SMB2_LEASE_HANDLE_CACHING_LE |
- SMB2_LEASE_READ_CACHING_LE |
- SMB2_LEASE_WRITE_CACHING_LE)) {
+ if ((lease_state & SMB2_LEASE_WRITE_CACHING_LE) &&
+ (lease_state & SMB2_LEASE_HANDLE_CACHING_LE)) {
return SMB2_OPLOCK_LEVEL_BATCH;
- } else if (lease_state != SMB2_LEASE_WRITE_CACHING_LE &&
- lease_state & SMB2_LEASE_WRITE_CACHING_LE) {
- if (!(lease_state & SMB2_LEASE_HANDLE_CACHING_LE))
- return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
- } else if (lease_state & SMB2_LEASE_READ_CACHING_LE) {
+ } else if (lease_state & SMB2_LEASE_WRITE_CACHING_LE) {
+ return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
+ } else if (lease_state & (SMB2_LEASE_READ_CACHING_LE |
+ SMB2_LEASE_HANDLE_CACHING_LE)) {
return SMB2_OPLOCK_LEVEL_II;
}
return 0;
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index b610cad470ea0..b16e1c156ee5f 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -8803,16 +8803,17 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work)
ksmbd_fd_put(work, fp);
}
-static int check_lease_state(struct lease *lease, __le32 req_state)
+static bool smb2_lease_state_valid(__le32 state)
{
- if ((lease->new_state ==
- (SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE)) &&
- !(req_state & SMB2_LEASE_WRITE_CACHING_LE)) {
- lease->new_state = req_state;
- return 0;
- }
+ return !(state & ~(SMB2_LEASE_READ_CACHING_LE |
+ SMB2_LEASE_HANDLE_CACHING_LE |
+ SMB2_LEASE_WRITE_CACHING_LE));
+}
- if (lease->new_state == req_state)
+static int check_lease_state(struct lease *lease, __le32 req_state)
+{
+ if (smb2_lease_state_valid(req_state) &&
+ !(req_state & ~lease->new_state))
return 0;
return 1;
@@ -8830,9 +8831,7 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
struct smb2_lease_ack *req;
struct smb2_lease_ack *rsp;
struct oplock_info *opinfo;
- __le32 err = 0;
int ret = 0;
- unsigned int lease_change_type;
__le32 lease_state;
struct lease *lease;
@@ -8856,80 +8855,23 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
goto err_out;
}
- if (check_lease_state(lease, req->LeaseState)) {
- rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED;
- ksmbd_debug(OPLOCK,
- "req lease state: 0x%x, expected state: 0x%x\n",
- req->LeaseState, lease->new_state);
- goto err_out;
- }
-
if (!atomic_read(&opinfo->breaking_cnt)) {
rsp->hdr.Status = STATUS_UNSUCCESSFUL;
goto err_out;
}
- /* check for bad lease state */
- if (req->LeaseState &
- (~(SMB2_LEASE_READ_CACHING_LE | SMB2_LEASE_HANDLE_CACHING_LE))) {
- err = STATUS_INVALID_OPLOCK_PROTOCOL;
- if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)
- lease_change_type = OPLOCK_WRITE_TO_NONE;
- else
- lease_change_type = OPLOCK_READ_TO_NONE;
- ksmbd_debug(OPLOCK, "handle bad lease state 0x%x -> 0x%x\n",
- le32_to_cpu(lease->state),
- le32_to_cpu(req->LeaseState));
- } else if (lease->state == SMB2_LEASE_READ_CACHING_LE &&
- req->LeaseState != SMB2_LEASE_NONE_LE) {
- err = STATUS_INVALID_OPLOCK_PROTOCOL;
- lease_change_type = OPLOCK_READ_TO_NONE;
- ksmbd_debug(OPLOCK, "handle bad lease state 0x%x -> 0x%x\n",
- le32_to_cpu(lease->state),
- le32_to_cpu(req->LeaseState));
- } else {
- /* valid lease state changes */
- err = STATUS_INVALID_DEVICE_STATE;
- if (req->LeaseState == SMB2_LEASE_NONE_LE) {
- if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)
- lease_change_type = OPLOCK_WRITE_TO_NONE;
- else
- lease_change_type = OPLOCK_READ_TO_NONE;
- } else if (req->LeaseState & SMB2_LEASE_READ_CACHING_LE) {
- if (lease->state & SMB2_LEASE_WRITE_CACHING_LE)
- lease_change_type = OPLOCK_WRITE_TO_READ;
- else
- lease_change_type = OPLOCK_READ_HANDLE_TO_READ;
- } else {
- lease_change_type = 0;
- }
- }
-
- switch (lease_change_type) {
- case OPLOCK_WRITE_TO_READ:
- ret = opinfo_write_to_read(opinfo);
- break;
- case OPLOCK_READ_HANDLE_TO_READ:
- ret = opinfo_read_handle_to_read(opinfo);
- break;
- case OPLOCK_WRITE_TO_NONE:
- ret = opinfo_write_to_none(opinfo);
- break;
- case OPLOCK_READ_TO_NONE:
- ret = opinfo_read_to_none(opinfo);
- break;
- default:
- ksmbd_debug(OPLOCK, "unknown lease change 0x%x -> 0x%x\n",
- le32_to_cpu(lease->state),
- le32_to_cpu(req->LeaseState));
- }
-
- if (ret < 0) {
- rsp->hdr.Status = err;
+ if (check_lease_state(lease, req->LeaseState)) {
+ rsp->hdr.Status = STATUS_REQUEST_NOT_ACCEPTED;
+ ksmbd_debug(OPLOCK,
+ "req lease state: 0x%x, expected state: 0x%x\n",
+ req->LeaseState, lease->new_state);
goto err_out;
}
- lease_state = lease->state;
+ lease_state = req->LeaseState;
+ lease->state = lease_state;
+ lease->new_state = SMB2_LEASE_NONE_LE;
+ opinfo->level = smb2_map_lease_to_oplock(lease_state);
rsp->StructureSize = cpu_to_le16(36);
rsp->Reserved = 0;
@@ -8938,16 +8880,20 @@ static void smb21_lease_break_ack(struct ksmbd_work *work)
rsp->LeaseState = lease_state;
rsp->LeaseDuration = 0;
ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_lease_ack));
- if (ret) {
-err_out:
- smb2_set_err_rsp(work);
- }
+ if (ret)
+ goto err_out;
opinfo->op_state = OPLOCK_STATE_NONE;
wake_up_interruptible_all(&opinfo->oplock_q);
atomic_dec(&opinfo->breaking_cnt);
wake_up_interruptible_all(&opinfo->oplock_brk);
opinfo_put(opinfo);
+ return;
+
+err_out:
+ smb2_set_err_rsp(work);
+ opinfo_put(opinfo);
+ return;
}
/**
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: fix n.data memory leak in ksmbd_vfs_set_dos_attrib_xattr
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (23 preceding siblings ...)
2026-08-31 13:29 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: fix lease break and ack state handling Sasha Levin
@ 2026-08-31 13:30 ` Sasha Levin
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: align SMB2 oplock break ack handling Sasha Levin
` (2 subsequent siblings)
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:30 UTC (permalink / raw)
To: patches, stable
Cc: Qiang Liu, ChenXiaoSong, Namjae Jeon, Steve French, Sasha Levin,
smfrench, linux-cifs, linux-kernel
From: Qiang Liu <liuqiang@kylinos.cn>
[ Upstream commit 7ac657bb9c5c1b0f7bdf1fa6d3ad532f969be5cf ]
Free ndr buffer data when ndr_encode_dos_attr() returns error
to avoid memory leak.
Signed-off-by: Qiang Liu <liuqiang@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `ksmbd: fix n.data memory leak in
ksmbd_vfs_set_dos_attrib_xattr`
**Local tree:** `v6.18.44` (`stable/linux-6.18.y`, `make kernelversion`
= 6.18.44)
**Commit under review:** `7ac657bb9c5c1` (on `master`, **not yet** in
this tree)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[ksmbd]` `[fix]` — memory leak of `n.data` in
`ksmbd_vfs_set_dos_attrib_xattr` when `ndr_encode_dos_attr()` fails.
### Step 1.2: Tags
**Record:**
- **Signed-off-by:** Qiang Liu `<liuqiang@kylinos.cn>` (author)
- **Reviewed-by:** ChenXiaoSong `<chenxiaosong@kylinos.cn>`
- **Acked-by:** Namjae Jeon `<linkinjeon@kernel.org>` (ksmbd maintainer)
- **Signed-off-by:** Steve French `<stfrench@microsoft.com>` (committer)
- No `Fixes:`, `Reported-by:`, `Link:`, `Cc: stable`, or `Tested-by:`
tags
- Notable: maintainer **Acked-by** is a strong quality signal
### Step 1.3: Body analysis
**Record:**
- **Bug:** `ndr_encode_dos_attr()` allocates an NDR buffer (`n.data`);
on encoding error, `ksmbd_vfs_set_dos_attrib_xattr()` returned early
without `kfree(n.data)`.
- **Symptom:** Memory leak (no crash/corruption described).
- **Root cause:** Missing cleanup on the `ndr_encode_dos_attr()` error
path.
- **Version info:** None in commit message.
### Step 1.4: Hidden bug fix?
**Record:** No — explicitly labeled as a memory leak fix, not disguised
cleanup.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **Files:** `fs/smb/server/vfs.c` only (+3 / −2 lines)
- **Function modified:** `ksmbd_vfs_set_dos_attrib_xattr()`
- **Scope:** Single-file, surgical fix
### Step 2.2: Code flow change
**Record:**
| Hunk | Before | After |
|------|--------|-------|
| Error from `ndr_encode_dos_attr()` | `return err;` (leaks `n.data`) |
`goto out;` |
| Success path cleanup | `kfree(n.data); return err;` | `out:
kfree(n.data); return err;` |
Both success and error paths now converge at `out:` and always free
`n.data` when it was allocated.
### Step 2.3: Bug mechanism
**Record:**
- **Category:** Resource leak on error path
- **Mechanism:** `ndr_encode_dos_attr()` calls `kzalloc(1024)` then may
fail in `ndr_write_string()` / `ndr_write_int*()` via
`try_to_realloc_ndr_blob()` returning `-ENOMEM`. The caller returned
without freeing the already-allocated buffer.
Verified in `ndr.c`:
```170:188:fs/smb/server/ndr.c
int ndr_encode_dos_attr(struct ndr *n, struct xattr_dos_attrib *da)
{
// ...
n->data = kzalloc(n->length, KSMBD_DEFAULT_GFP);
if (!n->data)
return -ENOMEM;
// ... ndr_write_* calls that can return -ENOMEM ...
if (ret)
return ret;
```
### Step 2.4: Fix quality
**Record:**
- **Quality:** Obviously correct; mirrors the `goto out` + `kfree`
pattern used elsewhere in the same file (e.g.
`ksmbd_vfs_set_sd_xattr`, `ksmbd_vfs_get_dos_attrib_xattr`).
- **Regression risk:** Very low — only adds cleanup on a previously
leaked path.
- **Red flags:** None.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:**
- Buggy logic introduced in `f44158485826c` ("cifsd: add file
operations", 2021-05-10).
- Function has been in ksmbd/cifsd since v5.13 era; present in this
6.18.y tree at `fs/smb/server/vfs.c:1651–1670`.
### Step 3.2: Fixes: tag
**Record:** N/A — no `Fixes:` tag present.
### Step 3.3: Related file history
**Record:**
- Part of v2 series: `[PATCH v2 0/3] ksmbd: fix some memory leaks in
ksmbd_vfs_* functions`
- Sibling commits on `master`:
- `d4d56b00c7df8` — `sd_ndr.data` leak in `ksmbd_vfs_set_sd_xattr`
- `d708a36634bb7` — `acl.sd_buf` leak in `ksmbd_vfs_get_sd_xattr`
- `7ac657bb9c5c1` — this commit (patch 3/3)
- **This commit is standalone** — fixes a different function; no
dependency on siblings.
### Step 3.4: Author context
**Record:** Qiang Liu submitted the 3-patch leak-fix series. Namjae Jeon
(maintainer) Acked all three. Steve French committed.
### Step 3.5: Prerequisites
**Record:** None. `git apply --check` against this tree succeeds
cleanly. No structural/API assumptions beyond existing code.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:**
- **b4 dig URL:**
https://patch.msgid.link/20260624011320.9146-4-liuqiangneo@163.com
- **Series revisions:** v1 (2026-06-23), v2 (2026-06-24); committed
version matches v2 patch 3/3
- **Lore fetch:** Blocked by Anubis bot protection — could not read
thread body for stable nominations or NAKs
### Step 4.2: Reviewers (b4 dig -w)
**Record:** CC'd to Steve French, Namjae Jeon, Ronnie Sahlberg, linux-
cifs@vger.kernel.org, and other ksmbd maintainers/reviewers.
### Step 4.3: Bug report
**Record:** N/A — no external bug report or syzbot link.
### Step 4.4: Related patches
**Record:** 3-patch series fixing independent leaks in `vfs.c`. Other
two patches are also absent from this tree but are not prerequisites for
this one.
### Step 4.5: Stable list history
**Record:** UNVERIFIED — lore stable search blocked by bot protection.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `ksmbd_vfs_set_dos_attrib_xattr()` modified;
`ndr_encode_dos_attr()` is the allocator whose errors were mishandled.
### Step 5.2: Callers
**Record:** Three call sites in `smb2pdu.c`, all behind
`KSMBD_SHARE_FLAG_STORE_DOS_ATTRS`:
1. `smb2_new_xattrs()` — file creation (called from `smb2_open` path)
2. `set_file_basic_info()` — SMB2 SET_INFO (file attribute/time updates)
3. `fsctl_set_sparse()` — FSCTL_SET_SPARSE IOCTL
All are SMB2 protocol handlers reachable by remote clients when the
share stores DOS attributes in xattrs.
### Step 5.3: Callees
**Record:** `ndr_encode_dos_attr()` → `kzalloc` / `krealloc` /
`ndr_write_*`; `ksmbd_vfs_setxattr()` on success path.
### Step 5.4: Reachability
**Record:** Reachable from network clients performing file create, set-
info, or sparse-file FSCTL on shares with `STORE_DOS_ATTRS` enabled
(`CONFIG_SMB_SERVER`). Trigger for the leak requires
`ndr_encode_dos_attr()` to fail after allocation (typically `-ENOMEM`
under memory pressure).
### Step 5.5: Similar patterns
**Record:** Same file already uses `goto out` + `kfree` for NDR buffers
in `ksmbd_vfs_set_sd_xattr` and `ksmbd_vfs_get_sd_xattr`. Sibling commit
`d4d56b00` applies the identical pattern fix to `sd_ndr.data` in
`ksmbd_vfs_set_sd_xattr`. This tree already has a precedent backport:
`d026f47db6863` ("ksmbd: Fix memory leak in get_file_all_info()").
---
## PHASE 6: CROSS-REFERENCE AGAINST LOCAL TREE
### Step 6.1: Buggy code present?
**Record:** **YES.** Current tree at `vfs.c:1659–1661`:
```1659:1661:fs/smb/server/vfs.c
err = ndr_encode_dos_attr(&n, da);
if (err)
return err;
```
Bug present since 2021; well predates 6.18.y branch.
### Step 6.2: Backport complications
**Record:** **Clean apply** — `git apply --check` passes with no
conflicts. File layout matches mainline.
### Step 6.3: Related fixes already present?
**Record:** Fix commit `7ac657bb9c5c1` is **NOT** in HEAD. Sibling
series commits `d4d56b00` and `d708a36634bb7` also **NOT** in HEAD. No
duplicate fix for this specific leak found.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem criticality
**Record:** `fs/smb/server` (ksmbd SMB3 server). **IMPORTANT** — affects
users running in-kernel SMB server (`CONFIG_SMB_SERVER`), not universal
but security/stability-sensitive for deployments using it.
### Step 7.2: Subsystem activity
**Record:** Highly active in 6.18.y — recent backports include UAF
fixes, integer overflow, ACL validation, transport leaks. Memory leak
fixes are routinely accepted.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who is affected
**Record:** Users with `CONFIG_SMB_SERVER` enabled and shares configured
with `STORE_DOS_ATTRS`. Driver/server-specific, not all kernel users.
### Step 8.2: Trigger conditions
**Record:** SMB file create, SET_INFO, or sparse FSCTL that stores DOS
attributes; `ndr_encode_dos_attr()` must fail after `kzalloc` (most
likely `-ENOMEM` during NDR buffer growth). Unprivileged remote clients
can trigger the code path; the leak itself requires the encoding error.
### Step 8.3: Failure mode severity
**Record:** Memory leak (~1 KB+ per failed encode, potentially more if
reallocs occurred). **Severity: MEDIUM** — no direct crash/corruption,
but under memory pressure the leak worsens OOM conditions in an active
server path.
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** Prevents per-operation leaks in a commonly-used ksmbd
path; aligns with existing stable backport policy for ksmbd leak
fixes.
- **Risk:** Minimal — 5-line, obviously correct cleanup addition.
- **Ratio:** Favorable.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Real, verified memory leak on error path (code inspection confirms)
- Bug present since 2021, exists in this 6.18.44 tree
- Surgical 5-line fix, applies cleanly
- Acked-by subsystem maintainer (Namjae Jeon)
- Reachable from SMB2 client operations on active server paths
- Precedent: similar ksmbd leak fix already backported to this tree
(`d026f47db6863`)
- Under memory pressure, leak compounds the failure mode
**AGAINST backport:**
- Only triggers on `ndr_encode_dos_attr()` failure (typically ENOMEM),
not the common success path
- No user crash reports, syzbot, or CVE
- Lore thread content unverified (bot blocked)
**Unresolved:** Whether reviewers explicitly nominated for stable on
lore (could not fetch thread).
### Step 9.2: Stable rules checklist
| Criterion | Result |
|-----------|--------|
| 1. Obviously correct and tested? | **PASS** — standard `goto
out`/`kfree` pattern; Reviewed-by + Acked-by; no Tested-by |
| 2. Fixes a real bug affecting users? | **PASS** — verified leak on SMB
server error path |
| 3. Important issue? | **PASS (borderline)** — MEDIUM severity memory
leak in active server code; not crash/corruption but worsens OOM |
| 4. Small and contained? | **PASS** — 1 file, 5 lines |
| 5. No new features/APIs? | **PASS** |
| 6. Can apply to local tree? | **PASS** — clean apply verified |
### Step 9.3: Exception categories
**Record:** None (not a device ID, quirk, DT, build, or docs fix).
Qualifies as a standard bug fix.
### Step 9.4: Decision rationale
This is a small, maintainer-acked fix for a long-standing resource leak
in ksmbd's DOS-attribute xattr storage path. The leak is real and
verified by reading `ndr_encode_dos_attr()` and the caller. While it
only fires on encoding errors (typically under memory pressure), that is
exactly when leaking memory is most harmful. The fix is trivial, applies
cleanly to 6.18.44, and matches established precedent for ksmbd leak
fixes already backported to this stable tree.
---
## Verification
- **[Phase 1]** Parsed commit `7ac657bb9c5c1` message and tags via `git
show`
- **[Phase 2]** Read diff and current `vfs.c:1651–1670` and
`ndr.c:170–227` — confirmed leak mechanism
- **[Phase 3]** `git blame -L 1651,1670` — bug since `f44158485826c`
(2021-05-10)
- **[Phase 3]** `git merge-base --is-ancestor 7ac657bb9c5c1 HEAD` — fix
**NOT** in tree
- **[Phase 3]** `git apply --check` — patch applies cleanly
- **[Phase 3]** Identified 3-patch series on master; confirmed this
patch is independent
- **[Phase 4]** `b4 dig -c 7ac657bb9c5c1` — found lore URL and v1/v2
revisions
- **[Phase 4]** `b4 dig -c 7ac657bb9c5c1 -w` — maintainer CC list
confirmed
- **[Phase 4]** WebFetch lore — blocked by Anubis (UNVERIFIED: thread
review comments)
- **[Phase 5]** `grep ksmbd_vfs_set_dos_attrib_xattr` — 3 callers in
`smb2pdu.c` identified
- **[Phase 5]** Read caller context: `smb2_new_xattrs`,
`set_file_basic_info`, `fsctl_set_sparse`
- **[Phase 6]** `git describe HEAD` = v6.18.44; `make kernelversion` =
6.18.44
- **[Phase 6]** Buggy code confirmed present at `vfs.c:1659–1661`
- **[Phase 6]** `git log --grep='memory leak in get_file_all_info'` —
precedent backport `d026f47db6863` in tree
- **[Phase 7]** `git log --oneline -20 -- fs/smb/server/` — active ksmbd
maintenance in 6.18.y
- **[Phase 8]** Assessed trigger (ENOMEM on NDR encode) and severity
(MEDIUM leak)
**YES**The sibling-patch check finished successfully: neither
`d4d56b00c7df8` (`sd_ndr.data` leak in `ksmbd_vfs_set_sd_xattr`) nor the
other series commits are in this `6.18.44` tree. That doesn’t block this
backport — `7ac657bb9c5c1` is a standalone fix for
`ksmbd_vfs_set_dos_attrib_xattr`, applies cleanly, and the leak is still
present here.
**Verdict for this tree: YES** — small, maintainer-acked error-path
memory leak fix in an active ksmbd SMB2 path.
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 263032adf0cd8..859ca7c87bd4c 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -1664,14 +1664,15 @@ int ksmbd_vfs_set_dos_attrib_xattr(struct mnt_idmap *idmap,
err = ndr_encode_dos_attr(&n, da);
if (err)
- return err;
+ goto out;
err = ksmbd_vfs_setxattr(idmap, path, XATTR_NAME_DOS_ATTRIBUTE,
(void *)n.data, n.offset, 0, get_write);
if (err)
ksmbd_debug(SMB, "failed to store dos attribute in xattr\n");
- kfree(n.data);
+out:
+ kfree(n.data);
return err;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.1] ksmbd: align SMB2 oplock break ack handling
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (24 preceding siblings ...)
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: fix n.data memory leak in ksmbd_vfs_set_dos_attrib_xattr Sasha Levin
@ 2026-08-31 13:30 ` Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: deny renaming directory with open children Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: treat unnamed DATA stream as base file Sasha Levin
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:30 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 80a56d4a826c6c84430286fcf7d8655f7c5b0868 ]
Handle SMB2 oplock break acknowledgments according to the server-side
validation rules in MS-SMB2.
Return STATUS_INVALID_DEVICE_STATE when an ACK arrives while the open is
not breaking, reject SMB2_OPLOCK_LEVEL_LEASE with
STATUS_INVALID_PARAMETER, allow BATCH acknowledgments to EXCLUSIVE, and
make invalid ACK levels fail with STATUS_INVALID_OPLOCK_PROTOCOL after
lowering the oplock to NONE.
Update the successful response from the final granted oplock level instead
of relying on the oplock transition helpers, which could turn invalid ACKs
into successful responses.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit Message Forensics
**Step 1.1 — Subject line**
Record: **[ksmbd] [align] SMB2 oplock break ack handling — correct SMB2
oplock-break ACK validation per MS-SMB2**
**Step 1.2 — Tags**
Record:
- **Signed-off-by:** Namjae Jeon `<linkinjeon@kernel.org>` (author)
- **Signed-off-by:** Steve French `<stfrench@microsoft.com>` (CIFS/ksmbd
maintainer, committer)
- No Fixes:, Reported-by:, Tested-by:, Reviewed-by:, Acked-by:, Link:,
or Cc: stable tags
- Notable: maintainer-authored and maintainer-committed; no syzbot or
user bug report in message
**Step 1.3 — Body analysis**
Record:
- **Bug:** `smb20_oplock_break_ack()` does not follow MS-SMB2 server-
side ACK validation
- **Symptoms:**
- ACK while open is not breaking → wrong handling
- `SMB2_OPLOCK_LEVEL_LEASE` in oplock-break ACK → not rejected
correctly
- Valid BATCH→EXCLUSIVE ACK → incorrectly rejected
- Invalid ACK levels → can return SUCCESS instead of
`STATUS_INVALID_OPLOCK_PROTOCOL`
- **Root cause:** State/level checks are wrong; transition helpers
(`opinfo_write_to_*`) can succeed on invalid ACKs and produce a
successful response
- **Version info:** None in message
**Step 1.4 — Hidden bug fix?**
Record: **Yes.** Despite “align” wording, this fixes real protocol/logic
bugs: wrong state gating, incorrect rejection of valid BATCH/EXCLUSIVE
ACKs, and invalid ACKs returning NTSTATUS success.
---
## Phase 2: Diff Analysis
**Step 2.1 — Inventory**
Record:
- **Files:** `fs/smb/server/smb2pdu.c` only (+46 / -58)
- **Function:** `smb20_oplock_break_ack()`
- **Scope:** Single-file, single-function surgical change
**Step 2.2 — Code flow changes**
Record:
- **Hunk 1 (state check):** Before: reject only if `op_state ==
OPLOCK_STATE_NONE` with `STATUS_UNSUCCESSFUL`. After: require
`op_state == OPLOCK_ACK_WAIT`; otherwise
`STATUS_INVALID_DEVICE_STATE`.
- **Hunk 2 (LEASE level):** Before: no explicit LEASE-level rejection.
After: reject `SMB2_OPLOCK_LEVEL_LEASE` with
`STATUS_INVALID_PARAMETER`, set level to NONE.
- **Hunk 3 (validation):** Before: complex `oplock_change_type` + switch
calling `opinfo_write_to_read/none`. After: explicit per-level
validation; invalid ACKs set level to NONE and error out.
- **Hunk 4 (BATCH/EXCLUSIVE):** Before: BATCH + EXCLUSIVE ACK treated as
invalid. After: EXCLUSIVE explicitly allowed for BATCH.
- **Hunk 5 (success path):** Before: response level from transition
helpers. After: set `opinfo->level` and `rsp_oplevel` directly from
validated request level.
- **Hunk 6 (error path):** Before: `err_out` could conflate pin failures
with protocol errors. After: clear `status` assignment and separate
`out` path.
**Step 2.3 — Bug mechanism**
Record: **[Logic / protocol correctness]**
- Wrong state machine gate (never required `OPLOCK_ACK_WAIT` in
`smb2pdu.c`)
- Incorrect protocol validation for BATCH/EXCLUSIVE
- Invalid ACKs could complete successfully via transition helpers
despite intended error status
**Step 2.4 — Fix quality**
Record: **High.** Simpler, directly mirrors MS-SMB2 rules, minimal
scope. Low regression risk; uses existing `OPLOCK_ACK_WAIT` constant
already defined in `oplock.h` and set in `oplock.c` during breaks.
---
## Phase 3: Git History Investigation
**Step 3.1 — Blame**
Record: Buggy logic introduced in **e2f34481b24db2** (“cifsd: add
server-side procedures for SMB3”, Namjae Jeon, 2021-03-16). BATCH
handling extended in **64b39f4a2fd293** (2021-03-30). Bug present since
ksmbd’s SMB3 server code landed.
**Step 3.2 — Fixes: tag**
Record: **N/A** — no Fixes: tag in commit message.
**Step 3.3 — Related file history**
Record: Recent `smb2pdu.c` changes in this tree are mostly ksmbd
security/UAF/permission fixes. No prior fix for this ACK-validation
issue. Commit is **patch 06/14** in Namjae’s June 2026 lease/oplock
series, but this hunk is self-contained in `smb20_oplock_break_ack()`.
**Step 3.4 — Author context**
Record: Namjae Jeon is ksmbd maintainer. Steve French committed to
mainline. Series was part of the 50-commit “ksmbd server fixes” pull for
Linux 7.2.
**Step 3.5 — Dependencies**
Record: **Standalone for this tree.** `OPLOCK_ACK_WAIT` already exists
in `oplock.h`; `oplock.c` already sets `op_state = OPLOCK_ACK_WAIT`
during breaks. No structural prerequisites from earlier series patches
required for compilation or semantics. Follow-up mainline commit “return
oplock protocol error for level II ack” builds on this but is separate.
---
## Phase 4: Mailing List and External Research
**Step 4.1 — Original discussion**
Record:
- **b4 dig -c 80a56d4a826c:**
https://patch.msgid.link/20260618141739.9029-6-linkinjeon@kernel.org
- **Series:** v1, patch 06/14 of lease/oplock series (2026-06-18)
- **Review thread:** No replies in saved mbox; no NAKs, no stable
nomination found
**Step 4.2 — Reviewers**
Record: **b4 dig -w** CC’d linux-cifs, Steve French, Senozhatsky, Tom
Talpey, Metze, Atte Pöyölä. No explicit Reviewed-by/Acked-by in thread.
**Step 4.3 — Bug reports**
Record: No direct bug report. Parent git pull (Steve French, 2026-06-26)
states fixes were “found by smbtorture where ksmbd diverged from SMB2/3
protocol requirements,” including “oplock break corner cases, including
ACK validation.”
**Step 4.4 — Related patches**
Record: Same series includes lease rework; separate follow-up “return
oplock protocol error for level II ack” depends on the `OPLOCK_ACK_WAIT`
check introduced here.
**Step 4.5 — Stable list**
Record: **Not searched on lore stable@** (lore blocked by bot protection
for web fetch). No Cc: stable in commit or thread.
---
## Phase 5: Code Semantic Analysis
**Step 5.1 — Key functions**
Record: `smb20_oplock_break_ack()` (modified); callers unchanged:
`smb2_oplock_break()`.
**Step 5.2 — Callers**
Record:
- `smb2_oplock_break()` → `smb20_oplock_break_ack()` for SMB 2.0 oplock
breaks
- Dispatched via `smb2_0_server_cmds[SMB2_OPLOCK_BREAK_HE]` in
`smb2ops.c`
- Reachable from remote SMB clients over network on established sessions
**Step 5.3 — Callees**
Record: `ksmbd_lookup_fd_slow()`, `opinfo_get()`, `ksmbd_iov_pin_rsp()`,
`smb2_set_err_rsp()`, `wake_up_interruptible_all()`, `opinfo_put()`,
`ksmbd_fd_put()`. Old path also called `opinfo_write_to_read/none()`;
new path removes that dependency for ACK handling.
**Step 5.4 — Reachability**
Record: **Yes, remotely reachable.** Any SMB client using oplocks
(Windows and Samba clients commonly do) triggers oplock breaks and ACKs
during concurrent file access.
**Step 5.5 — Similar patterns**
Record: `OPLOCK_ACK_WAIT` is checked in `oplock.c` (e.g.
`close_id_del_oplock()`), but was never checked in
`smb20_oplock_break_ack()` in this tree — inconsistent state handling.
---
## Phase 6: Cross-Reference Against Local Tree
**Step 6.1 — Buggy code present?**
Record: **Yes.** Local tree is **v6.18.44** (`git describe HEAD`).
Current `smb20_oplock_break_ack()` at lines 8723–8798 still has the old
logic (checks `OPLOCK_STATE_NONE`, rejects BATCH+EXCLUSIVE, uses
transition helpers). `OPLOCK_ACK_WAIT` is not referenced in `smb2pdu.c`.
**Step 6.2 — Backport complications**
Record: **`git apply --check` on mainline commit 80a56d4a826c applies
cleanly to HEAD.** Expected apply: clean.
**Step 6.3 — Related fixes already present?**
Record: **No.** `git merge-base --is-ancestor 80a56d4a826c HEAD` →
NOT_IN_TREE. `git log --grep="align SMB2 oplock"` on reachable history →
no match.
---
## Phase 7: Subsystem and Maintainer Context
**Step 7.1 — Subsystem**
Record: **ksmbd / SMB server** (`fs/smb/server/`). Criticality:
**IMPORTANT** for `CONFIG_SMB_SERVER` users (in-kernel NAS/file server);
not core kernel, but file-sharing correctness is critical for those
deployments.
**Step 7.2 — Activity**
Record: Actively maintained in 6.18.y — recent ksmbd UAF, permission,
and session fixes in this tree’s history.
---
## Phase 8: Impact and Risk Assessment
**Step 8.1 — Who is affected**
Record: Users running **ksmbd (CONFIG_SMB_SERVER)** with SMB2 clients
using oplocks — especially Windows clients using batch oplocks.
**Step 8.2 — Trigger conditions**
Record: Common multi-client file access scenarios: conflicting opens
causing oplock breaks, client sending oplock-break ACK. Not exotic;
standard SMB caching behavior.
**Step 8.3 — Failure severity**
Record:
- Valid BATCH→EXCLUSIVE ACK rejected → interoperability failure, broken
caching handshakes
- Invalid ACK returning SUCCESS → server/client oplock state divergence
→ **cache coherency risk / potential data corruption**
- ACK while not in `OPLOCK_ACK_WAIT` (e.g. `OPLOCK_CLOSING`) processed
incorrectly
- Severity: **HIGH** for ksmbd deployments (data integrity), not kernel
oops
**Step 8.4 — Risk vs benefit**
Record:
- **Benefit:** HIGH for SMB server users — fixes long-standing protocol
bugs verified by smbtorture
- **Risk:** LOW — one function, one file, applies cleanly, uses existing
constants/state machine
- **Ratio:** Strong benefit, low risk for affected users
---
## Phase 9: Final Synthesis
**Step 9.1 — Evidence**
**FOR:**
- Real, verified protocol bugs (smbtorture series context)
- Can cause oplock state mismatch → cache coherency / data integrity
risk
- Breaks valid Windows BATCH oplock ACK behavior
- Bug present since 2021 in this tree
- Small, surgical, maintainer-authored fix
- Applies cleanly to v6.18.44
**AGAINST:**
- Optional module (`CONFIG_SMB_SERVER`), not all kernel users
- No kernel crash/oops; protocol correctness rather than memory safety
- Part of larger 14-patch series (though this hunk is self-contained)
- No Cc: stable or user bug report in commit message
- Follow-up patch may also be desirable for complete level-II ACK
handling
**Step 9.2 — Stable rules checklist**
1. Obviously correct and tested? **PASS** — MS-SMB2 alignment,
smbtorture-tested series, maintainer commit
2. Fixes a real bug? **PASS** — incorrect ACK validation and wrong
success responses
3. Important issue? **PASS** — data integrity / interoperability for SMB
file server users
4. Small and contained? **PASS** — ~100 lines, one function, one file
5. No new features/APIs? **PASS** — validation correction only
6. Can apply to local tree? **PASS** — verified clean apply
**Step 9.3 — Exception category**
Record: **N/A** — not device ID, quirk, DT, build, or docs; standard
protocol bug fix.
**Step 9.4 — Decision rationale**
For **v6.18.44**, the buggy code is present and has been since ksmbd
landed. The fix is self-contained, applies cleanly, and addresses real
SMB2 oplock-break ACK validation errors that can cause client/server
oplock state divergence — a data-integrity concern for anyone using
ksmbd as a file server. This meets stable criteria for important,
contained correctness fixes in an actively used subsystem.
---
## Verification
- [Phase 1] Parsed commit message and tags from user-provided diff and
`git show 80a56d4a826c`
- [Phase 2] Read current `smb20_oplock_break_ack()` at lines 8687–8804
in `fs/smb/server/smb2pdu.c`; confirmed old logic matches “before”
side of diff
- [Phase 3] `git blame -L 8723,8763`: buggy code from e2f34481b24db2
(2021-03-16)
- [Phase 3] `git log --oneline -20 -- fs/smb/server/smb2pdu.c`: no prior
ACK-validation fix
- [Phase 3] `git merge-base --is-ancestor 80a56d4a826c HEAD` →
NOT_IN_TREE
- [Phase 4] `b4 dig -c 80a56d4a826c` → lore URL found
- [Phase 4] `b4 dig -c 80a56d4a826c -a` → patch 06/14 in v1 series
- [Phase 4] `b4 dig -c 80a56d4a826c -w` → linux-cifs, Steve French CC’d
- [Phase 4] `b4 dig -m /tmp/oplock_ack.mbx` → saved thread; no
stable/NAK mentions
- [Phase 4] OpenWall git pull (2026-06-26) → smbtorture protocol
divergence, oplock ACK validation listed
- [Phase 5] `grep smb2_oplock_break`: dispatch via `smb2ops.c` line 189
- [Phase 5] Read `oplock.c` lines 944–954: `op_state = OPLOCK_ACK_WAIT`
set during breaks
- [Phase 6] `git describe HEAD` → v6.18.44-1-g2736c32da98b9; Makefile
VERSION 6.18.44
- [Phase 6] `git show 80a56d4a826c -p | git apply --check` → applies
cleanly
- [Phase 6] `grep OPLOCK_ACK_WAIT fs/smb/server/smb2pdu.c` → no matches
(bug present)
- [Phase 8] Traced invalid-ACK path in old code: transition helpers can
return 0 → success response without error status
**YES**The background git searches finished and match the earlier
analysis:
- **`align SMB2 oplock break`** — no match in reachable history; the fix
is not in v6.18.44.
- **`oplock break ack`** — only older, unrelated oplock commits (e.g.
CIFS-era fixes from 2021).
- **`OPLOCK_ACK_WAIT` in `smb2pdu.c`** — no matches; the ACK handler
still uses the old logic.
That supports the **YES** backport recommendation for commit
`80a56d4a826c` on this tree.
fs/smb/server/smb2pdu.c | 104 ++++++++++++++++++----------------------
1 file changed, 46 insertions(+), 58 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 1921a87e20855..99a0108cb21f4 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -8712,11 +8712,10 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work)
struct smb2_oplock_break *rsp;
struct ksmbd_file *fp;
struct oplock_info *opinfo = NULL;
- __le32 err = 0;
- int ret = 0;
+ __le32 status = STATUS_SUCCESS;
+ int ret;
u64 volatile_id, persistent_id;
char req_oplevel = 0, rsp_oplevel = 0;
- unsigned int oplock_change_type;
WORK_BUFFERS(work, req, rsp);
@@ -8742,71 +8741,55 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work)
return;
}
- if (opinfo->level == SMB2_OPLOCK_LEVEL_NONE) {
- rsp->hdr.Status = STATUS_INVALID_OPLOCK_PROTOCOL;
+ if (opinfo->op_state != OPLOCK_ACK_WAIT) {
+ ksmbd_debug(SMB, "unexpected oplock state 0x%x\n",
+ opinfo->op_state);
+ status = STATUS_INVALID_DEVICE_STATE;
goto err_out;
}
- if (opinfo->op_state == OPLOCK_STATE_NONE) {
- ksmbd_debug(SMB, "unexpected oplock state 0x%x\n", opinfo->op_state);
- rsp->hdr.Status = STATUS_UNSUCCESSFUL;
+ if (req_oplevel == SMB2_OPLOCK_LEVEL_LEASE) {
+ opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
+ status = STATUS_INVALID_PARAMETER;
goto err_out;
}
- if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||
- opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) &&
- (req_oplevel != SMB2_OPLOCK_LEVEL_II &&
- req_oplevel != SMB2_OPLOCK_LEVEL_NONE)) {
- err = STATUS_INVALID_OPLOCK_PROTOCOL;
- oplock_change_type = OPLOCK_WRITE_TO_NONE;
- } else if (opinfo->level == SMB2_OPLOCK_LEVEL_II &&
- req_oplevel != SMB2_OPLOCK_LEVEL_NONE) {
- err = STATUS_INVALID_OPLOCK_PROTOCOL;
- oplock_change_type = OPLOCK_READ_TO_NONE;
- } else if (req_oplevel == SMB2_OPLOCK_LEVEL_II ||
- req_oplevel == SMB2_OPLOCK_LEVEL_NONE) {
- err = STATUS_INVALID_DEVICE_STATE;
- if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||
- opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) &&
- req_oplevel == SMB2_OPLOCK_LEVEL_II) {
- oplock_change_type = OPLOCK_WRITE_TO_READ;
- } else if ((opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE ||
- opinfo->level == SMB2_OPLOCK_LEVEL_BATCH) &&
- req_oplevel == SMB2_OPLOCK_LEVEL_NONE) {
- oplock_change_type = OPLOCK_WRITE_TO_NONE;
- } else if (opinfo->level == SMB2_OPLOCK_LEVEL_II &&
- req_oplevel == SMB2_OPLOCK_LEVEL_NONE) {
- oplock_change_type = OPLOCK_READ_TO_NONE;
- } else {
- oplock_change_type = 0;
- }
- } else {
- oplock_change_type = 0;
+ if (opinfo->level == SMB2_OPLOCK_LEVEL_NONE) {
+ status = STATUS_INVALID_OPLOCK_PROTOCOL;
+ goto err_out;
}
- switch (oplock_change_type) {
- case OPLOCK_WRITE_TO_READ:
- ret = opinfo_write_to_read(opinfo);
- rsp_oplevel = SMB2_OPLOCK_LEVEL_II;
- break;
- case OPLOCK_WRITE_TO_NONE:
- ret = opinfo_write_to_none(opinfo);
- rsp_oplevel = SMB2_OPLOCK_LEVEL_NONE;
- break;
- case OPLOCK_READ_TO_NONE:
- ret = opinfo_read_to_none(opinfo);
- rsp_oplevel = SMB2_OPLOCK_LEVEL_NONE;
- break;
- default:
- pr_err("unknown oplock change 0x%x -> 0x%x\n",
- opinfo->level, rsp_oplevel);
+ if (opinfo->level == SMB2_OPLOCK_LEVEL_EXCLUSIVE &&
+ req_oplevel != SMB2_OPLOCK_LEVEL_II &&
+ req_oplevel != SMB2_OPLOCK_LEVEL_NONE) {
+ opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
+ status = STATUS_INVALID_OPLOCK_PROTOCOL;
+ goto err_out;
}
- if (ret < 0) {
- rsp->hdr.Status = err;
+ if (opinfo->level == SMB2_OPLOCK_LEVEL_BATCH &&
+ req_oplevel != SMB2_OPLOCK_LEVEL_II &&
+ req_oplevel != SMB2_OPLOCK_LEVEL_NONE &&
+ req_oplevel != SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
+ opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
+ status = STATUS_INVALID_OPLOCK_PROTOCOL;
+ goto err_out;
+ }
+
+ if (opinfo->level == SMB2_OPLOCK_LEVEL_II &&
+ req_oplevel != SMB2_OPLOCK_LEVEL_NONE) {
+ opinfo->level = SMB2_OPLOCK_LEVEL_NONE;
+ status = STATUS_INVALID_OPLOCK_PROTOCOL;
goto err_out;
}
+ if (req_oplevel == SMB2_OPLOCK_LEVEL_EXCLUSIVE)
+ rsp_oplevel = SMB2_OPLOCK_LEVEL_NONE;
+ else
+ rsp_oplevel = req_oplevel;
+
+ opinfo->level = rsp_oplevel;
+
rsp->StructureSize = cpu_to_le16(24);
rsp->OplockLevel = rsp_oplevel;
rsp->Reserved = 0;
@@ -8814,11 +8797,16 @@ static void smb20_oplock_break_ack(struct ksmbd_work *work)
rsp->VolatileFid = volatile_id;
rsp->PersistentFid = persistent_id;
ret = ksmbd_iov_pin_rsp(work, rsp, sizeof(struct smb2_oplock_break));
- if (ret) {
+ if (ret)
+ ksmbd_debug(SMB, "failed to pin oplock break response: %d\n",
+ ret);
+ goto out;
+
err_out:
- smb2_set_err_rsp(work);
- }
+ rsp->hdr.Status = status;
+ smb2_set_err_rsp(work);
+out:
opinfo->op_state = OPLOCK_STATE_NONE;
wake_up_interruptible_all(&opinfo->oplock_q);
opinfo_put(opinfo);
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-6.6] ksmbd: deny renaming directory with open children
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (25 preceding siblings ...)
2026-08-31 13:30 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: align SMB2 oplock break ack handling Sasha Levin
@ 2026-08-31 13:31 ` Sasha Levin
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: treat unnamed DATA stream as base file Sasha Levin
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:31 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit c841bd3d8dec33a000d6e31b7e7fafb22c39e4e9 ]
Windows denies renaming a directory while a file below that directory is
still open. smb2.rename.rename_dir_openfile checks this by keeping a file
handle open under the directory and then attempting to rename the directory
handle. ksmbd did not check open children before calling vfs_rename(), so
the rename incorrectly succeeded.
For non-POSIX clients, scan the global open file table for active handles
whose dentries are below the directory being renamed. If any child is
open, fail the rename with -EACCES so the client receives
STATUS_ACCESS_DENIED.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `ksmbd: deny renaming directory with open
children`
**Local tree:** `v6.18.44` (`git describe HEAD` →
`v6.18.44-1-g2736c32da98b9`, Makefile `6.18.44`)
**Commit analyzed:** `c841bd3d8dec3` (on `origin/master`, not yet in
this checkout)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[ksmbd] [deny] — reject directory rename when descendant
files remain open (SMB/Windows semantics)`
### Step 1.2: Tags
**Record:**
- **Fixes:** none
- **Reported-by:** none
- **Tested-by:** none
- **Reviewed-by:** none
- **Acked-by:** none
- **Link:** none
- **Cc: stable@vger.kernel.org:** none (expected for manual review)
- **Signed-off-by:** Namjae Jeon, Steve French (ignore pipeline-added
SOBs)
Notable: no fuzzer or user bug reports; rationale is Windows conformance
(`smb2.rename.rename_dir_openfile`).
### Step 1.3: Body analysis
**Record:**
- **Bug:** ksmbd allowed `vfs_rename()` on a directory while files
beneath it were still open.
- **Symptom:** Rename succeeds; Windows returns `STATUS_ACCESS_DENIED`.
- **Root cause:** No scan of active SMB file handles under the target
directory before rename.
- **Fix approach:** For non-POSIX clients, walk `global_ft` and fail
with `-EACCES` if any `FP_INITED` handle dentry is a subdirectory of
the directory being renamed.
- **Version info:** none in message.
### Step 1.4: Hidden bug fix?
**Record:** Yes — described as conformance, but it corrects incorrect
server behavior that can surprise Windows SMB clients and fail MS
protocol tests. Not a kernel crash/UAF, but a real functional/protocol
bug.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
| File | Change |
|------|--------|
| `fs/smb/server/vfs.c` | +6 lines |
| `fs/smb/server/vfs_cache.c` | +25 lines, +1 include |
| `fs/smb/server/vfs_cache.h` | +1 prototype |
**Functions:** `ksmbd_vfs_rename()`, new `ksmbd_has_open_files()`
**Scope:** Single-subsystem, surgical (~32 lines). **Classification:**
small, contained fix.
### Step 2.2: Code flow per hunk
**Hunk 1 — `vfs.c`:**
- **Before:** Proceed from rename setup directly to parent sharing
checks and `vfs_rename()`.
- **After:** If non-POSIX tree connection, target is a directory, and
`ksmbd_has_open_files(old_child)` → return `-EACCES` before rename.
- **Path:** SMB2 `SET_INFO` / `FILE_RENAME_INFORMATION` →
`ksmbd_vfs_rename()`.
**Hunk 2 — `vfs_cache.c`:**
- **Before:** No helper to detect open descendants.
- **After:** `ksmbd_has_open_files()` iterates `global_ft.idr` under
`global_ft.lock`, skips non-`FP_INITED` entries and the directory
itself, uses `is_subdir(fp_dentry, dentry)`.
**Hunk 3 — `vfs_cache.h`:** Export prototype.
### Step 2.3: Bug mechanism
**Record:** **Category:** logic / SMB protocol correctness.
**Mechanism:** Linux VFS permits directory rename with open children;
Windows SMB does not. ksmbd delegated to VFS without enforcing SMB
semantics. Fix adds an explicit open-handle check for non-POSIX clients.
### Step 2.4: Fix quality
**Record:**
- **Correctness:** Mirrors documented Windows behavior; uses existing
`global_ft` + `is_subdir()` patterns.
- **Minimal:** Yes.
- **Regression risk:** Low. POSIX-extension connections are explicitly
excluded (`!work->tcon->posix_extensions`). Only denies renames that
Windows would deny.
- **Red flags:** None significant. Scan is O(n) in open files —
acceptable on rename path.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** `ksmbd_vfs_rename()` dates to cifsd/ksmbd origins (Namjae
Jeon, 2021). Missing open-children check has been present since rename
support; not a recently introduced regression.
### Step 3.2: Fixes: tag
**Record:** N/A — no `Fixes:` tag.
### Step 3.3: Related file history
**Record:**
- Part of 29-patch series (`[PATCH 08/29]`, Jun 2026).
- Related sibling: `9a5784f4d58b0` “check parent directory sharing
conflicts on rename” (patch 07/29) — separate concern, also not in
this tree.
- Prior rename fixes in this tree: `53e3e5babc096` (empty string),
`68477b5dc5710` (rename failure), `4973b04d3ea57` (RENAME_NOREPLACE).
- **Standalone:** This patch does not depend on other series members.
### Step 3.4: Author context
**Record:** Namjae Jeon is ksmbd maintainer; Steve French committed.
Active ksmbd development in this tree.
### Step 3.5: Dependencies
**Record:** Requires `global_ft`, `FP_INITED`, `posix_extensions`,
`is_subdir()` — all present in v6.18.44. No prerequisite commits needed
for the logic itself.
**Backport note:** `vfs.c` context differs from upstream commit parent.
Local tree uses `lock_rename_child()` / `unlock_rename()`; upstream
patch targets `start_renaming_dentry()` / `end_renaming()`.
`vfs_cache.c` and `vfs_cache.h` should apply cleanly; `vfs.c` needs
relocation after dentry validation (~line 749), before `parent_fp`
check.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:**
- `b4 dig -c c841bd3d8dec3` →
https://patch.msgid.link/20260621124844.6235-8-linkinjeon@kernel.org
- Series: `[PATCH 08/29]`
- WebFetch of lore URL blocked (bot protection); thread retrieved via
`b4 dig -m /tmp/ksmbd_rename_thread.mbx`
- No explicit `Cc: stable` found in thread grep
- No NAKs found in mbox grep
### Step 4.2: Reviewers
**Record:** `b4 dig -w` returned same lore URL; CC includes Steve French
/ linux-cifs list. Maintainer-authored.
### Step 4.3: Bug report
**Record:** N/A — reference is MS test
`smb2.rename.rename_dir_openfile`, not a user/syzbot report.
### Step 4.4: Series context
**Record:** 29-patch ksmbd series; this patch is independently
applicable.
### Step 4.5: Stable list
**Record:** Not searched separately; no stable nomination found in patch
thread.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `ksmbd_has_open_files()`, `ksmbd_vfs_rename()`, callers
`smb2_rename()` → `set_rename_info()` → `smb2_set_info_file()`.
### Step 5.2: Callers
**Record:** Reachable from SMB2 `SET_INFO` / rename — userspace-
triggerable by any SMB client with rename permission. Rename locks are
already held in `ksmbd_vfs_rename()` when the check would run.
### Step 5.3: Callees
**Record:** `idr_for_each_entry()`, `is_subdir()`, `d_is_dir()`,
`read_lock(&global_ft.lock)`.
### Step 5.4: Reachability
**Record:** **Userspace-reachable** via SMB2 rename of a directory
handle. Common file-server operation for `CONFIG_SMB_SERVER` / ksmbd
users.
### Step 5.5: Similar patterns
**Record:** `ksmbd_lookup_fd_cguid()` uses the same `global_ft`
iteration pattern. `ksmbd_lookup_fd_inode()` checks `FP_INITED`.
`-EACCES` maps to `STATUS_ACCESS_DENIED` in `smb2_set_info()` err_out
(lines 6722–6723).
---
## PHASE 6: CROSS-REFERENCE WITH LOCAL TREE
### Step 6.1: Buggy code present?
**Record:** **Yes.** `ksmbd_vfs_rename()` at lines 691–814 has no open-
children check. `ksmbd_has_open_files()` is absent. Bug present since
rename support landed.
### Step 6.2: Backport complications
**Record:** **Minor rework** for `vfs.c` only (different rename helper
API). `vfs_cache.c`/`vfs_cache.h` clean apply expected.
### Step 6.3: Related fixes already present?
**Record:** No equivalent fix. Related rename sharing fix
(`9a5784f4d58b0`) also absent but separate.
---
## PHASE 7: SUBSYSTEM CONTEXT
### Step 7.1: Subsystem criticality
**Record:** **ksmbd / SMB server** (`fs/smb/server/`). **IMPORTANT** for
deployments using in-kernel SMB server; not universal like mm/net core.
### Step 7.2: Activity
**Record:** Actively developed; many recent ksmbd commits in v6.18.y.
---
## PHASE 8: IMPACT AND RISK
### Step 8.1: Who is affected
**Record:** **CONFIG-dependent** — users running ksmbd with non-POSIX
SMB clients performing directory renames.
### Step 8.2: Trigger conditions
**Record:** Rename a directory via SMB while another open handle exists
on a file/subdirectory beneath it. Unprivileged SMB user with
delete/rename rights can trigger. Not timing-dependent.
### Step 8.3: Failure mode severity
**Record:** **Incorrect success** of forbidden rename (protocol
violation). Not kernel oops/UAF/leak. Possible client confusion /
namespace inconsistency vs Windows expectations. **Severity: MEDIUM**
(functional/protocol; not CRITICAL kernel stability).
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** Windows SMB compatibility; passes MS conformance test;
aligns with established Windows semantics; low-risk behavioral
correction.
- **Risk:** Very low — small, well-scoped denial path.
- **Ratio:** Favorable for ksmbd stable users; precedent exists for
ksmbd rename/protocol fixes in stable (e.g. `53e3e5babc096`,
`ca4974ca95456`).
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence compile
**FOR backport:**
- Real, reproducible protocol bug (MS test case named in commit).
- Small (32 lines), obviously correct, maintainer-authored.
- Buggy code exists in v6.18.44.
- All infrastructure present (`global_ft`, `is_subdir`,
`posix_extensions`).
- `-EACCES` → `STATUS_ACCESS_DENIED` mapping verified.
- ksmbd rename/protocol correctness fixes have stable precedent in this
tree.
**AGAINST backport:**
- Not crash, security, memory safety, or explicit data corruption.
- No user/syzbot reports.
- Part of larger series (though standalone).
- `vfs.c` needs minor context adaptation for this tree.
- Only affects ksmbd users; POSIX-extension clients excluded.
**Unresolved:** No production user reports verified; lore thread not
fully readable via WebFetch.
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — clear logic; MS test
reference; maintainer commit.
2. Fixes real bug affecting users? **PASS** — incorrect SMB rename
semantics for Windows clients.
3. Important issue? **PASS (borderline)** — protocol correctness
affecting SMB file-server interoperability; not kernel
crash/corruption, but “real bug that bothers people” per stable rules
for server workloads.
4. Small and contained? **PASS** — 32 lines, 3 files.
5. No new features/APIs? **PASS** — enforces existing protocol
semantics; no userspace API change.
6. Can apply to local tree? **PASS** — `vfs_cache.*` clean; `vfs.c`
needs relocated hunk.
### Step 9.3: Exception categories
**Record:** None (not device ID, quirk, DT, build, or docs). Protocol
correctness fix.
### Step 9.4: Decision rationale
This is not a kernel-stability fix, but it is a genuine, well-defined
SMB server bug: ksmbd incorrectly allows an operation Windows explicitly
forbids. For v6.18.y users running ksmbd as a Windows-compatible file
server, the fix is small, low-risk, and matches the class of ksmbd
rename/protocol corrections already carried in stable. The buggy path
exists in this tree and all prerequisites are present.
---
## Verification
- **[Phase 1]** Parsed commit `c841bd3d8dec3` message; no
Fixes/Reported-by/Link/Cc:stable tags.
- **[Phase 2]** Diff: +32 lines across 3 files; new
`ksmbd_has_open_files()`; check in `ksmbd_vfs_rename()`.
- **[Phase 3]** `git blame` on `ksmbd_vfs_rename()`: function since
2021; `git log origin/master`: commit not in HEAD; merge-base
confirmed divergence.
- **[Phase 3]** `git show 9a5784f4d58b0`: related rename sharing fix,
separate.
- **[Phase 4]** `b4 dig -c c841bd3d8dec3`: lore URL found; patch 08/29.
- **[Phase 4]** `b4 dig -m`: thread saved; no stable CC found in grep.
- **[Phase 5]** `grep ksmbd_vfs_rename`: called from `smb2pdu.c:6167`.
- **[Phase 5]** Read `smb2_set_info()` err_out: `-EACCES` →
`STATUS_ACCESS_DENIED` (lines 6722–6723).
- **[Phase 5]** `grep is_subdir` in `fs/dcache.c`: `bool
is_subdir(struct dentry *new, struct dentry *old)`.
- **[Phase 6]** `git describe HEAD`: v6.18.44; `ksmbd_has_open_files`
absent in tree.
- **[Phase 6]** Read local `ksmbd_vfs_rename()` (691–814): no open-
children check; uses `lock_rename_child`.
- **[Phase 6]** `grep global_ft` in `vfs_cache.c`: present since
durable-handle support.
- **[Phase 6]** `grep posix_extensions` in `fs/smb/server/`: present on
`tree_connect`.
- **[Phase 7]** ksmbd active in v6.18.44 per `git log --
fs/smb/server/`.
- **[Phase 8]** Failure mode: protocol violation, not kernel crash;
severity MEDIUM.
**YES**The background searches finished. The commit `c841bd3d8dec3`
(“ksmbd: deny renaming directory with open children”) is on
`origin/master` but not in your local v6.18.44 tree yet.
Recent history on `fs/smb/server/vfs.c` shows active ksmbd rename work
(path resolution, credential handling, VFS rename API updates), which
confirms the `vfs.c` hunk would need minor relocation for this tree —
the `vfs_cache.c`/`vfs_cache.h` parts should apply cleanly.
**Verdict from the full analysis: YES** — small SMB protocol correctness
fix worth backporting to this tree.
fs/smb/server/vfs.c | 6 ++++++
fs/smb/server/vfs_cache.c | 25 +++++++++++++++++++++++++
fs/smb/server/vfs_cache.h | 1 +
3 files changed, 32 insertions(+)
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index 764eca75291ce..32009ff8dfa45 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -748,6 +748,12 @@ int ksmbd_vfs_rename(struct ksmbd_work *work, const struct path *old_path,
goto out3;
}
+ if (!work->tcon->posix_extensions && d_is_dir(old_child) &&
+ ksmbd_has_open_files(old_child)) {
+ err = -EACCES;
+ goto out3;
+ }
+
parent_fp = ksmbd_lookup_fd_inode(old_child->d_parent);
if (parent_fp) {
if (parent_fp->daccess & FILE_DELETE_LE) {
diff --git a/fs/smb/server/vfs_cache.c b/fs/smb/server/vfs_cache.c
index 51e37e89d1aa5..aee974a264d51 100644
--- a/fs/smb/server/vfs_cache.c
+++ b/fs/smb/server/vfs_cache.c
@@ -10,6 +10,7 @@
#include <linux/vmalloc.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
+#include <linux/dcache.h>
#include "glob.h"
#include "vfs_cache.h"
@@ -649,6 +650,30 @@ struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry)
return NULL;
}
+bool ksmbd_has_open_files(struct dentry *dentry)
+{
+ struct ksmbd_file *fp;
+ unsigned int id;
+ bool ret = false;
+
+ read_lock(&global_ft.lock);
+ idr_for_each_entry(global_ft.idr, fp, id) {
+ struct dentry *fp_dentry = fp->filp->f_path.dentry;
+
+ if (fp->f_state != FP_INITED)
+ continue;
+ if (fp_dentry == dentry)
+ continue;
+ if (is_subdir(fp_dentry, dentry)) {
+ ret = true;
+ break;
+ }
+ }
+ read_unlock(&global_ft.lock);
+
+ return ret;
+}
+
#define OPEN_ID_TYPE_VOLATILE_ID (0)
#define OPEN_ID_TYPE_PERSISTENT_ID (1)
diff --git a/fs/smb/server/vfs_cache.h b/fs/smb/server/vfs_cache.h
index 10f4172ec8017..ad7a487a21bb0 100644
--- a/fs/smb/server/vfs_cache.h
+++ b/fs/smb/server/vfs_cache.h
@@ -165,6 +165,7 @@ struct ksmbd_file *ksmbd_lookup_durable_fd(unsigned long long id);
void ksmbd_put_durable_fd(struct ksmbd_file *fp);
struct ksmbd_file *ksmbd_lookup_fd_cguid(char *cguid);
struct ksmbd_file *ksmbd_lookup_fd_inode(struct dentry *dentry);
+bool ksmbd_has_open_files(struct dentry *dentry);
unsigned int ksmbd_open_durable_fd(struct ksmbd_file *fp);
struct ksmbd_file *ksmbd_open_fd(struct ksmbd_work *work, struct file *filp);
void ksmbd_launch_ksmbd_durable_scavenger(void);
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread* [PATCH AUTOSEL 6.18-5.15] ksmbd: treat unnamed DATA stream as base file
[not found] <20260831133314.4125787-1-sashal@kernel.org>
` (26 preceding siblings ...)
2026-08-31 13:31 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: deny renaming directory with open children Sasha Levin
@ 2026-08-31 13:31 ` Sasha Levin
27 siblings, 0 replies; 28+ messages in thread
From: Sasha Levin @ 2026-08-31 13:31 UTC (permalink / raw)
To: patches, stable
Cc: Namjae Jeon, Steve French, Sasha Levin, smfrench, linux-cifs,
linux-kernel
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 171b5d72dd80f99271c073c6e38d5263687c3b6d ]
The SMB path suffix :: names the unnamed data stream of the base
file, not an alternate data stream backed by a DosStream xattr.
Canonicalize an empty stream name with an explicit type to a NULL
stream name after parsing. This keeps the base filename produced by
strsep() and lets open continue through the normal base-file path instead
of looking for a non-existent empty stream xattr.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[ksmbd] [treat] — Correctly handle SMB `::$DATA` paths as
the base file's unnamed data stream, not as an alternate DosStream
xattr.`
### Step 1.2: Tags
**Record:**
- **Fixes:** — none
- **Reported-by:** — none
- **Tested-by:** — none
- **Reviewed-by:** — none
- **Acked-by:** — none
- **Link:** — none
- **Cc: stable:** — none (expected for manual review)
- **Signed-off-by:** Namjae Jeon `<linkinjeon@kernel.org>`, Steve French
`<stfrench@microsoft.com>`
- **Notable:** Part of `[PATCH 7/14]` series
(`20260618141739.9029-7-linkinjeon@kernel.org`); no syzbot, no
explicit stable nomination in the patch.
### Step 1.3: Body analysis
**Record:**
- **Bug:** SMB path suffix `::$DATA` names the *unnamed* (default) data
stream of the base file per SMB/NTFS semantics, not an alternate
stream stored in a `DosStream` xattr.
- **Symptom:** `parse_stream_name()` leaves `stream_name` pointing to an
empty string (`""`), which is non-NULL. Callers treat that as an
alternate stream and look up a non-existent empty-stream xattr;
`FILE_OPEN` fails with `-EBADF`.
- **Root cause:** Empty stream name after parsing `file::$DATA` is not
canonicalized to NULL, so the stream-specific open path is taken
instead of the normal base-file path.
- **Version info:** None in the message.
### Step 1.4: Hidden bug fix?
**Record:** Yes — despite the neutral verb "treat", this is a functional
correctness fix for SMB CREATE/open when clients use explicit `::$DATA`
syntax (common Windows behavior).
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **File:** `fs/smb/server/misc.c` (+11 / −3)
- **Function:** `parse_stream_name()`
- **Scope:** Single-file, surgical fix
### Step 2.2: Code flow change
**Record:**
| Hunk | Before | After |
|------|--------|-------|
| Init | `*stream_name` unset | `*stream_name = NULL` at entry |
| Type detection | Sets `*s_type` inline | Tracks `has_stream_type =
true` when `$DATA` or `$INDEX_ALLOCATION` matched |
| Empty unnamed stream | `*stream_name = s_name` (empty string, non-
NULL) | If `has_stream_type && !s_name[0] && *s_type == DATA_STREAM`,
skip assignment and `goto out` with `stream_name == NULL` |
**Affected path:** SMB2 CREATE/open (and any other caller of
`parse_stream_name()` when path contains `::$DATA`).
### Step 2.3: Bug mechanism
**Record:**
- **Category:** Logic / correctness fix (wrong interpretation of SMB
stream syntax)
- **Mechanism:** For `file::$DATA`, `strsep()` yields `s_name=""`. A
non-NULL pointer to `""` passes `if (stream_name)` in `smb2_create()`
and triggers `smb2_set_stream_name_xattr()`, which builds
`user.DosStream.:$DATA` via `ksmbd_vfs_xattr_stream_name()` and fails
lookup on `FILE_OPEN` (`-EBADF` at lines 2502–2504 of `smb2pdu.c`).
With the fix, `stream_name == NULL` and the normal base-file open path
runs.
### Step 2.4: Fix quality
**Record:**
- Fix is minimal and matches SMB semantics.
- Initializing `*stream_name = NULL` is correct defensive practice.
- Only empty **DATA** streams are canonicalized; named streams
(`file:alt::$DATA`) and `$INDEX_ALLOCATION` paths are unchanged.
- **Minor concern:** `smb2_rename()` also calls `parse_stream_name()`
and passes `stream_name` to `ksmbd_vfs_xattr_stream_name()` without a
NULL check. Deleting the default unnamed `$DATA` stream via rename is
not a normal SMB operation; this edge case appears unreachable in
practice and was already broken with the empty-string xattr lookup.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** `parse_stream_name()` introduced in `e2f34481b24db` ("cifsd:
add server-side procedures for SMB3", 2021-03-16). Confirmed ancestor of
current HEAD. Bug present since initial stream parsing; file later moved
to `fs/smb/server/misc.c` in `38c8a9a520825`.
### Step 3.2: Fixes: tag
**Record:** N/A — no `Fixes:` tag.
### Step 3.3: Related file history
**Record:** Recent `misc.c` changes in this tree: `c7c884a1305aa` (path
resolution), `0066f623bce8f` (__GFP_RETRY_MAYFAIL), directory move. No
conflicting stream-parsing changes. Fix is standalone (patch 7/14 of a
series, but only touches `misc.c` with no structural dependencies on
other patches).
### Step 3.4: Author context
**Record:** Namjae Jeon is the ksmbd maintainer. Patch is from the June
2026 ksmbd server fixes series later referenced in Steve French's GIT
PULL.
### Step 3.5: Dependencies
**Record:** None. `has_stream_type` is local; `DATA_STREAM` enum already
exists in `vfs.h`. Applies cleanly to current `misc.c` in this tree.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:**
- `b4 dig -c 178b490...` failed (commit not in this checkout).
- Found patch in local mbox:
`20260618_linkinjeon_ksmbd_validate_smb2_lease_create_contexts.mbx`,
`[PATCH 7/14]`, Message-Id
`20260618141739.9029-7-linkinjeon@kernel.org`.
- lore.kernel.org fetch blocked (bot protection).
- Web search: commit listed in June 2026 `[GIT PULL] ksmbd server fixes`
under "Tighten CREATE and stream semantics, including ... unnamed DATA
stream handling".
### Step 4.2: Reviewers
**Record:** Patch has author SOB and Steve French SOB. No Reviewed-
by/Acked-by in the mbox entry. Series CC'd to linux-cifs (inferred from
series context).
### Step 4.3: Bug reports
**Record:** No formal bug report or syzbot link. Related GitHub issue
#507 discusses separate stream SetInfo/truncation bugs, not this
specific `::$DATA` parsing issue.
### Step 4.4: Series context
**Record:** Patch 7/14 of a larger ksmbd fix series. This patch is self-
contained and does not require other series patches.
### Step 4.5: Stable list
**Record:** No stable-list discussion found for this specific patch.
(Unrelated ksmbd stream patches have been nominated to stable
historically.)
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `parse_stream_name()` (modified). Callers: `smb2_create()`
and `smb2_rename()` in `smb2pdu.c`.
### Step 5.2: Callers
**Record:**
- **`smb2_create()`** (line 2979): Called when `strchr(name, ':')` and
streams share flag set — primary SMB2 CREATE/open path, reachable from
any SMB client.
- **`smb2_rename()`** (line 6125): Stream-delete rename path; less
common.
### Step 5.3: Callees
**Record:** `strsep()`, `strchr()`, `ksmbd_validate_stream_name()`,
`strncasecmp()`. Downstream in open path: `smb2_set_stream_name_xattr()`
→ `ksmbd_vfs_xattr_stream_name()` → xattr lookup/create.
### Step 5.4: Reachability
**Record:** Any SMB client opening a file with explicit `::$DATA` suffix
(standard Windows unnamed-stream notation) on a ksmbd share with
`KSMBD_SHARE_FLAG_STREAMS` enabled triggers the bug. Reachable from
network clients without special privileges.
### Step 5.5: Similar patterns
**Record:** Related but distinct stable-worthy stream fixes exist in
ksmbd history (e.g., default stream in FILE_STREAM_INFORMATION). This
fix addresses CREATE/open parsing specifically.
---
## PHASE 6: CROSS-REFERENCING AGAINST LOCAL TREE
### Step 6.1: Buggy code in tree?
**Record:** **Yes.** Local tree is **v6.18.44** (`git describe HEAD` →
`v6.18.44-1-g2736c32da98b9`). `parse_stream_name()` at lines 119–151 of
`fs/smb/server/misc.c` lacks the fix (`has_stream_type` not present).
Bug has existed since ksmbd stream support landed (2021).
### Step 6.2: Backport complications
**Record:** Clean apply expected — `misc.c` is stable, minimal recent
churn, no conflicting edits at the target hunk.
### Step 6.3: Fix already present?
**Record:** **No.** `git grep has_stream_type` only finds the patch in
the mbox file, not in the tree. Fix commit not in this checkout.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem criticality
**Record:** **ksmbd** (in-kernel SMB server) under `fs/smb/server/`.
**IMPORTANT** — affects users who run the kernel SMB server
(`CONFIG_SMB_SERVER` in `fs/smb/server/Kconfig`), not all kernel users.
### Step 7.2: Subsystem activity
**Record:** Actively maintained; recent commits in this tree include UAF
fixes, NEGOTIATE fixes, and DACL validation — indicating ongoing ksmbd
stable fix activity.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who is affected
**Record:** Users running ksmbd with alternate data streams enabled on a
share, accessed by SMB clients (especially Windows) that open files
using `::$DATA` syntax.
### Step 8.2: Trigger conditions
**Record:** Client sends SMB2 CREATE for a path like
`document.docx::$DATA`. Common when streams support is enabled. Not
timing-dependent; deterministic logic bug.
### Step 8.3: Failure mode severity
**Record:** **MEDIUM-HIGH** — file open fails (`-EBADF` / SMB error),
breaking interoperability. No kernel crash/oops, but prevents access to
files that should open normally. Can affect Office documents and other
apps using explicit default-stream paths.
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** Restores correct open behavior for standard SMB unnamed
data stream syntax; fixes long-standing interoperability bug.
- **Risk:** Very low — ~11 lines, one function, no API changes,
maintainer-authored.
- **Ratio:** Strong benefit, minimal risk for ksmbd users.
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Real, reproducible functional bug in SMB2 CREATE/open
- Long present since 2021 stream parsing code
- Small, surgical, maintainer-authored fix
- Buggy code confirmed in local 6.18.44 tree; fix not yet applied
- Part of reviewed ksmbd server fixes pull request
- Correct per SMB/NTFS `::$DATA` semantics
**AGAINST backport:**
- Only affects ksmbd server users (not universal)
- No syzbot/CVE/crash report
- Theoretical rename-path NULL concern for `::$DATA/` stream delete
(likely invalid SMB operation, unverified)
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — logic matches SMB spec;
maintainer series merged to mainline.
2. Fixes a real bug affecting users? **PASS** — open failures for
`::$DATA` paths.
3. Important issue? **PASS** — MEDIUM-HIGH severity interoperability
failure on file open.
4. Small and contained? **PASS** — 1 file, ~14 lines.
5. No new features or APIs? **PASS** — parsing correction only.
6. Can apply to local tree? **PASS** — buggy code present, clean apply
expected.
### Step 9.3: Exception categories
**Record:** None (not a device ID, quirk, DT, build, or docs fix).
Qualifies as a standard bug fix.
### Step 9.4: Problem and decision
Windows and other SMB clients commonly reference the default data stream
with the `::$DATA` suffix. ksmbd's `parse_stream_name()` incorrectly
treats the resulting empty stream name as an alternate stream, routing
opens through xattr lookup that fails. The fix canonicalizes an empty
stream name with explicit `$DATA` type to NULL, allowing normal base-
file open — exactly what SMB semantics require.
For the **6.18.44** tree checked out here, ksmbd is present, the buggy
code is present, and the fix is small, correct, and addresses a real
interoperability failure for SMB server deployments.
---
## Verification
- **[Phase 1]** Parsed subject, body, tags from user-provided commit
message and mbox
`20260618_linkinjeon_ksmbd_validate_smb2_lease_create_contexts.mbx`.
- **[Phase 2]** Read diff and current `parse_stream_name()` at lines
119–151 of `fs/smb/server/misc.c`.
- **[Phase 2]** Traced open failure: `smb2_create()` line 2979 → `if
(stream_name)` line 3184/3451 → `smb2_set_stream_name_xattr()` →
`ksmbd_vfs_xattr_stream_name()` lines 1800–1818 → `FILE_OPEN` returns
`-EBADF` lines 2502–2504.
- **[Phase 3]** `git blame -L 119,151 fs/smb/server/misc.c`: introduced
`e2f34481b24db` (2021-03-16).
- **[Phase 3]** `git merge-base --is-ancestor e2f34481b24db HEAD`:
confirmed ancestor.
- **[Phase 3]** `git log --oneline -20 -- fs/smb/server/misc.c`: no
conflicting stream changes.
- **[Phase 4]** `b4 dig -c 178b490e56d8d4711c0c61d37652bcfd1269d5b0`:
failed (commit not in tree).
- **[Phase 4]** Grep mbox for patch 7/14: found full diff and Message-
Id.
- **[Phase 4]** lore.kernel.org fetch: blocked by bot protection.
- **[Phase 4]** Web search: found GIT PULL reference listing this fix
under stream semantics.
- **[Phase 5]** `grep parse_stream_name`: callers at `smb2pdu.c:2979`
and `smb2pdu.c:6125`.
- **[Phase 5]** Read `smb2_create()` stream handling at lines 3175–3458.
- **[Phase 5]** Read `ksmbd_vfs_xattr_stream_name()` at
`vfs.c:1800–1818`.
- **[Phase 6]** `git describe HEAD`: v6.18.44-1-g2736c32da98b9; `make
kernelversion`: 6.18.44.
- **[Phase 6]** `grep has_stream_type`: only in mbox, not in tree — fix
absent.
- **[Phase 6]** Read current `misc.c` lines 119–151: buggy code
confirmed.
- **[Phase 7]** Read `fs/smb/server/Kconfig`: ksmbd server is
`CONFIG_SMB_SERVER`.
- **[Phase 8]** Traced `file::$DATA` parsing manually via `strsep()`
logic.
- **UNVERIFIED:** Whether any SMB client issues rename/delete for
`::$DATA/` (theoretical NULL concern in `smb2_rename()`).
**YES**The background git searches didn’t add much beyond what we
already had:
- **Find commit hash:** Finished with no matches — `has_stream_type` and
the commit subject aren’t in this 6.18.44 tree, which matches the fix
not being applied yet.
- **Search git history:** Didn’t complete (timed out / was stopped). The
commit was already identified from the local mbox (`[PATCH 7/14]`) and
the GitHub mirror (`178b490`).
The backport recommendation stands: **YES** for this tree — ksmbd
mishandles `::$DATA` opens, and the fix is a small, self-contained
change in `fs/smb/server/misc.c`.
fs/smb/server/misc.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/fs/smb/server/misc.c b/fs/smb/server/misc.c
index 53ddcae31f719..d6abe574fc89b 100644
--- a/fs/smb/server/misc.c
+++ b/fs/smb/server/misc.c
@@ -121,7 +121,9 @@ int parse_stream_name(char *filename, char **stream_name, int *s_type)
char *stream_type;
char *s_name;
int rc = 0;
+ bool has_stream_type = false;
+ *stream_name = NULL;
s_name = filename;
filename = strsep(&s_name, ":");
ksmbd_debug(SMB, "filename : %s, streams : %s\n", filename, s_name);
@@ -137,14 +139,20 @@ int parse_stream_name(char *filename, char **stream_name, int *s_type)
ksmbd_debug(SMB, "stream name : %s, stream type : %s\n", s_name,
stream_type);
- if (!strncasecmp("$data", stream_type, 5))
+ if (!strncasecmp("$data", stream_type, 5)) {
*s_type = DATA_STREAM;
- else if (!strncasecmp("$index_allocation", stream_type, 17))
+ has_stream_type = true;
+ } else if (!strncasecmp("$index_allocation", stream_type, 17)) {
*s_type = DIR_STREAM;
- else
+ has_stream_type = true;
+ } else {
rc = -ENOENT;
+ }
}
+ if (has_stream_type && !s_name[0] && *s_type == DATA_STREAM)
+ goto out;
+
*stream_name = s_name;
out:
return rc;
--
2.53.0
^ permalink raw reply related [flat|nested] 28+ messages in thread