--- a/sys/dev/netif/alc/if_alc.c +++ b/sys/dev/netif/alc/if_alc.c @@ -3305,6 +3305,21 @@ nsegs = RRD_RD_CNT(rdinfo); sc->alc_cdata.alc_rxlen = RRD_BYTES(status); + /* + * Do not trust the controller-written frame length: the RRS + * length field is 14 bits wide (up to 16383) while the frame + * was DMA'd into at most nsegs buffers of alc_buf_size bytes + * each. A faulty or malicious controller must not be able to + * hand the network stack an mbuf chain whose m_len / + * m_pkthdr.len describes more data than the clusters actually + * hold (heap OOB read of up to ~14KB past a 2KB cluster), nor + * lengths below ETHER_CRC_LEN (signed underflow in the CRC + * strip below). Drop the frame; the buffers are reused in + * place, same as the CRC/runt error path below. + */ + if (sc->alc_cdata.alc_rxlen > nsegs * sc->alc_buf_size || + sc->alc_cdata.alc_rxlen < ETHER_CRC_LEN) + return; if ((status & (RRD_ERR_SUM | RRD_ERR_LENGTH)) != 0) { /* * We want to pass the following frames to upper