]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
fs: split off setxattr_copy and do_setxattr function from setxattr
authorStefan Roesch <shr@fb.com>
Mon, 25 Apr 2022 00:10:46 +0000 (18:10 -0600)
committerStefan Bader <stefan.bader@canonical.com>
Mon, 14 Nov 2022 10:25:35 +0000 (11:25 +0100)
BugLink: https://bugs.launchpad.net/bugs/1995517
[ Upstream commit 1a91794ce8481a293c5ef432feb440aee1455619 ]

This splits of the setup part of the function setxattr in its own
dedicated function called setxattr_copy. In addition it also exposes a new
function called do_setxattr for making the setxattr call.

This makes it possible to call these two functions from io_uring in the
processing of an xattr request.

Signed-off-by: Stefan Roesch <shr@fb.com>
Acked-by: Christian Brauner <christian.brauner@ubuntu.com>
Link: https://lore.kernel.org/r/20220323154420.3301504-2-shr@fb.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Stable-dep-of: 06bbaa6dc53c ("[coredump] don't use __kernel_write() on kmap_local_page()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
fs/internal.h
fs/xattr.c

index ad0eb48c35663887aa0b4f05c620d1f743ecc531..1ad82601f09e4f73087e45c3fd8e9b7d00f8b10e 100644 (file)
@@ -201,3 +201,27 @@ long splice_file_to_pipe(struct file *in,
                         struct pipe_inode_info *opipe,
                         loff_t *offset,
                         size_t len, unsigned int flags);
+
+/*
+ * fs/xattr.c:
+ */
+struct xattr_name {
+       char name[XATTR_NAME_MAX + 1];
+};
+
+struct xattr_ctx {
+       /* Value of attribute */
+       union {
+               const void __user *cvalue;
+               void __user *value;
+       };
+       void *kvalue;
+       size_t size;
+       /* Attribute name */
+       struct xattr_name *kname;
+       unsigned int flags;
+};
+
+int setxattr_copy(const char __user *name, struct xattr_ctx *ctx);
+int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
+               struct xattr_ctx *ctx);
index d1407f5c289484d97134e4f4dcdfa47742dd162d..25109848b37a988b6d2c6dce2c39664d54e221ae 100644 (file)
@@ -25,6 +25,8 @@
 
 #include <linux/uaccess.h>
 
+#include "internal.h"
+
 static const char *
 strcmp_prefix(const char *a, const char *a_prefix)
 {
@@ -564,44 +566,76 @@ EXPORT_SYMBOL_GPL(vfs_removexattr);
 /*
  * Extended attribute SET operations
  */
-static long
-setxattr(struct user_namespace *mnt_userns, struct dentry *d,
-        const char __user *name, const void __user *value, size_t size,
-        int flags)
+
+int setxattr_copy(const char __user *name, struct xattr_ctx *ctx)
 {
        int error;
-       void *kvalue = NULL;
-       char kname[XATTR_NAME_MAX + 1];
 
-       if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
+       if (ctx->flags & ~(XATTR_CREATE|XATTR_REPLACE))
                return -EINVAL;
 
-       error = strncpy_from_user(kname, name, sizeof(kname));
-       if (error == 0 || error == sizeof(kname))
-               error = -ERANGE;
+       error = strncpy_from_user(ctx->kname->name, name,
+                               sizeof(ctx->kname->name));
+       if (error == 0 || error == sizeof(ctx->kname->name))
+               return  -ERANGE;
        if (error < 0)
                return error;
 
-       if (size) {
-               if (size > XATTR_SIZE_MAX)
+       error = 0;
+       if (ctx->size) {
+               if (ctx->size > XATTR_SIZE_MAX)
                        return -E2BIG;
-               kvalue = kvmalloc(size, GFP_KERNEL);
-               if (!kvalue)
-                       return -ENOMEM;
-               if (copy_from_user(kvalue, value, size)) {
-                       error = -EFAULT;
-                       goto out;
+
+               ctx->kvalue = vmemdup_user(ctx->cvalue, ctx->size);
+               if (IS_ERR(ctx->kvalue)) {
+                       error = PTR_ERR(ctx->kvalue);
+                       ctx->kvalue = NULL;
                }
-               if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
-                   (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
-                       posix_acl_fix_xattr_from_user(mnt_userns, d_inode(d),
-                                                     kvalue, size);
        }
 
-       error = vfs_setxattr(mnt_userns, d, kname, kvalue, size, flags);
-out:
-       kvfree(kvalue);
+       return error;
+}
+
+static void setxattr_convert(struct user_namespace *mnt_userns,
+                            struct dentry *d, struct xattr_ctx *ctx)
+{
+       if (ctx->size &&
+               ((strcmp(ctx->kname->name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
+               (strcmp(ctx->kname->name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)))
+               posix_acl_fix_xattr_from_user(mnt_userns, d_inode(d),
+                                               ctx->kvalue, ctx->size);
+}
+
+int do_setxattr(struct user_namespace *mnt_userns, struct dentry *dentry,
+               struct xattr_ctx *ctx)
+{
+       setxattr_convert(mnt_userns, dentry, ctx);
+       return vfs_setxattr(mnt_userns, dentry, ctx->kname->name,
+                       ctx->kvalue, ctx->size, ctx->flags);
+}
+
+static long
+setxattr(struct user_namespace *mnt_userns, struct dentry *d,
+       const char __user *name, const void __user *value, size_t size,
+       int flags)
+{
+       struct xattr_name kname;
+       struct xattr_ctx ctx = {
+               .cvalue   = value,
+               .kvalue   = NULL,
+               .size     = size,
+               .kname    = &kname,
+               .flags    = flags,
+       };
+       int error;
+
+       error = setxattr_copy(name, &ctx);
+       if (error)
+               return error;
+
+       error = do_setxattr(mnt_userns, d, &ctx);
 
+       kvfree(ctx.kvalue);
        return error;
 }