[PATCH v1 2/5] fs: split off setxattr_setup function from setxattr

Stefan Roesch
2021-11-29T22:13:04Z

Summary:

This splits of the setup part of the function
setxattr in its own dedicated function called
setxattr_setup.

This makes it possible to call this function
from io_uring in the pre-processing of an
xattr request.

Signed-off-by: Stefan Roesch <shr@fb.com>
---
fs/internal.h | 17 ++++++++++++
fs/xattr.c | 77 ++++++++++++++++++++++++++++++++++-----------------
2 files changed, 68 insertions(+), 26 deletions(-)

diff --git a/fs/internal.h b/fs/internal.h
index 7979ff8d168c..c5c82bfb5ecf 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -194,3 +194,20 @@ 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_ctx {
+ /* Value of attribute */
+ const void __user *value;
+ size_t size;
+ /* Attribute name */
+ char *name;
+ int name_sz;
+ int flags;
+};
+
+void *setxattr_setup(struct user_namespace *mnt_userns,
+ const char __user *name,
+ struct xattr_ctx *data);
diff --git a/fs/xattr.c b/fs/xattr.c
index 5c8c5175b385..13963b914ac5 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -25,6 +25,8 @@

#include <linux/uaccess.h>

+#include "internal.h"
+
static const char *
strcmp_prefix(const char *a, const char *a_prefix)
{
@@ -539,43 +541,66 @@ 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)
+
+void *setxattr_setup(struct user_namespace *mnt_userns, const char __user *name,
+ struct xattr_ctx *ctx)
{
+ void *ret = NULL;
int error;
- void *kvalue = NULL;
- char kname[XATTR_NAME_MAX + 1];

- if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
- return -EINVAL;
+ if (ctx->flags & ~(XATTR_CREATE|XATTR_REPLACE))
+ return ERR_PTR(-EINVAL);

- error = strncpy_from_user(kname, name, sizeof(kname));
- if (error == 0 || error == sizeof(kname))
- error = -ERANGE;
+ error = strncpy_from_user(ctx->name, name, ctx->name_sz);
+ if (error == 0 || error == ctx->name_sz)
+ return ERR_PTR(-ERANGE);
if (error < 0)
- return error;
+ return ERR_PTR(error);

- if (size) {
- if (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;
+ if (ctx->size) {
+ if (ctx->size > XATTR_SIZE_MAX)
+ return ERR_PTR(-E2BIG);
+
+ ret = kvmalloc(ctx->size, GFP_KERNEL);
+ if (!ret)
+ return ERR_PTR(-ENOMEM);
+
+ if (copy_from_user(ret, ctx->value, ctx->size)) {
+ kfree(ret);
+ return ERR_PTR(-EFAULT);
}
- 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, kvalue, size);
+
+ if ((strcmp(ctx->name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
+ (strcmp(ctx->name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
+ posix_acl_fix_xattr_from_user(mnt_userns, ret, ctx->size);
}

+ return ret;
+}
+
+static long
+setxattr(struct user_namespace *mnt_userns, struct dentry *d,
+ const char __user *name, const void __user *value, size_t size,
+ int flags)
+{
+ char kname[XATTR_NAME_MAX + 1];
+ struct xattr_ctx ctx = {
+ .value = value,
+ .size = size,
+ .name = kname,
+ .name_sz = sizeof(kname),
+ .flags = flags,
+ };
+ void *kvalue;
+ int error;
+
+ kvalue = setxattr_setup(mnt_userns, name, &ctx);
+ if (IS_ERR(kvalue))
+ return PTR_ERR(kvalue);
+
error = vfs_setxattr(mnt_userns, d, kname, kvalue, size, flags);
-out:
- kvfree(kvalue);

+ kvfree(kvalue);
return error;
}

--
2.30.2