mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 16:24:13 +08:00
fs: split off setxattr_copy and do_setxattr function from setxattr
[ Upstream commit1a91794ce8
] 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:06bbaa6dc5
("[coredump] don't use __kernel_write() on kmap_local_page()") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
a0e3719e03
commit
19f4e16366
@ -195,3 +195,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);
|
||||||
|
90
fs/xattr.c
90
fs/xattr.c
@ -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);
|
|||||||
/*
|
/*
|
||||||
* Extended attribute SET operations
|
* Extended attribute SET operations
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
int setxattr_copy(const char __user *name, struct xattr_ctx *ctx)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (ctx->flags & ~(XATTR_CREATE|XATTR_REPLACE))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
error = 0;
|
||||||
|
if (ctx->size) {
|
||||||
|
if (ctx->size > XATTR_SIZE_MAX)
|
||||||
|
return -E2BIG;
|
||||||
|
|
||||||
|
ctx->kvalue = vmemdup_user(ctx->cvalue, ctx->size);
|
||||||
|
if (IS_ERR(ctx->kvalue)) {
|
||||||
|
error = PTR_ERR(ctx->kvalue);
|
||||||
|
ctx->kvalue = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
static long
|
||||||
setxattr(struct user_namespace *mnt_userns, struct dentry *d,
|
setxattr(struct user_namespace *mnt_userns, struct dentry *d,
|
||||||
const char __user *name, const void __user *value, size_t size,
|
const char __user *name, const void __user *value, size_t size,
|
||||||
int flags)
|
int flags)
|
||||||
{
|
{
|
||||||
|
struct xattr_name kname;
|
||||||
|
struct xattr_ctx ctx = {
|
||||||
|
.cvalue = value,
|
||||||
|
.kvalue = NULL,
|
||||||
|
.size = size,
|
||||||
|
.kname = &kname,
|
||||||
|
.flags = flags,
|
||||||
|
};
|
||||||
int error;
|
int error;
|
||||||
void *kvalue = NULL;
|
|
||||||
char kname[XATTR_NAME_MAX + 1];
|
|
||||||
|
|
||||||
if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
|
error = setxattr_copy(name, &ctx);
|
||||||
return -EINVAL;
|
if (error)
|
||||||
|
|
||||||
error = strncpy_from_user(kname, name, sizeof(kname));
|
|
||||||
if (error == 0 || error == sizeof(kname))
|
|
||||||
error = -ERANGE;
|
|
||||||
if (error < 0)
|
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
if (size) {
|
error = do_setxattr(mnt_userns, d, &ctx);
|
||||||
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 ((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);
|
|
||||||
|
|
||||||
|
kvfree(ctx.kvalue);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user