Commit 66d7ac6b authored by Al Viro's avatar Al Viro
Browse files

replace do_setxattr() with saner helpers.



io_uring setxattr logics duplicates stuff from fs/xattr.c; provide
saner helpers (filename_setxattr() and file_setxattr() resp.) and
use them.

NB: putname(ERR_PTR()) is a no-op

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent a10c4c5e
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -285,10 +285,10 @@ ssize_t do_getxattr(struct mnt_idmap *idmap,
		    struct dentry *d,
		    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);
int setxattr_copy(const char __user *name, struct kernel_xattr_ctx *ctx);
int do_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
		struct kernel_xattr_ctx *ctx);

int import_xattr_name(struct xattr_name *kname, const char __user *name);

int may_write_xattr(struct mnt_idmap *idmap, struct inode *inode);
+44 −25
Original line number Diff line number Diff line
@@ -626,7 +626,7 @@ int setxattr_copy(const char __user *name, struct kernel_xattr_ctx *ctx)
	return error;
}

int do_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
static int do_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
		struct kernel_xattr_ctx *ctx)
{
	if (is_posix_acl_xattr(ctx->kname->name))
@@ -637,32 +637,32 @@ int do_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
			ctx->kvalue, ctx->size, ctx->flags);
}

static int path_setxattr(const char __user *pathname,
			 const char __user *name, const void __user *value,
			 size_t size, int flags, unsigned int lookup_flags)
int file_setxattr(struct file *f, struct kernel_xattr_ctx *ctx)
{
	struct xattr_name kname;
	struct kernel_xattr_ctx ctx = {
		.cvalue   = value,
		.kvalue   = NULL,
		.size     = size,
		.kname    = &kname,
		.flags    = flags,
	};
	struct path path;
	int error;
	int error = mnt_want_write_file(f);

	error = setxattr_copy(name, &ctx);
	if (error)
	if (!error) {
		audit_file(f);
		error = do_setxattr(file_mnt_idmap(f), f->f_path.dentry, ctx);
		mnt_drop_write_file(f);
	}
	return error;
}

/* unconditionally consumes filename */
int filename_setxattr(int dfd, struct filename *filename,
		      unsigned int lookup_flags, struct kernel_xattr_ctx *ctx)
{
	struct path path;
	int error;

retry:
	error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
	error = filename_lookup(dfd, filename, lookup_flags, &path, NULL);
	if (error)
		goto out;
	error = mnt_want_write(path.mnt);
	if (!error) {
		error = do_setxattr(mnt_idmap(path.mnt), path.dentry, &ctx);
		error = do_setxattr(mnt_idmap(path.mnt), path.dentry, ctx);
		mnt_drop_write(path.mnt);
	}
	path_put(&path);
@@ -672,6 +672,30 @@ static int path_setxattr(const char __user *pathname,
	}

out:
	putname(filename);
	return error;
}

static int path_setxattr(const char __user *pathname,
			 const char __user *name, const void __user *value,
			 size_t size, int flags, unsigned int lookup_flags)
{
	struct xattr_name kname;
	struct kernel_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 = filename_setxattr(AT_FDCWD, getname(pathname), lookup_flags,
				  &ctx);
	kvfree(ctx.kvalue);
	return error;
}
@@ -707,17 +731,12 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,

	if (fd_empty(f))
		return -EBADF;
	audit_file(fd_file(f));

	error = setxattr_copy(name, &ctx);
	if (error)
		return error;

	error = mnt_want_write_file(fd_file(f));
	if (!error) {
		error = do_setxattr(file_mnt_idmap(fd_file(f)),
				    fd_file(f)->f_path.dentry, &ctx);
		mnt_drop_write_file(fd_file(f));
	}
	error = file_setxattr(fd_file(f), &ctx);
	kvfree(ctx.kvalue);
	return error;
}
+7 −34
Original line number Diff line number Diff line
@@ -187,12 +187,10 @@ int io_setxattr_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_fsetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
@@ -200,28 +198,14 @@ int io_fsetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
	return __io_setxattr_prep(req, sqe);
}

static int __io_setxattr(struct io_kiocb *req, unsigned int issue_flags,
			const struct path *path)
{
	struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
	int ret;

	ret = mnt_want_write(path->mnt);
	if (!ret) {
		ret = do_setxattr(mnt_idmap(path->mnt), path->dentry, &ix->ctx);
		mnt_drop_write(path->mnt);
	}

	return ret;
}

int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
{
	struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
	int ret;

	WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);

	ret = __io_setxattr(req, issue_flags, &req->file->f_path);
	ret = file_setxattr(req->file, &ix->ctx);
	io_xattr_finish(req, ret);
	return IOU_OK;
}
@@ -229,23 +213,12 @@ int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
int io_setxattr(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 = __io_setxattr(req, issue_flags, &path);
		path_put(&path);
		if (retry_estale(ret, lookup_flags)) {
			lookup_flags |= LOOKUP_REVAL;
			goto retry;
		}
	}

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