git: 18094609d301 - main - fsck_msdosfs: avoid signed integer overflow in readboot()

From: Xin LI <delphij_at_FreeBSD.org>
Date: Thu, 03 Sep 2026 07:04:13 UTC
The branch main has been updated by delphij:

URL: https://cgit.FreeBSD.org/src/commit/?id=18094609d301540526d3d57e92705bc989d29986

commit 18094609d301540526d3d57e92705bc989d29986
Author:     Chris Suter <csuter@google.com>
AuthorDate: 2026-09-03 05:23:46 +0000
Commit:     Xin LI <delphij@FreeBSD.org>
CommitDate: 2026-09-03 06:51:19 +0000

    fsck_msdosfs: avoid signed integer overflow in readboot()
    
    readboot() decoded the 32-bit little-endian BIOS Parameter Block and
    FSInfo fields by shifting the individual bytes of a u_char array into
    place.  The u_char operands are promoted to signed int, so shifting a
    most significant byte of 0x80 or greater left by 24 overflows int, which
    is undefined behavior.  Use le32dec() from <sys/endian.h> instead, which
    is both well defined and easier to read.
    
    No functional change intended.
    
    MFC after:      1 week
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/2350
---
 sbin/fsck_msdosfs/boot.c | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/sbin/fsck_msdosfs/boot.c b/sbin/fsck_msdosfs/boot.c
index f91609470ad7..ec59c3e02dde 100644
--- a/sbin/fsck_msdosfs/boot.c
+++ b/sbin/fsck_msdosfs/boot.c
@@ -32,6 +32,7 @@ __RCSID("$NetBSD: boot.c,v 1.22 2020/01/11 16:29:07 christos Exp $");
 #endif /* not lint */
 
 #include <sys/param.h>
+#include <sys/endian.h>
 
 #include <stdint.h>
 #include <stdlib.h>
@@ -127,12 +128,10 @@ readboot(int dosfs, struct bootblock *boot)
 	boot->bpbHeads = block[26] + (block[27] << 8);
 
 	/* Hidden sectors: ignored */
-	boot->bpbHiddenSecs = block[28] + (block[29] << 8) +
-	    (block[30] << 16) + (block[31] << 24);
+	boot->bpbHiddenSecs = le32dec(&block[28]);
 
 	/* Total sectors (32 bits) */
-	boot->bpbHugeSectors = block[32] + (block[33] << 8) +
-	    (block[34] << 16) + (block[35] << 24);
+	boot->bpbHugeSectors = le32dec(&block[32]);
 	if (boot->bpbHugeSectors == 0) {
 		if (boot->flags & FAT32) {
 			pfatal("FAT32 with sector count of zero");
@@ -158,8 +157,7 @@ readboot(int dosfs, struct bootblock *boot)
 		}
 
 		/* 32-bit count of sectors per FAT */
-		boot->FATsecs = block[36] + (block[37] << 8)
-				+ (block[38] << 16) + (block[39] << 24);
+		boot->FATsecs = le32dec(&block[36]);
 
 		if (block[40] & 0x80)
 			boot->ValidFat = block[40] & 0x0f;
@@ -176,8 +174,7 @@ readboot(int dosfs, struct bootblock *boot)
 		 *
 		 * Should be 2 but do not require it.
 		 */
-		boot->bpbRootClust = block[44] + (block[45] << 8)
-			       + (block[46] << 16) + (block[47] << 24);
+		boot->bpbRootClust = le32dec(&block[44]);
 
 		/* Sector number of the FSInfo structure, usually 1 */
 		boot->bpbFSInfo = block[48] + (block[49] << 8);
@@ -236,12 +233,8 @@ readboot(int dosfs, struct bootblock *boot)
 				boot->bpbFSInfo = 0;
 		} else {
 			/* We appear to have a valid FSInfo block, decode */
-			boot->FSFree = fsinfo[0x1e8] + (fsinfo[0x1e9] << 8)
-				       + (fsinfo[0x1ea] << 16)
-				       + (fsinfo[0x1eb] << 24);
-			boot->FSNext = fsinfo[0x1ec] + (fsinfo[0x1ed] << 8)
-				       + (fsinfo[0x1ee] << 16)
-				       + (fsinfo[0x1ef] << 24);
+			boot->FSFree = le32dec(&fsinfo[0x1e8]);
+			boot->FSNext = le32dec(&fsinfo[0x1ec]);
 		}
 	} else {
 		/* !FAT32: FAT12/FAT16 */