From 2b75ec7f3a2aa327b406a5cbe204fb02be3b7982 Mon Sep 17 00:00:00 2001 From: "Samin Y. Chowdhury" Date: Sun, 31 May 2026 18:45:07 -0400 Subject: [PATCH] blk-integrity: fix slab-out-of-bounds in t10_pi_verify on namespace revalidation Abort early with BLK_STS_PROTECTION if a namespace revalidation changed bi->metadata_size after bio_integrity_prep() sized the allocation. Found by FuzzNvme (Syzkaller with FEMU fuzzing framework). When a namespace is revalidated between bio_integrity_prep() and bio_integrity_verify_fn(), the integrity profile's metadata_size may change under the in-flight bio. bio_integrity_verify_fn() re-reads the live blk_integrity via blk_get_integrity(), so blk_integrity_iterate() uses the new metadata_size as the per-interval step size against a buffer sized for the old one, advancing iter->prot_buf past the end of the allocation. task 1: bio_integrity_prep() bio_integrity_alloc_buf() len = bio_integrity_bytes(bi, bio_sectors(bio)) ...(1) bip->bip_iter.bi_size = len task 2: nvme_update_ns_info_block() blk_mq_freeze_queue() nvme_init_integrity() bi->metadata_size = head->ms ...(2) blk_mq_unfreeze_queue() task 3: bio_integrity_verify_fn() bio_integrity_verify() blk_integrity_iterate() bi = blk_get_integrity() ...(3) iter->interval_remaining = 1 << bi->interval_exp iter->prot_buf += bi->metadata_size per interval /* step size from (3), buffer sized at (1): overrun */ Fixes: 8098514bd5ca ("block: always allocate integrity buffer when required") Signed-off-by: Samin Y. Chowdhury Acked-by: Sungwoo Kim Acked-by: Dave Tian Acked-by: Weidong Zhu Acked-by: Ruimin Sun --- block/bio-integrity-auto.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/block/bio-integrity-auto.c b/block/bio-integrity-auto.c index 353eed632fcc9..b404dbaa9f888 100644 --- a/block/bio-integrity-auto.c +++ b/block/bio-integrity-auto.c @@ -38,6 +38,18 @@ static void bio_integrity_verify_fn(struct work_struct *work) struct bio_integrity_data *bid = container_of(work, struct bio_integrity_data, work); struct bio *bio = bid->bio; + struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk); + + if (bi) { + unsigned int required = bio_integrity_bytes(bi, bio_sectors(bio)); + + if (unlikely(required > bid->bip.bip_iter.bi_size)) { + bio->bi_status = BLK_STS_PROTECTION; + bio_integrity_finish(bid); + bio_endio(bio); + return; + } + } bio->bi_status = bio_integrity_verify(bio, &bid->saved_bio_iter); bio_integrity_finish(bid);