Re: [PATCH v3 2/2] io_uring: add fremovexattr and flistxattr support

Gabriel Krisman Bertazi <[email protected]>
Newsgroups org.kernel.vger.linux-fsdevel,org.kernel.vger.io-uring,org.kernel.vger.linux-kernel
Organization SUSE
Message-ID <[email protected]>
Aditya Prakash Srivastava <[email protected]> writes:

> Add support for IORING_OP_FREMOVEXATTR and IORING_OP_FLISTXATTR. This
> enables xattr listing and removal operations to be executed in an
> asynchronous fashion.
>
> Signed-off-by: Aditya Prakash Srivastava <[email protected]>

Jens has made a point about avoiding new commands just punting to the wq
at [1].[1] https://github.com/axboe/liburing/issues/1492#issuecomment-4683773809

In this case, we have an immediate issue for inline submission with
acquiring the mount and the inode lock and there is no callbacks so we
are not really in good shape to work around it.  Beyond that...


> ---
>  include/uapi/linux/io_uring.h       |  2 +
>  io_uring/opdef.c                    | 18 +++++++
>  io_uring/xattr.c                    | 74 +++++++++++++++++++++++++++++
>  io_uring/xattr.h                    |  6 +++
>  tools/include/uapi/linux/io_uring.h | 13 +++++
>  5 files changed, 113 insertions(+)
>
> diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
> index 909fb7aea638..805f1e31f492 100644
> --- a/include/uapi/linux/io_uring.h
> +++ b/include/uapi/linux/io_uring.h
> @@ -318,6 +318,8 @@ enum io_uring_op {
>  	IORING_OP_PIPE,
>  	IORING_OP_NOP128,
>  	IORING_OP_URING_CMD128,
> +	IORING_OP_FREMOVEXATTR,
> +	IORING_OP_FLISTXATTR,
>  
>  	/* this goes last, obviously */
>  	IORING_OP_LAST,
> diff --git a/io_uring/opdef.c b/io_uring/opdef.c
> index 4e58eb1344ea..25d9229d8fc0 100644
> --- a/io_uring/opdef.c
> +++ b/io_uring/opdef.c
> @@ -591,6 +591,16 @@ const struct io_issue_def io_issue_defs[] = {
>  		.prep			= io_uring_cmd_prep,
>  		.issue			= io_uring_cmd,
>  	},
> +	[IORING_OP_FREMOVEXATTR] = {
> +		.needs_file		= 1,
> +		.prep			= io_fremovexattr_prep,
> +		.issue			= io_fremovexattr,
> +	},
> +	[IORING_OP_FLISTXATTR] = {
> +		.needs_file		= 1,
> +		.prep			= io_flistxattr_prep,
> +		.issue			= io_flistxattr,
> +	},
>  };
>  
>  const struct io_cold_def io_cold_defs[] = {
> @@ -849,6 +859,14 @@ const struct io_cold_def io_cold_defs[] = {
>  		.sqe_copy		= io_uring_cmd_sqe_copy,
>  		.cleanup		= io_uring_cmd_cleanup,
>  	},
> +	[IORING_OP_FREMOVEXATTR] = {
> +		.name			= "FREMOVEXATTR",
> +		.cleanup		= io_xattr_cleanup,
> +	},
> +	[IORING_OP_FLISTXATTR] = {
> +		.name			= "FLISTXATTR",
> +		.cleanup		= io_xattr_cleanup,
> +	},
>  };
>  
>  const char *io_uring_get_opcode(u8 opcode)
> diff --git a/io_uring/xattr.c b/io_uring/xattr.c
> index 5303df3f247f..9b410f91ef43 100644
> --- a/io_uring/xattr.c
> +++ b/io_uring/xattr.c
> @@ -195,3 +195,77 @@ int io_setxattr(struct io_kiocb *req, unsigned int issue_flags)
>  	io_xattr_finish(req, ret);
>  	return IOU_COMPLETE;
>  }
> +
> +int io_fremovexattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
> +{
> +	struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
> +	const char __user *name;
> +	int ret;
> +
> +	INIT_DELAYED_FILENAME(&ix->filename);
> +	name = u64_to_user_ptr(READ_ONCE(sqe->addr));
> +
> +	if (READ_ONCE(sqe->addr2) || READ_ONCE(sqe->len) || READ_ONCE(sqe->xattr_flags))
> +		return -EINVAL;

There are more fields to be rejected here, check the latest patches from
Yi Xie such as cc609376e9a4 ("io_uring/fs: check unused sqe fields for
unlinkat").

> +
> +	ix->ctx.kname = kmalloc_obj(*ix->ctx.kname);
> +	if (!ix->ctx.kname)
> +		return -ENOMEM;
> +
> +	ret = import_xattr_name(ix->ctx.kname, name);
> +	if (ret) {
> +		kfree(ix->ctx.kname);
> +		return ret;
> +	}
> +
> +	req->flags |= REQ_F_NEED_CLEANUP;
> +	req->flags |= REQ_F_FORCE_ASYNC;

This will cause the cleanup to call io_xattr_cleanup, which does kfree
on ix->ctx.kvalue, which is never initialized.  If it has garbage from a
previous command in the kiocb cmd space, you can craft a corruption or,
more likely, a crash.


> +	return 0;
> +}
> +
> +int io_fremovexattr(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 = file_removexattr(req->file, ix->ctx.kname);
> +	io_xattr_finish(req, ret);
> +	return IOU_COMPLETE;
> +}
> +
> +int io_flistxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
> +{
> +	struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr);
> +
> +	INIT_DELAYED_FILENAME(&ix->filename);
> +	ix->ctx.kname = NULL;
> +	ix->ctx.kvalue = NULL;
> +
> +	if (READ_ONCE(sqe->addr))
> +		return -EINVAL;
> +
> +	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);
> +
> +	if (ix->ctx.flags)
> +		return -EINVAL;
> +
> +	req->flags |= REQ_F_NEED_CLEANUP;
> +	req->flags |= REQ_F_FORCE_ASYNC;
> +	return 0;
> +}
> +
> +int io_flistxattr(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 = file_listxattr(req->file, ix->ctx.value, ix->ctx.size);
> +	io_xattr_finish(req, ret);
> +	return IOU_COMPLETE;
> +}
> diff --git a/io_uring/xattr.h b/io_uring/xattr.h
> index 9b459d2ae90c..d2487b49a5d2 100644
> --- a/io_uring/xattr.h
> +++ b/io_uring/xattr.h
> @@ -13,3 +13,9 @@ int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags);
>  
>  int io_getxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
>  int io_getxattr(struct io_kiocb *req, unsigned int issue_flags);
> +
> +int io_fremovexattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
> +int io_fremovexattr(struct io_kiocb *req, unsigned int issue_flags);
> +
> +int io_flistxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
> +int io_flistxattr(struct io_kiocb *req, unsigned int issue_flags);
> diff --git a/tools/include/uapi/linux/io_uring.h b/tools/include/uapi/linux/io_uring.h
> index f1c16f817742..79bf7c22009d 100644
> --- a/tools/include/uapi/linux/io_uring.h
> +++ b/tools/include/uapi/linux/io_uring.h
> @@ -253,6 +253,19 @@ enum io_uring_op {
>  	IORING_OP_FUTEX_WAIT,
>  	IORING_OP_FUTEX_WAKE,
>  	IORING_OP_FUTEX_WAITV,
> +	IORING_OP_FIXED_FD_INSTALL,
> +	IORING_OP_FTRUNCATE,
> +	IORING_OP_BIND,
> +	IORING_OP_LISTEN,
> +	IORING_OP_RECV_ZC,
> +	IORING_OP_EPOLL_WAIT,
> +	IORING_OP_READV_FIXED,
> +	IORING_OP_WRITEV_FIXED,
> +	IORING_OP_PIPE,
> +	IORING_OP_NOP128,
> +	IORING_OP_URING_CMD128,
> +	IORING_OP_FREMOVEXATTR,
> +	IORING_OP_FLISTXATTR,

I'd rather these (minus the xattr ones) go in a separate fix patch ahead of
the series...

-- 
Gabriel Krisman Bertazi
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.