git: 63f07c05de4e - stable/13 - g_raid concat: Fail requests to read beyond the end of the volume

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Wed, 06 Sep 2023 21:56:46 UTC
The branch stable/13 has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=63f07c05de4eed513054c5b3d1981eb4fffe5ae6

commit 63f07c05de4eed513054c5b3d1981eb4fffe5ae6
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2023-08-04 23:41:05 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2023-09-06 21:56:10 +0000

    g_raid concat: Fail requests to read beyond the end of the volume
    
    Previously a debug kernel would trigger an assertion failure if an I/O
    request attempted to read off the end of a concat volume, but a
    non-debug kernel would use an invalid sub-disk to try to complete the
    request eventually resulting in some sort of fault in the kernel.
    
    Instead, turn the assertions into explicit checks that fail requests
    beyond the end of the volume with EIO.  For requests which run over
    the end of the volume, return a short request.
    
    PR:             257838
    Reported by:    Robert Morris <rtm@lcs.mit.edu>
    Reviewed by:    emaste
    MFC after:      1 week
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D41222
    
    (cherry picked from commit 4c89c0127dcadaa0d337c23d028f3fea5e76317a)
---
 sys/geom/raid/tr_concat.c | 24 +++++++++++-------------
 1 file changed, 11 insertions(+), 13 deletions(-)

diff --git a/sys/geom/raid/tr_concat.c b/sys/geom/raid/tr_concat.c
index 159d1d76f688..9bdd37526d6a 100644
--- a/sys/geom/raid/tr_concat.c
+++ b/sys/geom/raid/tr_concat.c
@@ -238,8 +238,10 @@ g_raid_tr_iostart_concat(struct g_raid_tr_object *tr, struct bio *bp)
 		offset -= vol->v_subdisks[no].sd_size;
 		no++;
 	}
-	KASSERT(no < vol->v_disks_count,
-	    ("Request starts after volume end (%ju)", bp->bio_offset));
+	if (no >= vol->v_disks_count) {
+		g_raid_iodone(bp, EIO);
+		return;
+	}
 	bioq_init(&queue);
 	do {
 		sd = &vol->v_subdisks[no];
@@ -265,10 +267,8 @@ g_raid_tr_iostart_concat(struct g_raid_tr_object *tr, struct bio *bp)
 			addr += length;
 		offset = 0;
 		no++;
-		KASSERT(no < vol->v_disks_count || remain == 0,
-		    ("Request ends after volume end (%ju, %ju)",
-			bp->bio_offset, bp->bio_length));
-	} while (remain > 0);
+	} while (remain > 0 && no < vol->v_disks_count);
+	bp->bio_completed = bp->bio_length - remain;
 	while ((cbp = bioq_takefirst(&queue)) != NULL) {
 		sd = cbp->bio_caller1;
 		cbp->bio_caller1 = NULL;
@@ -306,8 +306,8 @@ g_raid_tr_kerneldump_concat(struct g_raid_tr_object *tr, void *virtual,
 		offset -= vol->v_subdisks[no].sd_size;
 		no++;
 	}
-	KASSERT(no < vol->v_disks_count,
-	    ("Request starts after volume end (%ju)", boffset));
+	if (no >= vol->v_disks_count)
+		return (EIO);
 	do {
 		sd = &vol->v_subdisks[no];
 		length = MIN(sd->sd_size - offset, remain);
@@ -319,10 +319,9 @@ g_raid_tr_kerneldump_concat(struct g_raid_tr_object *tr, void *virtual,
 		addr += length;
 		offset = 0;
 		no++;
-		KASSERT(no < vol->v_disks_count || remain == 0,
-		    ("Request ends after volume end (%ju, %zu)",
-			boffset, blength));
-	} while (remain > 0);
+	} while (remain > 0 && no < vol->v_disks_count);
+	if (remain > 0)
+		return (EIO);
 	return (0);
 }
 
@@ -338,7 +337,6 @@ g_raid_tr_iodone_concat(struct g_raid_tr_object *tr,
 	g_destroy_bio(bp);
 	pbp->bio_inbed++;
 	if (pbp->bio_children == pbp->bio_inbed) {
-		pbp->bio_completed = pbp->bio_length;
 		g_raid_iodone(pbp, pbp->bio_error);
 	}
 }