DragonFlyBSD Kernel Audit
DF-0852 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/vfs/isofs/cd9660/cd9660_vfsops.c b/sys/vfs/isofs/cd9660/cd9660_vfsops.c
--- a/sys/vfs/isofs/cd9660/cd9660_vfsops.c
+++ b/sys/vfs/isofs/cd9660/cd9660_vfsops.c
@@ -51,6 +51,7 @@
 #include <sys/stat.h>
 #include <sys/syslog.h>
 #include <sys/iconv.h>
+#include <machine/limits.h>
 
 #include <vm/vm_zone.h>
 
@@ -323,6 +324,19 @@
 	iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
 
 	joliet_level = 0;
+
+	/*
+	 * Validate the user-supplied starting sector.  argp->ssector is an
+	 * unchecked signed int copied in from userspace (cd9660_mount); left
+	 * unbounded it drives signed-integer overflow both in the volume
+	 * descriptor scan loop (16 + ssector / 100 + ssector) and in the
+	 * volume_space_size adjustment below.  Reject anything that would
+	 * overflow those expressions.
+	 */
+	if (argp->ssector < 0 || argp->ssector > INT_MAX - 100) {
+		error = EINVAL;
+		goto out;
+	}
 	for (iso_blknum = 16 + argp->ssector;
 	     iso_blknum < 100 + argp->ssector;
 	     iso_blknum++) {
@@ -424,6 +438,18 @@
 	 * can't do much better.  This is also important for the NFS
 	 * filehandle validation.
 	 */
+	/*
+	 * Guard the multi-session adjustment against signed-integer overflow:
+	 * volume_space_size (read from the volume descriptor, i.e. controlled
+	 * by the image) plus the user ssector must not wrap, otherwise the
+	 * poisoned value is published via statfs (f_blocks) and used as a bound
+	 * in fhtovp/cd9660_vget_internal.
+	 */
+	if (isomp->volume_space_size < 0 ||
+	    isomp->volume_space_size > INT_MAX - argp->ssector) {
+		error = EINVAL;
+		goto out;
+	}
 	isomp->volume_space_size += argp->ssector;
 	bcopy (rootp, isomp->root, sizeof isomp->root);
 	isomp->root_extent = isonum_733 (rootp->extent);