summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNamjae Jeon <linkinjeon@kernel.org>2026-06-13 22:00:03 +0900
committerSteve French <stfrench@microsoft.com>2026-06-16 18:57:22 -0500
commitbaa5e094886fffa7e6272edcb5e08be5ce28262c (patch)
tree62123f637087a4c919f74153ef688b10e592c9c2
parentcedff600f1642aa982178503552f0d007bc829c8 (diff)
ksmbd: use opener credentials for ADS I/O
Alternate data streams are stored as xattrs. Unlike regular file I/O, their read and write paths therefore call VFS xattr helpers which recheck inode permissions and LSM policy using the current task credentials. Run ADS I/O with the credentials captured when the SMB handle was opened. Cc: stable@vger.kernel.org Reported-by: Musaab Khan <musaab.khan@protonmail.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Steve French <stfrench@microsoft.com>
-rw-r--r--fs/smb/server/vfs.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c
index c002cc4b1c02..04a4bd0f492b 100644
--- a/fs/smb/server/vfs.c
+++ b/fs/smb/server/vfs.c
@@ -248,17 +248,20 @@ out:
static int ksmbd_vfs_stream_read(struct ksmbd_file *fp, char *buf, loff_t *pos,
size_t count)
{
+ const struct cred *saved_cred;
ssize_t v_len;
char *stream_buf = NULL;
ksmbd_debug(VFS, "read stream data pos : %llu, count : %zd\n",
*pos, count);
+ saved_cred = override_creds(fp->filp->f_cred);
v_len = ksmbd_vfs_getcasexattr(file_mnt_idmap(fp->filp),
fp->filp->f_path.dentry,
fp->stream.name,
fp->stream.size,
&stream_buf);
+ revert_creds(saved_cred);
if ((int)v_len <= 0)
return (int)v_len;
@@ -382,6 +385,7 @@ int ksmbd_vfs_read(struct ksmbd_work *work, struct ksmbd_file *fp, size_t count,
static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,
size_t count)
{
+ const struct cred *saved_cred;
char *stream_buf = NULL, *wbuf;
struct mnt_idmap *idmap = file_mnt_idmap(fp->filp);
size_t size;
@@ -402,6 +406,7 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,
count = XATTR_SIZE_MAX - *pos;
}
+ saved_cred = override_creds(fp->filp->f_cred);
v_len = ksmbd_vfs_getcasexattr(idmap,
fp->filp->f_path.dentry,
fp->stream.name,
@@ -410,14 +415,14 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,
if (v_len < 0) {
pr_err("not found stream in xattr : %zd\n", v_len);
err = v_len;
- goto out;
+ goto out_revert;
}
if (v_len < size) {
wbuf = kvzalloc(size, KSMBD_DEFAULT_GFP);
if (!wbuf) {
err = -ENOMEM;
- goto out;
+ goto out_revert;
}
if (v_len > 0)
@@ -435,6 +440,8 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,
size,
0,
true);
+out_revert:
+ revert_creds(saved_cred);
if (err < 0)
goto out;
else