⬢ DragonFlyBSD Kernel Audit
DF-3378 / trigger_mrt6_init.c
← back to finding ↓ download raw
/*
 * DF-3378 PoC: MRT6_INIT argument-length gate uses sizeof(int *) (8 on
 * amd64) instead of sizeof(int) (4) at sys/netinet6/ip6_mroute.c:426.
 *
 * A routing daemon calling the standard KAME API
 *     int v = 1; setsockopt(s, IPPROTO_IPV6, MRT6_INIT, &v, sizeof(v));
 * gets ENOPROTOOPT on 64-bit DragonFly -- the entire IPv6 multicast
 * routing subsystem cannot be enabled by any conforming daemon.
 *
 * Must run as root (raw ICMPv6 socket requires privilege).
 *
 * Expected (stock kernel):
 *     MRT6_INIT(4-byte int arg): rc=-1 errno=42 (Protocol not available)
 *     MRT6_INIT(8-byte arg):     rc=0  errno=0 (Success)
 *
 * Expected (fixed kernel, m_len >= sizeof(int)):
 *     both rc=0
 */
#include <sys/types.h>
#include <sys/param.h>		/* NBBY for ip6_mroute.h */
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netinet6/ip6_mroute.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>

int
main(void)
{
	int s, rc, rc2;
	int v = 1;
	long long w = 1;

	setvbuf(stdout, NULL, _IONBF, 0);

	s = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
	if (s < 0) {
		printf("socket(AF_INET6,SOCK_RAW,IPPROTO_ICMPV6): %s\n",
		    strerror(errno));
		return (1);
	}

	errno = 0;
	rc = setsockopt(s, IPPROTO_IPV6, MRT6_INIT, &v, sizeof(v));
	printf("MRT6_INIT(4-byte int arg): rc=%d errno=%d (%s)\n",
	    rc, errno, strerror(errno));

	errno = 0;
	rc2 = setsockopt(s, IPPROTO_IPV6, MRT6_INIT, &w, sizeof(w));
	printf("MRT6_INIT(8-byte arg):     rc=%d errno=%d (%s)\n",
	    rc2, errno, strerror(errno));

	/*
	 * Baseline stock kernel: rc=-1/errno=42 (the bug) and rc2=0
	 * (8 bytes satisfies the wrong check).  Fixed kernel: rc=0.
	 */
	return (0);
}