[PATCH] io_uring: check for valid register opcode earlier

Jens Axboe
2022-12-23T13:42:58Z

We only check the register opcode value inside the restricted ring
section, move it into the main io_uring_register() function instead
and check it up front.

Signed-off-by: Jens Axboe <axboe@kernel.dk>

---

Should not really matter in practice, but doing backports of changes
meant I hit test/sync-cancel.t waiting until interrupted on an older
kernel. The reason is it arms a poll request and then cancels, but
because we only check for validity later, we end up attempting to
quiesce the ring (as the opcode is unknown). This won't work on that
test case, as it knowingly arms a request for cancelation that doesn't
trigger on its own.

diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
index ac5d39eeb3d1..58ac13b69dc8 100644
--- a/io_uring/io_uring.c
+++ b/io_uring/io_uring.c
@@ -4020,8 +4020,6 @@ static int __io_uring_register(struct io_ring_ctx *ctx, unsigned opcode,
return -EEXIST;

if (ctx->restricted) {
- if (opcode >= IORING_REGISTER_LAST)
- return -EINVAL;
opcode = array_index_nospec(opcode, IORING_REGISTER_LAST);
if (!test_bit(opcode, ctx->restrictions.register_op))
return -EACCES;
@@ -4177,6 +4175,9 @@ SYSCALL_DEFINE4(io_uring_register, unsigned int, fd, unsigned int, opcode,
long ret = -EBADF;
struct fd f;

+ if (opcode >= IORING_REGISTER_LAST)
+ return -EINVAL;
+
f = fdget(fd);
if (!f.file)
return -EBADF;

--
Jens Axboe