Thread (33 messages) 33 messages, 9 authors, 12d ago

Re: [PATCH RFC -next 03/12] fs: pass struct path to xattr helpers

flat view

From: Amir Goldstein <amir73il@gmail.com>
Date: 2026-09-24 11:12:58
Also in: driver-core, linux-block, linux-cifs, linux-doc, linux-fsdevel, linux-integrity, linux-kselftest, linux-nfs, linux-unionfs, lkml, netfs, selinux

On Thu, Sep 24, 2026 at 12:22 PM Cai Xinchen [off-list ref] wrote:
vfs_setxattr(), vfs_getxattr(), vfs_listxattr() and vfs_removexattr()
along with their __vfs_setxattr_locked()/__vfs_removexattr_locked()
counterparts and the do_setxattr()/do_getxattr()/listxattr()/
removexattr() syscall helpers take a struct mnt_idmap and a struct
dentry even though callers either already hold a struct path (or a
struct file) or have to pass &nop_mnt_idmap because no idmapped
mount is involved.  Switch them all to take a struct path instead
and derive the idmap and dentry from it where needed.

__vfs_setxattr_noperm(), __vfs_getxattr(), __vfs_setxattr(),
__vfs_removexattr() and vfs_getxattr_alloc() keep taking the idmap
and dentry as they are only called from contexts that operate on
bare dentries such as LSM internals.  The SELinux and Smack
inode_setsecctx implementations now pass the path they got from the
previous patch straight through.

The security_inode_*xattr() hooks invoked from fs/xattr.c keep
taking the idmap and dentry for now; they will be converted together
with the LSM hooks themselves in separate patches.

evm_calc_hmac_or_hash() contains a redundant xattr size sanity check
which calls vfs_getxattr() only to emit a debug message when the
kernel-side and user-space-side xattr sizes differ, without ever
influencing the result.  Because that function only has a dentry, the
call cannot be migrated to the new path-based signature; drop the
check and the now unused user_space_size variable instead.

Assisted-by: opencode: glm-5.3
Signed-off-by: Cai Xinchen <redacted>
---
 drivers/block/zloop.c               |   4 +-
 fs/cachefiles/xattr.c               |  32 ++++----
 fs/ecryptfs/inode.c                 |   8 +-
 fs/nfsd/nfs4ctl.h                   |   4 +-
 fs/nfsd/vfs.c                       |  57 +++++++-------
 fs/overlayfs/copy_up.c              |   4 +-
 fs/overlayfs/overlayfs.h            |  18 +++--
 fs/overlayfs/xattrs.c               |  13 +++-
 fs/smb/server/smb2pdu.c             |  75 +++++++------------
 fs/smb/server/smb_common.c          |   2 -
 fs/smb/server/smbacl.c              |  19 +++--
 fs/smb/server/tests/smbacl_kunit.c  |   6 +-
 fs/smb/server/vfs.c                 | 112 ++++++++++++----------------
 fs/smb/server/vfs.h                 |  39 ++++------
 fs/smb/server/vfs_cache.c           |   3 +-
 fs/xattr.c                          |  92 ++++++++++++-----------
 include/linux/xattr.h               |  22 +++---
 security/integrity/evm/evm_crypto.c |   8 +-
 security/selinux/hooks.c            |   4 +-
 security/smack/smack_lsm.c          |   4 +-
 20 files changed, 243 insertions(+), 283 deletions(-)
[...]
quoted hunk ↗ jump to hunk
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index e963701b4c87..6dc241f195a6 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -83,7 +83,7 @@ int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct de
        if (!old->d_inode->i_op->listxattr || !new->d_inode->i_op->listxattr)
                return 0;

-       list_size = vfs_listxattr(old, NULL, 0);
+       list_size = vfs_listxattr(oldpath, NULL, 0);
        if (list_size <= 0) {
                if (list_size == -EOPNOTSUPP)
                        return 0;
@@ -94,7 +94,7 @@ int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct de
        if (!buf)
                return -ENOMEM;

-       list_size = vfs_listxattr(old, buf, list_size);
+       list_size = vfs_listxattr(oldpath, buf, list_size);
        if (list_size <= 0) {
                error = list_size;
                goto out;
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index d915b87c0b06..c13f6b2c915c 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -291,8 +291,7 @@ static inline ssize_t ovl_do_getxattr(const struct path *path, const char *name,

        WARN_ON(path->dentry->d_sb != path->mnt->mnt_sb);

-       err = vfs_getxattr(mnt_idmap(path->mnt), path->dentry,
-                              name, value, size);
+       err = vfs_getxattr(path, name, value, size);
        len = (value && err > 0) ? err : 0;

        pr_debug("getxattr(%pd2, \"%s\", \"%*pE\", %zu, 0) = %i\n",
@@ -325,9 +324,13 @@ static inline int ovl_do_setxattr(struct ovl_fs *ofs, struct dentry *dentry,
                                  const char *name, const void *value,
                                  size_t size, int flags)
 {
+       struct path path = {
+               .mnt = ovl_upper_mnt(ofs),
+               .dentry = dentry,
+       };
+
        /* Use vfs_setxattr(), not __vfs_setxattr(): it idmaps the security.capability rootid. */
-       int err = vfs_setxattr(ovl_upper_mnt_idmap(ofs), dentry, name,
-                              value, size, flags);
+       int err = vfs_setxattr(&path, name, value, size, flags);

        pr_debug("setxattr(%pd2, \"%s\", \"%*pE\", %zu, %d) = %i\n",
                 dentry, name, min((int)size, 48), value, size, flags, err);
@@ -344,7 +347,12 @@ static inline int ovl_setxattr(struct ovl_fs *ofs, struct dentry *dentry,
 static inline int ovl_do_removexattr(struct ovl_fs *ofs, struct dentry *dentry,
                                     const char *name)
 {
-       int err = vfs_removexattr(ovl_upper_mnt_idmap(ofs), dentry, name);
+       struct path path = {
+               .mnt = ovl_upper_mnt(ofs),
+               .dentry = dentry,
+       };
+
+       int err = vfs_removexattr(&path, name);
        pr_debug("removexattr(%pd2, \"%s\") = %i\n", dentry, name, err);
        return err;
 }
diff --git a/fs/overlayfs/xattrs.c b/fs/overlayfs/xattrs.c
index 5ae44b9c8790..b4658324b9f3 100644
--- a/fs/overlayfs/xattrs.c
+++ b/fs/overlayfs/xattrs.c
@@ -45,7 +45,7 @@ static int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char
        if (!value && !upperdentry) {
                ovl_path_lower(dentry, &realpath);
                with_ovl_creds(dentry->d_sb)
-                       err = vfs_getxattr(mnt_idmap(realpath.mnt), realdentry, name, NULL, 0);
+                       err = vfs_getxattr(&realpath, name, NULL, 0);
                if (err < 0)
                        goto out;
        }
@@ -86,7 +86,7 @@ static int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char
        ovl_i_path_real(inode, &realpath);
        /* Use vfs_getxattr(), not __vfs_getxattr(): it idmaps the security.capability rootid. */
        with_ovl_creds(dentry->d_sb)
-               return vfs_getxattr(mnt_idmap(realpath.mnt), realpath.dentry, name, value, size);
+               return vfs_getxattr(&realpath, name, value, size);
 }

 static bool ovl_can_list(struct super_block *sb, const char *s)
@@ -105,15 +105,20 @@ static bool ovl_can_list(struct super_block *sb, const char *s)

 ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
 {
-       struct dentry *realdentry = ovl_dentry_real(dentry);
+       struct path realpath;
        struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
        ssize_t res;
        size_t len;
        char *s;
        size_t prefix_len, name_len;

+       if (ovl_dentry_upper(dentry))
+               ovl_path_upper(dentry, &realpath);
+       else
+               ovl_path_lower(dentry, &realpath);
+
that's ovl_path_real()

I have no technical issue with the ovl patch bits in this series.
Anyway, I guess landlock is not going to enforce anything on the
private mnt with ovl_creds anyway?

Thanks,
Amir.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help