DF-0852 / fix.diff
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); |