⬢ DragonFlyBSD Kernel Audit
DF-3103 / df31xx_combined_fix.diff
← back to finding ↓ download raw
--- a/sys/vfs/udf/udf_vnops.c
+++ b/sys/vfs/udf/udf_vnops.c
@@ -251,7 +251,8 @@
 	t->tv_nsec = 0;
 
 	/* DirectCD seems to like using bogus year values */
-	if (time->year < 1970) {
+	/* month is used as an array index below, so validate it too. */
+	if (time->year < 1970 || time->month < 1 || time->month > 12) {
 		t->tv_sec = 0;
 		return;
 	}
@@ -403,7 +404,7 @@
 			error = uiomove(data, size, uio);
 		if (bp != NULL)
 			brelse(bp);
-		if (error)
+		if (error || size == 0)
 			break;
 	}
 
@@ -1037,6 +1038,12 @@
 		fentry = node->fentry;
 		*data = &fentry->data[fentry->l_ea];
 		*size = fentry->l_ad;
+		if (offset >= *size)
+			*size = 0;
+		else {
+			*data += offset;
+			*size -= offset;
+		}
 		return(0);
 	} else if (error != 0) {
 		return(error);
@@ -1046,6 +1053,7 @@
 	if (*size == 0 || *size > max_size)
 		*size = max_size;
 	*size = min(*size, MAXBSIZE);
+	*size = min(*size, udfmp->bsize - (offset % udfmp->bsize));
 
 	if ((error = udf_readlblks(udfmp, sector, *size, bp))) {
 		kprintf("warning: udf_readlblks returned error %d\n", error);
--- a/sys/vfs/udf/udf_vfsops.c
+++ b/sys/vfs/udf/udf_vfsops.c
@@ -524,6 +524,22 @@
 		brelse(bp);
 		return(ENOMEM);
 	}
+	/*
+	 * A file entry is exactly one logical block; the EA area and the
+	 * allocation-descriptor area must both fit in it.  Otherwise the
+	 * 32-bit UDF_FENTRY_SIZE + l_ea + l_ad sum can wrap and undersize
+	 * the fentry allocation while udf_readatoffset()'s embedded path
+	 * still trusts the raw l_ea/l_ad.
+	 */
+	if (udfmp->bsize < UDF_FENTRY_SIZE ||
+	    fe->l_ea > (uint32_t)(udfmp->bsize - UDF_FENTRY_SIZE) ||
+	    fe->l_ad > (uint32_t)(udfmp->bsize - UDF_FENTRY_SIZE) - fe->l_ea) {
+		kprintf("udf_vget: invalid l_ea %u / l_ad %u\n",
+		    fe->l_ea, fe->l_ad);
+		kfree(unode, M_UDFNODE);
+		brelse(bp);
+		return(EINVAL);
+	}
 	size = UDF_FENTRY_SIZE + fe->l_ea + fe->l_ad;
 	unode->fentry = kmalloc(size, M_UDFFENTRY, M_WAITOK | M_ZERO);