git: 82c41c9ffc42 - main - umb: avoid wild pointer dereference in umb_decap()

From: Pierre Pronchery <khorben_at_FreeBSD.org>
Date: Thu, 29 May 2025 13:09:53 UTC
The branch main has been updated by khorben:

URL: https://cgit.FreeBSD.org/src/commit/?id=82c41c9ffc42b8e95eabae7cdc4e0bfbbcad51fb

commit 82c41c9ffc42b8e95eabae7cdc4e0bfbbcad51fb
Author:     Pierre Pronchery <khorben@FreeBSD.org>
AuthorDate: 2025-05-27 00:10:49 +0000
Commit:     Pierre Pronchery <khorben@FreeBSD.org>
CommitDate: 2025-05-29 13:07:57 +0000

    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
---
 sys/dev/usb/net/if_umb.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sys/dev/usb/net/if_umb.c b/sys/dev/usb/net/if_umb.c
index a7d3bb764a2b..5703bc03dd39 100644
--- a/sys/dev/usb/net/if_umb.c
+++ b/sys/dev/usb/net/if_umb.c
@@ -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);