/*
 * DF-4231 trigger -- annotated hardware-precondition probe.
 *
 * BUG (source-certain): txp_rx_reclaim() in sys/dev/netif/txp/if_txp.c
 * stamps the device-fed frame length into the receive cluster mbuf
 * without any bound:
 *
 *   if_txp.c:676   m->m_pkthdr.len = m->m_len = rxd->rx_len;
 *                  // rxd->rx_len is 'volatile u_int16_t' inside the
 *                  // DMA-shared rx descriptor ring (if_txpreg.h:263),
 *                  // i.e. fully controlled by the Typhoon firmware
 *                  // (RX ring is in sc_ldata, DMA-coherent with the NIC).
 *
 *   if_txp.c:688-704 (__STRICT_ALIGNMENT is #defined at if_txp.c:85, so
 *                  this path is always compiled):
 *     mnew <- MGETHDR; if (m->m_len > MHLEN-2) mnew <- MCLGET  // 2048B cluster
 *     m_copydata(m, 0, m->m_pkthdr.len, mtod(mnew, void *));
 *
 * m_copydata() (sys/kern/uipc_mbuf.c:1671) copies
 *     count = min(m->m_len - off, len) = min(rx_len, rx_len) = rx_len
 * bytes in one bcopy:  rx_len bytes READ from the 2048-byte source
 * cluster and rx_len bytes WRITTEN into the 2048-byte destination
 * cluster.  For any rx_len > MCLBYTES (2048) both the read and the
 * write run past the end of an mbuf cluster; rx_len is a u_int16_t, so
 * a faulty/malicious 3c990 firmware can overrun the destination cluster
 * by up to 63531 bytes (contents = adjacent source-cluster heap bytes).
 * No KASSERT fires: the source mbuf really does have m_len == rx_len
 * (the driver itself stamped it), so m_copydata's chain walk succeeds.
 *
 * The driver only ever *tells* the firmware to cap frames at
 * TXP_MAX_PKTLEN (2048, if_txp.c:263/'TXP_CMD_MAX_PKT_SIZE_WRITE'), it
 * never *verifies* received lengths against it.
 *
 * PRECONDITION: a 3Com 3c990 (Typhoon, PCI 10b7:990x) whose firmware
 * writes rx_len > 2048 into a receive descriptor.  This is reachable
 * only by the device itself (malicious/faulty firmware, or a
 * passthrough-assigned device attacking the host).  No syscall path
 * can forge it.
 *
 * This program just proves, on the live audit guest, that the driver is
 * present in the running kernel while no 3c990 device exists -- i.e.
 * the audit guest cannot exercise this path (honest inconclusive).
 */
#include <stdio.h>
#include <stdlib.h>

int
main(void)
{
	printf("DF-4231: txp_rx_reclaim() trusts NIC-fed rxd->rx_len\n");
	printf("  sink : if_txp.c:676 m->m_len = rxd->rx_len (u_int16, DMA)\n");
	printf("  sink : if_txp.c:704 m_copydata(m, 0, m->m_pkthdr.len, mtod(mnew))\n");
	printf("  bound: none vs MCLBYTES(2048); overflow up to 63531 bytes past\n");
	printf("         the destination cluster, plus equal-size OOB read of the\n");
	printf("         source cluster.\n");
	printf("  needs: 3c990 Typhoon firmware lying about rx_len (hardware)\n");
	return (0);
}
