⬢ DragonFlyBSD Kernel Audit
DF-3398 / kpeek.c
← back to finding ↓ download raw
/* kmem peek for DF-3398: resolve ip_fw3_nat_ctx -> cfg_nat -> alias,
 * dump bytes around alias end (the OOB write target). usage: kpeek <cpu> */
#include <sys/types.h>
#include <sys/usched.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>

#define ALIAS_RANGE 64511
#define OFF_ICMP_IN (24 + 2 * (ALIAS_RANGE * 8))
#define CFG_ALIAS_SZ (24 + 3 * (ALIAS_RANGE * 8))

static int fd;
static int
rd(uint64_t addr, void *buf, size_t n)
{
	if (pread(fd, buf, n, (off_t)addr) != (ssize_t)n)
		return -1;
	return 0;
}

int
main(int argc, char **argv)
{
	int cpu = atoi(argv[1]);
	uint64_t ctxaddr, ctx, nat, alias, tgt;
	uint64_t v, i;
	unsigned char b[32];

	fd = open("/dev/kmem", O_RDONLY);
	if (fd < 0) { perror("/dev/kmem"); return 1; }

	/* symbol address passed via argv[2] (from nm) */
	ctxaddr = strtoull(argv[2], NULL, 16) + cpu * 8;
	if (rd(ctxaddr, &ctx, 8)) { perror("read ctx ptr"); return 1; }
	printf("nat_ctx[%d] = 0x%llx\n", cpu, (unsigned long long)ctx);
	if (rd(ctx, &nat, 8)) { perror("read nats"); return 1; }
	printf("nats[0] (cfg_nat) = 0x%llx\n", (unsigned long long)nat);
	if (rd(nat + 8, &alias, 8)) { perror("read alias list"); return 1; }
	printf("alias LIST_FIRST  = 0x%llx\n", (unsigned long long)alias);
	printf("alias size = %d (0x%x), page-aligned: %s\n",
	    CFG_ALIAS_SZ, CFG_ALIAS_SZ,
	    (CFG_ALIAS_SZ % 4096 == 0) ? "yes" : "no");

	/* dump alias head: next, ip, first tcp_in slots */
	for (i = 0; i < 4; i++) {
		rd(alias + i * 8, &v, 8);
		printf("alias+%-4lld = 0x%016llx\n", (long long)i * 8,
		    (unsigned long long)v);
	}

	/* the OOB target for idx=64512: alias + OFF_ICMP_IN + 8*64512 */
	tgt = alias + OFF_ICMP_IN + 8ULL * 64512;
	printf("target(idx=64512) = alias + 0x%llx = 0x%llx\n",
	    (unsigned long long)(OFF_ICMP_IN + 8ULL * 64512),
	    (unsigned long long)tgt);
	if (rd(tgt, b, 16) == 0) {
		int j;
		printf("bytes @target:");
		for (j = 0; j < 16; j++)
			printf(" %02x", b[j]);
		printf("\n");
		memcpy(&v, b, 8);
		printf("qword @target = 0x%016llx\n", (unsigned long long)v);
	} else {
		printf("read @target FAILED (unmapped?)\n");
	}
	return 0;
}