| From f8024f1f36a30a082b0457d5779c8847cea57f57 Mon Sep 17 00:00:00 2001 |
| From: Jens Axboe <axboe@kernel.dk> |
| Date: Mon, 2 Oct 2023 18:14:08 -0600 |
| Subject: io_uring/kbuf: don't allow registered buffer rings on highmem pages |
| |
| From: Jens Axboe <axboe@kernel.dk> |
| |
| commit f8024f1f36a30a082b0457d5779c8847cea57f57 upstream. |
| |
| syzbot reports that registering a mapped buffer ring on arm32 can |
| trigger an OOPS. Registered buffer rings have two modes, one of them |
| is the application passing in the memory that the buffer ring should |
| reside in. Once those pages are mapped, we use page_address() to get |
| a virtual address. This will obviously fail on highmem pages, which |
| aren't mapped. |
| |
| Add a check if we have any highmem pages after mapping, and fail the |
| attempt to register a provided buffer ring if we do. This will return |
| the same error as kernels that don't support provided buffer rings to |
| begin with. |
| |
| Link: https://lore.kernel.org/io-uring/000000000000af635c0606bcb889@google.com/ |
| Fixes: c56e022c0a27 ("io_uring: add support for user mapped provided buffer ring") |
| Cc: stable@vger.kernel.org |
| Reported-by: syzbot+2113e61b8848fa7951d8@syzkaller.appspotmail.com |
| Signed-off-by: Jens Axboe <axboe@kernel.dk> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| io_uring/kbuf.c | 27 +++++++++++++++++++-------- |
| 1 file changed, 19 insertions(+), 8 deletions(-) |
| |
| --- a/io_uring/kbuf.c |
| +++ b/io_uring/kbuf.c |
| @@ -481,7 +481,7 @@ static int io_pin_pbuf_ring(struct io_ur |
| { |
| struct io_uring_buf_ring *br; |
| struct page **pages; |
| - int nr_pages; |
| + int i, nr_pages; |
| |
| pages = io_pin_pages(reg->ring_addr, |
| flex_array_size(br, bufs, reg->ring_entries), |
| @@ -489,6 +489,17 @@ static int io_pin_pbuf_ring(struct io_ur |
| if (IS_ERR(pages)) |
| return PTR_ERR(pages); |
| |
| + /* |
| + * Apparently some 32-bit boxes (ARM) will return highmem pages, |
| + * which then need to be mapped. We could support that, but it'd |
| + * complicate the code and slowdown the common cases quite a bit. |
| + * So just error out, returning -EINVAL just like we did on kernels |
| + * that didn't support mapped buffer rings. |
| + */ |
| + for (i = 0; i < nr_pages; i++) |
| + if (PageHighMem(pages[i])) |
| + goto error_unpin; |
| + |
| br = page_address(pages[0]); |
| #ifdef SHM_COLOUR |
| /* |
| @@ -500,13 +511,8 @@ static int io_pin_pbuf_ring(struct io_ur |
| * should use IOU_PBUF_RING_MMAP instead, and liburing will handle |
| * this transparently. |
| */ |
| - if ((reg->ring_addr | (unsigned long) br) & (SHM_COLOUR - 1)) { |
| - int i; |
| - |
| - for (i = 0; i < nr_pages; i++) |
| - unpin_user_page(pages[i]); |
| - return -EINVAL; |
| - } |
| + if ((reg->ring_addr | (unsigned long) br) & (SHM_COLOUR - 1)) |
| + goto error_unpin; |
| #endif |
| bl->buf_pages = pages; |
| bl->buf_nr_pages = nr_pages; |
| @@ -514,6 +520,11 @@ static int io_pin_pbuf_ring(struct io_ur |
| bl->is_mapped = 1; |
| bl->is_mmap = 0; |
| return 0; |
| +error_unpin: |
| + for (i = 0; i < nr_pages; i++) |
| + unpin_user_page(pages[i]); |
| + kvfree(pages); |
| + return -EINVAL; |
| } |
| |
| static int io_alloc_pbuf_ring(struct io_uring_buf_reg *reg, |