Mercurial > dropbear
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 |