Commit 0158005a authored by Al Viro's avatar Al Viro
Browse files

replace do_getxattr() with saner helpers.



similar to do_setxattr() in the previous commit...

Reviewed-by: default avatarChristian Brauner <brauner@kernel.org>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 66d7ac6b
Loading
Loading
Loading
Loading
+3 −5
Original line number Diff line number Diff line
@@ -280,11 +280,9 @@ struct kernel_xattr_ctx {
	unsigned int flags;
};


ssize_t do_getxattr(struct mnt_idmap *idmap,
		    struct dentry *d,
		    struct kernel_xattr_ctx *ctx);

ssize_t file_getxattr(struct file *file, struct kernel_xattr_ctx *ctx);
ssize_t filename_getxattr(int dfd, struct filename *filename,
			  unsigned int lookup_flags, struct kernel_xattr_ctx *ctx);
int file_setxattr(struct file *file, struct kernel_xattr_ctx *ctx);
int filename_setxattr(int dfd, struct filename *filename,
		      unsigned int lookup_flags, struct kernel_xattr_ctx *ctx);
+51 −37
Original line number Diff line number Diff line
@@ -744,27 +744,28 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
/*
 * Extended attribute GET operations
 */
ssize_t
static ssize_t
do_getxattr(struct mnt_idmap *idmap, struct dentry *d,
	struct kernel_xattr_ctx *ctx)
{
	ssize_t error;
	char *kname = ctx->kname->name;
	void *kvalue = NULL;

	if (ctx->size) {
		if (ctx->size > XATTR_SIZE_MAX)
			ctx->size = XATTR_SIZE_MAX;
		ctx->kvalue = kvzalloc(ctx->size, GFP_KERNEL);
		if (!ctx->kvalue)
		kvalue = kvzalloc(ctx->size, GFP_KERNEL);
		if (!kvalue)
			return -ENOMEM;
	}

	if (is_posix_acl_xattr(ctx->kname->name))
		error = do_get_acl(idmap, d, kname, ctx->kvalue, ctx->size);
	if (is_posix_acl_xattr(kname))
		error = do_get_acl(idmap, d, kname, kvalue, ctx->size);
	else
		error = vfs_getxattr(idmap, d, kname, ctx->kvalue, ctx->size);
		error = vfs_getxattr(idmap, d, kname, kvalue, ctx->size);
	if (error > 0) {
		if (ctx->size && copy_to_user(ctx->value, ctx->kvalue, error))
		if (ctx->size && copy_to_user(ctx->value, kvalue, error))
			error = -EFAULT;
	} else if (error == -ERANGE && ctx->size >= XATTR_SIZE_MAX) {
		/* The file system tried to returned a value bigger
@@ -772,52 +773,56 @@ do_getxattr(struct mnt_idmap *idmap, struct dentry *d,
		error = -E2BIG;
	}

	kvfree(kvalue);
	return error;
}

static ssize_t
getxattr(struct mnt_idmap *idmap, struct dentry *d,
	 const char __user *name, void __user *value, size_t size)
ssize_t file_getxattr(struct file *f, struct kernel_xattr_ctx *ctx)
{
	ssize_t error;
	struct xattr_name kname;
	struct kernel_xattr_ctx ctx = {
		.value    = value,
		.kvalue   = NULL,
		.size     = size,
		.kname    = &kname,
		.flags    = 0,
	};

	error = import_xattr_name(&kname, name);
	if (error)
		return error;

	error =  do_getxattr(idmap, d, &ctx);

	kvfree(ctx.kvalue);
	return error;
	audit_file(f);
	return do_getxattr(file_mnt_idmap(f), f->f_path.dentry, ctx);
}

static ssize_t path_getxattr(const char __user *pathname,
			     const char __user *name, void __user *value,
			     size_t size, unsigned int lookup_flags)
/* unconditionally consumes filename */
ssize_t filename_getxattr(int dfd, struct filename *filename,
			  unsigned int lookup_flags, struct kernel_xattr_ctx *ctx)
{
	struct path path;
	ssize_t error;
retry:
	error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
	error = filename_lookup(dfd, filename, lookup_flags, &path, NULL);
	if (error)
		return error;
	error = getxattr(mnt_idmap(path.mnt), path.dentry, name, value, size);
		goto out;
	error = do_getxattr(mnt_idmap(path.mnt), path.dentry, ctx);
	path_put(&path);
	if (retry_estale(error, lookup_flags)) {
		lookup_flags |= LOOKUP_REVAL;
		goto retry;
	}
out:
	putname(filename);
	return error;
}

static ssize_t path_getxattr(const char __user *pathname,
			     const char __user *name, void __user *value,
			     size_t size, unsigned int lookup_flags)
{
	ssize_t error;
	struct xattr_name kname;
	struct kernel_xattr_ctx ctx = {
		.value    = value,
		.size     = size,
		.kname    = &kname,
		.flags    = 0,
	};

	error = import_xattr_name(&kname, name);
	if (error)
		return error;
	return filename_getxattr(AT_FDCWD, getname(pathname), lookup_flags, &ctx);
}

SYSCALL_DEFINE4(getxattr, const char __user *, pathname,
		const char __user *, name, void __user *, value, size_t, size)
{
@@ -833,13 +838,22 @@ SYSCALL_DEFINE4(lgetxattr, const char __user *, pathname,
SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
		void __user *, value, size_t, size)
{
	ssize_t error;
	struct xattr_name kname;
	struct kernel_xattr_ctx ctx = {
		.value    = value,
		.size     = size,
		.kname    = &kname,
		.flags    = 0,
	};
	CLASS(fd, f)(fd);

	if (fd_empty(f))
		return -EBADF;
	audit_file(fd_file(f));
	return getxattr(file_mnt_idmap(fd_file(f)), fd_file(f)->f_path.dentry,
			 name, value, size);
	error = import_xattr_name(&kname, name);
	if (error)
		return error;
	return file_getxattr(fd_file(f), &ctx);
}

/*
+7 −24
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ static int __io_getxattr_prep(struct io_kiocb *req,
	ix->filename = NULL;
	ix->ctx.kvalue = NULL;
	name = u64_to_user_ptr(READ_ONCE(sqe->addr));
	ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2));
	ix->ctx.value = u64_to_user_ptr(READ_ONCE(sqe->addr2));
	ix->ctx.size = READ_ONCE(sqe->len);
	ix->ctx.flags = READ_ONCE(sqe->xattr_flags);

@@ -94,12 +94,10 @@ int io_getxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
	path = u64_to_user_ptr(READ_ONCE(sqe->addr3));

	ix->filename = getname(path);
	if (IS_ERR(ix->filename)) {
		ret = PTR_ERR(ix->filename);
		ix->filename = NULL;
	}
	if (IS_ERR(ix->filename))
		return PTR_ERR(ix->filename);

	return ret;
	return 0;
}

int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
@@ -109,10 +107,7 @@ int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)

	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);

	ret = do_getxattr(file_mnt_idmap(req->file),
			req->file->f_path.dentry,
			&ix->ctx);

	ret = file_getxattr(req->file, &ix->ctx);
	io_xattr_finish(req, ret);
	return IOU_OK;
}
@@ -120,24 +115,12 @@ int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags)
int io_getxattr(struct io_kiocb *req, unsigned int issue_flags)
{
	struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
	unsigned int lookup_flags = LOOKUP_FOLLOW;
	struct path path;
	int ret;

	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);

retry:
	ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL);
	if (!ret) {
		ret = do_getxattr(mnt_idmap(path.mnt), path.dentry, &ix->ctx);

		path_put(&path);
		if (retry_estale(ret, lookup_flags)) {
			lookup_flags |= LOOKUP_REVAL;
			goto retry;
		}
	}

	ret = filename_getxattr(AT_FDCWD, ix->filename, LOOKUP_FOLLOW, &ix->ctx);
	ix->filename = NULL;
	io_xattr_finish(req, ret);
	return IOU_OK;
}