io_uring/rsrc: fix folio unpinning

syzbot complains about an unmapping failure:

[  108.070381][   T14] kernel BUG at mm/gup.c:71!
[  108.070502][   T14] Internal error: Oops - BUG: 00000000f2000800 [#1]  SMP
[  108.123672][   T14] Hardware name: QEMU KVM Virtual Machine, BIOS edk2-20250221-8.fc42 02/21/2025
[  108.127458][   T14] Workqueue: iou_exit io_ring_exit_work
[  108.174205][   T14] Call trace:
[  108.175649][   T14]  sanity_check_pinned_pages+0x7cc/0x7d0 (P)
[  108.178138][   T14]  unpin_user_page+0x80/0x10c
[  108.180189][   T14]  io_release_ubuf+0x84/0xf8
[  108.182196][   T14]  io_free_rsrc_node+0x250/0x57c
[  108.184345][   T14]  io_rsrc_data_free+0x148/0x298
[  108.186493][   T14]  io_sqe_buffers_unregister+0x84/0xa0
[  108.188991][   T14]  io_ring_ctx_free+0x48/0x480
[  108.191057][   T14]  io_ring_exit_work+0x764/0x7d8
[  108.193207][   T14]  process_one_work+0x7e8/0x155c
[  108.195431][   T14]  worker_thread+0x958/0xed8
[  108.197561][   T14]  kthread+0x5fc/0x75c
[  108.199362][   T14]  ret_from_fork+0x10/0x20

We can pin a tail page of a folio, but then io_uring will try to unpin
the head page of the folio. While it should be fine in terms of keeping
the page actually alive, mm folks say it's wrong and triggers a debug
warning. Use unpin_user_folio() instead of unpin_user_page*.

Cc: stable@vger.kernel.org
Debugged-by: David Hildenbrand <david@redhat.com>
Reported-by: syzbot+1d335893772467199ab6@syzkaller.appspotmail.com
Closes: https://lkml.kernel.org/r/683f1551.050a0220.55ceb.0017.GAE@google.com
Fixes: a8edbb424b ("io_uring/rsrc: enable multi-hugepage buffer coalescing")
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/io-uring/a28b0f87339ac2acf14a645dad1e95bbcbf18acd.1750771718.git.asml.silence@gmail.com/
[axboe: adapt to current tree, massage commit message]
Signed-off-by: Jens Axboe <axboe@kernel.dk>
pull/1280/head
Pavel Begunkov 2025-06-24 14:40:33 +01:00 committed by Jens Axboe
parent 88a80066af
commit 5afb4bf9fc
1 changed files with 9 additions and 4 deletions

View File

@ -112,8 +112,11 @@ static void io_release_ubuf(void *priv)
struct io_mapped_ubuf *imu = priv; struct io_mapped_ubuf *imu = priv;
unsigned int i; unsigned int i;
for (i = 0; i < imu->nr_bvecs; i++) for (i = 0; i < imu->nr_bvecs; i++) {
unpin_user_page(imu->bvec[i].bv_page); struct folio *folio = page_folio(imu->bvec[i].bv_page);
unpin_user_folio(folio, 1);
}
} }
static struct io_mapped_ubuf *io_alloc_imu(struct io_ring_ctx *ctx, static struct io_mapped_ubuf *io_alloc_imu(struct io_ring_ctx *ctx,
@ -840,8 +843,10 @@ done:
if (ret) { if (ret) {
if (imu) if (imu)
io_free_imu(ctx, imu); io_free_imu(ctx, imu);
if (pages) if (pages) {
unpin_user_pages(pages, nr_pages); for (i = 0; i < nr_pages; i++)
unpin_user_folio(page_folio(pages[i]), 1);
}
io_cache_free(&ctx->node_cache, node); io_cache_free(&ctx->node_cache, node);
node = ERR_PTR(ret); node = ERR_PTR(ret);
} }