1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 /* Targeted fuzzer that targets specific codecs depending on two
20 compile-time flags.
21 INSTRUCTIONS:
22
23 * Get the very fresh clang, e.g. see http://libfuzzer.info#versions
24 * Get and build libFuzzer:
25 svn co http://llvm.org/svn/llvm-project/llvm/trunk/lib/Fuzzer
26 ./Fuzzer/build.sh
27 * build ffmpeg for fuzzing:
28 FLAGS="-fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp -g" CC="clang $FLAGS" CXX="clang++ $FLAGS" ./configure --disable-x86asm
29 make clean && make -j
30 * build the fuzz target.
31 Choose the value of FFMPEG_CODEC (e.g. AV_CODEC_ID_DVD_SUBTITLE) and
32 choose one of FUZZ_FFMPEG_VIDEO, FUZZ_FFMPEG_AUDIO, FUZZ_FFMPEG_SUBTITLE.
33 clang -fsanitize=address -fsanitize-coverage=trace-pc-guard,trace-cmp tools/target_dec_fuzzer.c -o target_dec_fuzzer -I. -DFFMPEG_CODEC=AV_CODEC_ID_MPEG1VIDEO -DFUZZ_FFMPEG_VIDEO ../../libfuzzer/libFuzzer.a -Llibavcodec -Llibavdevice -Llibavfilter -Llibavformat -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -ldl -lxcb -lxcb-shm -lxcb -lxcb-xfixes -lxcb -lxcb-shape -lxcb -lX11 -lasound -lm -lbz2 -lz -pthread
34 * create a corpus directory and put some samples there (empty dir is ok too):
35 mkdir CORPUS && cp some-files CORPUS
36
37 * Run fuzzing:
38 ./target_dec_fuzzer -max_len=100000 CORPUS
39
40 More info:
41 http://libfuzzer.info
42 http://tutorial.libfuzzer.info
43 https://github.com/google/oss-fuzz
44 http://lcamtuf.coredump.cx/afl/
45 https://security.googleblog.com/2016/08/guided-in-process-fuzzing-of-chrome.html
46 */
47
48 #include "config.h"
53
57
58 //For FF_SANE_NB_CHANNELS, so we dont waste energy testing things that will get instantly rejected
60
62
64
65 static void error(
const char *err)
66 {
67 fprintf(stderr, "%s", err);
68 exit(1);
69 }
70
73 {
75
77 if (!res)
78 error(
"Failed to find decoder");
79 return res;
80 }
81
84 {
87 if (
ret >= 0 && *got_sub_ptr)
90 }
91
94 {
96 *got_frame =
ret >= 0;
98 }
99
100 // Ensure we don't loop forever
102
103 static const uint64_t
FUZZ_TAG = 0x4741542D5A5A5546ULL;
104
106 uint64_t maxpixels_per_frame = 4096 * 4096;
107 uint64_t maxpixels;
108
109 uint64_t maxsamples_per_frame = 256*1024*32;
110 uint64_t maxsamples;
112 const uint8_t *last =
data;
115 uint64_t ec_pixels = 0;
116 uint64_t nb_samples = 0;
118 int *got_picture_ptr,
121 uint64_t keyframes = 0;
122 uint64_t flushpattern = -1;
124
126 #ifdef FFMPEG_DECODER
127 #define DECODER_SYMBOL0(CODEC) ff_##CODEC##_decoder
128 #define DECODER_SYMBOL(CODEC) DECODER_SYMBOL0(CODEC)
129 extern AVCodec DECODER_SYMBOL(FFMPEG_DECODER);
130 codec_list[0] = &DECODER_SYMBOL(FFMPEG_DECODER);
131
132 #if FFMPEG_DECODER == tiff || FFMPEG_DECODER == tdsc
133 extern AVCodec DECODER_SYMBOL(mjpeg);
135 #endif
136
137 c = &DECODER_SYMBOL(FFMPEG_DECODER);
138 #else
140 #endif
142 }
143
148 }
151 }
224 }
225
226 maxsamples_per_frame =
FFMIN(maxsamples_per_frame, maxsamples);
227 maxpixels_per_frame =
FFMIN(maxpixels_per_frame , maxpixels);
228
231 if (!
ctx || !parser_avctx)
232 error(
"Failed memory allocation");
233
234 if (
ctx->max_pixels == 0 ||
ctx->max_pixels > maxpixels_per_frame)
235 ctx->max_pixels = maxpixels_per_frame;
//To reduce false positive OOM and hangs
236
237 ctx->max_samples = maxsamples_per_frame;
238
241 int extradata_size;
243 int64_t flags64;
244
247 ctx->width = bytestream2_get_le32(&gbc);
248 ctx->height = bytestream2_get_le32(&gbc);
250 ctx->bits_per_coded_sample = bytestream2_get_le32(&gbc);
251 // Try to initialize a parser for this codec, note, this may fail which just means we test without one
252 flags = bytestream2_get_byte(&gbc);
261 }
266
269
270 extradata_size = bytestream2_get_le32(&gbc);
271
272 ctx->sample_rate = bytestream2_get_le32(&gbc) & 0x7FFFFFFF;
274 ctx->block_align = bytestream2_get_le32(&gbc) & 0x7FFFFFFF;
275 ctx->codec_tag = bytestream2_get_le32(&gbc);
277 int n;
280 }
281 keyframes = bytestream2_get_le64(&gbc);
282 ctx->request_channel_layout = bytestream2_get_le64(&gbc);
283
284 ctx->idct_algo = bytestream2_get_byte(&gbc) % 25;
285 flushpattern = bytestream2_get_le64(&gbc);
287
288
290 switch (
ctx->codec_id) {
297 break;
298 }
299 }
300
301 flags64 = bytestream2_get_le64(&gbc);
302 if (flags64 &1)
304 if (flags64 &2)
306 if (flags64 &4)
308
309 if (extradata_size <
size) {
311 if (
ctx->extradata) {
312 ctx->extradata_size = extradata_size;
315 }
316 }
318 ctx->width =
ctx->height = 0;
319 }
320
322 if (res < 0) {
327 return 0; // Failure of avcodec_open2() does not imply that a issue was found
328 }
332
333
334 int got_frame;
338 if (!
frame || !avpkt || !parsepkt)
339 error(
"Failed memory allocation");
340
341 // Read very simple container
343 // Search for the TAG
344 while (
data +
sizeof(fuzz_tag) < end) {
346 break;
348 }
349 if (
data +
sizeof(fuzz_tag) > end)
351
353 if (res < 0)
354 error(
"Failed memory allocation");
355 memcpy(parsepkt->
data, last,
data - last);
357 keyframes = (keyframes >> 2) + (keyframes<<62);
358 data +=
sizeof(fuzz_tag);
360
361 while (parsepkt->
size > 0) {
362 int decode_more;
363
364 if (parser) {
367 parsepkt->
pts, parsepkt->
dts, parsepkt->
pos);
368 if (avpkt->
data == parsepkt->
data) {
371 error(
"Failed memory allocation");
372 } else {
374 error(
"Failed memory allocation");
375 }
386 } else {
388 }
389
390 if (!(flushpattern & 7))
392 flushpattern = (flushpattern >> 3) + (flushpattern << 61);
393
396 decode_more =
ret >= 0;
397 if(!decode_more) {
398 ec_pixels += (
ctx->width + 32LL) * (
ctx->height + 32LL);
399 if (
it > 20 || ec_pixels > 4 *
ctx->max_pixels) {
400 ctx->error_concealment = 0;
402 }
403 if (ec_pixels > maxpixels)
404 goto maximums_reached;
405 }
406 } else
407 decode_more = 1;
408
409 // Iterate through all data
412 int ret = decode_handler(
ctx,
frame, &got_frame, avpkt);
413
414 ec_pixels += (
ctx->width + 32LL) * (
ctx->height + 32LL);
415 if (
it > 20 || ec_pixels > 4 *
ctx->max_pixels) {
416 ctx->error_concealment = 0;
418 }
419 if (ec_pixels > maxpixels)
420 goto maximums_reached;
421
423 frame->nb_samples == 0 && !got_frame &&
425 nb_samples +=
ctx->max_samples;
426
427 nb_samples +=
frame->nb_samples;
428 if (nb_samples > maxsamples)
429 goto maximums_reached;
430
431 if (ret <= 0 || ret > avpkt->
size)
432 break;
433
437 decode_more = avpkt->
size > 0;
438 } else
439 decode_more =
ret >= 0;
440 }
442 }
444 }
445 maximums_reached:
446
448
451
452 do {
453 got_frame = 0;
455 decode_handler(
ctx,
frame, &got_frame, avpkt);
456
457 nb_samples +=
frame->nb_samples;
458 if (nb_samples > maxsamples)
459 break;
461
462 fprintf(stderr,
"pixels decoded: %"PRId64
", samples decoded: %"PRId64
", iterations: %d\n", ec_pixels, nb_samples,
it);
463
471 return 0;
472 }