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"
54
59
60 //For FF_SANE_NB_CHANNELS, so we dont waste energy testing things that will get instantly rejected
62
64
66
67 static void error(
const char *err)
68 {
69 fprintf(stderr, "%s", err);
70 exit(1);
71 }
72
75 {
77
79 if (!res)
80 error(
"Failed to find decoder");
82 }
83
86 {
89 if (
ret >= 0 && *got_sub_ptr)
92 }
93
96 {
98 *got_frame =
ret >= 0;
100 }
101
102 // Ensure we don't loop forever
104
105 static const uint64_t
FUZZ_TAG = 0x4741542D5A5A5546ULL;
106
108 {
109 ptrdiff_t linesize1[4];
113
118
119 for (
i = 0;
i < 4 &&
frame->linesize[
i];
i++)
120 linesize1[
i] =
frame->linesize[
i] =
124
128
130 for (
i = 0;
i < 4 &&
size[
i];
i++) {
135 }
139 }
140
141 return 0;
145 }
146
148 {
149 switch (
ctx->codec_type) {
156 default:
158 }
159 }
160
162 uint64_t maxpixels_per_frame = 4096 * 4096;
163 uint64_t maxpixels;
164
165 uint64_t maxsamples_per_frame = 256*1024*32;
166 uint64_t maxsamples;
168 const uint8_t *last =
data;
171 uint64_t ec_pixels = 0;
172 uint64_t nb_samples = 0;
174 int *got_picture_ptr,
177 uint64_t keyframes = 0;
178 uint64_t flushpattern = -1;
180
182 #ifdef FFMPEG_DECODER
183 #define DECODER_SYMBOL0(CODEC) ff_##CODEC##_decoder
184 #define DECODER_SYMBOL(CODEC) DECODER_SYMBOL0(CODEC)
185 extern FFCodec DECODER_SYMBOL(FFMPEG_DECODER);
186 codec_list[0] = &DECODER_SYMBOL(FFMPEG_DECODER);
187
188 #if FFMPEG_DECODER == tiff || FFMPEG_DECODER == tdsc
189 extern FFCodec DECODER_SYMBOL(mjpeg);
191 #endif
192
193 c = &DECODER_SYMBOL(FFMPEG_DECODER);
194 #else
196 #endif
198 }
199
204 }
207 }
297 }
298
299 maxsamples_per_frame =
FFMIN(maxsamples_per_frame, maxsamples);
300 maxpixels_per_frame =
FFMIN(maxpixels_per_frame , maxpixels);
301
304 if (!
ctx || !parser_avctx)
305 error(
"Failed memory allocation");
306
307 if (
ctx->max_pixels == 0 ||
ctx->max_pixels > maxpixels_per_frame)
308 ctx->max_pixels = maxpixels_per_frame;
//To reduce false positive OOM and hangs
309
310 ctx->max_samples = maxsamples_per_frame;
312
315 int extradata_size;
317 uint64_t request_channel_layout;
318 int64_t flags64;
319
322 ctx->width = bytestream2_get_le32(&gbc);
323 ctx->height = bytestream2_get_le32(&gbc);
325 ctx->bits_per_coded_sample = bytestream2_get_le32(&gbc);
326 // Try to initialize a parser for this codec, note, this may fail which just means we test without one
327 flags = bytestream2_get_byte(&gbc);
336 }
341
344
345 extradata_size = bytestream2_get_le32(&gbc);
346
347 ctx->sample_rate = bytestream2_get_le32(&gbc) & 0x7FFFFFFF;
349 ctx->block_align = bytestream2_get_le32(&gbc) & 0x7FFFFFFF;
350 ctx->codec_tag = bytestream2_get_le32(&gbc);
352 int n;
355 }
356 keyframes = bytestream2_get_le64(&gbc);
357 request_channel_layout = bytestream2_get_le64(&gbc);
358
359 ctx->idct_algo = bytestream2_get_byte(&gbc) % 25;
360 flushpattern = bytestream2_get_le64(&gbc);
362
363
365 switch (
ctx->codec_id) {
372 break;
373 }
374 }
375
376 // Keep the deprecated request_channel_layout behavior to ensure old fuzzing failures
377 // remain reproducible.
378 if (request_channel_layout) {
379 switch (
ctx->codec_id) {
385 if (request_channel_layout & ~INT64_MIN) {
387 if (!downmix_layout)
388 error(
"Failed memory allocation");
389 av_strlcatf(downmix_layout, 19,
"0x%"PRIx64, request_channel_layout & ~INT64_MIN);
391 }
393 break;
394 // fall-through
397 break;
398 }
399 }
400
401 flags64 = bytestream2_get_le64(&gbc);
402 if (flags64 &1)
404 if (flags64 &2)
406 if (flags64 &4)
408
409 if (extradata_size <
size) {
411 if (
ctx->extradata) {
412 ctx->extradata_size = extradata_size;
415 }
416 }
418 ctx->width =
ctx->height = 0;
419 }
420
422 if (res < 0) {
427 return 0; // Failure of avcodec_open2() does not imply that a issue was found
428 }
432
433
434 int got_frame;
438 if (!
frame || !avpkt || !parsepkt)
439 error(
"Failed memory allocation");
440
441 // Read very simple container
443 // Search for the TAG
444 while (
data +
sizeof(fuzz_tag) < end) {
446 break;
448 }
449 if (
data +
sizeof(fuzz_tag) > end)
451
453 if (res < 0)
454 error(
"Failed memory allocation");
455 memcpy(parsepkt->
data, last,
data - last);
457 keyframes = (keyframes >> 2) + (keyframes<<62);
458 data +=
sizeof(fuzz_tag);
460
461 while (parsepkt->
size > 0) {
462 int decode_more;
463
464 if (parser) {
467 parsepkt->
pts, parsepkt->
dts, parsepkt->
pos);
468 if (avpkt->
data == parsepkt->
data) {
471 error(
"Failed memory allocation");
472 } else {
474 error(
"Failed memory allocation");
475 }
486 } else {
488 }
489
490 if (!(flushpattern & 7))
492 flushpattern = (flushpattern >> 3) + (flushpattern << 61);
493
496 decode_more =
ret >= 0;
497 if(!decode_more) {
498 ec_pixels += (
ctx->width + 32LL) * (
ctx->height + 32LL);
499 if (
it > 20 || ec_pixels > 4 *
ctx->max_pixels) {
500 ctx->error_concealment = 0;
502 }
503 if (ec_pixels > maxpixels)
504 goto maximums_reached;
505 }
506 } else
507 decode_more = 1;
508
509 // Iterate through all data
512 int ret = decode_handler(
ctx,
frame, &got_frame, avpkt);
513
514 ec_pixels += (
ctx->width + 32LL) * (
ctx->height + 32LL);
515 if (
it > 20 || ec_pixels > 4 *
ctx->max_pixels) {
516 ctx->error_concealment = 0;
518 }
519 if (ec_pixels > maxpixels)
520 goto maximums_reached;
521
523 frame->nb_samples == 0 && !got_frame &&
525 nb_samples +=
ctx->max_samples;
526
527 nb_samples +=
frame->nb_samples;
528 if (nb_samples > maxsamples)
529 goto maximums_reached;
530
531 if (ret <= 0 || ret > avpkt->
size)
532 break;
533
537 decode_more = avpkt->
size > 0;
538 } else
539 decode_more =
ret >= 0;
540 }
542 }
544 }
545 maximums_reached:
546
548
551
552 do {
553 got_frame = 0;
555 decode_handler(
ctx,
frame, &got_frame, avpkt);
556
557 nb_samples +=
frame->nb_samples;
558 if (nb_samples > maxsamples)
559 break;
561
562 fprintf(stderr,
"pixels decoded: %"PRId64
", samples decoded: %"PRId64
", iterations: %d\n", ec_pixels, nb_samples,
it);
563
571 return 0;
572 }