]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ksmbd: use opener credentials for FSCTL mutations
authorNamjae Jeon <linkinjeon@kernel.org>
Sat, 13 Jun 2026 13:00:04 +0000 (22:00 +0900)
committerSteve French <stfrench@microsoft.com>
Tue, 16 Jun 2026 23:57:22 +0000 (18:57 -0500)
SET_SPARSE, SET_ZERO_DATA and SET_COMPRESSION operate on an open SMB
handle but call VFS xattr, fallocate or fileattr helpers with the current
ksmbd worker credentials. Those helpers can revalidate inode permissions,
ownership and LSM policy independently of the SMB handle access mask.

Run each operation with the credentials captured in the target file when
the handle was opened. Keep credential handling local to these single-file
FSCTLs rather than applying session credentials to the complete IOCTL
handler, which also contains handle-less and multi-handle operations.

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/smb2pdu.c
fs/smb/server/vfs.c

index fcb1bcd5de95d2eb04f65276e3ad13efe003d3e7..c1c6c1a64f600e393bda4ae95bb483576197dbaf 100644 (file)
@@ -8387,6 +8387,7 @@ static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id,
        if (fp->f_ci->m_fattr != old_fattr &&
            test_share_config_flag(work->tcon->share_conf,
                                   KSMBD_SHARE_FLAG_STORE_DOS_ATTRS)) {
+               const struct cred *saved_cred;
                struct xattr_dos_attrib da;
 
                ret = ksmbd_vfs_get_dos_attrib_xattr(idmap,
@@ -8395,9 +8396,11 @@ static inline int fsctl_set_sparse(struct ksmbd_work *work, u64 id,
                        goto out;
 
                da.attr = le32_to_cpu(fp->f_ci->m_fattr);
+               saved_cred = override_creds(fp->filp->f_cred);
                ret = ksmbd_vfs_set_dos_attrib_xattr(idmap,
                                                     &fp->filp->f_path,
                                                     &da, true);
+               revert_creds(saved_cred);
                if (ret)
                        fp->f_ci->m_fattr = old_fattr;
        }
index 04a4bd0f492b1b293e5dd23b8cd254261d410274..fe376453a51986ab69e1b5fbe80ff403bba56bdf 100644 (file)
@@ -918,15 +918,21 @@ void ksmbd_vfs_set_fadvise(struct file *filp, __le32 option)
 int ksmbd_vfs_zero_data(struct ksmbd_work *work, struct ksmbd_file *fp,
                        loff_t off, loff_t len)
 {
+       const struct cred *saved_cred;
+       int err;
+
        smb_break_all_levII_oplock(work, fp, 1);
+       saved_cred = override_creds(fp->filp->f_cred);
        if (fp->f_ci->m_fattr & FILE_ATTRIBUTE_SPARSE_FILE_LE)
-               return vfs_fallocate(fp->filp,
-                                    FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
-                                    off, len);
-
-       return vfs_fallocate(fp->filp,
-                            FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE,
-                            off, len);
+               err = vfs_fallocate(fp->filp,
+                                   FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+                                   off, len);
+       else
+               err = vfs_fallocate(fp->filp,
+                                   FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE,
+                                   off, len);
+       revert_creds(saved_cred);
+       return err;
 }
 
 int ksmbd_vfs_fqar_lseek(struct ksmbd_file *fp, loff_t start, loff_t length,
@@ -1935,6 +1941,7 @@ out:
 
 int ksmbd_vfs_set_compression(struct ksmbd_work *work, struct ksmbd_file *fp, u16 fmt)
 {
+       const struct cred *saved_cred = NULL;
        struct file_kattr fa;
        struct dentry *dentry = fp->filp->f_path.dentry;
        struct mnt_idmap *idmap = file_mnt_idmap(fp->filp);
@@ -1947,6 +1954,7 @@ int ksmbd_vfs_set_compression(struct ksmbd_work *work, struct ksmbd_file *fp, u1
                goto out;
        }
 
+       saved_cred = override_creds(fp->filp->f_cred);
        rc = vfs_fileattr_get(dentry, &fa);
        if (rc)
                goto out;
@@ -2000,5 +2008,7 @@ int ksmbd_vfs_set_compression(struct ksmbd_work *work, struct ksmbd_file *fp, u1
        }
 
 out:
+       if (saved_cred)
+               revert_creds(saved_cred);
        return rc;
 }