From 710b7ec0713307a6d26d0ca7fad1369a75a01edb Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Mon, 27 May 2019 21:50:08 +0200 Subject: [PATCH] tools: Add fuzzer for demuxers This is based on target_dec_fuzzer Signed-off-by: Michael Niedermayer --- Makefile | 3 + tools/Makefile | 3 + tools/target_dem_fuzzer.c | 163 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+) create mode 100644 tools/target_dem_fuzzer.c diff --git a/Makefile b/Makefile index 48c59733b8..532372c9c4 100644 --- a/Makefile +++ b/Makefile @@ -50,6 +50,9 @@ $(TOOLS): %$(EXESUF): %.o target_dec_%_fuzzer$(EXESUF): target_dec_%_fuzzer.o $(FF_DEP_LIBS) $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) +tools/target_dem_fuzzer$(EXESUF): tools/target_dem_fuzzer.o $(FF_DEP_LIBS) + $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) + tools/sofa2wavs$(EXESUF): ELIBS = $(FF_EXTRALIBS) tools/uncoded_frame$(EXESUF): $(FF_DEP_LIBS) tools/uncoded_frame$(EXESUF): ELIBS = $(FF_EXTRALIBS) diff --git a/tools/Makefile b/tools/Makefile index b347caf82a..370ee35416 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -5,6 +5,9 @@ TOOLS-$(CONFIG_ZLIB) += cws2fws tools/target_dec_%_fuzzer.o: tools/target_dec_fuzzer.c $(COMPILE_C) -DFFMPEG_DECODER=$* +tools/target_dem_fuzzer.o: tools/target_dem_fuzzer.c + $(COMPILE_C) + OUTDIRS += tools clean:: diff --git a/tools/target_dem_fuzzer.c b/tools/target_dem_fuzzer.c new file mode 100644 index 0000000000..b51c766878 --- /dev/null +++ b/tools/target_dem_fuzzer.c @@ -0,0 +1,163 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include "libavutil/avassert.h" + +#include "libavcodec/avcodec.h" +#include "libavcodec/bytestream.h" +#include "libavformat/avformat.h" + + +typedef struct IOContext { + int64_t pos; + int64_t filesize; + uint8_t *fuzz; + int fuzz_size; +} IOContext; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size); + +static void error(const char *err) +{ + fprintf(stderr, "%s", err); + exit(1); +} + +static int io_read(void *opaque, uint8_t *buf, int buf_size) +{ + IOContext *c = opaque; + int size = FFMIN(buf_size, c->fuzz_size); + + if (!c->fuzz_size) { + c->filesize = FFMIN(c->pos, c->filesize); + return AVERROR_EOF; + } + + memcpy(buf, c->fuzz, size); + c->fuzz += size; + c->fuzz_size -= size; + c->pos += size; + c->filesize = FFMAX(c->filesize, c->pos); + + return size; +} + +static int64_t io_seek(void *opaque, int64_t offset, int whence) +{ + IOContext *c = opaque; + + if (whence == SEEK_CUR) { + if (offset > INT64_MAX - c->pos) + return -1; + offset += c->pos; + } else if (whence == SEEK_END) { + if (offset > INT64_MAX - c->filesize) + return -1; + offset += c->filesize; + } + if (offset < 0 || offset > c->filesize) + return -1; + c->pos = offset; + return 0; +} + +// Ensure we don't loop forever +const uint32_t maxiteration = 8096; + +static const uint64_t FUZZ_TAG = 0x4741542D5A5A5546ULL; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + const uint64_t fuzz_tag = FUZZ_TAG; + uint32_t it = 0; + AVFormatContext *avfmt = avformat_alloc_context(); + AVPacket pkt; + char filename[1025] = {0}; + AVIOContext *fuzzed_pb = NULL; + uint8_t *io_buffer; + int io_buffer_size = 32768; + int64_t filesize = size; + IOContext opaque; + static int c; + int seekable = 0; + int ret; + + if (!c) { + av_register_all(); + avcodec_register_all(); + av_log_set_level(AV_LOG_PANIC); + c=1; + } + + if (!avfmt) + error("Failed avformat_alloc_context()"); + + if (size > 2048) { + GetByteContext gbc; + memcpy (filename, data + size - 1024, 1024); + bytestream2_init(&gbc, data + size - 2048, 1024); + size -= 2048; + + io_buffer_size = bytestream2_get_le32(&gbc) & 0xFFFFFFF; + seekable = bytestream2_get_byte(&gbc) & 1; + filesize = bytestream2_get_le64(&gbc) & 0x7FFFFFFFFFFFFFFF; + } + io_buffer = av_malloc(io_buffer_size); + if (!io_buffer) + error("Failed to allocate io_buffer"); + + opaque.filesize = filesize; + opaque.pos = 0; + opaque.fuzz = data; + opaque.fuzz_size= size; + fuzzed_pb = avio_alloc_context(io_buffer, io_buffer_size, 0, &opaque, + io_read, NULL, seekable ? io_seek : NULL); + if (!fuzzed_pb) + error("avio_alloc_context failed"); + + avfmt->pb = fuzzed_pb; + + ret = avformat_open_input(&avfmt, filename, NULL, NULL); + if (ret < 0) { + av_freep(&fuzzed_pb->buffer); + av_freep(&fuzzed_pb); + avformat_free_context(avfmt); + return 0; + } + + ret = avformat_find_stream_info(avfmt, NULL); + if (ret < 0) + goto end; + + av_init_packet(&pkt); + + //TODO, test seeking + + for(it = 0; it < maxiteration; it++) { + ret = av_read_frame(avfmt, &pkt); + if (ret < 0) + break; + av_packet_unref(&pkt); + } +end: + av_freep(&fuzzed_pb->buffer); + av_freep(&fuzzed_pb); + avformat_close_input(&avfmt); + + return 0; +}