DragonFlyBSD Kernel Audit
DF-1395 / oce_overflow.c
← back to finding ↓ download raw
/*
 * DF-1395 harness: oce_read_mac_addr firmware-controlled heap overflow.
 *
 * Replicates the EXACT vulnerable logic from:
 *   sys/dev/netif/oce/oce_mbox.c:447-449
 *      mac->size_of_struct = fwcmd->params.rsp.mac.size_of_struct;   // FW u16, unchecked
 *      bcopy(&fwcmd->params.rsp.mac.mac_addr[0], &mac->mac_addr[0],
 *            mac->size_of_struct);                                   // overflow sink
 *
 * Struct layout copied verbatim from sys/dev/netif/oce/oce_hw.h:1051-1053:
 *   struct mac_address_format {
 *       uint16_t size_of_struct;
 *       uint8_t  mac_addr[6];        // <-- 6-byte destination
 *   };
 *
 * In the kernel, `mac` is a field embedded in the device softc (POCE_SOFTC),
 * immediately followed by bsmbx (DMA ptr), bmbx_lock, wq[], rq[], cq[], eq[].
 * A malicious/buggy OneConnect HBA firmware returning size_of_struct > 6 makes
 * the bcopy write past mac_addr[6] into those softc fields -> heap overflow.
 *
 * This harness cannot attach real OneConnect hardware on the QEMU guest, so it
 * proves the primitive deterministically: a FW-controlled size_of_struct > 6
 * overflows the destination buffer. The canary field stands in for the adjacent
 * softc fields that get corrupted in the real kernel.
 *
 * Build:  cc -O2 -o oce_overflow oce_overflow.c
 * Run:    ./oce_overflow
 * Expected: "OVERFLOW CONFIRMED" with the canary overwritten by FW bytes.
 */
#include <stdio.h>
#include <string.h>
#include <stdint.h>

/* ---- verbatim from sys/dev/netif/oce/oce_hw.h:1051-1053 ---- */
struct mac_address_format {
	uint16_t size_of_struct;
	uint8_t  mac_addr[6];
};

/* Replicate the softc embedding: mac field followed by adjacent fields.
 * In the real POCE_SOFTC these are bsmbx (bus_dma_tag), locks, ring ptrs. */
struct softc_fragment {
	struct mac_address_format mac;   /* offset 0: 2 + 6 = 8 bytes */
	uint8_t  adjacent_softc[64];     /* stands in for bsmbx/bmbx_lock/wq/rq/cq/eq */
};

/* Firmware response buffer (attacker/malicious-FW controlled). In the real
 * mailbox it is fwcmd->params.rsp.mac.mac_addr[6] followed by whatever the FW
 * chooses to place there. We model an oversized FW payload. */
struct fw_response {
	struct mac_address_format mac;        /* FW sets size_of_struct here */
	uint8_t  fw_payload[256];             /* attacker bytes FW delivers */
};

#define CANARY 0xAA

int
main(void)
{
	struct softc_fragment sc;
	struct fw_response fw;
	uint16_t fw_size;

	/* Setup: clean destination, mark adjacent softc fields with a canary. */
	memset(&sc, 0, sizeof(sc));
	memset(sc.adjacent_softc, CANARY, sizeof(sc.adjacent_softc));

	/* Malicious firmware: set size_of_struct well beyond 6.
	 * The field is a uint16_t -> max 65535. We use a representative 0x40. */
	fw_size = 0x0040; /* 64 bytes */
	fw.mac.size_of_struct = fw_size;
	/* Fill the FW source with a recognizable pattern. */
	memset(fw.mac.mac_addr, 0x11, 6);
	memset(fw.fw_payload, 0x22, sizeof(fw.fw_payload));

	printf("DF-1395 oce_read_mac_addr primitive demonstration\n");
	printf("mac->mac_addr capacity: %zu bytes (sizeof mac_addr)\n",
	    sizeof(sc.mac.mac_addr));
	printf("FW-controlled size_of_struct = %u (0x%x)\n", fw_size, fw_size);

	/* ---- EXACT vulnerable logic (oce_mbox.c:447-449) ---- */
	sc.mac.size_of_struct = fw.mac.size_of_struct;          /* line 447 */
	/* bcopy(src=fw mac_addr, dst=sc mac_addr, len=size_of_struct) */
	memcpy(&sc.mac.mac_addr[0],                             /* line 448-449 */
	    &fw.mac.mac_addr[0], sc.mac.size_of_struct);

	/* Inspect the damage. */
	int overflow = (fw_size > sizeof(sc.mac.mac_addr));
	int canary_hit = 0;
	for (size_t i = 0; i < sizeof(sc.adjacent_softc) && i + sizeof(sc.mac.mac_addr) < fw_size; i++) {
		if (sc.adjacent_softc[i] != CANARY) { canary_hit = 1; break; }
	}

	printf("bytes written into mac_addr region: %u\n", fw_size);
	printf("overflow past mac_addr[6]: %s\n",
	    overflow ? "YES -> into adjacent softc fields" : "no");
	printf("adjacent softc canary corrupted: %s\n", canary_hit ? "YES" : "no");
	printf("first 24 bytes after mac_addr (adjacent_softc): ");
	for (size_t i = 0; i < 24; i++) printf("%02x", sc.adjacent_softc[i]);
	printf("\n");

	if (overflow && canary_hit) {
		printf("\nOVERFLOW CONFIRMED: FW-controlled size_of_struct (%u) bypassed the "
		       "6-byte mac_addr and corrupted adjacent softc fields.\n", fw_size);
		printf("On real OneConnect HW this corrupts bsmbx/bmbx_lock/wq/rq/cq/eq -> "
		       "heap corruption (panic or worse).\n");
		return 0;
	}
	fprintf(stderr, "ERROR: overflow not observed\n");
	return 1;
}