From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Namjae Jeon <linkinjeon@kernel.org>,
Sasha Levin <sashal@kernel.org>,
linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH AUTOSEL 6.18-5.15] ksmbd: protect private extended attributes
Date: Mon, 19 Oct 2026 09:48:20 -0400 [thread overview]
Message-ID: <20261019135441.1420968-209-sashal@kernel.org> (raw)
In-Reply-To: <20261019135441.1420968-1-sashal@kernel.org>
From: Namjae Jeon <linkinjeon@kernel.org>
[ Upstream commit 4ea46ea602fc7055eee4b5b0e84f90f22da7f7e7 ]
SMB clients can currently create an EA named NTACL because SMB EAs are
mapped into the user namespace while the ksmbd security descriptor is
stored as security.NTACL. Allowing the reserved logical name makes the
server-private ACL metadata appear writable through the SMB EA API.
Reject NTACL, DOSATTRIB, and DosStream-prefixed EA names without regard
to case. Filter the same private names from EA query results so stale or
externally-created user namespace attributes cannot be exposed.
This fixes smb2.ea.acl_xattr when acl_xattr_name is configured as
NTACL.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
LLM Generated explanations, may be completely bogus:
## Phase 1: Commit message forensics
**Step 1.1 — Subject**
- Record: `[ksmbd] [protect] keep server-private xattr names off the SMB
EA API`
**Step 1.2 — Tags**
- Record: `Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>` (ksmbd
maintainer; author and committer).
- No `Fixes:`, `Reported-by:`, `Tested-by:`, `Reviewed-by:`, `Acked-
by:`, `Link:`, or `Cc: stable`. Absence of `Fixes:`/`Cc: stable` is
expected for this review and is not a negative signal.
**Step 1.3 — Body**
- Record: SMB EAs are stored as `user.*` xattrs. ksmbd keeps NT ACL
metadata in `security.NTACL`. Clients can still create an EA named
`NTACL`, so the reserved logical name looks writable over SMB
SET_INFO/QUERY_INFO EA. The patch rejects `NTACL`, `DOSATTRIB`, and
`DosStream.`-prefixed names case-insensitively on set, and filters the
same names from query results so leftover `user.*` copies are not
exposed. Failure mode: reserved metadata can be written or listed
through the EA API. Symptom: Samba smbtorture `smb2.ea.acl_xattr`
fails when `acl_xattr_name=NTACL`. Introduced with original ksmbd EA
mapping; not a new 7.x-only bug.
**Step 1.4 — Hidden bug fix?**
- Record: Yes. “Protect” is a security/integrity fix, not cleanup. SET
currently does not reject reserved names. GET already skipped
`DosStream.` / `DOSATTRIB` with case-sensitive `strncmp`, but not
`NTACL` and not case variants.
## Phase 2: Diff analysis
**Step 2.1 — Inventory**
- Record: `fs/smb/server/smb2pdu.c` only (`+22/-6`). Functions: new
`smb2_is_private_ea()`; `smb2_set_ea()`; `smb2_get_ea()`.
Classification: single-file surgical fix.
**Step 2.2 — Flow**
- Record:
- SET: after the EA name-length check, reserved names return `-EACCES`
instead of `ksmbd_vfs_setxattr`/`remove_xattr` on `user.<name>`.
- GET: STREAM and DOSATTRIB `strncmp` skips become one
`smb2_is_private_ea()` skip (adds `NTACL`, case-insensitive).
Specific-name QUERY still cannot return those names.
**Step 2.3 — Bug mechanism**
- Record: Logic/correctness plus a hardware/protocol reserved-name
filter (category g/h). Same-namespace collisions: `user.DOSATTRIB`
(DOS flags/create time) and `user.DosStream.*` (named streams).
`security.NTACL` is a different namespace, so SET of EA `NTACL`
creates `user.NTACL` rather than overwriting the SD; the patch still
blocks that reserved name and hides any leftover `user.NTACL`.
**Step 2.4 — Fix quality**
- Record: Obviously correct. `strncasecmp` + exact length for
`NTACL`/`DOSATTRIB`, prefix match for streams. `-EACCES` maps to
`STATUS_ACCESS_DENIED` in both `smb2_set_info()` and CREATE error
mapping, matching smbtorture. Regression risk is low: only reserved
Samba/ksmbd names are rejected. Query of a private name still yields
`STATUS_NO_EAS_ON_FILE` rather than ACCESS_DENIED; that is pre-
existing GET skip behavior, not a new crash path.
## Phase 3: Git history
**Step 3.1 — Blame**
- Record: Unfiltered SET and GET STREAM/DOSATTRIB skips come from
`e2f34481b24db` (“cifsd: add server-side procedures for SMB3”,
2021-03-16). Present since ksmbd entered the kernel (5.15 era). `git
merge-base --is-ancestor e2f34481b24db HEAD` succeeds.
**Step 3.2 — Fixes tag**
- Record: None. Buggy behavior is the original EA mapping, not a later
regression.
**Step 3.3 — File history**
- Record: Recent 6.12 ksmbd work is unrelated (buffer sizes, leases,
durable reconnect). No competing private-EA helper in this tree.
**Step 3.4 — Author**
- Record: Namjae Jeon is the ksmbd maintainer. Surrounding 7.3 ksmbd
commits are other protocol/security fixes; this commit is standalone
(`4ea46ea602fc`).
**Step 3.5 — Dependencies**
- Record: Needs `SD_PREFIX`, `DOS_ATTRIBUTE_PREFIX`, `STREAM_PREFIX`
from `fs/smb/server/xattr.h` (included via `vfs.h` in `smb2pdu.c`).
All exist here. `strncasecmp` is in `include/linux/string.h`. Applies
standalone.
## Phase 4: Mailing list / external
**Step 4.1**
- Record: SHA `4ea46ea602fc7055eee4b5b0e84f90f22da7f7e7` (v7.3-rc1). `b4
dig -c 4ea46ea602fc` failed: lore.kernel.org returned errors (Anubis
bot challenge). WebFetch to lore also 403. UNVERIFIED: original thread
text, NAKs, reviewer Cc:stable.
**Step 4.2**
- Record: UNVERIFIED recipients. Commit is authored and committed by the
subsystem maintainer; Linus merged it in `ksmbd-for-7.3-rc1`
(`61a09cfc12147`), described as smbtorture-validated protocol fixes
and security hardening.
**Step 4.3**
- Record: Samba `source4/torture/smb2/ea.c` `torture_smb2_acl_xattr`
(`smb2.ea.acl_xattr`) requires `acl_xattr_name`, checks the name is
not listed, and expects SET to fail with `NT_STATUS_ACCESS_DENIED`.
Confirmed from samba-team/samba master.
**Step 4.4**
- Record: Standalone. No later revert or follow-up on
`smb2_is_private_ea` through v7.3-rc1 (`git grep` still shows the
helper at three sites).
**Step 4.5**
- Record: UNVERIFIED on lore.kernel.org/stable (lore blocked). No in-
tree revert.
## Phase 5: Code semantics
**Step 5.1**
- Record: `smb2_is_private_ea`, `smb2_set_ea`, `smb2_get_ea`.
**Step 5.2**
- Record: `smb2_set_ea` callers: CREATE EA context (`smb2_open` path
~3322) and `FILE_FULL_EA_INFORMATION` in `smb2_set_info_file` (~6644).
`smb2_get_ea` caller: `smb2_get_info_file` (~5493). Reachable from
SMB2 CREATE / SET_INFO / QUERY_INFO.
**Step 5.3**
- Record: SET uses `ksmbd_vfs_setxattr` / `ksmbd_vfs_remove_xattr` after
prefixing `XATTR_USER_PREFIX`. GET uses `ksmbd_vfs_listxattr` /
`ksmbd_vfs_getxattr`. Internal DOS/stream/SD writers
(`ksmbd_vfs_set_dos_attrib_xattr`, stream helpers,
`ksmbd_vfs_set_sd_xattr`) do not go through `smb2_set_ea`, so server-
internal writes remain allowed.
**Step 5.4**
- Record: Yes, from userspace: authenticated SMB client with
`FILE_WRITE_EA` / `FILE_READ_EA`. Those rights are normally part of
generic write/read.
**Step 5.5**
- Record: GET already special-cased STREAM and DOSATTRIB; SET did not.
Same reserved names as Samba (`user.DOSATTRIB`, `user.DosStream.*`,
`security.NTACL`).
## Phase 6: This tree (6.12.111)
**Step 6.1**
- Record: Local tree is `pending-6.12`, `git describe`
`p-6.12-3-gc504cf0baa3d8`, `make kernelversion` **6.12.111**.
Candidate is **not** an ancestor of HEAD. Buggy SET/GET code is
present (`smb2_set_ea` at 2392, `smb2_get_ea` at 4758).
`smb2_is_private_ea` is absent.
**Step 6.2**
- Record: `git apply --check` of `4ea46ea602fc` succeeded (hunks at
2379, 2436, 4852; offsets only). Clean apply.
**Step 6.3**
- Record: No alternate fix. GET still uses case-sensitive
STREAM/DOSATTRIB skips and does not filter NTACL.
## Phase 7: Subsystem
**Step 7.1**
- Record: `fs/smb/server` (ksmbd). Criticality: IMPORTANT — network file
server, optional (`CONFIG_SMB_SERVER` default n), but a common stable
attack/integrity surface.
**Step 7.2**
- Record: Actively maintained. This bug is old (original EA code), not a
7.3-only feature.
## Phase 8: Impact and risk
**Step 8.1**
- Record: ksmbd users only (NAS, appliances, distro ksmbd). Not
universal.
**Step 8.2**
- Record: Trigger: SMB2 SET_INFO FULL_EA or CREATE with EA context using
reserved names. Common for any client that can write EAs. Unprivileged
local processes cannot hit it unless they are SMB clients; an
authenticated SMB user can.
**Step 8.3**
- Record: Failure mode: overwrite `user.DOSATTRIB` (hidden/system/create
time) and `user.DosStream.*` (stream data); expose or plant
`user.NTACL`. Severity: **HIGH** (metadata/stream integrity and
reserved-name ACL confusion). Not a kernel oops. Default ksmbd ACL
store is `security.NTACL`, so SET EA `NTACL` does not overwrite the
SD; DOSATTRIB/streams are the real same-namespace collisions.
**Step 8.4**
- Record: Benefit high for ksmbd hosts. Risk very low (~20-line filter,
no locking/API change). Ratio favors backport.
## Phase 9: Synthesis
**Step 9.1 — Evidence**
FOR:
- Real reserved-name hole on a network server: SET can write
`user.DOSATTRIB` and `user.DosStream.*`.
- GET can leak `user.NTACL` if that xattr exists.
- Matches Samba’s long-standing hide/reject of those names; smbtorture
`smb2.ea.acl_xattr` expects ACCESS_DENIED.
- Small, maintainer-authored, in v7.3-rc1 with no revert.
- Applies cleanly to this 6.12 tree; macros and callers exist.
- `-EACCES` already maps to `STATUS_ACCESS_DENIED`.
AGAINST:
- Not a crash/UAF.
- NTACL SD lives in `security.*`, so this is not a direct ACL overwrite
on default ksmbd.
- Commit message is partly a test fix.
- Lore review UNVERIFIED.
UNRESOLVED:
- Original lore thread / reviewer stable nomination (lore blocked).
**Step 9.2 — Stable rules**
1. Obviously correct and tested? **PASS** (applies cleanly; smbtorture
named; maintainer).
2. Real user-visible bug? **PASS** (EA write/list of private metadata).
3. Important (crash/security/corruption/deadlock)? **PASS** (HIGH:
metadata/stream integrity on an SMB server; security-boundary).
4. Small and contained? **PASS** (+22/-6, one file).
5. No new features/APIs? **PASS** (reject/filter only).
6. Applies to this tree? **PASS** (`git apply --check` succeeded).
**Step 9.3 — Exceptions**
- Record: Not a device-ID/quirk/DT/build/docs exception. Qualifies as a
normal security/integrity bug fix.
**Step 9.4 — Decision**
Backport to this 6.12 tree. The important part is not the Samba test
name; it is that authenticated clients can currently smash DOS attribute
and named-stream xattrs that ksmbd treats as private.
---
### What this solves for 6.12 users
ksmbd maps SMB EAs to `user.*`. It stores DOS attributes in
`user.DOSATTRIB` and streams in `user.DosStream.*`. `smb2_set_ea()` does
not reject those names, so a client with `FILE_WRITE_EA` can overwrite
that metadata. Query already hid some of those names, but not `NTACL`
and not case variants. The patch closes SET and GET.
### Stable-rules / risk
Meets all six criteria. Benefit is integrity of ksmbd private xattrs;
risk is a tight ACCESS_DENIED on reserved names that Samba has treated
as private for years.
### Verification
- [Phase 1] Parsed message/tags on `4ea46ea602fc`; only author SOB; no
Fixes/Link.
- [Phase 2] Full `git show 4ea46ea602fc` diff: helper + SET `-EACCES` +
GET filter.
- [Phase 2] Confirmed `-EACCES` → `STATUS_ACCESS_DENIED` at
`smb2_set_info` err_out (~6761) and CREATE err_out (~3812).
- [Phase 2] Confirmed `XATTR_NAME_DOS_ATTRIBUTE` = `user.`+`DOSATTRIB`,
`XATTR_NAME_STREAM` = `user.`+`DosStream.`, `XATTR_NAME_SD` =
`security.`+`NTACL` in `xattr.h`.
- [Phase 3] `git blame` SET/GET: `e2f34481b24db` (2021); ancestor of
HEAD.
- [Phase 3] `git merge-base --is-ancestor 4ea46ea602fc HEAD` → no (not
in 6.12).
- [Phase 4] `b4 dig -c 4ea46ea602fc` → lore error. UNVERIFIED mailing-
list discussion.
- [Phase 4] Samba `torture_smb2_acl_xattr` expects SET ACCESS_DENIED and
no list leak.
- [Phase 4] Merge `61a09cfc12147` mentions smbtorture protocol fixes /
security hardening.
- [Phase 4] `smb2_is_private_ea` still in v7.3-rc1; no revert.
- [Phase 5] Callers: CREATE EA context, SET_INFO FULL_EA, QUERY_INFO EA.
- [Phase 6] `git describe HEAD` = `p-6.12-3-gc504cf0baa3d8`;
kernelversion 6.12.111.
- [Phase 6] `git apply --check` of the commit succeeded with line
offsets only.
- [Phase 8] Same-namespace overwrite of DOSATTRIB/streams verified in
`vfs.c` / `smb2_update_xattrs`.
- UNVERIFIED: lore reviewers, CVE assignment, whether any distro already
carries a different backport.
**YES**
fs/smb/server/smb2pdu.c | 28 ++++++++++++++++++++++------
1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index e73edf006df72..4f8e2a6307602 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -2378,6 +2378,22 @@ static noinline int create_smb2_pipe(struct ksmbd_work *work)
return err;
}
+static bool smb2_is_private_ea(const char *name, size_t name_len)
+{
+ if (name_len == SD_PREFIX_LEN &&
+ !strncasecmp(name, SD_PREFIX, SD_PREFIX_LEN))
+ return true;
+ if (name_len == DOS_ATTRIBUTE_PREFIX_LEN &&
+ !strncasecmp(name, DOS_ATTRIBUTE_PREFIX,
+ DOS_ATTRIBUTE_PREFIX_LEN))
+ return true;
+ if (name_len >= STREAM_PREFIX_LEN &&
+ !strncasecmp(name, STREAM_PREFIX, STREAM_PREFIX_LEN))
+ return true;
+
+ return false;
+}
+
/**
* smb2_set_ea() - handler for setting extended attributes using set
* info command
@@ -2419,6 +2435,10 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
rc = -EINVAL;
break;
}
+ if (smb2_is_private_ea(eabuf->name, eabuf->EaNameLength)) {
+ rc = -EACCES;
+ break;
+ }
memcpy(attr_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
memcpy(&attr_name[XATTR_USER_PREFIX_LEN], eabuf->name,
@@ -4828,17 +4848,13 @@ static int smb2_get_ea(struct ksmbd_work *work, struct ksmbd_file *fp,
if (strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
continue;
- if (!strncmp(&name[XATTR_USER_PREFIX_LEN], STREAM_PREFIX,
- STREAM_PREFIX_LEN))
- continue;
-
if (req->InputBufferLength &&
strncmp(&name[XATTR_USER_PREFIX_LEN], ea_req->name,
ea_req->EaNameLength))
continue;
- if (!strncmp(&name[XATTR_USER_PREFIX_LEN],
- DOS_ATTRIBUTE_PREFIX, DOS_ATTRIBUTE_PREFIX_LEN))
+ if (smb2_is_private_ea(&name[XATTR_USER_PREFIX_LEN],
+ name_len - XATTR_USER_PREFIX_LEN))
continue;
if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
--
2.53.0
next prev parent reply other threads:[~2026-10-19 13:59 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <20261019135441.1420968-1-sashal@kernel.org>
2026-10-19 13:45 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: skip fallocate for SMB2_CREATE_ALLOCATION_SIZE on a stream handle Sasha Levin
2026-10-19 13:45 ` [PATCH AUTOSEL 6.18-6.12] ksmbd: fix off-by-one rejecting minimal COPYCHUNK query-limits request Sasha Levin
2026-10-19 13:46 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: handle empty QUERY_ALLOCATED_RANGES output Sasha Levin
2026-10-19 13:46 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: notify parent directory leases on child create Sasha Levin
2026-10-19 13:46 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: handle allocated range queries on dense files Sasha Levin
2026-10-19 13:47 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: report actual xattr value length in stream enumeration Sasha Levin
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] smb/server: cancel async requests when closing connection Sasha Levin
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: allow FSCTL_SET_SPARSE without input buffer Sasha Levin
2026-10-19 13:48 ` Sasha Levin [this message]
2026-10-19 13:48 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: allow I/O on directory named streams Sasha Levin
2026-10-19 13:49 ` [PATCH AUTOSEL 6.18-5.15] smb: server: Free session data in user_session.c with kfree_sensitive() Sasha Levin
2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: return buffer too small for short security queries Sasha Levin
2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: honor client signing-required in all modes Sasha Levin
2026-10-19 13:50 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: preserve access denied status for copychunk Sasha Levin
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: fix heap out-of-bounds write in krb5_authenticate() Sasha Levin
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.6] smb: server: Make sure that passkey is not leaked on the heap in user_config.c Sasha Levin
2026-10-19 13:51 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: honor byte-range locks for zero data Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: reject blocking compound lock requests Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.12] ksmbd: reject SMB3.1.1 binding with mismatched cipher Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.1] ksmbd: fix AsyncId zeroed before use in smb2_lock() cancel response Sasha Levin
2026-10-19 13:52 ` [PATCH AUTOSEL 6.18-6.6] ksmbd: fix durable handle v2 default timeout units (60 -> 60000) Sasha Levin
2026-10-19 13:53 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: enable TCP keepalive for accepted connections Sasha Levin
2026-10-19 13:53 ` [PATCH AUTOSEL 6.18-5.15] ksmbd: fix SMB2 byte-range lock end offset Sasha Levin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261019135441.1420968-209-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=linkinjeon@kernel.org \
--cc=linux-cifs@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=patches@lists.linux.dev \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox