DragonFlyBSD Kernel Audit
DF-2675 / ovrdump.c
← back to finding ↓ download raw
/*
 * DF-2675 ovrdump: for buffer slots 0..N, print kvabase, present-PTE count,
 * the buffer's b_loffset (offset 160), int fields equal to 65536
 * (b_bufsize/b_bcount candidates), and the first 48 bytes of physical
 * memory currently mapped at kvabase + MAXBSIZE (the overflow page).
 */
#include <sys/types.h>
#include <err.h>
#include <fcntl.h>
#include <kvm.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define PMASK 0x000FFFFFFFFFF000ULL
#define MAXBSIZE_ 65536

static int memfd;
static uint64_t KPML4;

static int
rdphys(uint64_t pa, void *buf, size_t len)
{
	return (pread(memfd, buf, len, (off_t)pa) == (ssize_t)len);
}

static uint64_t
pteof(uint64_t va)
{
	uint64_t pml4[512], pud[512], pd[512], pt[512];
	int i4, i3, i2;

	i4 = (int)((va >> 39) & 511);
	i3 = (int)((va >> 30) & 511);
	i2 = (int)((va >> 21) & 511);
	if (!rdphys(KPML4, pml4, 4096) || !(pml4[i4] & 1)) return 0;
	if (!rdphys(pml4[i4] & PMASK, pud, 4096) || !(pud[i3] & 1)) return 0;
	if (pud[i3] & 0x80) return 0;
	if (!rdphys(pud[i3] & PMASK, pd, 4096) || !(pd[i2] & 1)) return 0;
	if (pd[i2] & 0x80) return 0;
	if (!rdphys(pd[i2] & PMASK, pt, 4096)) return 0;
	return pt[(va >> 12) & 511];
}

int
main(int argc, char **argv)
{
	kvm_t *kd;
	struct nlist nl[] = { { "_buf" }, { "_KPML4phys" }, { NULL } };
	unsigned char *arr;
	long nbuf, szbuf, n, lim;
	uint64_t bufva;

	kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "ovrdump");
	if (!kd) return 1;
	if (kvm_nlist(kd, nl) != 0) errx(1, "nlist");
	if (kvm_read(kd, nl[1].n_value, &KPML4, 8) != 8) errx(1, "kpml4");
	if (kvm_read(kd, nl[0].n_value, &bufva, 8) != 8) errx(1, "bufptr");
	{
		int v; size_t l = sizeof(v);
		if (sysctlbyname("vfs.nbuf", &v, &l, NULL, 0) < 0) err(1, "nbuf");
		nbuf = v;
		l = sizeof(v);
		if (sysctlbyname("debug.sizeof.buf", &v, &l, NULL, 0) < 0) err(1, "sz");
		szbuf = v;
	}
	kvm_close(kd);

	memfd = open("/dev/mem", O_RDONLY);
	if (memfd < 0) err(1, "/dev/mem");

	arr = malloc(nbuf * szbuf);
	if (!arr) err(1, "malloc");
	kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "ovrdump2");
	if (kvm_read(kd, bufva, arr, nbuf * szbuf) != nbuf * szbuf)
		errx(1, "read array");
	kvm_close(kd);

	lim = (argc > 1) ? atol(argv[1]) : 60;
	for (n = 0; n < nbuf && n < lim; n++) {
		uint64_t kv;
		unsigned char rec[1400];
		memcpy(rec, arr + n * szbuf, szbuf);
		memcpy(&kv, rec + 1024, 8);
		if (kv == 0) continue;
		{
			uint64_t loff = 0;
			int xio_npages, kvasize, i;
			memcpy(&xio_npages, rec + 1056, 4);
			memcpy(&kvasize, rec + 1032, 4);
			if (xio_npages > kvasize / 4096) {
				uint64_t p16;
				char hex[128];
				unsigned char buf[48];
				memcpy(&loff, rec + 176, 8);
				p16 = pteof(kv + MAXBSIZE_) & PMASK;
				memset(buf, 0, sizeof(buf));
				if (p16) rdphys(p16, buf, 48);
				for (i = 0; i < 24; i++)
					snprintf(hex + i*2, 4, "%02x", buf[i]);
				printf("OVRBUF n=%ld kva=%#llx npages=%d kvasize=%d "
				       "loff=%#llx p16phys=%#llx\n    data=%s\n    ascii: ",
				       n, (unsigned long long)kv, xio_npages, kvasize,
				       (unsigned long long)loff,
				       (unsigned long long)p16, hex);
				for (i = 0; i < 48; i++)
					putchar((buf[i] >= 32 && buf[i] < 127) ? buf[i] : '.');
				putchar('\n');
			}
		}
	}
	return 0;
}