comparison fuzz/fuzz-sshpacketmutator.c @ 1767:3e1e1f82eba6

Preallocate memory for sshpacketmutator. Add fuzzer-client_mutator_nomaths
author Matt Johnston <matt@ucc.asn.au>
date Mon, 26 Oct 2020 23:31:24 +0800
parents b14e0a19bcbe
children af9ed0815818
comparison
equal deleted inserted replaced
1766:b14e0a19bcbe 1767:3e1e1f82eba6
1 #include "fuzz.h" 1 #include "fuzz.h"
2 #include "dbutil.h" 2 #include "dbutil.h"
3 3
4 size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); 4 size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
5 5
6 /* out_packets an array of num_out_packets*buffer, each of size RECV_MAX_PACKET_LEN */
6 static void fuzz_get_packets(buffer *inp, buffer **out_packets, unsigned int *num_out_packets) { 7 static void fuzz_get_packets(buffer *inp, buffer **out_packets, unsigned int *num_out_packets) {
7 /* Skip any existing banner. Format is 8 /* Skip any existing banner. Format is
8 SSH-protoversion-softwareversion SP comments CR LF 9 SSH-protoversion-softwareversion SP comments CR LF
9 so we look for SSH-2. then a subsequent LF */ 10 so we look for SSH-2. then a subsequent LF */
10 unsigned char* version = memmem(inp->data, inp->len, "SSH-2.", strlen("SSH-2.")); 11 unsigned char* version = memmem(inp->data, inp->len, "SSH-2.", strlen("SSH-2."));
31 /* End of output */ 32 /* End of output */
32 break; 33 break;
33 } 34 }
34 35
35 /* Read packet */ 36 /* Read packet */
36 //printf("at %d\n", inp->pos);
37 //printhex("lenget", buf_getptr(inp, 48), 48);
38 unsigned int packet_len = buf_getint(inp); 37 unsigned int packet_len = buf_getint(inp);
39 // printf("len %u\n", packet_len);
40 if (packet_len > RECV_MAX_PACKET_LEN-4) { 38 if (packet_len > RECV_MAX_PACKET_LEN-4) {
41 /* Bad length, try skipping a single byte */ 39 /* Bad length, try skipping a single byte */
42 buf_decrpos(inp, 3); 40 buf_decrpos(inp, 3);
43 continue; 41 continue;
44 } 42 }
45 packet_len = MIN(packet_len, inp->len - inp->pos); 43 packet_len = MIN(packet_len, inp->len - inp->pos);
46 44
47 /* Copy to output buffer */ 45 /* Copy to output buffer. We're reusing buffers */
48 buffer* new_packet = buf_new(RECV_MAX_PACKET_LEN); 46 buffer* new_packet = out_packets[*num_out_packets];
47 (*num_out_packets)++;
48 buf_setlen(new_packet, 0);
49 buf_putint(new_packet, packet_len); 49 buf_putint(new_packet, packet_len);
50 buf_putbytes(new_packet, buf_getptr(inp, packet_len), packet_len); 50 buf_putbytes(new_packet, buf_getptr(inp, packet_len), packet_len);
51 buf_incrpos(inp, packet_len); 51 buf_incrpos(inp, packet_len);
52 // printf("incr pos %d to %d\n", packet_len, inp->pos);
53
54 out_packets[*num_out_packets] = new_packet;
55 (*num_out_packets)++;
56 } 52 }
57 } 53 }
58 54
59 /* Mutate in-place */ 55 /* Mutate in-place */
60 void buf_llvm_mutate(buffer *buf) { 56 void buf_llvm_mutate(buffer *buf) {
76 static const char* FIXED_VERSION = "SSH-2.0-dbfuzz\r\n"; 72 static const char* FIXED_VERSION = "SSH-2.0-dbfuzz\r\n";
77 static const size_t MAX_FUZZ_PACKETS = 500; 73 static const size_t MAX_FUZZ_PACKETS = 500;
78 /* XXX This might need tuning */ 74 /* XXX This might need tuning */
79 static const size_t MAX_OUT_SIZE = 50000; 75 static const size_t MAX_OUT_SIZE = 50000;
80 76
77 /* Persistent buffers to avoid constant allocations */
78 static buffer *oup;
79 static buffer *alloc_packetA;
80 static buffer *alloc_packetB;
81 buffer* packets1[MAX_FUZZ_PACKETS];
82 buffer* packets2[MAX_FUZZ_PACKETS];
83
84 /* Allocate buffers once at startup.
85 'constructor' here so it runs before dbmalloc's interceptor */
86 static void alloc_static_buffers() __attribute__((constructor));
87 static void alloc_static_buffers() {
88
89 int i;
90 oup = buf_new(MAX_OUT_SIZE);
91 alloc_packetA = buf_new(RECV_MAX_PACKET_LEN);
92 alloc_packetB = buf_new(RECV_MAX_PACKET_LEN);
93
94 for (i = 0; i < MAX_FUZZ_PACKETS; i++) {
95 packets1[i] = buf_new(RECV_MAX_PACKET_LEN);
96 }
97 for (i = 0; i < MAX_FUZZ_PACKETS; i++) {
98 packets2[i] = buf_new(RECV_MAX_PACKET_LEN);
99 }
100 }
101
81 size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, 102 size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
82 size_t MaxSize, unsigned int Seed) { 103 size_t MaxSize, unsigned int Seed) {
83 104
84 /* Avoid some allocations */ 105 buf_setlen(alloc_packetA, 0);
85 /* XXX perhaps this complication isn't worthwhile */ 106 buf_setlen(alloc_packetB, 0);
86 static buffer buf_oup, buf_alloc_packetA, buf_alloc_packetB; 107 buf_setlen(oup, 0);
87 static buffer *oup = &buf_oup;
88 static buffer *alloc_packetA = &buf_alloc_packetA;
89 static buffer *alloc_packetB = &buf_alloc_packetB;
90 static int once = 1;
91 if (once) {
92 once = 0;
93 // malloc doesn't get intercepted by epoch deallocator
94 oup->size = MAX_OUT_SIZE;
95 alloc_packetA->size = RECV_MAX_PACKET_LEN;
96 alloc_packetB->size = RECV_MAX_PACKET_LEN;
97 oup->data = malloc(oup->size);
98 alloc_packetA->data = malloc(alloc_packetA->size);
99 alloc_packetB->data = malloc(alloc_packetB->size);
100 }
101 alloc_packetA->pos = 0;
102 alloc_packetA->len = 0;
103 alloc_packetB->pos = 0;
104 alloc_packetB->len = 0;
105 oup->pos = 0;
106 oup->len = 0;
107 108
108 unsigned int i; 109 unsigned int i;
109 unsigned short randstate[3] = {0,0,0}; 110 unsigned short randstate[3] = {0,0,0};
110 memcpy(randstate, &Seed, sizeof(Seed)); 111 memcpy(randstate, &Seed, sizeof(Seed));
111 112
119 120
120 buffer inp_buf = {.data = Data, .size = Size, .len = Size, .pos = 0}; 121 buffer inp_buf = {.data = Data, .size = Size, .len = Size, .pos = 0};
121 buffer *inp = &inp_buf; 122 buffer *inp = &inp_buf;
122 123
123 /* Parse packets */ 124 /* Parse packets */
124 buffer* packets[MAX_FUZZ_PACKETS];
125 unsigned int num_packets = MAX_FUZZ_PACKETS; 125 unsigned int num_packets = MAX_FUZZ_PACKETS;
126 buffer **packets = packets1;
126 fuzz_get_packets(inp, packets, &num_packets); 127 fuzz_get_packets(inp, packets, &num_packets);
127 // printf("%d packets\n", num_packets);
128 128
129 if (num_packets == 0) { 129 if (num_packets == 0) {
130 // gotta do something 130 // gotta do something
131 memcpy(Data, FIXED_VERSION, MIN(strlen(FIXED_VERSION), MaxSize)); 131 memcpy(Data, FIXED_VERSION, MIN(strlen(FIXED_VERSION), MaxSize));
132 return LLVMFuzzerMutate(Data, Size, MaxSize); 132 return LLVMFuzzerMutate(Data, Size, MaxSize);
138 138
139 /* Iterate output */ 139 /* Iterate output */
140 for (i = 0; i < num_packets+1; i++) { 140 for (i = 0; i < num_packets+1; i++) {
141 // These are pointers to output 141 // These are pointers to output
142 buffer *out_packetA = NULL, *out_packetB = NULL; 142 buffer *out_packetA = NULL, *out_packetB = NULL;
143 alloc_packetA->pos = 0; 143 buf_setlen(alloc_packetA, 0);
144 alloc_packetA->len = 0; 144 buf_setlen(alloc_packetB, 0);
145 alloc_packetB->pos = 0;
146 alloc_packetB->len = 0;
147 145
148 /* 5% chance each */ 146 /* 5% chance each */
149 const int optA = nrand48(randstate) % 20; 147 const int optA = nrand48(randstate) % 20;
150 if (optA == 0) { 148 if (optA == 0) {
151 /* Copy another */ 149 /* Copy another */
152 unsigned int other = nrand48(randstate) % num_packets; 150 unsigned int other = nrand48(randstate) % num_packets;
153 out_packetA = packets[other]; 151 out_packetA = packets[other];
154 // printf("%d copy another %d\n", i, other);
155 } 152 }
156 if (optA == 1) { 153 if (optA == 1) {
157 /* Mutate another */ 154 /* Mutate another */
158 unsigned int other = nrand48(randstate) % num_packets; 155 unsigned int other = nrand48(randstate) % num_packets;
159 buffer *from = packets[other]; 156 buffer *from = packets[other];
160 buf_putbytes(alloc_packetA, from->data, from->len); 157 buf_putbytes(alloc_packetA, from->data, from->len);
161 out_packetA = alloc_packetA; 158 out_packetA = alloc_packetA;
162 buf_llvm_mutate(out_packetA); 159 buf_llvm_mutate(out_packetA);
163 // printf("%d mutate another %d\n", i, other);
164 } 160 }
165 161
166 if (i < num_packets) { 162 if (i < num_packets) {
167 int optB = nrand48(randstate) % 10; 163 int optB = nrand48(randstate) % 10;
168 if (optB == 1) { 164 if (optB == 1) {
189 if (out_packetB && oup->len + out_packetB->len <= oup->size) { 185 if (out_packetB && oup->len + out_packetB->len <= oup->size) {
190 buf_putbytes(oup, out_packetB->data, out_packetB->len); 186 buf_putbytes(oup, out_packetB->data, out_packetB->len);
191 } 187 }
192 } 188 }
193 189
194 for (i = 0; i < num_packets; i++) {
195 buf_free(packets[i]);
196 }
197
198 size_t ret_len = MIN(MaxSize, oup->len); 190 size_t ret_len = MIN(MaxSize, oup->len);
199 memcpy(Data, oup->data, ret_len); 191 memcpy(Data, oup->data, ret_len);
200 // printhex("mutator done", Data, ret_len); 192 // printhex("mutator done", Data, ret_len);
201 return ret_len; 193 return ret_len;
202 } 194 }
212 buffer inp_buf1 = {.data = (void*)Data1, .size = Size1, .len = Size1, .pos = 0}; 204 buffer inp_buf1 = {.data = (void*)Data1, .size = Size1, .len = Size1, .pos = 0};
213 buffer *inp1 = &inp_buf1; 205 buffer *inp1 = &inp_buf1;
214 buffer inp_buf2 = {.data = (void*)Data2, .size = Size2, .len = Size2, .pos = 0}; 206 buffer inp_buf2 = {.data = (void*)Data2, .size = Size2, .len = Size2, .pos = 0};
215 buffer *inp2 = &inp_buf2; 207 buffer *inp2 = &inp_buf2;
216 208
217 buffer* packets1[MAX_FUZZ_PACKETS];
218 unsigned int num_packets1 = MAX_FUZZ_PACKETS; 209 unsigned int num_packets1 = MAX_FUZZ_PACKETS;
219 fuzz_get_packets(inp1, packets1, &num_packets1); 210 fuzz_get_packets(inp1, packets1, &num_packets1);
220 buffer* packets2[MAX_FUZZ_PACKETS];
221 unsigned int num_packets2 = MAX_FUZZ_PACKETS; 211 unsigned int num_packets2 = MAX_FUZZ_PACKETS;
222 fuzz_get_packets(inp2, packets2, &num_packets2); 212 fuzz_get_packets(inp2, packets2, &num_packets2);
223 213
224 buffer *oup = buf_new(MAX_OUT_SIZE); 214 buf_setlen(oup, 0);
225 /* Put a new banner to output */ 215 /* Put a new banner to output */
226 buf_putbytes(oup, FIXED_VERSION, strlen(FIXED_VERSION)); 216 buf_putbytes(oup, FIXED_VERSION, strlen(FIXED_VERSION));
227 217
228 for (i = 0; i < num_packets1+1; i++) { 218 for (i = 0; i < num_packets1+1; i++) {
229 if (num_packets2 > 0 && nrand48(randstate) % 10 == 0) { 219 if (num_packets2 > 0 && nrand48(randstate) % 10 == 0) {
230 /* 10% chance of taking another packet at each position */ 220 /* 10% chance of taking another packet at each position */
231 int other = nrand48(randstate) % num_packets2; 221 int other = nrand48(randstate) % num_packets2;
222 // printf("inserted other packet %d at %d\n", other, i);
232 buffer *otherp = packets2[other]; 223 buffer *otherp = packets2[other];
233 if (oup->len + otherp->len <= oup->size) { 224 if (oup->len + otherp->len <= oup->size) {
234 buf_putbytes(oup, otherp->data, otherp->len); 225 buf_putbytes(oup, otherp->data, otherp->len);
235 } 226 }
236 } 227 }
240 buf_putbytes(oup, thisp->data, thisp->len); 231 buf_putbytes(oup, thisp->data, thisp->len);
241 } 232 }
242 } 233 }
243 } 234 }
244 235
245 for (i = 0; i < num_packets1; i++) {
246 buf_free(packets1[i]);
247 }
248 for (i = 0; i < num_packets2; i++) {
249 buf_free(packets2[i]);
250 }
251
252 size_t ret_len = MIN(MaxOutSize, oup->len); 236 size_t ret_len = MIN(MaxOutSize, oup->len);
253 memcpy(Out, oup->data, ret_len); 237 memcpy(Out, oup->data, ret_len);
254 buf_free(oup);
255 return ret_len; 238 return ret_len;
256 } 239 }
257 240