ovl: Move xattr support to new xattrs.c file
authorAmir Goldstein <amir73il@gmail.com>
Tue, 10 Oct 2023 11:17:59 +0000 (14:17 +0300)
committerAmir Goldstein <amir73il@gmail.com>
Mon, 30 Oct 2023 22:12:59 +0000 (00:12 +0200)
This moves the code from super.c and inode.c, and makes ovl_xattr_get/set()
static.

This is in preparation for doing more work on xattrs support.

Signed-off-by: Alexander Larsson <alexl@redhat.com>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
fs/overlayfs/Makefile
fs/overlayfs/inode.c
fs/overlayfs/overlayfs.h
fs/overlayfs/super.c
fs/overlayfs/xattrs.c [new file with mode: 0644]

index 4e173d5..5648954 100644 (file)
@@ -6,4 +6,4 @@
 obj-$(CONFIG_OVERLAY_FS) += overlay.o
 
 overlay-objs := super.o namei.o util.o inode.o file.o dir.o readdir.o \
-               copy_up.o export.o params.o
+               copy_up.o export.o params.o xattrs.o
index 9e9192a..345b8f1 100644 (file)
@@ -339,128 +339,6 @@ static const char *ovl_get_link(struct dentry *dentry,
        return p;
 }
 
-bool ovl_is_private_xattr(struct super_block *sb, const char *name)
-{
-       struct ovl_fs *ofs = OVL_FS(sb);
-
-       if (ofs->config.userxattr)
-               return strncmp(name, OVL_XATTR_USER_PREFIX,
-                              sizeof(OVL_XATTR_USER_PREFIX) - 1) == 0;
-       else
-               return strncmp(name, OVL_XATTR_TRUSTED_PREFIX,
-                              sizeof(OVL_XATTR_TRUSTED_PREFIX) - 1) == 0;
-}
-
-int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
-                 const void *value, size_t size, int flags)
-{
-       int err;
-       struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
-       struct dentry *upperdentry = ovl_i_dentry_upper(inode);
-       struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
-       struct path realpath;
-       const struct cred *old_cred;
-
-       if (!value && !upperdentry) {
-               ovl_path_lower(dentry, &realpath);
-               old_cred = ovl_override_creds(dentry->d_sb);
-               err = vfs_getxattr(mnt_idmap(realpath.mnt), realdentry, name, NULL, 0);
-               revert_creds(old_cred);
-               if (err < 0)
-                       goto out;
-       }
-
-       if (!upperdentry) {
-               err = ovl_copy_up(dentry);
-               if (err)
-                       goto out;
-
-               realdentry = ovl_dentry_upper(dentry);
-       }
-
-       err = ovl_want_write(dentry);
-       if (err)
-               goto out;
-
-       old_cred = ovl_override_creds(dentry->d_sb);
-       if (value) {
-               err = ovl_do_setxattr(ofs, realdentry, name, value, size,
-                                     flags);
-       } else {
-               WARN_ON(flags != XATTR_REPLACE);
-               err = ovl_do_removexattr(ofs, realdentry, name);
-       }
-       revert_creds(old_cred);
-       ovl_drop_write(dentry);
-
-       /* copy c/mtime */
-       ovl_copyattr(inode);
-out:
-       return err;
-}
-
-int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
-                 void *value, size_t size)
-{
-       ssize_t res;
-       const struct cred *old_cred;
-       struct path realpath;
-
-       ovl_i_path_real(inode, &realpath);
-       old_cred = ovl_override_creds(dentry->d_sb);
-       res = vfs_getxattr(mnt_idmap(realpath.mnt), realpath.dentry, name, value, size);
-       revert_creds(old_cred);
-       return res;
-}
-
-static bool ovl_can_list(struct super_block *sb, const char *s)
-{
-       /* Never list private (.overlay) */
-       if (ovl_is_private_xattr(sb, s))
-               return false;
-
-       /* List all non-trusted xattrs */
-       if (strncmp(s, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0)
-               return true;
-
-       /* list other trusted for superuser only */
-       return ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN);
-}
-
-ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
-{
-       struct dentry *realdentry = ovl_dentry_real(dentry);
-       ssize_t res;
-       size_t len;
-       char *s;
-       const struct cred *old_cred;
-
-       old_cred = ovl_override_creds(dentry->d_sb);
-       res = vfs_listxattr(realdentry, list, size);
-       revert_creds(old_cred);
-       if (res <= 0 || size == 0)
-               return res;
-
-       /* filter out private xattrs */
-       for (s = list, len = res; len;) {
-               size_t slen = strnlen(s, len) + 1;
-
-               /* underlying fs providing us with an broken xattr list? */
-               if (WARN_ON(slen > len))
-                       return -EIO;
-
-               len -= slen;
-               if (!ovl_can_list(dentry->d_sb, s)) {
-                       res -= slen;
-                       memmove(s, s + slen, len);
-               } else {
-                       s += slen;
-               }
-       }
-
-       return res;
-}
-
 #ifdef CONFIG_FS_POSIX_ACL
 /*
  * Apply the idmapping of the layer to POSIX ACLs. The caller must pass a clone
index 26e4fc4..59ee6ba 100644 (file)
@@ -699,17 +699,8 @@ int ovl_set_nlink_lower(struct dentry *dentry);
 unsigned int ovl_get_nlink(struct ovl_fs *ofs, struct dentry *lowerdentry,
                           struct dentry *upperdentry,
                           unsigned int fallback);
-int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
-               struct iattr *attr);
-int ovl_getattr(struct mnt_idmap *idmap, const struct path *path,
-               struct kstat *stat, u32 request_mask, unsigned int flags);
 int ovl_permission(struct mnt_idmap *idmap, struct inode *inode,
                   int mask);
-int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
-                 const void *value, size_t size, int flags);
-int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
-                 void *value, size_t size);
-ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
 
 #ifdef CONFIG_FS_POSIX_ACL
 struct posix_acl *do_ovl_get_acl(struct mnt_idmap *idmap,
@@ -846,3 +837,12 @@ static inline bool ovl_force_readonly(struct ovl_fs *ofs)
 {
        return (!ovl_upper_mnt(ofs) || !ofs->workdir);
 }
+
+/* xattr.c */
+
+const struct xattr_handler * const *ovl_xattr_handlers(struct ovl_fs *ofs);
+int ovl_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
+               struct iattr *attr);
+int ovl_getattr(struct mnt_idmap *idmap, const struct path *path,
+               struct kstat *stat, u32 request_mask, unsigned int flags);
+ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size);
index 5476dbf..0a42a25 100644 (file)
@@ -445,68 +445,6 @@ static bool ovl_workdir_ok(struct dentry *workdir, struct dentry *upperdir)
        return ok;
 }
 
-static int ovl_own_xattr_get(const struct xattr_handler *handler,
-                            struct dentry *dentry, struct inode *inode,
-                            const char *name, void *buffer, size_t size)
-{
-       return -EOPNOTSUPP;
-}
-
-static int ovl_own_xattr_set(const struct xattr_handler *handler,
-                            struct mnt_idmap *idmap,
-                            struct dentry *dentry, struct inode *inode,
-                            const char *name, const void *value,
-                            size_t size, int flags)
-{
-       return -EOPNOTSUPP;
-}
-
-static int ovl_other_xattr_get(const struct xattr_handler *handler,
-                              struct dentry *dentry, struct inode *inode,
-                              const char *name, void *buffer, size_t size)
-{
-       return ovl_xattr_get(dentry, inode, name, buffer, size);
-}
-
-static int ovl_other_xattr_set(const struct xattr_handler *handler,
-                              struct mnt_idmap *idmap,
-                              struct dentry *dentry, struct inode *inode,
-                              const char *name, const void *value,
-                              size_t size, int flags)
-{
-       return ovl_xattr_set(dentry, inode, name, value, size, flags);
-}
-
-static const struct xattr_handler ovl_own_trusted_xattr_handler = {
-       .prefix = OVL_XATTR_TRUSTED_PREFIX,
-       .get = ovl_own_xattr_get,
-       .set = ovl_own_xattr_set,
-};
-
-static const struct xattr_handler ovl_own_user_xattr_handler = {
-       .prefix = OVL_XATTR_USER_PREFIX,
-       .get = ovl_own_xattr_get,
-       .set = ovl_own_xattr_set,
-};
-
-static const struct xattr_handler ovl_other_xattr_handler = {
-       .prefix = "", /* catch all */
-       .get = ovl_other_xattr_get,
-       .set = ovl_other_xattr_set,
-};
-
-static const struct xattr_handler * const ovl_trusted_xattr_handlers[] = {
-       &ovl_own_trusted_xattr_handler,
-       &ovl_other_xattr_handler,
-       NULL
-};
-
-static const struct xattr_handler * const ovl_user_xattr_handlers[] = {
-       &ovl_own_user_xattr_handler,
-       &ovl_other_xattr_handler,
-       NULL
-};
-
 static int ovl_setup_trap(struct super_block *sb, struct dentry *dir,
                          struct inode **ptrap, const char *name)
 {
@@ -1501,8 +1439,7 @@ int ovl_fill_super(struct super_block *sb, struct fs_context *fc)
        cap_lower(cred->cap_effective, CAP_SYS_RESOURCE);
 
        sb->s_magic = OVERLAYFS_SUPER_MAGIC;
-       sb->s_xattr = ofs->config.userxattr ? ovl_user_xattr_handlers :
-               ovl_trusted_xattr_handlers;
+       sb->s_xattr = ovl_xattr_handlers(ofs);
        sb->s_fs_info = ofs;
 #ifdef CONFIG_FS_POSIX_ACL
        sb->s_flags |= SB_POSIXACL;
diff --git a/fs/overlayfs/xattrs.c b/fs/overlayfs/xattrs.c
new file mode 100644 (file)
index 0000000..8e7e4ca
--- /dev/null
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/fs.h>
+#include <linux/xattr.h>
+#include "overlayfs.h"
+
+bool ovl_is_private_xattr(struct super_block *sb, const char *name)
+{
+       struct ovl_fs *ofs = OVL_FS(sb);
+
+       if (ofs->config.userxattr)
+               return strncmp(name, OVL_XATTR_USER_PREFIX,
+                              sizeof(OVL_XATTR_USER_PREFIX) - 1) == 0;
+       else
+               return strncmp(name, OVL_XATTR_TRUSTED_PREFIX,
+                              sizeof(OVL_XATTR_TRUSTED_PREFIX) - 1) == 0;
+}
+
+static int ovl_xattr_set(struct dentry *dentry, struct inode *inode, const char *name,
+                        const void *value, size_t size, int flags)
+{
+       int err;
+       struct ovl_fs *ofs = OVL_FS(dentry->d_sb);
+       struct dentry *upperdentry = ovl_i_dentry_upper(inode);
+       struct dentry *realdentry = upperdentry ?: ovl_dentry_lower(dentry);
+       struct path realpath;
+       const struct cred *old_cred;
+
+       if (!value && !upperdentry) {
+               ovl_path_lower(dentry, &realpath);
+               old_cred = ovl_override_creds(dentry->d_sb);
+               err = vfs_getxattr(mnt_idmap(realpath.mnt), realdentry, name, NULL, 0);
+               revert_creds(old_cred);
+               if (err < 0)
+                       goto out;
+       }
+
+       if (!upperdentry) {
+               err = ovl_copy_up(dentry);
+               if (err)
+                       goto out;
+
+               realdentry = ovl_dentry_upper(dentry);
+       }
+
+       err = ovl_want_write(dentry);
+       if (err)
+               goto out;
+
+       old_cred = ovl_override_creds(dentry->d_sb);
+       if (value) {
+               err = ovl_do_setxattr(ofs, realdentry, name, value, size,
+                                     flags);
+       } else {
+               WARN_ON(flags != XATTR_REPLACE);
+               err = ovl_do_removexattr(ofs, realdentry, name);
+       }
+       revert_creds(old_cred);
+       ovl_drop_write(dentry);
+
+       /* copy c/mtime */
+       ovl_copyattr(inode);
+out:
+       return err;
+}
+
+static int ovl_xattr_get(struct dentry *dentry, struct inode *inode, const char *name,
+                        void *value, size_t size)
+{
+       ssize_t res;
+       const struct cred *old_cred;
+       struct path realpath;
+
+       ovl_i_path_real(inode, &realpath);
+       old_cred = ovl_override_creds(dentry->d_sb);
+       res = vfs_getxattr(mnt_idmap(realpath.mnt), realpath.dentry, name, value, size);
+       revert_creds(old_cred);
+       return res;
+}
+
+static bool ovl_can_list(struct super_block *sb, const char *s)
+{
+       /* Never list private (.overlay) */
+       if (ovl_is_private_xattr(sb, s))
+               return false;
+
+       /* List all non-trusted xattrs */
+       if (strncmp(s, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) != 0)
+               return true;
+
+       /* list other trusted for superuser only */
+       return ns_capable_noaudit(&init_user_ns, CAP_SYS_ADMIN);
+}
+
+ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+       struct dentry *realdentry = ovl_dentry_real(dentry);
+       ssize_t res;
+       size_t len;
+       char *s;
+       const struct cred *old_cred;
+
+       old_cred = ovl_override_creds(dentry->d_sb);
+       res = vfs_listxattr(realdentry, list, size);
+       revert_creds(old_cred);
+       if (res <= 0 || size == 0)
+               return res;
+
+       /* filter out private xattrs */
+       for (s = list, len = res; len;) {
+               size_t slen = strnlen(s, len) + 1;
+
+               /* underlying fs providing us with an broken xattr list? */
+               if (WARN_ON(slen > len))
+                       return -EIO;
+
+               len -= slen;
+               if (!ovl_can_list(dentry->d_sb, s)) {
+                       res -= slen;
+                       memmove(s, s + slen, len);
+               } else {
+                       s += slen;
+               }
+       }
+
+       return res;
+}
+
+static int ovl_own_xattr_get(const struct xattr_handler *handler,
+                            struct dentry *dentry, struct inode *inode,
+                            const char *name, void *buffer, size_t size)
+{
+       return -EOPNOTSUPP;
+}
+
+static int ovl_own_xattr_set(const struct xattr_handler *handler,
+                            struct mnt_idmap *idmap,
+                            struct dentry *dentry, struct inode *inode,
+                            const char *name, const void *value,
+                            size_t size, int flags)
+{
+       return -EOPNOTSUPP;
+}
+
+static int ovl_other_xattr_get(const struct xattr_handler *handler,
+                              struct dentry *dentry, struct inode *inode,
+                              const char *name, void *buffer, size_t size)
+{
+       return ovl_xattr_get(dentry, inode, name, buffer, size);
+}
+
+static int ovl_other_xattr_set(const struct xattr_handler *handler,
+                              struct mnt_idmap *idmap,
+                              struct dentry *dentry, struct inode *inode,
+                              const char *name, const void *value,
+                              size_t size, int flags)
+{
+       return ovl_xattr_set(dentry, inode, name, value, size, flags);
+}
+
+static const struct xattr_handler ovl_own_trusted_xattr_handler = {
+       .prefix = OVL_XATTR_TRUSTED_PREFIX,
+       .get = ovl_own_xattr_get,
+       .set = ovl_own_xattr_set,
+};
+
+static const struct xattr_handler ovl_own_user_xattr_handler = {
+       .prefix = OVL_XATTR_USER_PREFIX,
+       .get = ovl_own_xattr_get,
+       .set = ovl_own_xattr_set,
+};
+
+static const struct xattr_handler ovl_other_xattr_handler = {
+       .prefix = "", /* catch all */
+       .get = ovl_other_xattr_get,
+       .set = ovl_other_xattr_set,
+};
+
+static const struct xattr_handler * const ovl_trusted_xattr_handlers[] = {
+       &ovl_own_trusted_xattr_handler,
+       &ovl_other_xattr_handler,
+       NULL
+};
+
+static const struct xattr_handler * const ovl_user_xattr_handlers[] = {
+       &ovl_own_user_xattr_handler,
+       &ovl_other_xattr_handler,
+       NULL
+};
+
+const struct xattr_handler * const *ovl_xattr_handlers(struct ovl_fs *ofs)
+{
+       return ofs->config.userxattr ? ovl_user_xattr_handlers :
+               ovl_trusted_xattr_handlers;
+}
+