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