* FAILED: patch "[PATCH] ksmbd: use the existing xattr name for a named stream" failed to apply to 6.18-stable tree
@ 2026-11-03 10:21 gregkh
2026-11-03 19:48 ` [PATCH 6.18.y] ksmbd: use the existing xattr name for a named stream Sasha Levin
0 siblings, 1 reply; 2+ messages in thread
From: gregkh @ 2026-11-03 10:21 UTC (permalink / raw)
To: charsyam, linkinjeon; +Cc: stable
The patch below does not apply to the 6.18-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.18.y
git checkout FETCH_HEAD
git cherry-pick -x a7d1d52748e0fe4d06fdb871fc9899904fbba93f
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026110358-jaywalker-relapse-2135@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From a7d1d52748e0fe4d06fdb871fc9899904fbba93f Mon Sep 17 00:00:00 2001
From: DaeMyung Kang <charsyam@gmail.com>
Date: Fri, 9 Oct 2026 00:25:36 +0900
Subject: [PATCH] ksmbd: use the existing xattr name for a named stream
SMB stream names are case-insensitive, but ksmbd stores each named
stream in an xattr whose name is case-sensitive. Opening an existing
stream finds its xattr with a case-insensitive match, yet the handle
keeps the name as the client spelled it, and every later operation that
needs an exact name uses that spelling:
- a WRITE or an end-of-file change creates a second xattr, so a stream
created as "Foo" and written through "foo" ends up stored twice, and
which value a later lookup returns depends on xattr list order;
- delete-on-close and delete-pending removal can fail with -ENODATA,
or remove only a case-variant copy and leave the original;
- the share mode check compares stream names with strcmp(), so two
opens of the same stream that differ only in case do not conflict.
Have ksmbd_vfs_casexattr_len() copy the matching xattr's name into the
handle when the stream is opened, so later operations use the name
already on disk. The match must have the same length as the name it
replaces; the stream lookup passes a length that includes the
terminating NUL, which already guarantees that, and the check makes the
copy safe for any caller. A stream that does not exist yet keeps the
client's spelling, as before.
smb2_rename() compares and looks up fp->stream.name case-insensitively,
so it behaves the same with either spelling.
Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Cc: stable@vger.kernel.org
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 0154c0deaf8b..79b0a9aee860 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -3341,7 +3341,7 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
path->dentry,
attr_name,
XATTR_USER_PREFIX_LEN +
- eabuf->EaNameLength);
+ eabuf->EaNameLength, NULL);
/* delete the EA only when it exits */
if (rc > 0) {
@@ -3413,11 +3413,11 @@ static noinline int smb2_set_stream_name_xattr(const struct path *path,
fp->stream.name = xattr_stream_name;
fp->stream.size = xattr_stream_size;
- /* Check if there is stream prefix in xattr space */
+ /* Keep the existing xattr's case for subsequent writes and removal. */
rc = ksmbd_vfs_casexattr_len(idmap,
path->dentry,
xattr_stream_name,
- xattr_stream_size);
+ xattr_stream_size, xattr_stream_name);
if (rc >= 0)
return 0;
@@ -3469,7 +3469,7 @@ static loff_t ksmbd_stream_eof(struct ksmbd_file *fp)
ssize_t slen = ksmbd_vfs_casexattr_len(file_mnt_idmap(fp->filp),
fp->filp->f_path.dentry,
fp->stream.name,
- fp->stream.size);
+ fp->stream.size, NULL);
return slen < 0 ? 0 : (loff_t)slen;
}
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index 02ee73d8d631..eb0212e9a5f4 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -1956,7 +1956,7 @@ int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work,
ssize_t ksmbd_vfs_casexattr_len(const struct mnt_idmap *idmap,
struct dentry *dentry, char *attr_name,
- int attr_name_len)
+ int attr_name_len, char *actual_name)
{
char *name, *xattr_list = NULL;
ssize_t value_len = -ENOENT, xattr_list_len;
@@ -1970,8 +1970,13 @@ ssize_t ksmbd_vfs_casexattr_len(const struct mnt_idmap *idmap,
ksmbd_debug(VFS, "%s, len %zd\n", name, strlen(name));
if (strncasecmp(attr_name, name, attr_name_len))
continue;
+ if (actual_name && strlen(name) + 1 != attr_name_len)
+ continue;
value_len = ksmbd_vfs_xattr_len(idmap, dentry, name);
+ /* The caller provides attr_name_len bytes for the actual name. */
+ if (value_len >= 0 && actual_name)
+ memcpy(actual_name, name, attr_name_len);
break;
}
@@ -2126,7 +2131,7 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work,
src_file_size = ksmbd_vfs_casexattr_len(
file_mnt_idmap(src_fp->filp),
src_fp->filp->f_path.dentry,
- src_fp->stream.name, src_fp->stream.size);
+ src_fp->stream.name, src_fp->stream.size, NULL);
revert_creds(saved_cred);
if (src_file_size < 0)
return src_file_size;
diff --git a/fs/smb/server/vfs.h b/fs/smb/server/vfs.h
index 7e545d13a3ff..21b0d29a3db0 100644
--- a/fs/smb/server/vfs.h
+++ b/fs/smb/server/vfs.h
@@ -116,7 +116,7 @@ ssize_t ksmbd_vfs_getcasexattr(const struct mnt_idmap *idmap,
int attr_name_len, char **attr_value);
ssize_t ksmbd_vfs_casexattr_len(const struct mnt_idmap *idmap,
struct dentry *dentry, char *attr_name,
- int attr_name_len);
+ int attr_name_len, char *actual_name);
int ksmbd_vfs_setxattr(const struct mnt_idmap *idmap,
const struct path *path, const char *attr_name,
void *attr_value, size_t attr_size, int flags,
^ permalink raw reply related [flat|nested] 2+ messages in thread* [PATCH 6.18.y] ksmbd: use the existing xattr name for a named stream
2026-11-03 10:21 FAILED: patch "[PATCH] ksmbd: use the existing xattr name for a named stream" failed to apply to 6.18-stable tree gregkh
@ 2026-11-03 19:48 ` Sasha Levin
0 siblings, 0 replies; 2+ messages in thread
From: Sasha Levin @ 2026-11-03 19:48 UTC (permalink / raw)
To: stable; +Cc: DaeMyung Kang, Namjae Jeon, Sasha Levin
From: DaeMyung Kang <charsyam@gmail.com>
[ Upstream commit a7d1d52748e0fe4d06fdb871fc9899904fbba93f ]
SMB stream names are case-insensitive, but ksmbd stores each named
stream in an xattr whose name is case-sensitive. Opening an existing
stream finds its xattr with a case-insensitive match, yet the handle
keeps the name as the client spelled it, and every later operation that
needs an exact name uses that spelling:
- a WRITE or an end-of-file change creates a second xattr, so a stream
created as "Foo" and written through "foo" ends up stored twice, and
which value a later lookup returns depends on xattr list order;
- delete-on-close and delete-pending removal can fail with -ENODATA,
or remove only a case-variant copy and leave the original;
- the share mode check compares stream names with strcmp(), so two
opens of the same stream that differ only in case do not conflict.
Have ksmbd_vfs_casexattr_len() copy the matching xattr's name into the
handle when the stream is opened, so later operations use the name
already on disk. The match must have the same length as the name it
replaces; the stream lookup passes a length that includes the
terminating NUL, which already guarantees that, and the check makes the
copy safe for any caller. A stream that does not exist yet keeps the
client's spelling, as before.
smb2_rename() compares and looks up fp->stream.name case-insensitively,
so it behaves the same with either spelling.
Fixes: e2f34481b24d ("cifsd: add server-side procedures for SMB3")
Cc: stable@vger.kernel.org
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
[ sashal: adapted stream lookup signature changes to the existing callers and non-const mnt_idmap interface ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/smb/server/smb2pdu.c | 8 ++++----
fs/smb/server/vfs.c | 7 ++++++-
fs/smb/server/vfs.h | 2 +-
3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 793c219b9a610..9af1ef5a13d6a 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -2464,7 +2464,7 @@ static int smb2_set_ea(struct smb2_ea_info *eabuf, unsigned int buf_len,
path->dentry,
attr_name,
XATTR_USER_PREFIX_LEN +
- eabuf->EaNameLength);
+ eabuf->EaNameLength, NULL);
/* delete the EA only when it exits */
if (rc > 0) {
@@ -2536,11 +2536,11 @@ static noinline int smb2_set_stream_name_xattr(const struct path *path,
fp->stream.name = xattr_stream_name;
fp->stream.size = xattr_stream_size;
- /* Check if there is stream prefix in xattr space */
+ /* Keep the existing xattr's case for subsequent writes and removal. */
rc = ksmbd_vfs_casexattr_len(idmap,
path->dentry,
xattr_stream_name,
- xattr_stream_size);
+ xattr_stream_size, xattr_stream_name);
if (rc >= 0)
return 0;
if (rc != -ENOENT && rc != -ENODATA)
@@ -5243,7 +5243,7 @@ static int get_file_stream_info(struct ksmbd_work *work,
*/
slen = ksmbd_vfs_casexattr_len(file_mnt_idmap(fp->filp),
path->dentry, stream_name,
- strlen(stream_name) + 1);
+ strlen(stream_name) + 1, NULL);
ssize = slen < 0 ? 0 : (loff_t)slen;
file_info->StreamSize = cpu_to_le64(ssize);
file_info->StreamAllocationSize = cpu_to_le64(ssize);
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index c18ab8431e0d2..b23179a7b780c 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -1812,7 +1812,7 @@ int ksmbd_vfs_fill_dentry_attrs(struct ksmbd_work *work,
ssize_t ksmbd_vfs_casexattr_len(struct mnt_idmap *idmap,
struct dentry *dentry, char *attr_name,
- int attr_name_len)
+ int attr_name_len, char *actual_name)
{
char *name, *xattr_list = NULL;
ssize_t value_len = -ENOENT, xattr_list_len;
@@ -1830,8 +1830,13 @@ ssize_t ksmbd_vfs_casexattr_len(struct mnt_idmap *idmap,
ksmbd_debug(VFS, "%s, len %zd\n", name, strlen(name));
if (strncasecmp(attr_name, name, attr_name_len))
continue;
+ if (actual_name && strlen(name) + 1 != attr_name_len)
+ continue;
value_len = ksmbd_vfs_xattr_len(idmap, dentry, name);
+ /* The caller provides attr_name_len bytes for the actual name. */
+ if (value_len >= 0 && actual_name)
+ memcpy(actual_name, name, attr_name_len);
break;
}
diff --git a/fs/smb/server/vfs.h b/fs/smb/server/vfs.h
index df6421b4590ba..ccf289592718c 100644
--- a/fs/smb/server/vfs.h
+++ b/fs/smb/server/vfs.h
@@ -107,7 +107,7 @@ ssize_t ksmbd_vfs_getxattr(struct mnt_idmap *idmap,
char **xattr_buf);
ssize_t ksmbd_vfs_casexattr_len(struct mnt_idmap *idmap,
struct dentry *dentry, char *attr_name,
- int attr_name_len);
+ int attr_name_len, char *actual_name);
int ksmbd_vfs_setxattr(struct mnt_idmap *idmap,
const struct path *path, const char *attr_name,
void *attr_value, size_t attr_size, int flags,
--
2.53.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-03 19:48 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-03 10:21 FAILED: patch "[PATCH] ksmbd: use the existing xattr name for a named stream" failed to apply to 6.18-stable tree gregkh
2026-11-03 19:48 ` [PATCH 6.18.y] ksmbd: use the existing xattr name for a named stream Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox