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.