Commit 1a91794c authored by Stefan Roesch's avatar Stefan Roesch Committed by Jens Axboe

fs: split off setxattr_copy and do_setxattr function from setxattr

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: default avatarStefan Roesch <shr@fb.com>
Acked-by: default avatarChristian Brauner <christian.brauner@ubuntu.com>
Link: https://lore.kernel.org/r/20220323154420.3301504-2-shr@fb.comSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 155bc950
...@@ -191,3 +191,27 @@ long splice_file_to_pipe(struct file *in, ...@@ -191,3 +191,27 @@ long splice_file_to_pipe(struct file *in,
struct pipe_inode_info *opipe, struct pipe_inode_info *opipe,
loff_t *offset, loff_t *offset,
size_t len, unsigned int flags); 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);
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include "internal.h"
static const char * static const char *
strcmp_prefix(const char *a, const char *a_prefix) strcmp_prefix(const char *a, const char *a_prefix)
{ {
...@@ -539,44 +541,76 @@ EXPORT_SYMBOL_GPL(vfs_removexattr); ...@@ -539,44 +541,76 @@ EXPORT_SYMBOL_GPL(vfs_removexattr);
/* /*
* Extended attribute SET operations * Extended attribute SET operations
*/ */
static long
setxattr(struct user_namespace *mnt_userns, struct dentry *d, int setxattr_copy(const char __user *name, struct xattr_ctx *ctx)
const char __user *name, const void __user *value, size_t size,
int flags)
{ {
int error; 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; return -EINVAL;
error = strncpy_from_user(kname, name, sizeof(kname)); error = strncpy_from_user(ctx->kname->name, name,
if (error == 0 || error == sizeof(kname)) sizeof(ctx->kname->name));
error = -ERANGE; if (error == 0 || error == sizeof(ctx->kname->name))
return -ERANGE;
if (error < 0) if (error < 0)
return error; return error;
if (size) { error = 0;
if (size > XATTR_SIZE_MAX) if (ctx->size) {
if (ctx->size > XATTR_SIZE_MAX)
return -E2BIG; return -E2BIG;
kvalue = kvmalloc(size, GFP_KERNEL);
if (!kvalue) ctx->kvalue = vmemdup_user(ctx->cvalue, ctx->size);
return -ENOMEM; if (IS_ERR(ctx->kvalue)) {
if (copy_from_user(kvalue, value, size)) { error = PTR_ERR(ctx->kvalue);
error = -EFAULT; ctx->kvalue = NULL;
goto out;
} }
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); return error;
out: }
kvfree(kvalue);
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; return error;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment