Skip to content

Commit f8024f1

Browse files
committed
io_uring/kbuf: don't allow registered buffer rings on highmem pages
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: c56e022 ("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>
1 parent a52d4f6 commit f8024f1

File tree

1 file changed

+19
-8
lines changed

1 file changed

+19
-8
lines changed

io_uring/kbuf.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -477,14 +477,25 @@ static int io_pin_pbuf_ring(struct io_uring_buf_reg *reg,
477477
{
478478
struct io_uring_buf_ring *br;
479479
struct page **pages;
480-
int nr_pages;
480+
int i, nr_pages;
481481

482482
pages = io_pin_pages(reg->ring_addr,
483483
flex_array_size(br, bufs, reg->ring_entries),
484484
&nr_pages);
485485
if (IS_ERR(pages))
486486
return PTR_ERR(pages);
487487

488+
/*
489+
* Apparently some 32-bit boxes (ARM) will return highmem pages,
490+
* which then need to be mapped. We could support that, but it'd
491+
* complicate the code and slowdown the common cases quite a bit.
492+
* So just error out, returning -EINVAL just like we did on kernels
493+
* that didn't support mapped buffer rings.
494+
*/
495+
for (i = 0; i < nr_pages; i++)
496+
if (PageHighMem(pages[i]))
497+
goto error_unpin;
498+
488499
br = page_address(pages[0]);
489500
#ifdef SHM_COLOUR
490501
/*
@@ -496,20 +507,20 @@ static int io_pin_pbuf_ring(struct io_uring_buf_reg *reg,
496507
* should use IOU_PBUF_RING_MMAP instead, and liburing will handle
497508
* this transparently.
498509
*/
499-
if ((reg->ring_addr | (unsigned long) br) & (SHM_COLOUR - 1)) {
500-
int i;
501-
502-
for (i = 0; i < nr_pages; i++)
503-
unpin_user_page(pages[i]);
504-
return -EINVAL;
505-
}
510+
if ((reg->ring_addr | (unsigned long) br) & (SHM_COLOUR - 1))
511+
goto error_unpin;
506512
#endif
507513
bl->buf_pages = pages;
508514
bl->buf_nr_pages = nr_pages;
509515
bl->buf_ring = br;
510516
bl->is_mapped = 1;
511517
bl->is_mmap = 0;
512518
return 0;
519+
error_unpin:
520+
for (i = 0; i < nr_pages; i++)
521+
unpin_user_page(pages[i]);
522+
kvfree(pages);
523+
return -EINVAL;
513524
}
514525

515526
static int io_alloc_pbuf_ring(struct io_uring_buf_reg *reg,

0 commit comments

Comments
 (0)