DragonFlyBSD Kernel Audit
DF-1606 / df1606_fixed.c
← back to finding ↓ download raw
/*
 * DF-1606 - fixed-logic variant of the cmi_order[128] heap-overflow harness.
 *
 * Applies the same bound check the fix.diff introduces at acpi_hp.c:1180: if
 * cmi_order_size >= nitems(cmi_order), break out of the insert loop instead
 * of writing past the array end. With the check in place, no OOB write
 * occurs even with maxInstance > 128.
 *
 * Build:  cc -O2 -o df1606_fixed df1606_fixed.c
 * Run:    ./df1606_fixed   ; exits 0 if NO OOB write (fix confirmed)
 */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#define CMI_ORDER_N       128
#define CMI_INSTANCES     140
#define CANARY_BYTES      1024

struct acpi_hp_inst_seq_pair {
	uint32_t sequence;
	uint8_t  instance;
	uint8_t  _pad[3];
};

struct fake_softc {
	unsigned char                   header[64];
	int                             cmi_order_size;
	struct acpi_hp_inst_seq_pair    cmi_order[CMI_ORDER_N];
};

static int fake_wmi_seq_counter = 1;

static int
fake_get_cmi_block(uint32_t *sequence)
{
	*sequence = fake_wmi_seq_counter++;
	return 0;
}

#define nitems_local(x) (sizeof((x)) / sizeof((x)[0]))

int
main(void)
{
	unsigned char *block;
	struct fake_softc *sc;
	unsigned char *NEXT_SLOT_CANARY;
	uint32_t sequence;
	uint8_t  instance;
	int maxInstance = CMI_INSTANCES;
	int pos, i, corrupted, first_off;

	block = calloc(1, sizeof(struct fake_softc) + CANARY_BYTES);
	if (block == NULL) {
		fprintf(stderr, "calloc failed\n");
		return 2;
	}
	sc = (struct fake_softc *)block;
	NEXT_SLOT_CANARY = block + sizeof(struct fake_softc);
	memset(NEXT_SLOT_CANARY, 0xAA, CANARY_BYTES);

	/* replicate acpi_hp_hpcmi_read() lines 1171-1204 WITH the fix.diff guard */
	sc->cmi_order_size = 0;
	for (instance = 0; instance < maxInstance; ++instance) {
		if (fake_get_cmi_block(&sequence)) {
			instance = maxInstance;
		} else {
			/* === the fix.diff guard === */
			if (sc->cmi_order_size >= (int)nitems_local(sc->cmi_order)) {
				break;
			}
			pos = sc->cmi_order_size;
			for (i = 0; i < sc->cmi_order_size && i < 127; ++i) {
				if (sc->cmi_order[i].sequence > sequence) {
					pos = i;
					break;
				}
			}
			for (i = sc->cmi_order_size; i > pos; --i) {
				sc->cmi_order[i].sequence = sc->cmi_order[i-1].sequence;
				sc->cmi_order[i].instance = sc->cmi_order[i-1].instance;
			}
			sc->cmi_order[pos].sequence = sequence;
			sc->cmi_order[pos].instance = instance;
			sc->cmi_order_size++;
		}
	}

	corrupted = 0;
	first_off = -1;
	for (i = 0; i < CANARY_BYTES; ++i) {
		if (NEXT_SLOT_CANARY[i] != 0xAA) {
			if (first_off < 0) first_off = i;
			corrupted++;
		}
	}

	printf("maxInstance           = %d\n", maxInstance);
	printf("cmi_order_size after  = %d entries (capped at array bound %d)\n",
	    sc->cmi_order_size, CMI_ORDER_N);
	printf("adjacent-slab canary corrupted bytes = %d\n", corrupted);

	if (corrupted == 0 && sc->cmi_order_size == CMI_ORDER_N) {
		printf("[OK] fix confirmed: bound check stopped the insert at %d; "
		    "no OOB write past cmi_order[127].\n", CMI_ORDER_N);
		free(block);
		return 0;
	}
	printf("[FAIL] OOB still detected (%d bytes) or wrong cap.\n", corrupted);
	free(block);
	return 1;
}