struct io_uring_sqe::optval is a strange field, because in reality it is part of the cmd payload (for IORING_OP_URING_CMD). The layout of this payload is not converted before the SQE is submitted (in convert_compat64_io_uring_sqe()), because it is specific to each .uring_cmd handler. Even if we wanted to handle all the conversions upfront, it would be difficult to achieve as the target file (and thus the .uring_cmd handler) has not been determined at that point.
Since optval is a user pointer, we need to perform the usual conversion for compat64. This is done by getting a pointer to the payload using io_uring_sqe_cmd(), and then interpreting that payload as either __u64 or __kernel_uintptr_t. The optval field is no longer used, as it is not meaningful in compat64. Since struct io_uring_sqe is uapi, the field is retained for userspace usage.
Signed-off-by: Kevin Brodsky kevin.brodsky@arm.com ---
Another patch for the branch rebased on 6.7. Testing it with checked uaccess revealed that additional handling was needed for compat64. The OP_{G,S}ETSOCKOPT commands were introduced by [1].
The patch is available in my 6.7-based branch:
https://git.morello-project.org/kbrodsky-arm/linux/-/commits/morello/next-6....
[1] https://lore.kernel.org/all/20231016134750.1381153-1-leitao@debian.org/
io_uring/uring_cmd.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c index 4c4431e9616b..db184905c20d 100644 --- a/io_uring/uring_cmd.c +++ b/io_uring/uring_cmd.c @@ -214,6 +214,17 @@ int io_uring_cmd_import_fixed(void __user *ubuf, unsigned long len, int rw, } EXPORT_SYMBOL_GPL(io_uring_cmd_import_fixed);
+static inline void __user *sqe_get_optval(const struct io_uring_sqe *sqe) +{ + if (IS_ENABLED(CONFIG_COMPAT64) && in_compat_syscall()) { + const __u64 *val = io_uring_sqe_cmd(sqe); + return compat_ptr(READ_ONCE(*val)); + } else { + const __kernel_uintptr_t *val = io_uring_sqe_cmd(sqe); + return (void __user *)READ_ONCE(*val); + } +} + static inline int io_uring_cmd_getsockopt(struct socket *sock, struct io_uring_cmd *cmd, unsigned int issue_flags) @@ -226,7 +237,7 @@ static inline int io_uring_cmd_getsockopt(struct socket *sock, if (level != SOL_SOCKET) return -EOPNOTSUPP;
- optval = (void __user *)READ_ONCE(cmd->sqe->optval); + optval = sqe_get_optval(cmd->sqe); optname = READ_ONCE(cmd->sqe->optname); optlen = READ_ONCE(cmd->sqe->optlen);
@@ -249,7 +260,7 @@ static inline int io_uring_cmd_setsockopt(struct socket *sock, void __user *optval; sockptr_t optval_s;
- optval = (void __user *)READ_ONCE(cmd->sqe->optval); + optval = sqe_get_optval(cmd->sqe); optname = READ_ONCE(cmd->sqe->optname); optlen = READ_ONCE(cmd->sqe->optlen); level = READ_ONCE(cmd->sqe->level);
On 13/12/2023 11:04, Kevin Brodsky wrote:
struct io_uring_sqe::optval is a strange field, because in reality it is part of the cmd payload (for IORING_OP_URING_CMD). The layout of this payload is not converted before the SQE is submitted (in convert_compat64_io_uring_sqe()), because it is specific to each .uring_cmd handler. Even if we wanted to handle all the conversions upfront, it would be difficult to achieve as the target file (and thus the .uring_cmd handler) has not been determined at that point.
Since optval is a user pointer, we need to perform the usual conversion for compat64. This is done by getting a pointer to the payload using io_uring_sqe_cmd(), and then interpreting that payload as either __u64 or __kernel_uintptr_t. The optval field is no longer used, as it is not meaningful in compat64. Since struct io_uring_sqe is uapi, the field is retained for userspace usage.
Signed-off-by: Kevin Brodsky kevin.brodsky@arm.com
Another patch for the branch rebased on 6.7. Testing it with checked uaccess revealed that additional handling was needed for compat64. The OP_{G,S}ETSOCKOPT commands were introduced by [1].
The patch is available in my 6.7-based branch:
https://git.morello-project.org/kbrodsky-arm/linux/-/commits/morello/next-6....
[1] https://lore.kernel.org/all/20231016134750.1381153-1-leitao@debian.org/
io_uring/uring_cmd.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
morello/next is now based on 6.7 and includes this patch.
Kevin
diff --git a/io_uring/uring_cmd.c b/io_uring/uring_cmd.c index 4c4431e9616b..db184905c20d 100644 --- a/io_uring/uring_cmd.c +++ b/io_uring/uring_cmd.c @@ -214,6 +214,17 @@ int io_uring_cmd_import_fixed(void __user *ubuf, unsigned long len, int rw, } EXPORT_SYMBOL_GPL(io_uring_cmd_import_fixed); +static inline void __user *sqe_get_optval(const struct io_uring_sqe *sqe) +{
- if (IS_ENABLED(CONFIG_COMPAT64) && in_compat_syscall()) {
const __u64 *val = io_uring_sqe_cmd(sqe);
return compat_ptr(READ_ONCE(*val));
- } else {
const __kernel_uintptr_t *val = io_uring_sqe_cmd(sqe);
return (void __user *)READ_ONCE(*val);
- }
+}
static inline int io_uring_cmd_getsockopt(struct socket *sock, struct io_uring_cmd *cmd, unsigned int issue_flags) @@ -226,7 +237,7 @@ static inline int io_uring_cmd_getsockopt(struct socket *sock, if (level != SOL_SOCKET) return -EOPNOTSUPP;
- optval = (void __user *)READ_ONCE(cmd->sqe->optval);
- optval = sqe_get_optval(cmd->sqe); optname = READ_ONCE(cmd->sqe->optname); optlen = READ_ONCE(cmd->sqe->optlen);
@@ -249,7 +260,7 @@ static inline int io_uring_cmd_setsockopt(struct socket *sock, void __user *optval; sockptr_t optval_s;
- optval = (void __user *)READ_ONCE(cmd->sqe->optval);
- optval = sqe_get_optval(cmd->sqe); optname = READ_ONCE(cmd->sqe->optname); optlen = READ_ONCE(cmd->sqe->optlen); level = READ_ONCE(cmd->sqe->level);
linux-morello@op-lists.linaro.org