On Thu, Jun 05, 2025 at 11:58:26AM +0000, Gerhard Roth wrote: > On Wed, 2025-06-04 at 19:11 +0200, Alexander Bluhm wrote: > > On Mon, May 26, 2025 at 01:05:51PM +0000, Gerhard Roth wrote: > > > Hi Pierre, > > > > > > On Sun, 2025-05-25 at 12:44 +0200, Pierre Pronchery wrote: > > > > ????????????????????????????????????????????????Dear OpenBSD team, > > > > > > > > I would like to bring your attention to the following bug report from > > > > FreeBSD, where I have ported and imported the umb(4) driver recently: > > > > https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=284920 > > > > > > > > The bug report mentions: > > > > > > > > > When processing a message produced by a USB device, umb_decap() > > > > > says: > > > > > > > > > > ptroff = UGETDW(hdr32->dwNdpIndex); > > > > > ...; > > > > > ptr16 = (struct ncm_pointer16 *)(buf + ptroff); > > > > > psig = UGETDW(ptr16->dwSignature); > > > > > > > > > > But ptroff can be any 32-bit value, so the a broken or malicious USB > > > > > device can cause ptr16 to point outside the message buffer. > > > > > > > > And: > > > > > > > > > And later, umb_decap() pulls dlen and doff out of a message sent by > > > > > the USB device, and uses doff to form a pointer without a sanity > > > > > check: > > > > > > > > > > dgram32 = (struct ncm_pointer32_dgram *) > > > > > (buf + ptroff + dgentryoff); > > > > > ...; > > > > > dlen = UGETDW(dgram32->dwDatagramLen); > > > > > doff = UGETDW(dgram32->dwDatagramIndex); > > > > > ...; > > > > > dp = buf + doff; > > > > > ...; > > > > > m = m_devget(dp, dlen, 0, ifp, NULL); > > > > > > > > > > A malicious USB device could cause the wrong memory to be copied, or a > > > > > page fault. > > > > > > > > From my reading of the current version of the umb(4) driver in OpenBSD, > > > > ISTM that you are vulnerable to this issue as well. > > > > > > > > Thoughts? > > > > > > > > HTH, > > > > > > 64bit integers should prevent overlows in the check. > > > Also validate 'ptroff' before using it the first time. > > > > I would prefer to have uint32_t variables for values coming from > > UGETW() and uint64_t for UGETDW().?? Then I don't have to think about > > negative values and sign conversions in all the other comparions. > > > > uint32_t ptrlen, dgentryoff; > > uint64_t blen, ptroff, dlen, doff; > > > > bluhm > > > > Thanks for the review, updated diff below.
Can (int)dlen be negative? I am not an USB expert, but it seems that this length ultimatly comes from sc_rx_bufsz or sc_tx_bufsz. There I see another UGETDW(np.dwNtbInMaxSize) and UGETDW(np.dwNtbOutMaxSize). Do we need a size check in umb_ncm_setup()? And are your casts necessary? The compiler should handle that himself now. Anyway, better than before, OK bluhm@ > Index: sys/dev/usb/if_umb.c > =================================================================== > RCS file: /cvs/src/sys/dev/usb/if_umb.c,v > diff -u -p -u -p -r1.61 if_umb.c > --- sys/dev/usb/if_umb.c 5 Jun 2025 08:22:25 -0000 1.61 > +++ sys/dev/usb/if_umb.c 5 Jun 2025 11:54:00 -0000 > @@ -2407,9 +2407,8 @@ umb_decap(struct umb_softc *sc, struct u > struct ncm_pointer16_dgram *dgram16; > struct ncm_pointer32_dgram *dgram32; > uint32_t hsig, psig; > - int blen; > - int ptrlen, ptroff, dgentryoff; > - uint32_t doff, dlen; > + uint32_t ptrlen, dgentryoff; > + uint64_t blen, ptroff, doff, dlen; > struct mbuf_list ml = MBUF_LIST_INITIALIZER(); > struct mbuf *m; > > @@ -2453,15 +2452,17 @@ umb_decap(struct umb_softc *sc, struct u > goto fail; > } > if (blen != 0 && len < blen) { > - DPRINTF("%s: bad NTB len (%d) for %d bytes of data\n", > + DPRINTF("%s: bad NTB len (%llu) for %d bytes of data\n", > DEVNAM(sc), blen, len); > 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 + ptroff) > goto toosmall; > if (!MBIM_NCM_NTH16_ISISG(psig) && !MBIM_NCM_NTH32_ISISG(psig)) { > DPRINTF("%s: unsupported NCM pointer signature (0x%08x)\n", > @@ -2508,16 +2509,16 @@ umb_decap(struct umb_softc *sc, struct u > /* Terminating zero entry */ > if (dlen == 0 || doff == 0) > break; > - if (len < dlen + doff) { > + if ((uint64_t)len < dlen + doff) { > /* Skip giant datagram but continue processing */ > - DPRINTF("%s: datagram too large (%d @ off %d)\n", > + DPRINTF("%s: datagram too large (%llu @ off %llu)\n", > DEVNAM(sc), dlen, doff); > continue; > } > > dp = buf + doff; > - DPRINTFN(3, "%s: decap %d bytes\n", DEVNAM(sc), dlen); > - m = m_devget(dp, dlen, sizeof(uint32_t)); > + DPRINTFN(3, "%s: decap %llu bytes\n", DEVNAM(sc), dlen); > + m = m_devget(dp, (int)dlen, sizeof(uint32_t)); > if (m == NULL) { > ifp->if_iqdrops++; > continue; > >