tools/target_dec_fuzzer: Use decoder and not codec_id as argument
[ffmpeg.git] / tools / target_dec_fuzzer.c
index 533aa37..19423e2 100644 (file)
    https://security.googleblog.com/2016/08/guided-in-process-fuzzing-of-chrome.html
 */
 
+#include "config.h"
 #include "libavutil/avassert.h"
+#include "libavutil/imgutils.h"
+#include "libavutil/intreadwrite.h"
 
 #include "libavcodec/avcodec.h"
+#include "libavcodec/bytestream.h"
 #include "libavformat/avformat.h"
 
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
 static void error(const char *err)
 {
     fprintf(stderr, "%s", err);
@@ -60,7 +66,7 @@ static AVCodec *c = NULL;
 static AVCodec *AVCodecInitialize(enum AVCodecID codec_id)
 {
     AVCodec *res;
-    av_register_all();
+
     av_log_set_level(AV_LOG_PANIC);
     res = avcodec_find_decoder(codec_id);
     if (!res)
@@ -68,11 +74,6 @@ static AVCodec *AVCodecInitialize(enum AVCodecID codec_id)
     return res;
 }
 
-#if defined(FUZZ_FFMPEG_VIDEO)
-#define decode_handler avcodec_decode_video2
-#elif defined(FUZZ_FFMPEG_AUDIO)
-#define decode_handler avcodec_decode_audio4
-#elif defined(FUZZ_FFMPEG_SUBTITLE)
 static int subtitle_handler(AVCodecContext *avctx, void *frame,
                             int *got_sub_ptr, AVPacket *avpkt)
 {
@@ -83,27 +84,22 @@ static int subtitle_handler(AVCodecContext *avctx, void *frame,
     return ret;
 }
 
-#define decode_handler subtitle_handler
-#else
-#error "Specify encoder type"  // To catch mistakes
-#endif
-
 // Class to handle buffer allocation and resize for each frame
 typedef struct FuzzDataBuffer {
     size_t size_;
     uint8_t *data_;
 } FuzzDataBuffer;
 
-void FDBCreate(FuzzDataBuffer *FDB) {
+static void FDBCreate(FuzzDataBuffer *FDB) {
     FDB->size_ = 0x1000;
     FDB->data_ = av_malloc(FDB->size_);
     if (!FDB->data_)
         error("Failed memory allocation");
 }
 
-void FDBDesroy(FuzzDataBuffer *FDB) { av_free(FDB->data_); }
+static void FDBDesroy(FuzzDataBuffer *FDB) { av_free(FDB->data_); }
 
-void FDBRealloc(FuzzDataBuffer *FDB, size_t size) {
+static void FDBRealloc(FuzzDataBuffer *FDB, size_t size) {
     size_t needed = size + FF_INPUT_BUFFER_PADDING_SIZE;
     av_assert0(needed > size);
     if (needed > FDB->size_) {
@@ -115,7 +111,7 @@ void FDBRealloc(FuzzDataBuffer *FDB, size_t size) {
     }
 }
 
-void FDBPrepare(FuzzDataBuffer *FDB, AVPacket *dst, const uint8_t *data,
+static void FDBPrepare(FuzzDataBuffer *FDB, AVPacket *dst, const uint8_t *data,
                 size_t size)
 {
     FDBRealloc(FDB, size);
@@ -140,9 +136,30 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
     const uint8_t *last = data;
     const uint8_t *end = data + size;
     uint32_t it = 0;
-
-    if (!c)
+    int (*decode_handler)(AVCodecContext *avctx, AVFrame *picture,
+                          int *got_picture_ptr,
+                          const AVPacket *avpkt) = NULL;
+
+    if (!c) {
+#ifdef FFMPEG_DECODER
+#define DECODER_SYMBOL0(CODEC) ff_##CODEC##_decoder
+#define DECODER_SYMBOL(CODEC) DECODER_SYMBOL0(CODEC)
+        extern AVCodec DECODER_SYMBOL(FFMPEG_DECODER);
+        avcodec_register(&DECODER_SYMBOL(FFMPEG_DECODER));
+        int codec_id = DECODER_SYMBOL(FFMPEG_DECODER).id;
+
+        c = AVCodecInitialize(codec_id);  // Done once.
+#else
+        avcodec_register_all();
         c = AVCodecInitialize(FFMPEG_CODEC);  // Done once.
+#endif
+    }
+
+    switch (c->type) {
+    case AVMEDIA_TYPE_AUDIO   : decode_handler = avcodec_decode_audio4; break;
+    case AVMEDIA_TYPE_VIDEO   : decode_handler = avcodec_decode_video2; break;
+    case AVMEDIA_TYPE_SUBTITLE: decode_handler = subtitle_handler     ; break;
+    }
 
     AVCodecContext* ctx = avcodec_alloc_context3(NULL);
     if (!ctx)
@@ -150,9 +167,21 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
 
     ctx->max_pixels = 4096 * 4096; //To reduce false positive OOM and hangs
 
+    if (size > 1024) {
+        GetByteContext gbc;
+        bytestream2_init(&gbc, data + size - 1024, 1024);
+        ctx->width                              = bytestream2_get_le32(&gbc);
+        ctx->height                             = bytestream2_get_le32(&gbc);
+        ctx->bit_rate                           = bytestream2_get_le64(&gbc);
+        ctx->bits_per_coded_sample              = bytestream2_get_le32(&gbc);
+        if (av_image_check_size(ctx->width, ctx->height, 0, ctx))
+            ctx->width = ctx->height = 0;
+        size -= 1024;
+    }
+
     int res = avcodec_open2(ctx, c, NULL);
     if (res < 0)
-        return res;
+        return 0; // Failure of avcodec_open2() does not imply that a issue was found
 
     FDBCreate(&buffer);
     int got_frame;
@@ -165,7 +194,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
     while (data < end && it < maxiteration) {
         // Search for the TAG
         while (data + sizeof(fuzz_tag) < end) {
-            if (data[0] == (fuzz_tag & 0xFF) && *(const uint64_t *)(data) == fuzz_tag)
+            if (data[0] == (fuzz_tag & 0xFF) && AV_RN64(data) == fuzz_tag)
                 break;
             data++;
         }
@@ -186,6 +215,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
 
             if (ret <= 0 || ret > avpkt.size)
                break;
+            if (ctx->codec_type != AVMEDIA_TYPE_AUDIO)
+                ret = avpkt.size;
             avpkt.data += ret;
             avpkt.size -= ret;
         }