From 40d070cbb1906896d6fd65c39722d2411830ed9f Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Sun, 18 Oct 2026 17:30:00 -0700 Subject: [PATCH] block: restore the iterator when rejecting a misaligned bio bio_iov_iter_get_pages() can extract some iovecs before encountering a misaligned one. It releases the pages and rejects the entire bio, but leaves the supplied iterator advanced. An iomap direct-I/O caller may subsequently reexpand the iterator's byte count and fall back to buffered I/O. The reexpanded count then includes bytes before the iterator's current segment, potentially causing iterate_iovec() to read beyond the imported iovec array. In a reproducer using an initial empty iovec followed by 10-byte and 1015-byte segments, writev() returned 1015 instead of 1025 and KASAN reported an 8-byte read beyond the nine-element iovec allocation. Saving and restoring the iterator on the rejected-bio path makes writev() return 1025 and eliminates the KASAN report. Restore the entire iterator rather than reverting a byte count: advancing past an empty segment changes its position without consuming any bytes. Leave successful and partially accepted bio paths unchanged. Fixes: 14b007e17881 ("block: validate user space vectors during extraction") Signed-off-by: Andrew Morton Reported-by: Haocheng Yu Closes: https://lore.kernel.org/20261018081203.2431035-1-l1za0.sec@gmail.com Cc: Jens Axboe Cc: Keith Busch Cc: Christoph Hellwig Cc: Tal Zussman Cc: Daehyeon Ko <4ncienth@gmail.com> Cc: Al Viro Cc: Hannes Reinecke Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20261020170250.014BD1F000C9@smtp.kernel.org Signed-off-by: Jens Axboe --- block/bio.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/block/bio.c b/block/bio.c index a1e9ffd5982d..41d9f1c5992d 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1311,6 +1311,7 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter, unsigned mem_align_mask, unsigned len_align_mask) { iov_iter_extraction_t flags = 0; + struct iov_iter saved_iter; int ret; if (WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED))) @@ -1330,6 +1331,7 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter, if (bio->bi_bdev && blk_queue_pci_p2pdma(bio->bi_bdev->bd_disk->queue)) flags |= ITER_ALLOW_P2PDMA; + saved_iter = *iter; do { ssize_t size; @@ -1371,6 +1373,7 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter, bio_release_pages(bio, false); bio_clear_flag(bio, BIO_PAGE_PINNED); bio->bi_vcnt = 0; + *iter = saved_iter; return -EINVAL; }