umb: avoid wild pointer dereference in umb_decap()

When processing messages produced by the USB device, umb_decap() trusts
ptroff and later dlen and doff with pointer arithmetic, without
sufficient sanity checks. The resulting pointer address may be outside
of the valid boundary, causing the wrong memory to be copied or a page
fault.

This fix from Gerhard Roth was obtained after coordination upstream with
OpenBSD. It converts the variables to 64-bit integers, which should
mitigate the risk of overflows.

PR:             284920
Reported by:    Robert Morris <rtm@lcs.mit.edu>
Approved by:	philip (mentor)
Sponsored by:   The FreeBSD Foundation
This commit is contained in:
Pierre Pronchery
2025-05-27 02:10:49 +02:00
parent 152bb8e302
commit 82c41c9ffc
+4 -2
View File
@@ -2147,10 +2147,12 @@ umb_decap(struct umb_softc *sc, struct usb_xfer *xfer, int frame)
goto fail;
}
if (len < ptroff)
goto toosmall;
ptr16 = (struct ncm_pointer16 *)(buf + ptroff);
psig = UGETDW(ptr16->dwSignature);
ptrlen = UGETW(ptr16->wLength);
if (len < ptrlen + ptroff)
if ((uint64_t)len < (uint64_t)ptrlen + (uint64_t)ptroff)
goto toosmall;
if (!MBIM_NCM_NTH16_ISISG(psig) && !MBIM_NCM_NTH32_ISISG(psig)) {
DPRINTF("%s: unsupported NCM pointer signature (0x%08x)\n",
@@ -2197,7 +2199,7 @@ umb_decap(struct umb_softc *sc, struct usb_xfer *xfer, int frame)
/* Terminating zero entry */
if (dlen == 0 || doff == 0)
break;
if (len < dlen + doff) {
if ((uint64_t)len < (uint64_t)dlen + (uint64_t)doff) {
/* Skip giant datagram but continue processing */
DPRINTF("%s: datagram too large (%d @ off %d)\n",
DEVNAM(sc), dlen, doff);