DragonFlyBSD Kernel Audit
DF-1851 / fix.diff
← back to finding ↓ download raw
diff --git a/sys/dev/raid/hptmv/hptproc.c b/sys/dev/raid/hptmv/hptproc.c
--- a/sys/dev/raid/hptmv/hptproc.c
+++ b/sys/dev/raid/hptmv/hptproc.c
@@ -289,19 +289,32 @@
 			/*
 			 * map buffer to kernel.
 			 */
-			if (piop->nInBufferSize+piop->nOutBufferSize > PAGE_SIZE) {
+			/* Per-field bounds + size_t cast to prevent 32-bit
+			 * unsigned wraparound in the sum (FreeBSD-SA-09:11.
+			 * hptmv class). */
+			if (piop->nInBufferSize  > PAGE_SIZE ||
+			    piop->nOutBufferSize > PAGE_SIZE ||
+			    (size_t)piop->nInBufferSize +
+			    (size_t)piop->nOutBufferSize > PAGE_SIZE) {
 				KdPrintE(("User buffer too large\n"));
 				return -EINVAL;
 			}
 
-			ke_area = kmalloc(piop->nInBufferSize+piop->nOutBufferSize, M_DEVBUF, M_NOWAIT);
+			ke_area = kmalloc((size_t)piop->nInBufferSize +
+			    (size_t)piop->nOutBufferSize, M_DEVBUF,
+			    M_NOWAIT | M_ZERO);
 				if (ke_area == NULL) {
 					KdPrintE(("Couldn't allocate kernel mem.\n"));
 					return -EINVAL;
 				}
 
-			if (piop->nInBufferSize)
-				copyin((void*)(ULONG_PTR)piop->lpInBuffer, ke_area, piop->nInBufferSize);
+			if (piop->nInBufferSize) {
+				if (copyin((void*)(ULONG_PTR)piop->lpInBuffer,
+				    ke_area, piop->nInBufferSize) != 0) {
+					kfree(ke_area, M_DEVBUF);
+					return -EINVAL;
+				}
+			}
 
 			/*
 			  * call kernel handler.