⬢ DragonFlyBSD Kernel Audit
DF-3786 / harness_signcard.c
← back to finding ↓ download raw
/*
 * DF-3786 -- BT848_SIGNATURE / signCard() unbounded sig[] bit-set loop
 *           -> OOB read-modify-write up to ~3.8 KiB past the 260-byte
 *              M_IOCTLOPS ioctl buffer (single-bit OR per mapped i2c dev).
 *
 * Harness: exact port of signCard() from sys/dev/video/bktr/bktr_card.c:461-476
 * with an i2c stub that ACKs at the tuner read addresses (0xC1/0xC3 pattern),
 * exactly as any card with a tuner does.
 */
#include <stdio.h>
#include <string.h>

struct eeProm {			/* ioctl_bt848.h:93-97 */
	short offset;
	short count;
	unsigned char bytes[256];
};

/* i2cRead() on a real card: ACKs (returns != ABSENT) for tuner read
 * addresses 0xC1/0xC3 -> (2*x+1) & 0xff in {0xC1, 0xC3} */
static int i2c_stub_read(int addr)
{
	addr &= 0xff;
	return (addr == 0xC1 || addr == 0xC3) ? 0x55 : -1;	/* ABSENT=-1 */
}

/* verbatim port of signCard() (bktr_card.c:461-476) */
static int signCard(int count, unsigned char *sig)
{
	int x;

	for (x = 0; x < 16; ++x)
		sig[x] = 0;

	for (x = 0; x < count; ++x) {
		if (i2c_stub_read((2 * x) + 1) != -1) {
			sig[x / 8] |= (1 << (x % 8));
		}
	}
	return 0;
}

int main(void)
{
	/* 260-byte ioctl arg, canary after it */
	struct { struct eeProm p; unsigned char canary[8192]; } buf;
	int count = 32767;		/* short max, no driver-side bound */
	int i, maxoff = -1;

	memset(&buf, 0, sizeof(buf));
	buf.p.count = (short)count;

	signCard(count, buf.p.bytes);

	for (i = 0; i < 8192; i++)
		if (buf.canary[i] != 0)
			maxoff = i;
	printf("signCard(count=%d): OOB bit-set writes reach ioctl-buffer "
	       "offset %d (allocation: 260 bytes)\n",
	       count, maxoff >= 0 ? 4 + maxoff : -1);
	printf("highest touched index sig[%d] vs bytes[256] boundary\n",
	       maxoff >= 0 ? maxoff : -1);
	printf("CONFIRMED: no bound on count; single-bit OR over ~%d bytes "
	       "past the heap allocation\n", maxoff >= 0 ? maxoff : 0);
	return 0;
}