git: 116a988f99cd - stable/12 - geom_label: Add more validation for NTFS volume tasting

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Mon, 18 Oct 2021 13:08:46 UTC
The branch stable/12 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=116a988f99cd9fcac1a34c17ec0aa81be70d5e4f

commit 116a988f99cd9fcac1a34c17ec0aa81be70d5e4f
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2021-10-04 21:48:44 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2021-10-18 13:08:32 +0000

    geom_label: Add more validation for NTFS volume tasting
    
    - Ensure that the computed MFT record size isn't negative or larger than
      maxphys before trying to read $Volume.
    - Guard against truncated records in volume metadata.
    - Ensure that the record length is large enough to contain the volume
      name.
    - Verify that the (UTF-16-encoded) volume name's length is a multiple of
      two.
    
    PR:             258833, 258914
    Sponsored by:   The FreeBSD Foundation
    
    (cherry picked from commit f0a08fa9f532a58f5d7a4814d6eb7ddd49f368da)
---
 sys/geom/label/g_label_ntfs.c | 37 ++++++++++++++++++++++++-------------
 1 file changed, 24 insertions(+), 13 deletions(-)

diff --git a/sys/geom/label/g_label_ntfs.c b/sys/geom/label/g_label_ntfs.c
index 653524ab654c..bcf6a3a72b36 100644
--- a/sys/geom/label/g_label_ntfs.c
+++ b/sys/geom/label/g_label_ntfs.c
@@ -101,7 +101,8 @@ g_label_ntfs_taste(struct g_consumer *cp, char *label, size_t size)
 	struct ntfs_filerec *fr;
 	struct ntfs_attr *atr;
 	off_t voloff;
-	char *filerecp, *ap;
+	size_t recoff;
+	char *filerecp;
 	int8_t mftrecsz;
 	char vnchar;
 	int recsize, j;
@@ -117,8 +118,9 @@ g_label_ntfs_taste(struct g_consumer *cp, char *label, size_t size)
 		goto done;
 
 	mftrecsz = bf->bf_mftrecsz;
-	recsize = (mftrecsz > 0) ? (mftrecsz * bf->bf_bps * bf->bf_spc) : (1 << -mftrecsz);
-	if (recsize == 0 || recsize % pp->sectorsize != 0)
+	recsize = (mftrecsz > 0) ? (mftrecsz * bf->bf_bps * bf->bf_spc) :
+	    (1 << -mftrecsz);
+	if (recsize <= 0 || recsize > maxphys || recsize % pp->sectorsize != 0)
 		goto done;
 
 	voloff = bf->bf_mftcn * bf->bf_spc * bf->bf_bps +
@@ -130,24 +132,33 @@ g_label_ntfs_taste(struct g_consumer *cp, char *label, size_t size)
 	if (filerecp == NULL)
 		goto done;
 	fr = (struct ntfs_filerec *)filerecp;
-
 	if (fr->fr_hdrmagic != NTFS_FILEMAGIC)
 		goto done;
 
-	for (ap = filerecp + fr->fr_attroff;
-	    atr = (struct ntfs_attr *)ap, atr->a_type != -1;
-	    ap += atr->reclen) {
+	for (recoff = fr->fr_attroff;
+	    recoff <= recsize - 2 * sizeof(uint32_t);
+	    recoff += atr->reclen) {
+		atr = (struct ntfs_attr *)(filerecp + recoff);
+		if (atr->a_type == -1)
+			break;
+		if (atr->reclen < sizeof(*atr))
+			break;
+		if (recsize - recoff < atr->reclen)
+			break;
 		if (atr->a_type == NTFS_A_VOLUMENAME) {
-			if(atr->a_datalen >= size *2){
-				label[0] = 0;
-				goto done;
-			}
+			if (atr->a_dataoff > atr->reclen ||
+			    atr->a_datalen > atr->reclen - atr->a_dataoff)
+				break;
+
 			/*
-			 *UNICODE to ASCII.
+			 * UNICODE to ASCII.
 			 * Should we need to use iconv(9)?
 			 */
+			if (atr->a_datalen >= size * 2 ||
+			    atr->a_datalen % 2 != 0)
+				break;
 			for (j = 0; j < atr->a_datalen; j++) {
-				vnchar = *(ap + atr->a_dataoff + j);
+				vnchar = ((char *)atr)[atr->a_dataoff + j];
 				if (j & 1) {
 					if (vnchar) {
 						label[0] = 0;