Skip to content

Commit 67d1189

Browse files
krismanaxboe
authored andcommitted
io_uring: Fix release of pinned pages when __io_uaddr_map fails
Looking at the error path of __io_uaddr_map, if we fail after pinning the pages for any reasons, ret will be set to -EINVAL and the error handler won't properly release the pinned pages. I didn't manage to trigger it without forcing a failure, but it can happen in real life when memory is heavily fragmented. Signed-off-by: Gabriel Krisman Bertazi <krisman@suse.de> Fixes: 223ef47 ("io_uring: don't allow IORING_SETUP_NO_MMAP rings on highmem pages") Link: https://lore.kernel.org/r/20240313213912.1920-1-krisman@suse.de Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 9219e4a commit 67d1189

File tree

1 file changed

+13
-9
lines changed

1 file changed

+13
-9
lines changed

io_uring/io_uring.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2714,7 +2714,7 @@ static void *__io_uaddr_map(struct page ***pages, unsigned short *npages,
27142714
struct page **page_array;
27152715
unsigned int nr_pages;
27162716
void *page_addr;
2717-
int ret, i;
2717+
int ret, i, pinned;
27182718

27192719
*npages = 0;
27202720

@@ -2728,12 +2728,12 @@ static void *__io_uaddr_map(struct page ***pages, unsigned short *npages,
27282728
if (!page_array)
27292729
return ERR_PTR(-ENOMEM);
27302730

2731-
ret = pin_user_pages_fast(uaddr, nr_pages, FOLL_WRITE | FOLL_LONGTERM,
2732-
page_array);
2733-
if (ret != nr_pages) {
2734-
err:
2735-
io_pages_free(&page_array, ret > 0 ? ret : 0);
2736-
return ret < 0 ? ERR_PTR(ret) : ERR_PTR(-EFAULT);
2731+
2732+
pinned = pin_user_pages_fast(uaddr, nr_pages, FOLL_WRITE | FOLL_LONGTERM,
2733+
page_array);
2734+
if (pinned != nr_pages) {
2735+
ret = (pinned < 0) ? pinned : -EFAULT;
2736+
goto free_pages;
27372737
}
27382738

27392739
page_addr = page_address(page_array[0]);
@@ -2747,7 +2747,7 @@ static void *__io_uaddr_map(struct page ***pages, unsigned short *npages,
27472747
* didn't support this feature.
27482748
*/
27492749
if (PageHighMem(page_array[i]))
2750-
goto err;
2750+
goto free_pages;
27512751

27522752
/*
27532753
* No support for discontig pages for now, should either be a
@@ -2756,13 +2756,17 @@ static void *__io_uaddr_map(struct page ***pages, unsigned short *npages,
27562756
* just fail them with EINVAL.
27572757
*/
27582758
if (page_address(page_array[i]) != page_addr)
2759-
goto err;
2759+
goto free_pages;
27602760
page_addr += PAGE_SIZE;
27612761
}
27622762

27632763
*pages = page_array;
27642764
*npages = nr_pages;
27652765
return page_to_virt(page_array[0]);
2766+
2767+
free_pages:
2768+
io_pages_free(&page_array, pinned > 0 ? pinned : 0);
2769+
return ERR_PTR(ret);
27662770
}
27672771

27682772
static void *io_rings_map(struct io_ring_ctx *ctx, unsigned long uaddr,

0 commit comments

Comments
 (0)