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. */

Reply via email to