Mercurial > dropbear
comparison fuzz/fuzz-sshpacketmutator.c @ 1765:b688c884dad7
Fix fuzz-sshpacketmutator to work
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Mon, 26 Oct 2020 22:52:07 +0800 |
parents | 2406a9987810 |
children | b14e0a19bcbe |
comparison
equal
deleted
inserted
replaced
1764:a339b1c4b9f2 | 1765:b688c884dad7 |
---|---|
1 #include "fuzz.h" | 1 #include "fuzz.h" |
2 #include "dbutil.h" | |
2 | 3 |
3 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); |
4 | 5 |
5 static void fuzz_get_packets(buffer *inp, buffer **out_packets, unsigned int *num_out_packets) { | 6 static void fuzz_get_packets(buffer *inp, buffer **out_packets, unsigned int *num_out_packets) { |
6 /* Skip any existing banner. Format is | 7 /* Skip any existing banner. Format is |
9 unsigned char* version = memmem(inp->data, inp->len, "SSH-2.", strlen("SSH-2.")); | 10 unsigned char* version = memmem(inp->data, inp->len, "SSH-2.", strlen("SSH-2.")); |
10 if (version) { | 11 if (version) { |
11 buf_incrpos(inp, version - inp->data); | 12 buf_incrpos(inp, version - inp->data); |
12 unsigned char* newline = memchr(&inp->data[inp->pos], '\n', inp->len - inp->pos); | 13 unsigned char* newline = memchr(&inp->data[inp->pos], '\n', inp->len - inp->pos); |
13 if (newline) { | 14 if (newline) { |
14 buf_incrpos(inp, newline - &inp->data[inp->pos]); | 15 buf_incrpos(inp, newline - &inp->data[inp->pos]+1); |
15 } else { | 16 } else { |
16 /* Give up on any version string */ | 17 /* Give up on any version string */ |
17 buf_setpos(inp, 0); | 18 buf_setpos(inp, 0); |
18 } | 19 } |
19 } | 20 } |
30 /* End of output */ | 31 /* End of output */ |
31 break; | 32 break; |
32 } | 33 } |
33 | 34 |
34 /* Read packet */ | 35 /* Read packet */ |
36 //printf("at %d\n", inp->pos); | |
37 //printhex("lenget", buf_getptr(inp, 48), 48); | |
35 unsigned int packet_len = buf_getint(inp); | 38 unsigned int packet_len = buf_getint(inp); |
36 if (packet_len <= RECV_MAX_PACKET_LEN) { | 39 // printf("len %u\n", packet_len); |
40 if (packet_len > RECV_MAX_PACKET_LEN-4) { | |
37 /* Bad length, try skipping a single byte */ | 41 /* Bad length, try skipping a single byte */ |
38 buf_decrpos(inp, 3); | 42 buf_decrpos(inp, 3); |
39 continue; | 43 continue; |
40 } | 44 } |
41 packet_len = MIN(packet_len, inp->len - inp->pos); | 45 packet_len = MIN(packet_len, inp->len - inp->pos); |
43 /* Copy to output buffer */ | 47 /* Copy to output buffer */ |
44 buffer* new_packet = buf_new(RECV_MAX_PACKET_LEN); | 48 buffer* new_packet = buf_new(RECV_MAX_PACKET_LEN); |
45 buf_putint(new_packet, packet_len); | 49 buf_putint(new_packet, packet_len); |
46 buf_putbytes(new_packet, buf_getptr(inp, packet_len), packet_len); | 50 buf_putbytes(new_packet, buf_getptr(inp, packet_len), packet_len); |
47 buf_incrpos(inp, packet_len); | 51 buf_incrpos(inp, packet_len); |
52 // printf("incr pos %d to %d\n", packet_len, inp->pos); | |
48 | 53 |
49 out_packets[*num_out_packets] = new_packet; | 54 out_packets[*num_out_packets] = new_packet; |
50 (*num_out_packets)++; | 55 (*num_out_packets)++; |
51 } | 56 } |
52 | |
53 } | 57 } |
54 | 58 |
55 /* Mutate in-place */ | 59 /* Mutate in-place */ |
56 void buf_llvm_mutate(buffer *buf) { | 60 void buf_llvm_mutate(buffer *buf) { |
57 /* Position it after packet_length and padding_length */ | 61 /* Position it after packet_length and padding_length */ |
74 /* XXX This might need tuning */ | 78 /* XXX This might need tuning */ |
75 static const size_t MAX_OUT_SIZE = 50000; | 79 static const size_t MAX_OUT_SIZE = 50000; |
76 | 80 |
77 size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, | 81 size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, |
78 size_t MaxSize, unsigned int Seed) { | 82 size_t MaxSize, unsigned int Seed) { |
79 int i; | 83 |
84 /* Avoid some allocations */ | |
85 /* XXX perhaps this complication isn't worthwhile */ | |
86 static buffer buf_oup, buf_alloc_packetA, buf_alloc_packetB; | |
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 unsigned int i; | |
80 unsigned short randstate[3] = {0,0,0}; | 109 unsigned short randstate[3] = {0,0,0}; |
81 memcpy(randstate, &Seed, sizeof(Seed)); | 110 memcpy(randstate, &Seed, sizeof(Seed)); |
82 | 111 |
112 // printhex("mutator input", Data, Size); | |
113 #if 0 | |
83 /* 1% chance straight llvm mutate */ | 114 /* 1% chance straight llvm mutate */ |
84 if (nrand48(randstate) % 100 == 0) { | 115 if (nrand48(randstate) % 100 == 0) { |
85 return LLVMFuzzerMutate(Data, Size, MaxSize); | 116 return LLVMFuzzerMutate(Data, Size, MaxSize); |
86 } | 117 } |
118 #endif | |
87 | 119 |
88 buffer inp_buf = {.data = Data, .size = Size, .len = Size, .pos = 0}; | 120 buffer inp_buf = {.data = Data, .size = Size, .len = Size, .pos = 0}; |
89 buffer *inp = &inp_buf; | 121 buffer *inp = &inp_buf; |
90 | 122 |
91 /* Parse packets */ | 123 /* Parse packets */ |
92 buffer* packets[MAX_FUZZ_PACKETS] = {0}; | 124 buffer* packets[MAX_FUZZ_PACKETS]; |
93 unsigned int num_packets = MAX_FUZZ_PACKETS; | 125 unsigned int num_packets = MAX_FUZZ_PACKETS; |
94 fuzz_get_packets(inp, packets, &num_packets); | 126 fuzz_get_packets(inp, packets, &num_packets); |
127 // printf("%d packets\n", num_packets); | |
95 | 128 |
96 if (num_packets == 0) { | 129 if (num_packets == 0) { |
97 // gotta do something | 130 // gotta do something |
98 memcpy(Data, FIXED_VERSION, MIN(strlen(FIXED_VERSION), MaxSize)); | 131 memcpy(Data, FIXED_VERSION, MIN(strlen(FIXED_VERSION), MaxSize)); |
99 return LLVMFuzzerMutate(Data, Size, MaxSize); | 132 return LLVMFuzzerMutate(Data, Size, MaxSize); |
100 } | 133 } |
101 | 134 |
102 /* Start output */ | 135 /* Start output */ |
103 buffer *oup = buf_new(MAX_OUT_SIZE); | |
104 /* Put a new banner to output */ | 136 /* Put a new banner to output */ |
105 buf_putbytes(oup, FIXED_VERSION, strlen(FIXED_VERSION)); | 137 buf_putbytes(oup, FIXED_VERSION, strlen(FIXED_VERSION)); |
106 | 138 |
107 /* Iterate output */ | 139 /* Iterate output */ |
108 for (i = 0; i < num_packets+1; i++) { | 140 for (i = 0; i < num_packets+1; i++) { |
109 // These are pointers to output | 141 // These are pointers to output |
110 buffer *out_packetA = NULL, *out_packetB = NULL; | 142 buffer *out_packetA = NULL, *out_packetB = NULL; |
111 // These need to be freed | 143 alloc_packetA->pos = 0; |
112 buffer *alloc_packetA = NULL, *alloc_packetB = NULL; | 144 alloc_packetA->len = 0; |
145 alloc_packetB->pos = 0; | |
146 alloc_packetB->len = 0; | |
113 | 147 |
114 /* 5% chance each */ | 148 /* 5% chance each */ |
115 const int optA = nrand48(randstate) % 20; | 149 const int optA = nrand48(randstate) % 20; |
116 const int other = nrand48(randstate) % num_packets; | |
117 if (optA == 0) { | 150 if (optA == 0) { |
118 /* Copy another */ | 151 /* Copy another */ |
119 out_packetA = packets[nrand48(randstate) % num_packets]; | 152 unsigned int other = nrand48(randstate) % num_packets; |
153 out_packetA = packets[other]; | |
154 // printf("%d copy another %d\n", i, other); | |
120 } | 155 } |
121 if (optA == 1) { | 156 if (optA == 1) { |
122 /* Mutate another */ | 157 /* Mutate another */ |
123 alloc_packetA = buf_new(RECV_MAX_PACKET_LEN); | 158 unsigned int other = nrand48(randstate) % num_packets; |
124 buffer *from = packets[nrand48(randstate) % num_packets]; | 159 buffer *from = packets[other]; |
125 buf_putbytes(alloc_packetA, from->data, from->len); | 160 buf_putbytes(alloc_packetA, from->data, from->len); |
126 out_packetA = alloc_packetA; | 161 out_packetA = alloc_packetA; |
127 buf_llvm_mutate(out_packetA); | 162 buf_llvm_mutate(out_packetA); |
128 } | 163 // printf("%d mutate another %d\n", i, other); |
129 | 164 } |
130 /* 10% chance each of mutate or drop */ | 165 |
131 if (i < num_packets) { | 166 if (i < num_packets) { |
132 int optB = nrand48(randstate) % 10; | 167 int optB = nrand48(randstate) % 10; |
133 if (optB == 0) { | |
134 /* Copy as-is */ | |
135 out_packetB = packets[i]; | |
136 } | |
137 if (optB == 1) { | 168 if (optB == 1) { |
169 /* 10% chance of drop */ | |
138 /* Drop it */ | 170 /* Drop it */ |
139 } | 171 // printf("%d drop\n", i); |
140 if (optB == 2) { | 172 } else if (optB <= 6) { |
141 /* Mutate it */ | 173 /* Mutate it, 50% chance */ |
142 alloc_packetB = buf_new(RECV_MAX_PACKET_LEN); | 174 // printf("%d mutate\n", i); |
143 buffer *from = packets[nrand48(randstate) % num_packets]; | 175 buffer *from = packets[nrand48(randstate) % num_packets]; |
144 buf_putbytes(alloc_packetB, from->data, from->len); | 176 buf_putbytes(alloc_packetB, from->data, from->len); |
145 out_packetB = alloc_packetB; | 177 out_packetB = alloc_packetB; |
146 buf_llvm_mutate(out_packetB); | 178 buf_llvm_mutate(out_packetB); |
179 } else { | |
180 /* Copy as-is */ | |
181 out_packetB = packets[i]; | |
182 // printf("%d as-is\n", i); | |
147 } | 183 } |
148 } | 184 } |
149 | 185 |
150 if (out_packetA && oup->len + out_packetA->len <= oup->size) { | 186 if (out_packetA && oup->len + out_packetA->len <= oup->size) { |
151 buf_putbytes(oup, out_packetA->data, out_packetA->len); | 187 buf_putbytes(oup, out_packetA->data, out_packetA->len); |
152 } | 188 } |
153 if (out_packetB && oup->len + out_packetB->len <= oup->size) { | 189 if (out_packetB && oup->len + out_packetB->len <= oup->size) { |
154 buf_putbytes(oup, out_packetB->data, out_packetB->len); | 190 buf_putbytes(oup, out_packetB->data, out_packetB->len); |
155 } | 191 } |
156 if (alloc_packetA) { | |
157 buf_free(alloc_packetA); | |
158 alloc_packetA = NULL; | |
159 } | |
160 if (alloc_packetB) { | |
161 buf_free(alloc_packetB); | |
162 alloc_packetB = NULL; | |
163 } | |
164 } | 192 } |
165 | 193 |
166 for (i = 0; i < num_packets; i++) { | 194 for (i = 0; i < num_packets; i++) { |
167 buf_free(packets[i]); | 195 buf_free(packets[i]); |
168 } | 196 } |
169 | 197 |
170 size_t ret_len = MIN(MaxSize, oup->len); | 198 size_t ret_len = MIN(MaxSize, oup->len); |
171 memcpy(Data, oup->data, ret_len); | 199 memcpy(Data, oup->data, ret_len); |
172 buf_free(oup); | 200 // printhex("mutator done", Data, ret_len); |
173 return ret_len; | 201 return ret_len; |
174 } | 202 } |
175 | 203 |
204 |