io_query() loops over query items that the application or liburing passes in. But it has no checking for a max number of items, or if a loop could be present. If someone were to do: struct io_uring_query_hdr hdr1, hdr2, hdr3; hdr3.next_entry = &hdr1; hdr2.next_entry = &hdr3; hdr1.next_entry = &hdr2; io_uring_register(fd, IORING_REGISTER_QUERY, &hdr1, 0); then it'll happily loop forever and process hdr1 -> hdr2 -> hdr3 and then loop back to hdr1. Add a max cap for these kinds of cases, which is arbitrarily set to 1024 as well. Since there's now a cap, it seems that it would be saner to have this interface return the number of items processed. Eg 0..N for success, and < 0 for an error. Then if someone does need to query more than the supported number of items, they can do so iteratively. Fixes: c265ae75f900 ("io_uring: introduce io_uring querying") Signed-off-by: Jens Axboe --- This would obviously need liburing changes too, but not a big deal since a) the changes aren't in liburing yet, and b) this is still unreleased code. diff --git a/io_uring/query.c b/io_uring/query.c index 9eed0f371956..99402e8e0a4a 100644 --- a/io_uring/query.c +++ b/io_uring/query.c @@ -70,11 +70,14 @@ static int io_handle_query_entry(struct io_ring_ctx *ctx, return 0; } +/* + * Returns number of items processed, or < 0 in case of error. + */ int io_query(struct io_ring_ctx *ctx, void __user *arg, unsigned nr_args) { char entry_buffer[IO_MAX_QUERY_SIZE]; void __user *uhdr = arg; - int ret; + int ret, nr = 0; memset(entry_buffer, 0, sizeof(entry_buffer)); @@ -86,8 +89,11 @@ int io_query(struct io_ring_ctx *ctx, void __user *arg, unsigned nr_args) ret = io_handle_query_entry(ctx, entry_buffer, uhdr, &next_hdr); if (ret) - return ret; + break; uhdr = u64_to_user_ptr(next_hdr); + /* Have some limit to avoid a potential loop */ + if (++nr >= 1024) + break; } - return 0; + return nr ?: ret; } -- Jens Axboe