1 #include <cstddef>
2 #include <cstdint>
3
4 #include <fuzzing/datasource/datasource.hpp>
5 #include <fuzzing/memory.hpp>
6
7 #include "FLAC++/decoder.h"
8
Get(const uint64_t id)9 template <> FLAC__MetadataType fuzzing::datasource::Base::Get<FLAC__MetadataType>(const uint64_t id) {
10 (void)id;
11 switch ( Get<uint8_t>() ) {
12 case 0:
13 return FLAC__METADATA_TYPE_STREAMINFO;
14 case 1:
15 return FLAC__METADATA_TYPE_PADDING;
16 case 2:
17 return FLAC__METADATA_TYPE_APPLICATION;
18 case 3:
19 return FLAC__METADATA_TYPE_SEEKTABLE;
20 case 4:
21 return FLAC__METADATA_TYPE_VORBIS_COMMENT;
22 case 5:
23 return FLAC__METADATA_TYPE_CUESHEET;
24 case 6:
25 return FLAC__METADATA_TYPE_PICTURE;
26 case 7:
27 return FLAC__METADATA_TYPE_UNDEFINED;
28 case 8:
29 return FLAC__MAX_METADATA_TYPE;
30 default:
31 return FLAC__METADATA_TYPE_STREAMINFO;
32 }
33 }
34
35 namespace FLAC {
36 namespace Decoder {
37 class FuzzerStream : public Stream {
38 private:
39 fuzzing::datasource::Datasource& ds;
40 public:
FuzzerStream(fuzzing::datasource::Datasource & dsrc)41 FuzzerStream(fuzzing::datasource::Datasource& dsrc) :
42 Stream(), ds(dsrc) { }
43
read_callback(FLAC__byte buffer[],size_t * bytes)44 ::FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], size_t *bytes) override {
45 try {
46 const size_t maxCopySize = *bytes;
47
48 if ( maxCopySize > 0 ) {
49 /* memset just to test if this overwrites anything, and triggers ASAN */
50 memset(buffer, 0, maxCopySize);
51 }
52
53 const auto data = ds.GetData(0);
54 const auto dataSize = data.size();
55 const auto copySize = std::min(maxCopySize, dataSize);
56
57 if ( copySize > 0 ) {
58 memcpy(buffer, data.data(), copySize);
59 }
60
61 *bytes = copySize;
62
63 return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
64 } catch ( ... ) {
65 return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
66 }
67 }
68
write_callback(const::FLAC__Frame * frame,const FLAC__int32 * const buffer[])69 ::FLAC__StreamDecoderWriteStatus write_callback(const ::FLAC__Frame *frame, const FLAC__int32 * const buffer[]) override {
70 {
71 fuzzing::memory::memory_test(&(frame->header), sizeof(frame->header));
72 fuzzing::memory::memory_test(&(frame->footer), sizeof(frame->footer));
73 }
74
75 {
76 const auto numChannels = get_channels();
77 const size_t bytesPerChannel = frame->header.blocksize * sizeof(FLAC__int32);
78 for (size_t i = 0; i < numChannels; i++) {
79 fuzzing::memory::memory_test(buffer[i], bytesPerChannel);
80 }
81 }
82
83 try {
84 if ( ds.Get<bool>() == true ) {
85 return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
86 }
87 } catch ( ... ) { }
88 return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
89 }
90
error_callback(::FLAC__StreamDecoderErrorStatus status)91 void error_callback(::FLAC__StreamDecoderErrorStatus status) override {
92 fuzzing::memory::memory_test(status);
93 }
94
metadata_callback(const::FLAC__StreamMetadata * metadata)95 void metadata_callback(const ::FLAC__StreamMetadata *metadata) override {
96 fuzzing::memory::memory_test(metadata->type);
97 fuzzing::memory::memory_test(metadata->is_last);
98 fuzzing::memory::memory_test(metadata->length);
99 fuzzing::memory::memory_test(metadata->data);
100 }
101
seek_callback(FLAC__uint64 absolute_byte_offset)102 ::FLAC__StreamDecoderSeekStatus seek_callback(FLAC__uint64 absolute_byte_offset) override {
103 fuzzing::memory::memory_test(absolute_byte_offset);
104
105 try {
106 if ( ds.Get<bool>() == true ) {
107 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
108 } else {
109 return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
110 }
111 } catch ( ... ) {
112 return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
113 }
114 }
115 #if 0
116 ::FLAC__StreamDecoderTellStatus tell_callback(FLAC__uint64 *absolute_byte_offset) override {
117 fuzzing::memory::memory_test(*absolute_byte_offset);
118
119 try {
120 if ( ds.Get<bool>() == true ) {
121 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
122 } else {
123 return FLAC__STREAM_DECODER_TELL_STATUS_ERROR;
124 }
125 } catch ( ... ) {
126 return FLAC__STREAM_DECODER_TELL_STATUS_OK;
127 }
128 }
129
130 ::FLAC__StreamDecoderLengthStatus length_callback(FLAC__uint64 *stream_length) override {
131 fuzzing::memory::memory_test(*stream_length);
132
133 try {
134 if ( ds.Get<bool>() == true ) {
135 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
136 } else {
137 return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR;
138 }
139 } catch ( ... ) {
140 return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
141 }
142 }
143 #endif
144 };
145 }
146 }
147
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)148 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
149 fuzzing::datasource::Datasource ds(data, size);
150 FLAC::Decoder::FuzzerStream decoder(ds);
151
152 try {
153 {
154 ::FLAC__StreamDecoderInitStatus ret;
155
156 if ( ds.Get<bool>() ) {
157 ret = decoder.init();
158 } else {
159 ret = decoder.init_ogg();
160 }
161
162 if ( ret != FLAC__STREAM_DECODER_INIT_STATUS_OK ) {
163 goto end;
164 }
165 }
166
167 if ( ds.Get<bool>() ) {
168 #ifdef FUZZER_DEBUG
169 printf("set_ogg_serial_number\n");
170 #endif
171 decoder.set_ogg_serial_number(ds.Get<long>());
172 }
173 if ( ds.Get<bool>() ) {
174 #ifdef FUZZER_DEBUG
175 printf("set_md5_checking\n");
176 #endif
177 decoder.set_md5_checking(ds.Get<bool>());
178 }
179 if ( ds.Get<bool>() ) {
180 #ifdef FUZZER_DEBUG
181 printf("set_metadata_respond\n");
182 #endif
183 decoder.set_metadata_respond(ds.Get<::FLAC__MetadataType>());
184 }
185 if ( ds.Get<bool>() ) {
186 const auto idVector = ds.GetData(0);
187 unsigned char id[4];
188 if ( idVector.size() >= sizeof(id) ) {
189 memcpy(id, idVector.data(), sizeof(id));
190 #ifdef FUZZER_DEBUG
191 printf("set_metadata_respond_application\n");
192 #endif
193 decoder.set_metadata_respond_application(id);
194 }
195 }
196 if ( ds.Get<bool>() ) {
197 #ifdef FUZZER_DEBUG
198 printf("set_metadata_respond_all\n");
199 #endif
200 decoder.set_metadata_respond_all();
201 }
202 if ( ds.Get<bool>() ) {
203 #ifdef FUZZER_DEBUG
204 printf("set_metadata_ignore\n");
205 #endif
206 decoder.set_metadata_ignore(ds.Get<::FLAC__MetadataType>());
207 }
208 if ( ds.Get<bool>() ) {
209 const auto idVector = ds.GetData(0);
210 unsigned char id[4];
211 if ( idVector.size() >= sizeof(id) ) {
212 memcpy(id, idVector.data(), sizeof(id));
213 #ifdef FUZZER_DEBUG
214 printf("set_metadata_ignore_application\n");
215 #endif
216 decoder.set_metadata_ignore_application(id);
217 }
218 }
219 if ( ds.Get<bool>() ) {
220 #ifdef FUZZER_DEBUG
221 printf("set_metadata_ignore_all\n");
222 #endif
223 decoder.set_metadata_ignore_all();
224 }
225
226 while ( ds.Get<bool>() ) {
227 switch ( ds.Get<uint8_t>() ) {
228 case 0:
229 {
230 #ifdef FUZZER_DEBUG
231 printf("flush\n");
232 #endif
233 const bool res = decoder.flush();
234 fuzzing::memory::memory_test(res);
235 }
236 break;
237 case 1:
238 {
239 #ifdef FUZZER_DEBUG
240 printf("reset\n");
241 #endif
242 const bool res = decoder.reset();
243 fuzzing::memory::memory_test(res);
244 }
245 break;
246 case 2:
247 {
248 #ifdef FUZZER_DEBUG
249 printf("process_single\n");
250 #endif
251 const bool res = decoder.process_single();
252 fuzzing::memory::memory_test(res);
253 }
254 break;
255 case 3:
256 {
257 #ifdef FUZZER_DEBUG
258 printf("process_until_end_of_metadata\n");
259 #endif
260 const bool res = decoder.process_until_end_of_metadata();
261 fuzzing::memory::memory_test(res);
262 }
263 break;
264 case 4:
265 {
266 #ifdef FUZZER_DEBUG
267 printf("process_until_end_of_stream\n");
268 #endif
269 const bool res = decoder.process_until_end_of_stream();
270 fuzzing::memory::memory_test(res);
271 }
272 break;
273 case 5:
274 {
275 #ifdef FUZZER_DEBUG
276 printf("skip_single_frame\n");
277 #endif
278 const bool res = decoder.skip_single_frame();
279 fuzzing::memory::memory_test(res);
280 }
281 break;
282 case 6:
283 {
284 #ifdef FUZZER_DEBUG
285 printf("seek_absolute\n");
286 #endif
287 const bool res = decoder.seek_absolute(ds.Get<uint64_t>());
288 fuzzing::memory::memory_test(res);
289 }
290 break;
291 case 7:
292 {
293 #ifdef FUZZER_DEBUG
294 printf("get_md5_checking\n");
295 #endif
296 const bool res = decoder.get_md5_checking();
297 fuzzing::memory::memory_test(res);
298 }
299 break;
300 case 8:
301 {
302 #ifdef FUZZER_DEBUG
303 printf("get_total_samples\n");
304 #endif
305 const bool res = decoder.get_total_samples();
306 fuzzing::memory::memory_test(res);
307 }
308 break;
309 case 9:
310 {
311 #ifdef FUZZER_DEBUG
312 printf("get_channels\n");
313 #endif
314 const bool res = decoder.get_channels();
315 fuzzing::memory::memory_test(res);
316 }
317 break;
318 case 10:
319 {
320 #ifdef FUZZER_DEBUG
321 printf("get_bits_per_sample\n");
322 #endif
323 const bool res = decoder.get_bits_per_sample();
324 fuzzing::memory::memory_test(res);
325 }
326 break;
327 case 11:
328 {
329 #ifdef FUZZER_DEBUG
330 printf("get_sample_rate\n");
331 #endif
332 const bool res = decoder.get_sample_rate();
333 fuzzing::memory::memory_test(res);
334 }
335 break;
336 case 12:
337 {
338 #ifdef FUZZER_DEBUG
339 printf("get_blocksize\n");
340 #endif
341 const bool res = decoder.get_blocksize();
342 fuzzing::memory::memory_test(res);
343 }
344 break;
345 }
346 }
347 } catch ( ... ) { }
348
349 end:
350 {
351 const bool res = decoder.finish();
352 fuzzing::memory::memory_test(res);
353 }
354 return 0;
355 }
356