⬢ DragonFlyBSD Kernel Audit
DF-2253 / harness_hexncpy.c
← back to finding ↓ download raw
/*
 * ==========================================================================
 * DF-2252 / DF-2253 audit verification harness (GUEST-ONLY, NOT FOR UPSTREAM)
 *
 * Compiled into the kernel by appending to sys/libkern/hexncpy.c so that it
 * links against the REAL production hexncpy() in the same translation unit.
 * Runtime kldload GPFs this guest, so the harness is built into the kernel
 * via `make nativekernel`.
 *
 * Trigger (root):  sysctl kern.df_hexncpy=1   -> canary/output matrix
 *                  sysctl kern.df_hexncpy=2   -> m_print() with a legal
 *                                                zero-m_len mbuf in the chain
 * Output goes to console + msgbuf (dmesg / serial log), lines prefixed DFTEST.
 * ==========================================================================
 */
#include <sys/kernel.h>
#include <sys/sysctl.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>

static int df_hexncpy_run(int mode);

static int
sysctl_df_hexncpy(SYSCTL_HANDLER_ARGS)
{
	int error, mode = 0;

	error = sysctl_handle_int(oidp, &mode, 0, req);
	if (error != 0 || req->newptr == NULL)
		return (error);
	return (df_hexncpy_run(mode));
}

SYSCTL_PROC(_kern, OID_AUTO, df_hexncpy, (CTLTYPE_INT | CTLFLAG_RW),
	    0, 0, sysctl_df_hexncpy, "I",
	    "DF-2252/DF-2253 hexncpy audit harness");

#define DF_CANARY	0xAA

static int
df_hexncpy_run(int mode)
{
	u_char inbuf[8] = { 0xde, 0xad, 0xbe, 0xef, 0x12, 0x34, 0x56, 0x78 };
	u_char hrd1244[2] = { 0x12, 0x34 };	/* ar_hrd wire bytes for 0x1234 */
	u_char *region;
	char *outb;
	int i, underflows = 0;

	if (mode == 2) {
		/* m_print() path: legal zero-m_len mbuf leading the chain */
		struct mbuf *mh, *m2;

		mh = m_gethdr(M_WAITOK, MT_DATA);
		m2 = m_get(M_WAITOK, MT_DATA);
		if (mh == NULL || m2 == NULL)
			return (ENOMEM);
		mh->m_pkthdr.len = 8;
		mh->m_len = 0;			/* legal: empty leading mbuf */
		m2->m_len = 8;
		mh->m_next = m2;
		kprintf("DFTEST M1 m_print begin (pkthdr.len=8, m_len=0 lead)\n");
		m_print(mh);
		kprintf("DFTEST M1 m_print returned\n");
		m_freem(mh);
		return (0);
	}
	if (mode != 1)
		return (EINVAL);

	/*
	 * Canary-guarded matrix: kmalloc 32 bytes, all 0xAA, hand hexncpy
	 * &region[16] as the destination.  Any write to region[15] is a
	 * 1-byte underflow before the caller buffer (DF-2252).
	 */
	region = kmalloc(32, M_TEMP, M_WAITOK | M_ZERO);
	outb = (char *)&region[16];

	for (i = 0; i < 32; i++)
		region[i] = DF_CANARY;

	kprintf("DFTEST C1 sep=\"-\" inlen=4 outlen=12 (control)\n");
	kprintf("DFTEST C1 canary_before=0x%02x\n", region[15]);
	kprintf("DFTEST C1 out=[%s]\n", hexncpy(inbuf, 4, outb, 12, "-"));
	kprintf("DFTEST C1 canary_after=0x%02x\n", region[15]);
	underflows += (region[15] != DF_CANARY);
	for (i = 0; i < 32; i++)
		region[i] = DF_CANARY;

	kprintf("DFTEST C2 inlen=0 outlen=12 sep=\"-\" (DF-2252 core)\n");
	kprintf("DFTEST C2 canary_before=0x%02x\n", region[15]);
	hexncpy(inbuf, 0, outb, 12, "-");
	kprintf("DFTEST C2 canary_after=0x%02x buf0=0x%02x\n",
	    region[15], region[16]);
	underflows += (region[15] != DF_CANARY);
	for (i = 0; i < 32; i++)
		region[i] = DF_CANARY;

	kprintf("DFTEST C3 inlen=-1 outlen=12 sep=\"-\" (DF-2252 core)\n");
	kprintf("DFTEST C3 canary_before=0x%02x\n", region[15]);
	hexncpy(inbuf, -1, outb, 12, "-");
	kprintf("DFTEST C3 canary_after=0x%02x buf0=0x%02x\n",
	    region[15], region[16]);
	underflows += (region[15] != DF_CANARY);
	for (i = 0; i < 32; i++)
		region[i] = DF_CANARY;

	kprintf("DFTEST C4 sep=NULL inlen=6 outlen=18 (DF-2253 generic)\n");
	kprintf("DFTEST C4 out=[%s]\n", hexncpy(inbuf, 6, outb, 18, NULL));
	kprintf("DFTEST C4 canary_after=0x%02x\n", region[15]);
	underflows += (region[15] != DF_CANARY);
	for (i = 0; i < 32; i++)
		region[i] = DF_CANARY;

	kprintf("DFTEST C5 if_ether.c:643 shape inlen=2 outlen=5 sep=NULL\n");
	kprintf("DFTEST C5 out=[%s]\n", hexncpy(hrd1244, 2, outb, 5, NULL));
	kprintf("DFTEST C5 canary_after=0x%02x\n", region[15]);
	underflows += (region[15] != DF_CANARY);
	for (i = 0; i < 32; i++)
		region[i] = DF_CANARY;

	kprintf("DFTEST C6 mly.c:1344 shape inlen=4 outlen=12 sep=NULL\n");
	kprintf("DFTEST C6 out=[%s]\n", hexncpy(inbuf, 4, outb, 12, NULL));
	kprintf("DFTEST C6 canary_after=0x%02x\n", region[15]);
	underflows += (region[15] != DF_CANARY);

	kfree(region, M_TEMP);
	kprintf("DFTEST matrix done underflow_canary_hits=%d\n", underflows);
	return (0);
}