@@ -194,3 +194,19 @@ 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 kname[XATTR_NAME_MAX + 1];
+ unsigned int flags;
+};
+
+void *setxattr_setup(struct user_namespace *mnt_userns,
+ const char __user *name,
+ struct xattr_ctx *data);
@@ -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,63 @@ 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)
{
- int error;
void *kvalue = NULL;
- char kname[XATTR_NAME_MAX + 1];
+ int error;
- 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->kname, name, sizeof(ctx->kname));
+ if (error == 0 || error == sizeof(ctx->kname))
+ 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 (ctx->size) {
+ if (ctx->size > XATTR_SIZE_MAX)
+ return ERR_PTR(-E2BIG);
+
+ kvalue = kvmalloc(ctx->size, GFP_KERNEL);
if (!kvalue)
- return -ENOMEM;
- if (copy_from_user(kvalue, value, size)) {
- error = -EFAULT;
- goto out;
+ return ERR_PTR(-ENOMEM);
+
+ if (copy_from_user(kvalue, ctx->value, ctx->size)) {
+ kvfree(kvalue);
+ 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->kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
+ (strcmp(ctx->kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
+ posix_acl_fix_xattr_from_user(mnt_userns, kvalue, ctx->size);
}
- error = vfs_setxattr(mnt_userns, d, kname, kvalue, size, flags);
-out:
- kvfree(kvalue);
+ return kvalue;
+}
+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_ctx ctx = {
+ .value = value,
+ .size = size,
+ .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, ctx.kname, kvalue, size, flags);
+
+ kvfree(kvalue);
return error;
}
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 | 16 +++++++++++ fs/xattr.c | 74 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 64 insertions(+), 26 deletions(-)