Module Name:    src
Committed By:   mlelstv
Date:           Sun Aug 13 22:23:16 UTC 2017

Modified Files:
        src/sys/dev: dksubr.c

Log Message:
validate length for discard operation and split operation when byte length
doesn't fit into 'int'.


To generate a diff of this commit:
cvs rdiff -u -r1.97 -r1.98 src/sys/dev/dksubr.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/dev/dksubr.c
diff -u src/sys/dev/dksubr.c:1.97 src/sys/dev/dksubr.c:1.98
--- src/sys/dev/dksubr.c:1.97	Thu Apr 27 17:07:22 2017
+++ src/sys/dev/dksubr.c	Sun Aug 13 22:23:16 2017
@@ -1,4 +1,4 @@
-/* $NetBSD: dksubr.c,v 1.97 2017/04/27 17:07:22 jdolecek Exp $ */
+/* $NetBSD: dksubr.c,v 1.98 2017/08/13 22:23:16 mlelstv Exp $ */
 
 /*-
  * Copyright (c) 1996, 1997, 1998, 1999, 2002, 2008 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dksubr.c,v 1.97 2017/04/27 17:07:22 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dksubr.c,v 1.98 2017/08/13 22:23:16 mlelstv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -497,7 +497,7 @@ dk_discard(struct dk_softc *dksc, dev_t 
 	const struct dkdriver *dkd = dksc->sc_dkdev.dk_driver;
 	unsigned secsize = dksc->sc_dkdev.dk_geom.dg_secsize;
 	struct buf tmp, *bp = &tmp;
-	int error;
+	int maxsz, error;
 
 	DPRINTF_FOLLOW(("%s(%s, %p, 0x"PRIx64", %jd, %jd)\n", __func__,
 	    dksc->sc_xname, dksc, (intmax_t)pos, (intmax_t)len));
@@ -507,22 +507,32 @@ dk_discard(struct dk_softc *dksc, dev_t 
 		return ENXIO;
 	}
 
-	if (secsize == 0 || (pos % secsize) != 0)
+	if (secsize == 0 || (pos % secsize) != 0 || (len % secsize) != 0)
 		return EINVAL;
 
-	/* enough data to please the bounds checking code */
-	bp->b_dev = dev;
-	bp->b_blkno = (daddr_t)(pos / secsize);
-	bp->b_bcount = len;
-	bp->b_flags = B_WRITE;
+	/* largest value that b_bcount can store */
+	maxsz = rounddown(INT_MAX, secsize);
 
-	error = dk_translate(dksc, bp);
-	if (error >= 0)
-		return error;
+	while (len > 0) {
+		/* enough data to please the bounds checking code */
+		bp->b_dev = dev;
+		bp->b_blkno = (daddr_t)(pos / secsize);
+		bp->b_bcount = min(len, maxsz);
+		bp->b_flags = B_WRITE;
+
+		error = dk_translate(dksc, bp);
+		if (error >= 0)
+			break;
+
+		error = dkd->d_discard(dksc->sc_dev,
+			(off_t)bp->b_rawblkno * secsize,
+			(off_t)bp->b_bcount);
+		if (error)
+			break;
 
-	error = dkd->d_discard(dksc->sc_dev,
-		(off_t)bp->b_rawblkno * secsize,
-		(off_t)bp->b_bcount);
+		pos += bp->b_bcount;
+		len -= bp->b_bcount;
+	}
 
 	return error;
 }

Reply via email to