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 
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) {
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  uint64_t ec_pixels = 0;
141  int (*decode_handler)(AVCodecContext *avctx, AVFrame *picture,
142  int *got_picture_ptr,
143  const AVPacket *avpkt) = NULL;
144  AVCodecParserContext *parser = NULL;
145 
146 
147  if (!c) {
148 #ifdef FFMPEG_DECODER
149 #define DECODER_SYMBOL0(CODEC) ff_##CODEC##_decoder
150 #define DECODER_SYMBOL(CODEC) DECODER_SYMBOL0(CODEC)
151  extern AVCodec DECODER_SYMBOL(FFMPEG_DECODER);
152  codec_list[0] = &DECODER_SYMBOL(FFMPEG_DECODER);
153  avcodec_register(&DECODER_SYMBOL(FFMPEG_DECODER));
154 
155  c = &DECODER_SYMBOL(FFMPEG_DECODER);
156 #else
158  c = AVCodecInitialize(FFMPEG_CODEC); // Done once.
159 #endif
161  }
162 
163  switch (c->type) {
164  case AVMEDIA_TYPE_AUDIO : decode_handler = avcodec_decode_audio4; break;
165  case AVMEDIA_TYPE_VIDEO : decode_handler = avcodec_decode_video2; break;
166  case AVMEDIA_TYPE_SUBTITLE: decode_handler = subtitle_handler ; break;
167  }
168 
170  AVCodecContext* parser_avctx = avcodec_alloc_context3(NULL);
171  if (!ctx || !parser_avctx)
172  error("Failed memory allocation");
173 
174  ctx->max_pixels = 4096 * 4096; //To reduce false positive OOM and hangs
175 
176  if (size > 1024) {
177  GetByteContext gbc;
178  int extradata_size;
179  size -= 1024;
180  bytestream2_init(&gbc, data + size, 1024);
181  ctx->width = bytestream2_get_le32(&gbc);
182  ctx->height = bytestream2_get_le32(&gbc);
183  ctx->bit_rate = bytestream2_get_le64(&gbc);
184  ctx->bits_per_coded_sample = bytestream2_get_le32(&gbc);
185  // Try to initialize a parser for this codec, note, this may fail which just means we test without one
186  if (bytestream2_get_byte(&gbc) & 1)
187  parser = av_parser_init(c->id);
188 
189  extradata_size = bytestream2_get_le32(&gbc);
190  if (extradata_size < size) {
191  ctx->extradata = av_mallocz(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
192  if (ctx->extradata) {
193  ctx->extradata_size = extradata_size;
194  size -= ctx->extradata_size;
195  memcpy(ctx->extradata, data + size, ctx->extradata_size);
196  }
197  }
198  if (av_image_check_size(ctx->width, ctx->height, 0, ctx))
199  ctx->width = ctx->height = 0;
200  }
201 
202  int res = avcodec_open2(ctx, c, NULL);
203  if (res < 0) {
204  av_free(ctx);
205  av_free(parser_avctx);
206  av_parser_close(parser);
207  return 0; // Failure of avcodec_open2() does not imply that a issue was found
208  }
209  parser_avctx->codec_id = ctx->codec_id;
210 
211  FDBCreate(&buffer);
212  int got_frame;
214  if (!frame)
215  error("Failed memory allocation");
216 
217  // Read very simple container
218  AVPacket avpkt, parsepkt;
219  while (data < end && it < maxiteration) {
220  // Search for the TAG
221  while (data + sizeof(fuzz_tag) < end) {
222  if (data[0] == (fuzz_tag & 0xFF) && AV_RN64(data) == fuzz_tag)
223  break;
224  data++;
225  }
226  if (data + sizeof(fuzz_tag) > end)
227  data = end;
228 
229  FDBPrepare(&buffer, &parsepkt, last, data - last);
230  data += sizeof(fuzz_tag);
231  last = data;
232 
233  while (parsepkt.size > 0) {
234 
235  if (parser) {
236  av_init_packet(&avpkt);
237  int ret = av_parser_parse2(parser, parser_avctx, &avpkt.data, &avpkt.size,
238  parsepkt.data, parsepkt.size,
239  parsepkt.pts, parsepkt.dts, parsepkt.pos);
240  parsepkt.data += ret;
241  parsepkt.size -= ret;
242  parsepkt.pos += ret;
243  avpkt.pts = parser->pts;
244  avpkt.dts = parser->dts;
245  avpkt.pos = parser->pos;
246  if ( parser->key_frame == 1 ||
247  (parser->key_frame == -1 && parser->pict_type == AV_PICTURE_TYPE_I))
248  avpkt.flags |= AV_PKT_FLAG_KEY;
249  avpkt.flags |= parsepkt.flags & AV_PKT_FLAG_DISCARD;
250  } else {
251  avpkt = parsepkt;
252  parsepkt.size = 0;
253  }
254 
255  // Iterate through all data
256  while (avpkt.size > 0 && it++ < maxiteration) {
258  int ret = decode_handler(ctx, frame, &got_frame, &avpkt);
259 
260  ec_pixels += ctx->width * ctx->height;
261  if (it > 20 || ec_pixels > 4 * ctx->max_pixels)
262  ctx->error_concealment = 0;
263 
264  if (ret <= 0 || ret > avpkt.size)
265  break;
266  if (ctx->codec_type != AVMEDIA_TYPE_AUDIO)
267  ret = avpkt.size;
268  avpkt.data += ret;
269  avpkt.size -= ret;
270  }
271  }
272  }
273 
274  av_init_packet(&avpkt);
275  avpkt.data = NULL;
276  avpkt.size = 0;
277 
278  do {
279  got_frame = 0;
280  decode_handler(ctx, frame, &got_frame, &avpkt);
281  } while (got_frame == 1 && it++ < maxiteration);
282 
285  avcodec_free_context(&parser_avctx);
286  av_parser_close(parser);
287  FDBDesroy(&buffer);
288  return 0;
289 }
AVSubtitle
Definition: avcodec.h:3933
AVCodec
AVCodec.
Definition: avcodec.h:3481
AVMEDIA_TYPE_SUBTITLE
@ AVMEDIA_TYPE_SUBTITLE
Definition: avutil.h:204
codec_list
AVCodec * codec_list[]
AVCodecParserContext::pts
int64_t pts
Definition: avcodec.h:5127
FuzzDataBuffer::size_
size_t size_
Definition: target_dec_fuzzer.c:90
codec_id
enum AVCodecID codec_id
Definition: qsv.c:72
AVCodecParserContext::pict_type
int pict_type
Definition: avcodec.h:5116
GetByteContext
Definition: bytestream.h:33
avcodec_decode_audio4
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:905
AV_LOG_PANIC
#define AV_LOG_PANIC
Something went really wrong and we will crash now.
Definition: log.h:163
AV_PKT_FLAG_DISCARD
#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:1516
av_frame_free
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:202
end
static av_cold int end(AVCodecContext *avctx)
Definition: avrndec.c:90
AV_RN64
#define AV_RN64(p)
Definition: intreadwrite.h:368
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:295
avcodec_decode_subtitle2
int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, AVPacket *avpkt)
Decode a subtitle message.
Definition: decode.c:1070
AVPacket::data
uint8_t * data
Definition: avcodec.h:1477
data
const char data[16]
Definition: mxf.c:91
avcodec_register_all
void avcodec_register_all(void)
Register all the codecs, parsers and bitstream filters which were enabled at configuration time.
Definition: allcodecs.c:848
AV_PKT_FLAG_KEY
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: avcodec.h:1509
av_malloc
#define av_malloc(s)
Definition: tableprint_vlc.h:31
AVCodecParserContext::key_frame
int key_frame
Set by parser to 1 for key frames and 0 for non-key frames.
Definition: avcodec.h:5157
av_parser_init
AVCodecParserContext * av_parser_init(int codec_id)
Definition: parser.c:34
AVCodecParserContext::dts
int64_t dts
Definition: avcodec.h:5128
c
static AVCodec * c
Definition: target_dec_fuzzer.c:67
avsubtitle_free
void avsubtitle_free(AVSubtitle *sub)
Free all allocated data in the given subtitle struct.
Definition: utils.c:1098
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:189
AVFormatContext::bit_rate
int64_t bit_rate
Total stream bitrate in bit/s, 0 if not available.
Definition: avformat.h:1464
avassert.h
FDBCreate
static void FDBCreate(FuzzDataBuffer *FDB)
Definition: target_dec_fuzzer.c:94
LLVMFuzzerTestOneInput
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
Definition: target_dec_fuzzer.c:134
avcodec_alloc_context3
AVCodecContext * avcodec_alloc_context3(const AVCodec *codec)
Allocate an AVCodecContext and set its fields to default values.
Definition: options.c:156
intreadwrite.h
AVMEDIA_TYPE_AUDIO
@ AVMEDIA_TYPE_AUDIO
Definition: avutil.h:202
AVCodecInitialize
static AVCodec * AVCodecInitialize(enum AVCodecID codec_id)
Definition: target_dec_fuzzer.c:68
av_assert0
#define av_assert0(cond)
assert() equivalent, that is always enabled.
Definition: avassert.h:37
ctx
AVFormatContext * ctx
Definition: movenc.c:48
AVCodecContext::codec_id
enum AVCodecID codec_id
Definition: avcodec.h:1575
FUZZ_TAG
static const uint64_t FUZZ_TAG
Definition: target_dec_fuzzer.c:132
NULL
#define NULL
Definition: coverity.c:32
AVCodec::type
enum AVMediaType type
Definition: avcodec.h:3494
avcodec_free_context
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
AV_PICTURE_TYPE_I
@ AV_PICTURE_TYPE_I
Intra.
Definition: avutil.h:274
avcodec_open2
int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
Initialize the AVCodecContext to use the given AVCodec.
Definition: utils.c:565
error
static void error(const char *err)
Definition: target_dec_fuzzer.c:61
AVCodecID
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: avcodec.h:215
subtitle_handler
static int subtitle_handler(AVCodecContext *avctx, void *frame, int *got_sub_ptr, AVPacket *avpkt)
Definition: target_dec_fuzzer.c:78
AVPacket::size
int size
Definition: avcodec.h:1478
size
int size
Definition: twinvq_data.h:11134
avcodec_find_decoder
AVCodec * avcodec_find_decoder(enum AVCodecID id)
Find a registered decoder with a matching codec ID.
Definition: allcodecs.c:890
AVPacket::dts
int64_t dts
Decompression timestamp in AVStream->time_base units; the time at which the packet is decompressed.
Definition: avcodec.h:1476
AVPacket::flags
int flags
A combination of AV_PKT_FLAG values.
Definition: avcodec.h:1483
AVCodec::id
enum AVCodecID id
Definition: avcodec.h:3495
av_log_set_level
void av_log_set_level(int level)
Set the log level.
Definition: log.c:385
AVCodecParserContext::pos
int64_t pos
Byte position of currently parsed frame in stream.
Definition: avcodec.h:5218
AVPacket::pts
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1470
avcodec_register
av_cold void avcodec_register(AVCodec *codec)
Register the codec codec and initialize libavcodec.
Definition: allcodecs.c:833
avcodec_decode_video2
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:898
needed
The exact code depends on how similar the blocks are and how related they are to the and needs to apply these operations to the correct inlink or outlink if there are several Macros are available to factor that when no extra processing is needed
Definition: filter_design.txt:212
uint8_t
uint8_t
Definition: audio_convert.c:194
av_frame_unref
void av_frame_unref(AVFrame *frame)
Unreference all the buffers referenced by frame and reset the frame fields.
Definition: frame.c:553
av_mallocz
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
avcodec.h
AVCodecParserContext
Definition: avcodec.h:5108
ret
ret
Definition: filter_design.txt:187
frame
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
Definition: filter_design.txt:264
avformat.h
AV_INPUT_BUFFER_PADDING_SIZE
#define AV_INPUT_BUFFER_PADDING_SIZE
Definition: avcodec.h:790
AVCodecContext
main external API structure.
Definition: avcodec.h:1565
buffer
the frame and frame reference mechanism is intended to as much as expensive copies of that data while still allowing the filters to produce correct results The data is stored in buffers represented by AVFrame structures Several references can point to the same frame buffer
Definition: filter_design.txt:49
FuzzDataBuffer
Definition: target_dec_fuzzer.c:89
config.h
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
av_parser_parse2
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
it
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
Definition: writing_filters.txt:31
FDBPrepare
static void FDBPrepare(FuzzDataBuffer *FDB, AVPacket *dst, const uint8_t *data, size_t size)
Definition: target_dec_fuzzer.c:115
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34
AVPacket
This structure stores compressed data.
Definition: avcodec.h:1454
FDBRealloc
static void FDBRealloc(FuzzDataBuffer *FDB, size_t size)
Definition: target_dec_fuzzer.c:103
AVPacket::pos
int64_t pos
byte position in stream, -1 if unknown
Definition: avcodec.h:1497
bytestream.h
imgutils.h
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:133
av_image_check_size
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
int
int
Definition: ffmpeg_filter.c:191
maxiteration
const uint32_t maxiteration
Definition: target_dec_fuzzer.c:130
FuzzDataBuffer::data_
uint8_t * data_
Definition: target_dec_fuzzer.c:91
av_parser_close
void av_parser_close(AVCodecParserContext *s)
Definition: parser.c:224
av_init_packet
void av_init_packet(AVPacket *pkt)
Initialize optional fields of a packet with default values.
Definition: avpacket.c:33
FDBDesroy
static void FDBDesroy(FuzzDataBuffer *FDB)
Definition: target_dec_fuzzer.c:101