Module Name: src Committed By: snj Date: Tue May 19 04:53:02 UTC 2015
Modified Files: src/sys/kern [netbsd-7]: subr_disk.c Log Message: Pull up following revision(s) (requested by chs in ticket #766): sys/kern/subr_disk.c: revision 1.113 in bounds_check_with_*, reject negative block numbers and avoid a potential overflow in calculating the size of the request. To generate a diff of this commit: cvs rdiff -u -r1.103 -r1.103.4.1 src/sys/kern/subr_disk.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/subr_disk.c diff -u src/sys/kern/subr_disk.c:1.103 src/sys/kern/subr_disk.c:1.103.4.1 --- src/sys/kern/subr_disk.c:1.103 Sat Oct 19 22:36:57 2013 +++ src/sys/kern/subr_disk.c Tue May 19 04:53:02 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: subr_disk.c,v 1.103 2013/10/19 22:36:57 mlelstv Exp $ */ +/* $NetBSD: subr_disk.c,v 1.103.4.1 2015/05/19 04:53:02 snj Exp $ */ /*- * Copyright (c) 1996, 1997, 1999, 2000, 2009 The NetBSD Foundation, Inc. @@ -67,7 +67,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: subr_disk.c,v 1.103 2013/10/19 22:36:57 mlelstv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: subr_disk.c,v 1.103.4.1 2015/05/19 04:53:02 snj Exp $"); #include <sys/param.h> #include <sys/kernel.h> @@ -323,7 +323,18 @@ bounds_check_with_mediasize(struct buf * { int64_t sz; - sz = howmany(bp->b_bcount, secsize); + if (bp->b_blkno < 0) { + /* Reject negative offsets immediately. */ + bp->b_error = EINVAL; + return 0; + } + + sz = howmany((int64_t)bp->b_bcount, secsize); + + /* + * bp->b_bcount is a 32-bit value, and we rejected a negative + * bp->b_blkno already, so "bp->b_blkno + sz" cannot overflow. + */ if (bp->b_blkno + sz > mediasize) { sz = mediasize - bp->b_blkno; @@ -357,6 +368,12 @@ bounds_check_with_label(struct disk *dk, uint64_t p_size, p_offset, labelsector; int64_t sz; + if (bp->b_blkno < 0) { + /* Reject negative offsets immediately. */ + bp->b_error = EINVAL; + return -1; + } + /* Protect against division by zero. XXX: Should never happen?!?! */ if (lp->d_secpercyl == 0) { bp->b_error = EINVAL; @@ -372,8 +389,14 @@ bounds_check_with_label(struct disk *dk, #endif labelsector = (labelsector + dk->dk_labelsector) << dk->dk_blkshift; - sz = howmany(bp->b_bcount, DEV_BSIZE); - if ((bp->b_blkno + sz) > p_size) { + sz = howmany((int64_t)bp->b_bcount, DEV_BSIZE); + + /* + * bp->b_bcount is a 32-bit value, and we rejected a negative + * bp->b_blkno already, so "bp->b_blkno + sz" cannot overflow. + */ + + if (bp->b_blkno + sz > p_size) { sz = p_size - bp->b_blkno; if (sz == 0) { /* If exactly at end of disk, return EOF. */