DragonFlyBSD Kernel Audit
DF-2488 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/disk/nata/ata-disk.c b/sys/dev/disk/nata/ata-disk.c
--- a/sys/dev/disk/nata/ata-disk.c
+++ b/sys/dev/disk/nata/ata-disk.c
@@ -507,10 +507,30 @@
     struct ad_softc *adp = device_get_ivars(dev);
     u_int8_t *marker, vendor[64], product[64];
 
-    /* try to seperate the ATA model string into vendor and model parts */
-    if ((marker = index(atadev->param.model, ' ')) ||
-	(marker = index(atadev->param.model, '-'))) {
-	int len = (marker - atadev->param.model);
+    /* try to seperate the ATA model string into vendor and model parts.
+     * The 40-byte ATA IDENTIFY model field is not guaranteed to be
+     * NUL-terminated, so search it bounded by the field width (NOT index(),
+     * which scans until it finds a byte) and clamp len to [0,40] to keep
+     * strncpy()/vendor[] from operating on a negative (sign-extended to
+     * ~SIZE_MAX) length.  See DF-2488. */
+    {
+	int i;
+	marker = NULL;
+	for (i = 0; i < (int)sizeof(atadev->param.model); i++) {
+	    if (atadev->param.model[i] == ' ' ||
+		atadev->param.model[i] == '-') {
+		marker = &atadev->param.model[i];
+		break;
+	    }
+	}
+    }
+    if (marker) {
+	int len = (int)(marker - atadev->param.model);
+
+	if (len < 0)
+	    len = 0;
+	else if (len > 40)
+	    len = 40;
 
 	strncpy(vendor, atadev->param.model, len);
 	vendor[len++] = 0;