]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ksmbd: use opener credentials for ADS I/O
authorNamjae Jeon <linkinjeon@kernel.org>
Sat, 13 Jun 2026 13:00:03 +0000 (22:00 +0900)
committerSteve French <stfrench@microsoft.com>
Tue, 16 Jun 2026 23:57:22 +0000 (18:57 -0500)
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>
fs/smb/server/vfs.c

index c002cc4b1c026a7aac3a22685a9862464f9936c0..04a4bd0f492b1b293e5dd23b8cd254261d410274 100644 (file)
@@ -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