FFmpeg
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 // Class to handle buffer allocation and resize for each frame
89 typedef struct FuzzDataBuffer {
90  size_t size_;
93 
94 static void FDBCreate(FuzzDataBuffer *FDB) {
95  FDB->size_ = 0x1000;
96  FDB->data_ = av_malloc(FDB->size_);
97  if (!FDB->data_)
98  error("Failed memory allocation");
99 }
100 
101 static void FDBDesroy(FuzzDataBuffer *FDB) { av_free(FDB->data_); }
102 
103 static void FDBRealloc(FuzzDataBuffer *FDB, size_t size) {
104  size_t needed = size + AV_INPUT_BUFFER_PADDING_SIZE;
105  av_assert0(needed > size);
106  if (needed > FDB->size_) {
107  av_free(FDB->data_);
108  FDB->size_ = needed;
109  FDB->data_ = av_malloc(FDB->size_);
110  if (!FDB->data_)
111  error("Failed memory allocation");
112  }
113 }
114 
115 static void FDBPrepare(FuzzDataBuffer *FDB, AVPacket *dst, const uint8_t *data,
116  size_t size)
117 {
118  FDBRealloc(FDB, size);
119  memcpy(FDB->data_, data, size);
120  size_t padd = FDB->size_ - size;
121  if (padd > AV_INPUT_BUFFER_PADDING_SIZE)
123  memset(FDB->data_ + size, 0, padd);
124  av_init_packet(dst);
125  dst->data = FDB->data_;
126  dst->size = size;
127 }
128 
129 // Ensure we don't loop forever
130 const uint32_t maxiteration = 8096;
131 
132 static const uint64_t FUZZ_TAG = 0x4741542D5A5A5546ULL;
133 
135  const uint64_t fuzz_tag = FUZZ_TAG;
137  const uint8_t *last = data;
138  const uint8_t *end = data + size;
139  uint32_t it = 0;
140  int (*decode_handler)(AVCodecContext *avctx, AVFrame *picture,
141  int *got_picture_ptr,
142  const AVPacket *avpkt) = NULL;
143  AVCodecParserContext *parser = NULL;
144 
145 
146  if (!c) {
147 #ifdef FFMPEG_DECODER
148 #define DECODER_SYMBOL0(CODEC) ff_##CODEC##_decoder
149 #define DECODER_SYMBOL(CODEC) DECODER_SYMBOL0(CODEC)
150  extern AVCodec DECODER_SYMBOL(FFMPEG_DECODER);
151  codec_list[0] = &DECODER_SYMBOL(FFMPEG_DECODER);
152  avcodec_register(&DECODER_SYMBOL(FFMPEG_DECODER));
153 
154  c = &DECODER_SYMBOL(FFMPEG_DECODER);
155 #else
157  c = AVCodecInitialize(FFMPEG_CODEC); // Done once.
158 #endif
160  }
161 
162  switch (c->type) {
163  case AVMEDIA_TYPE_AUDIO : decode_handler = avcodec_decode_audio4; break;
164  case AVMEDIA_TYPE_VIDEO : decode_handler = avcodec_decode_video2; break;
165  case AVMEDIA_TYPE_SUBTITLE: decode_handler = subtitle_handler ; break;
166  }
167 
169  AVCodecContext* parser_avctx = avcodec_alloc_context3(NULL);
170  if (!ctx || !parser_avctx)
171  error("Failed memory allocation");
172 
173  ctx->max_pixels = 4096 * 4096; //To reduce false positive OOM and hangs
174 
175  if (size > 1024) {
176  GetByteContext gbc;
177  bytestream2_init(&gbc, data + size - 1024, 1024);
178  ctx->width = bytestream2_get_le32(&gbc);
179  ctx->height = bytestream2_get_le32(&gbc);
180  ctx->bit_rate = bytestream2_get_le64(&gbc);
181  ctx->bits_per_coded_sample = bytestream2_get_le32(&gbc);
182  // Try to initialize a parser for this codec, note, this may fail which just means we test without one
183  if (bytestream2_get_byte(&gbc) & 1)
184  parser = av_parser_init(c->id);
185  if (av_image_check_size(ctx->width, ctx->height, 0, ctx))
186  ctx->width = ctx->height = 0;
187  size -= 1024;
188  }
189 
190  int res = avcodec_open2(ctx, c, NULL);
191  if (res < 0) {
192  av_free(ctx);
193  av_free(parser_avctx);
194  return 0; // Failure of avcodec_open2() does not imply that a issue was found
195  }
196  parser_avctx->codec_id = ctx->codec_id;
197 
198  FDBCreate(&buffer);
199  int got_frame;
201  if (!frame)
202  error("Failed memory allocation");
203 
204  // Read very simple container
205  AVPacket avpkt, parsepkt;
206  while (data < end && it < maxiteration) {
207  // Search for the TAG
208  while (data + sizeof(fuzz_tag) < end) {
209  if (data[0] == (fuzz_tag & 0xFF) && AV_RN64(data) == fuzz_tag)
210  break;
211  data++;
212  }
213  if (data + sizeof(fuzz_tag) > end)
214  data = end;
215 
216  FDBPrepare(&buffer, &parsepkt, last, data - last);
217  data += sizeof(fuzz_tag);
218  last = data;
219 
220  while (parsepkt.size > 0) {
221 
222  if (parser) {
223  av_init_packet(&avpkt);
224  int ret = av_parser_parse2(parser, parser_avctx, &avpkt.data, &avpkt.size,
225  parsepkt.data, parsepkt.size,
226  parsepkt.pts, parsepkt.dts, parsepkt.pos);
227  parsepkt.data += ret;
228  parsepkt.size -= ret;
229  parsepkt.pos += ret;
230  avpkt.pts = parser->pts;
231  avpkt.dts = parser->dts;
232  avpkt.pos = parser->pos;
233  if ( parser->key_frame == 1 ||
234  (parser->key_frame == -1 && parser->pict_type == AV_PICTURE_TYPE_I))
235  avpkt.flags |= AV_PKT_FLAG_KEY;
236  avpkt.flags |= parsepkt.flags & AV_PKT_FLAG_DISCARD;
237  } else {
238  avpkt = parsepkt;
239  parsepkt.size = 0;
240  }
241 
242  // Iterate through all data
243  while (avpkt.size > 0 && it++ < maxiteration) {
244  av_frame_unref(frame);
245  int ret = decode_handler(ctx, frame, &got_frame, &avpkt);
246 
247  if (it > 20)
248  ctx->error_concealment = 0;
249 
250  if (ret <= 0 || ret > avpkt.size)
251  break;
252  if (ctx->codec_type != AVMEDIA_TYPE_AUDIO)
253  ret = avpkt.size;
254  avpkt.data += ret;
255  avpkt.size -= ret;
256  }
257  }
258  }
259 
260  av_init_packet(&avpkt);
261  avpkt.data = NULL;
262  avpkt.size = 0;
263 
264  do {
265  got_frame = 0;
266  decode_handler(ctx, frame, &got_frame, &avpkt);
267  } while (got_frame == 1 && it++ < maxiteration);
268 
269  av_frame_free(&frame);
270  avcodec_free_context(&ctx);
271  av_freep(&ctx);
272  avcodec_free_context(&parser_avctx);
273  av_freep(&parser_avctx);
274  av_parser_close(parser);
275  FDBDesroy(&buffer);
276  return 0;
277 }
const uint32_t maxiteration
#define NULL
Definition: coverity.c:32
This structure describes decoded (raw) audio or video data.
Definition: frame.h:218
ptrdiff_t const GLvoid * data
Definition: opengl_enc.c:101
misc image utilities
int64_t bit_rate
the average bitrate
Definition: avcodec.h:1571
int64_t pos
byte position in stream, -1 if unknown
Definition: avcodec.h:1453
void av_log_set_level(int level)
Set the log level.
Definition: log.c:385
int size
Definition: avcodec.h:1434
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:864
enum AVMediaType type
Definition: avcodec.h:3424
static void FDBCreate(FuzzDataBuffer *FDB)
int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, AVPacket *avpkt)
Decode a subtitle message.
Definition: decode.c:1029
AVCodec.
Definition: avcodec.h:3411
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
uint8_t
#define av_malloc(s)
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)
static AVFrame * frame
uint8_t * data
Definition: avcodec.h:1433
av_cold void avcodec_register(AVCodec *codec)
Register the codec codec and initialize libavcodec.
Definition: allcodecs.c:814
ptrdiff_t size
Definition: opengl_enc.c:101
int bits_per_coded_sample
bits per sample/pixel from the demuxer (needed for huffyuv).
Definition: avcodec.h:2737
void avcodec_register_all(void)
Register all the codecs, parsers and bitstream filters which were enabled at configuration time...
Definition: allcodecs.c:829
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: avcodec.h:1465
static AVCodec * c
enum AVCodecID id
Definition: avcodec.h:3425
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:5145
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:2591
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:3230
int flags
A combination of AV_PKT_FLAG values.
Definition: avcodec.h:1439
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:1693
AVFormatContext * ctx
Definition: movenc.c:48
void av_parser_close(AVCodecParserContext *s)
Definition: parser.c:224
enum AVCodecID codec_id
Definition: vaapi_decode.c:362
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:1529
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:857
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:1531
main external API structure.
Definition: avcodec.h:1521
AVCodec * avcodec_find_decoder(enum AVCodecID id)
Find a registered decoder with a matching codec ID.
Definition: allcodecs.c:871
void avsubtitle_free(AVSubtitle *sub)
Free all allocated data in the given subtitle struct.
Definition: utils.c:1050
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
Initialize the AVCodecContext to use the given AVCodec.
Definition: utils.c:538
static void FDBPrepare(FuzzDataBuffer *FDB, AVPacket *dst, const uint8_t *data, size_t size)
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:551
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:1472
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:776
#define av_free(p)
#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:1432
#define av_freep(p)
static void FDBDesroy(FuzzDataBuffer *FDB)
static void FDBRealloc(FuzzDataBuffer *FDB, size_t size)
This structure stores compressed data.
Definition: avcodec.h:1410
int key_frame
Set by parser to 1 for key frames and 0 for non-key frames.
Definition: avcodec.h:5084
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1426
GLuint buffer
Definition: opengl_enc.c:102
AVCodec * codec_list[]