FFmpeg
target_dec_fuzzer.c
Go to the documentation of this file.
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 -Llibavresample -Llibavutil -Llibpostproc -Llibswscale -Llibswresample -Wl,--as-needed -Wl,-z,noexecstack -Wl,--warn-common -Wl,-rpath-link=:libpostproc:libswresample:libswscale:libavfilter:libavdevice:libavformat:libavcodec:libavutil:libavresample -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"
49 #include "libavutil/avassert.h"
50 #include "libavutil/imgutils.h"
51 #include "libavutil/intreadwrite.h"
52 
53 #include "libavcodec/avcodec.h"
54 #include "libavcodec/bytestream.h"
55 #include "libavformat/avformat.h"
56 
57 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
58 
59 extern AVCodec * codec_list[];
60 
61 static void error(const char *err)
62 {
63  fprintf(stderr, "%s", err);
64  exit(1);
65 }
66 
67 static AVCodec *c = NULL;
69 {
70  AVCodec *res;
71 
72  res = avcodec_find_decoder(codec_id);
73  if (!res)
74  error("Failed to find decoder");
75  return res;
76 }
77 
78 static int subtitle_handler(AVCodecContext *avctx, void *frame,
79  int *got_sub_ptr, AVPacket *avpkt)
80 {
81  AVSubtitle sub;
82  int ret = avcodec_decode_subtitle2(avctx, &sub, got_sub_ptr, avpkt);
83  if (ret >= 0 && *got_sub_ptr)
84  avsubtitle_free(&sub);
85  return ret;
86 }
87 
88 // Ensure we don't loop forever
89 const uint32_t maxiteration = 8096;
90 const uint64_t maxpixels_per_frame = 4096 * 4096;
91 uint64_t maxpixels;
92 
93 static const uint64_t FUZZ_TAG = 0x4741542D5A5A5546ULL;
94 
95 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
96  const uint64_t fuzz_tag = FUZZ_TAG;
97  const uint8_t *last = data;
98  const uint8_t *end = data + size;
99  uint32_t it = 0;
100  uint64_t ec_pixels = 0;
101  int (*decode_handler)(AVCodecContext *avctx, AVFrame *picture,
102  int *got_picture_ptr,
103  const AVPacket *avpkt) = NULL;
104  AVCodecParserContext *parser = NULL;
105 
106 
107  if (!c) {
108 #ifdef FFMPEG_DECODER
109 #define DECODER_SYMBOL0(CODEC) ff_##CODEC##_decoder
110 #define DECODER_SYMBOL(CODEC) DECODER_SYMBOL0(CODEC)
111  extern AVCodec DECODER_SYMBOL(FFMPEG_DECODER);
112  codec_list[0] = &DECODER_SYMBOL(FFMPEG_DECODER);
113  avcodec_register(&DECODER_SYMBOL(FFMPEG_DECODER));
114 
115  c = &DECODER_SYMBOL(FFMPEG_DECODER);
116 #else
118  c = AVCodecInitialize(FFMPEG_CODEC); // Done once.
119 #endif
121  }
122 
123  switch (c->type) {
124  case AVMEDIA_TYPE_AUDIO : decode_handler = avcodec_decode_audio4; break;
125  case AVMEDIA_TYPE_VIDEO : decode_handler = avcodec_decode_video2; break;
126  case AVMEDIA_TYPE_SUBTITLE: decode_handler = subtitle_handler ; break;
127  }
129  switch (c->id) {
130  // Allows a small input to generate gigantic output
131  case AV_CODEC_ID_DIRAC: maxpixels /= 8192; break;
132  case AV_CODEC_ID_MSRLE: maxpixels /= 16; break;
133  case AV_CODEC_ID_QTRLE: maxpixels /= 16; break;
134  case AV_CODEC_ID_SANM: maxpixels /= 16; break;
135  case AV_CODEC_ID_GIF: maxpixels /= 16; break;
136  // Performs slow frame rescaling in C
137  case AV_CODEC_ID_GDV: maxpixels /= 512; break;
138  // Postprocessing in C
139  case AV_CODEC_ID_HNM4_VIDEO:maxpixels /= 128; break;
140  // Cliping in C, generally slow even with small input
141  case AV_CODEC_ID_INDEO4: maxpixels /= 128; break;
142  case AV_CODEC_ID_LSCR: maxpixels /= 16; break;
143  case AV_CODEC_ID_TRUEMOTION2: maxpixels /= 1024; break;
144  }
145 
146 
148  AVCodecContext* parser_avctx = avcodec_alloc_context3(NULL);
149  if (!ctx || !parser_avctx)
150  error("Failed memory allocation");
151 
152  if (ctx->max_pixels == 0 || ctx->max_pixels > maxpixels_per_frame)
153  ctx->max_pixels = maxpixels_per_frame; //To reduce false positive OOM and hangs
154  ctx->refcounted_frames = 1; //To reduce false positive timeouts and focus testing on the refcounted API
155 
156  if (size > 1024) {
157  GetByteContext gbc;
158  int extradata_size;
159  size -= 1024;
160  bytestream2_init(&gbc, data + size, 1024);
161  ctx->width = bytestream2_get_le32(&gbc);
162  ctx->height = bytestream2_get_le32(&gbc);
163  ctx->bit_rate = bytestream2_get_le64(&gbc);
164  ctx->bits_per_coded_sample = bytestream2_get_le32(&gbc);
165  // Try to initialize a parser for this codec, note, this may fail which just means we test without one
166  if (bytestream2_get_byte(&gbc) & 1)
167  parser = av_parser_init(c->id);
168 
169  extradata_size = bytestream2_get_le32(&gbc);
170  if (extradata_size < size) {
171  ctx->extradata = av_mallocz(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
172  if (ctx->extradata) {
173  ctx->extradata_size = extradata_size;
174  size -= ctx->extradata_size;
175  memcpy(ctx->extradata, data + size, ctx->extradata_size);
176  }
177  }
178  if (av_image_check_size(ctx->width, ctx->height, 0, ctx))
179  ctx->width = ctx->height = 0;
180  }
181 
182  int res = avcodec_open2(ctx, c, NULL);
183  if (res < 0) {
184  avcodec_free_context(&ctx);
185  av_free(parser_avctx);
186  av_parser_close(parser);
187  return 0; // Failure of avcodec_open2() does not imply that a issue was found
188  }
189  parser_avctx->codec_id = ctx->codec_id;
190 
191  int got_frame;
193  if (!frame)
194  error("Failed memory allocation");
195 
196  // Read very simple container
197  AVPacket avpkt, parsepkt;
198  av_init_packet(&avpkt);
199  av_init_packet(&parsepkt);
200  while (data < end && it < maxiteration) {
201  // Search for the TAG
202  while (data + sizeof(fuzz_tag) < end) {
203  if (data[0] == (fuzz_tag & 0xFF) && AV_RN64(data) == fuzz_tag)
204  break;
205  data++;
206  }
207  if (data + sizeof(fuzz_tag) > end)
208  data = end;
209 
210  res = av_new_packet(&parsepkt, data - last);
211  if (res < 0)
212  error("Failed memory allocation");
213  memcpy(parsepkt.data, last, data - last);
214  data += sizeof(fuzz_tag);
215  last = data;
216 
217  while (parsepkt.size > 0) {
218 
219  if (parser) {
220  av_init_packet(&avpkt);
221  int ret = av_parser_parse2(parser, parser_avctx, &avpkt.data, &avpkt.size,
222  parsepkt.data, parsepkt.size,
223  parsepkt.pts, parsepkt.dts, parsepkt.pos);
224  if (avpkt.data == parsepkt.data) {
225  avpkt.buf = av_buffer_ref(parsepkt.buf);
226  if (!avpkt.buf)
227  error("Failed memory allocation");
228  } else {
229  if (av_packet_make_refcounted(&avpkt) < 0)
230  error("Failed memory allocation");
231  }
232  parsepkt.data += ret;
233  parsepkt.size -= ret;
234  parsepkt.pos += ret;
235  avpkt.pts = parser->pts;
236  avpkt.dts = parser->dts;
237  avpkt.pos = parser->pos;
238  if ( parser->key_frame == 1 ||
239  (parser->key_frame == -1 && parser->pict_type == AV_PICTURE_TYPE_I))
240  avpkt.flags |= AV_PKT_FLAG_KEY;
241  avpkt.flags |= parsepkt.flags & AV_PKT_FLAG_DISCARD;
242  } else {
243  av_packet_move_ref(&avpkt, &parsepkt);
244  }
245 
246  // Iterate through all data
247  while (avpkt.size > 0 && it++ < maxiteration) {
248  av_frame_unref(frame);
249  int ret = decode_handler(ctx, frame, &got_frame, &avpkt);
250 
251  ec_pixels += ctx->width * ctx->height;
252  if (it > 20 || ec_pixels > 4 * ctx->max_pixels)
253  ctx->error_concealment = 0;
254  if (ec_pixels > maxpixels)
255  goto maximums_reached;
256 
257  if (ret <= 0 || ret > avpkt.size)
258  break;
259  if (ctx->codec_type != AVMEDIA_TYPE_AUDIO)
260  ret = avpkt.size;
261  avpkt.data += ret;
262  avpkt.size -= ret;
263  }
264  av_packet_unref(&avpkt);
265  }
266  av_packet_unref(&parsepkt);
267  }
268 maximums_reached:
269 
270  av_packet_unref(&avpkt);
271 
272  do {
273  got_frame = 0;
274  av_frame_unref(frame);
275  decode_handler(ctx, frame, &got_frame, &avpkt);
276  } while (got_frame == 1 && it++ < maxiteration);
277 
278  fprintf(stderr, "pixels decoded: %"PRId64", iterations: %d\n", ec_pixels, it);
279 
280  av_frame_free(&frame);
281  avcodec_free_context(&ctx);
282  avcodec_free_context(&parser_avctx);
283  av_parser_close(parser);
284  av_packet_unref(&parsepkt);
285  return 0;
286 }
const uint32_t maxiteration
#define NULL
Definition: coverity.c:32
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:100
misc image utilities
int64_t bit_rate
the average bitrate
Definition: avcodec.h:1616
int64_t pos
byte position in stream, -1 if unknown
Definition: avcodec.h:1498
void av_log_set_level(int level)
Set the log level.
Definition: log.c:385
enum AVCodecID codec_id
Definition: qsv.c:77
int size
Definition: avcodec.h:1479
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
attribute_deprecated int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, const AVPacket *avpkt)
Decode the audio frame of size avpkt->size from avpkt->data into frame.
Definition: decode.c:904
enum AVMediaType type
Definition: avcodec.h:3495
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:236
int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, AVPacket *avpkt)
Decode a subtitle message.
Definition: decode.c:1069
AVCodec.
Definition: avcodec.h:3482
uint8_t
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:189
#define AV_LOG_PANIC
Something went really wrong and we will crash now.
Definition: log.h:163
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:1667
uint8_t * data
Definition: avcodec.h:1478
s EdgeDetect Foobar g libavfilter vf_edgedetect c libavfilter vf_foobar c edit libavfilter and add an entry for foobar following the pattern of the other filters edit libavfilter allfilters and add an entry for foobar following the pattern of the other filters configure make j< whatever > ffmpeg ffmpeg i you should get a foobar png with Lena edge detected That s it
void av_packet_move_ref(AVPacket *dst, AVPacket *src)
Move every field in src to dst and reset src.
Definition: avpacket.c:655
av_cold void avcodec_register(AVCodec *codec)
Register the codec codec and initialize libavcodec.
Definition: allcodecs.c:836
ptrdiff_t size
Definition: opengl_enc.c:100
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
Definition: avcodec.h:2790
void avcodec_register_all(void)
Register all the codecs, parsers and bitstream filters which were enabled at configuration time...
Definition: allcodecs.c:851
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: avcodec.h:1510
static AVCodec * c
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:86
enum AVCodecID id
Definition: avcodec.h:3496
static const uint64_t FUZZ_TAG
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: avcodec.h:215
int64_t pos
Byte position of currently parsed frame in stream.
Definition: avcodec.h:5219
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:202
int error_concealment
error concealment flags
Definition: avcodec.h:2641
AVBufferRef * buf
A reference to the reference-counted buffer where the packet data is stored.
Definition: avcodec.h:1461
simple assert() macros that are a bit more flexible than ISO C assert().
int64_t max_pixels
The number of pixels per image to maximally accept.
Definition: avcodec.h:3293
const uint64_t maxpixels_per_frame
int flags
A combination of AV_PKT_FLAG values.
Definition: avcodec.h:1484
int av_image_check_size(unsigned int w, unsigned int h, int log_offset, void *log_ctx)
Check if the given dimension of an image is valid, meaning that all bytes of the image can be address...
Definition: imgutils.c:282
AVCodecContext * avcodec_alloc_context3(const AVCodec *codec)
Allocate an AVCodecContext and set its fields to default values.
Definition: options.c:156
int av_parser_parse2(AVCodecParserContext *s, AVCodecContext *avctx, uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size, int64_t pts, int64_t dts, int64_t pos)
Parse a packet.
Definition: parser.c:120
static AVCodec * AVCodecInitialize(enum AVCodecID codec_id)
int width
picture width / height.
Definition: avcodec.h:1739
int av_packet_make_refcounted(AVPacket *pkt)
Ensure the data described by a given packet is reference counted.
Definition: avpacket.c:663
AVFormatContext * ctx
Definition: movenc.c:48
void av_parser_close(AVCodecParserContext *s)
Definition: parser.c:224
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
static void error(const char *err)
static int subtitle_handler(AVCodecContext *avctx, void *frame, int *got_sub_ptr, AVPacket *avpkt)
AVCodecParserContext * av_parser_init(int codec_id)
Definition: parser.c:34
Libavcodec external API header.
enum AVMediaType codec_type
Definition: avcodec.h:1574
attribute_deprecated int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture, int *got_picture_ptr, const AVPacket *avpkt)
Decode the video frame of size avpkt->size from avpkt->data into picture.
Definition: decode.c:897
void avcodec_free_context(AVCodecContext **avctx)
Free the codec context and everything associated with it and write NULL to the provided pointer...
Definition: options.c:171
enum AVCodecID codec_id
Definition: avcodec.h:1576
main external API structure.
Definition: avcodec.h:1566
AVCodec * avcodec_find_decoder(enum AVCodecID id)
Find a registered decoder with a matching codec ID.
Definition: allcodecs.c:893
void av_packet_unref(AVPacket *pkt)
Wipe the packet.
Definition: avpacket.c:599
void avsubtitle_free(AVSubtitle *sub)
Free all allocated data in the given subtitle struct.
Definition: utils.c:1062
int extradata_size
Definition: avcodec.h:1668
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
Initialize the AVCodecContext to use the given AVCodec.
Definition: utils.c:542
attribute_deprecated int refcounted_frames
If non-zero, the decoded audio and video frames returned from avcodec_decode_video2() and avcodec_dec...
Definition: avcodec.h:2397
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:553
Main libavformat public API header.
int
#define AV_PKT_FLAG_DISCARD
Flag is used to discard packets which are required to maintain valid decoder state but are not requir...
Definition: avcodec.h:1517
AVBufferRef * av_buffer_ref(AVBufferRef *buf)
Create a new reference to an AVBuffer.
Definition: buffer.c:93
void av_init_packet(AVPacket *pkt)
Initialize optional fields of a packet with default values.
Definition: avpacket.c:33
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding...
Definition: avcodec.h:791
#define av_free(p)
uint64_t maxpixels
#define AV_RN64(p)
Definition: intreadwrite.h:368
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed...
Definition: avcodec.h:1477
This structure stores compressed data.
Definition: avcodec.h:1455
int key_frame
Set by parser to 1 for key frames and 0 for non-key frames.
Definition: avcodec.h:5158
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1471
AVCodec * codec_list[]