From: Andrew Morton Subject: block: restore the iterator when rejecting a misaligned bio Date: Sun, 18 Oct 2026 17:30:00 -0700 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: --- Testing on x86-64 QEMU/KVM with generic KASAN: - Before: the ext4 writev() reproducer returned 1015 instead of 1025 and triggered an 8-byte slab out-of-bounds read. - After: 100 consecutive reproducer runs returned 1025 without KASAN; 60-second buffered and direct ext4 fio runs passed. - Daehyeon's alignment patch independently avoids the reproducer. Tal Zussman's pending atomic-write changes introduce another rejected-bio cleanup path. If both patches are combined, restore the iterator there too. block/bio.c | 3 +++ 1 file changed, 3 insertions(+) --- a/block/bio.c~block-restore-the-iterator-when-rejecting-a-misaligned-bio +++ a/block/bio.c @@ -1285,6 +1285,7 @@ int bio_iov_iter_get_pages(struct bio *b unsigned mem_align_mask, unsigned len_align_mask) { iov_iter_extraction_t flags = 0; + struct iov_iter saved_iter; if (WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED))) return -EIO; @@ -1303,6 +1304,7 @@ int bio_iov_iter_get_pages(struct bio *b if (bio->bi_bdev && blk_queue_pci_p2pdma(bio->bi_bdev->bd_disk->queue)) flags |= ITER_ALLOW_P2PDMA; + saved_iter = *iter; do { ssize_t ret; @@ -1320,6 +1322,7 @@ int bio_iov_iter_get_pages(struct bio *b bio_release_pages(bio, false); bio_clear_flag(bio, BIO_PAGE_PINNED); bio->bi_vcnt = 0; + *iter = saved_iter; } if (!bio->bi_vcnt) return ret; _