โฌข DragonFlyBSD Kernel Audit
DF-3664 / trigger.c
โ† back to finding โ†“ download raw
/*
 * DF-3664 โ€” bge(4) NVRAM arbitration lock leaked on error paths
 *
 * Trigger (HARDWARE REQUIRED โ€” cannot run on the audit guest):
 *
 *   bge_nvram_getbyte() (sys/dev/netif/bge/if_bge.c:544-592) implements
 *   the NVRAM software-arbitration handshake for BCM5906 (the only chip
 *   for which bge_read_nvram proceeds, if_bge.c:603-604; reached at
 *   attach time via bge_get_eaddr_nvram, if_bge.c:4977-4985):
 *
 *     551:  CSR_WRITE_4(sc, BGE_NVRAM_SWARB, BGE_NVRAMSWARB_SET1);  <- REQ
 *     552:  for (i = 0; i < 8000; i++) { if (GNT1) break; DELAY(20); }
 *     557:  if (i == 8000)
 *     558:      return (1);        <- BUG #1: request bit still latched,
 *                                      no BGE_NVRAMSWARB_CLR1 written
 *     561:  access = CSR_READ_4(sc, BGE_NVRAM_ACCESS);
 *     562:  CSR_WRITE_4(sc, BGE_NVRAM_ACCESS, access|BGE_NVRAMACC_ENABLE);
 *     566:  for (i = 0; i < BGE_TIMEOUT*10; i++) { ... }
 *     574:  if (i == BGE_TIMEOUT * 10) {
 *     575:      if_printf(..., "nvram read timed out\n");
 *     576:      return (1);        <- BUG #2: SWARB lock STILL HELD and
 *                                      BGE_NVRAMACC_ENABLE left set; the
 *                                      success path restores both
 *                                      (584-589)
 *     585:  CSR_WRITE_4(sc, BGE_NVRAM_ACCESS, access);   <- paired
 *     588:  CSR_WRITE_4(sc, BGE_NVRAM_SWARB, BGE_NVRAMSWARB_CLR1); <- paired
 *
 *   Contrast with the bnx sibling DF-3640, whose reset path never
 *   released the lock at all; bge pairs acquire/release on the success
 *   path but leaks both the arbitration request and the access-enable
 *   bit on its two timeout paths.
 *
 *   Impact: after a single NVRAM read timeout (device already
 *   malfunctioning), the driver holds the flash arbiter for its whole
 *   lifetime and leaves the NVRAM access window enabled, locking the
 *   ASF/management firmware (and other agents sharing the arbiter) out
 *   of NVRAM.  Device-side functional denial of service only โ€” no host
 *   memory-safety impact.
 *
 *   On real hardware the reproduction is:
 *     1. Attach a BCM5906-based NIC (bge0) whose NVRAM state machine
 *        stalls (or force the read-complete bit to never assert).
 *     2. bge_get_eaddr_nvram -> bge_read_nvram -> bge_nvram_getbyte
 *        times out and returns without releasing SWARB/ACCESS.
 *     3. Observe the management firmware can no longer arbitrate for
 *        NVRAM (BGE_NVRAM_SWARB GNT never grants to other requesters).
 *
 *   The audit QEMU guest has virtio-net only (run.log: NO_BROADCOM_
 *   DEVICE); bge is compiled into the kernel (kldstat -v: pci/if_bge)
 *   but bge_attach/bge_nvram_getbyte are unreachable there, so this
 *   trigger CANNOT be exercised on it.  See VERDICT.md.
 */
#include <sys/types.h>
#include <stdio.h>

int
main(void)
{
	fprintf(stderr,
	    "DF-3664: this trigger requires bge(4) hardware (BCM5906) with\n"
	    "a stalling NVRAM state machine.  On such a system, an attach-time\n"
	    "eeprom/nvram read timeout leaves BGE_NVRAM_SWARB SET1 latched and\n"
	    "BGE_NVRAMACC_ENABLE set forever; verify via the management\n"
	    "firmware failing to arbitrate for NVRAM afterwards.\n");
	return 0;
}