[vlc-commits] vlc-demux-run: add demux fuzzing helper
Rémi Denis-Courmont
git at videolan.org
Tue Sep 5 19:58:09 CEST 2017
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Tue Oct 25 17:01:35 2016 +0300| [6aaa5f129a6947c05c32b914388a9cf94f9dacf5] | committer: Rémi Denis-Courmont
vlc-demux-run: add demux fuzzing helper
This includes support for statically linked plugins. It vastly increases
the test iteration speed, which is critical for fuzz testing.
Furthermore, it is necessary for coverage-driven fuzz testing to work at
all.
This also provides a (manually compiled only) back-end for LLVM's
LibFuzzer using mostly the same code.
1) Debugging, regression testing or unguided fuzzing:
- Make a normal build (debug and sanitization recommended).
- Execute: "test/vlc-demux-run [demux name] <file path>"
2) American Fuzzy Lop run:
- Make a *static* build with AFL as the toolchain.
- (Where applicable) perform adequate religious luck granting
offerings or other rites.
- Run AFL with test/vlc-demux-run as the fuzzed executable.
3) LibFuzzer:
- Make a preferrably static build with Clang as the toolchain.
- Manually build test/vlc-demux-libfuzzer.
- Run the executable with the LibFuzzer command line parameters syntax.
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=6aaa5f129a6947c05c32b914388a9cf94f9dacf5
---
test/Makefile.am | 69 +++++++++
test/src/input/demux-run.c | 362 +++++++++++++++++++++++++++++++++++++++++++++
test/src/input/demux-run.h | 31 ++++
test/vlc-demux-libfuzzer.c | 41 +++++
test/vlc-demux-run.c | 52 +++++++
5 files changed, 555 insertions(+)
diff --git a/test/Makefile.am b/test/Makefile.am
index 95d4df6516..222edbde96 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -137,3 +137,72 @@ FORCE:
@exit 1
.PHONY: FORCE
+
+libvlc_demux_run_la_SOURCES = src/input/demux-run.c src/input/demux-run.h
+libvlc_demux_run_la_CPPFLAGS = $(AM_CPPFLAGS) \
+ -DTOP_BUILDDIR=\"$$(cd "$(top_builddir)"; pwd)\" \
+ -DTOP_SRCDIR=\"$$(cd "$(top_srcdir)"; pwd)\"
+libvlc_demux_run_la_LDFLAGS = -no-install -static
+libvlc_demux_run_la_LIBADD = \
+ ../lib/libvlc.la ../src/libvlccore.la ../compat/libcompat.la
+if !HAVE_DYNAMIC_PLUGINS
+libvlc_demux_run_la_CPPFLAGS += -DHAVE_STATIC_MODULES
+libvlc_demux_run_la_LIBADD += \
+ ../modules/libaiff_plugin.la \
+ ../modules/libasf_plugin.la \
+ ../modules/libau_plugin.la \
+ ../modules/libavi_plugin.la \
+ ../modules/libcaf_plugin.la \
+ ../modules/libdiracsys_plugin.la \
+ ../modules/libes_plugin.la \
+ ../modules/libflacsys_plugin.la \
+ ../modules/libh26x_plugin.la \
+ ../modules/libmjpeg_plugin.la \
+ ../modules/libmkv_plugin.la \
+ ../modules/libmp4_plugin.la \
+ ../modules/libnsc_plugin.la \
+ ../modules/libnsv_plugin.la \
+ ../modules/libnuv_plugin.la \
+ ../modules/libps_plugin.la \
+ ../modules/libpva_plugin.la \
+ ../modules/libsap_plugin.la \
+ ../modules/libsmf_plugin.la \
+ ../modules/libsubtitle_plugin.la \
+ ../modules/libtta_plugin.la \
+ ../modules/libttml_plugin.la \
+ ../modules/libty_plugin.la \
+ ../modules/libvoc_plugin.la \
+ ../modules/libwav_plugin.la \
+ ../modules/libxa_plugin.la \
+ ../modules/libpacketizer_a52_plugin.la \
+ ../modules/libpacketizer_dts_plugin.la \
+ ../modules/libpacketizer_dirac_plugin.la \
+ ../modules/libpacketizer_flac_plugin.la \
+ ../modules/libpacketizer_h264_plugin.la \
+ ../modules/libpacketizer_hevc_plugin.la \
+ ../modules/libpacketizer_mlp_plugin.la \
+ ../modules/libpacketizer_mpeg4audio_plugin.la \
+ ../modules/libpacketizer_mpeg4video_plugin.la \
+ ../modules/libpacketizer_mpegaudio_plugin.la \
+ ../modules/libpacketizer_mpegvideo_plugin.la \
+ ../modules/libpacketizer_vc1_plugin.la \
+ ../modules/libfilesystem_plugin.la \
+ ../modules/libxml_plugin.la \
+ -lstdc++
+if HAVE_DVBPSI
+libvlc_demux_run_la_CPPFLAGS += -DHAVE_DVBPSI
+libvlc_demux_run_la_LIBADD += ../modules/libts_plugin.la
+endif
+endif
+noinst_LTLIBRARIES = libvlc_demux_run.la
+
+#
+# Fuzzers
+#
+vlc_demux_run_LDFLAGS = -no-install -static
+vlc_demux_run_LDADD = libvlc_demux_run.la
+noinst_PROGRAMS = vlc-demux-run
+
+vlc_demux_libfuzzer_CPPFLAGS = $(vlc_static_CPPFLAGS)
+vlc_demux_libfuzzer_LDADD = -lFuzzer libvlc_demux_run.la
+EXTRA_PROGRAMS += vlc-demux-libfuzzer
diff --git a/test/src/input/demux-run.c b/test/src/input/demux-run.c
new file mode 100644
index 0000000000..e6f239a1d2
--- /dev/null
+++ b/test/src/input/demux-run.c
@@ -0,0 +1,362 @@
+/**
+ * @file demux-run.c
+ */
+/*****************************************************************************
+ * Copyright © 2016 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rémi Denis-Courmont reserves the right to redistribute this file under
+ * the terms of the GNU Lesser General Public License as published by the
+ * the Free Software Foundation; either version 2.1 or the License, or
+ * (at his option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <vlc_common.h>
+#include <vlc_access.h>
+#include <vlc_block.h>
+#include <vlc_demux.h>
+#include <vlc_es_out.h>
+#include <vlc_url.h>
+#include "../../lib/libvlc_internal.h"
+
+#include <vlc/vlc.h>
+
+#include "demux-run.h"
+
+#if 0
+#define debug(...) printf(__VA_ARGS__)
+#else
+#define debug(...) (void)0
+#endif
+
+struct test_es_out_t
+{
+ struct es_out_t out;
+ struct es_out_id_t *ids;
+};
+
+struct es_out_id_t
+{
+ struct es_out_id_t *next;
+};
+
+static es_out_id_t *EsOutAdd(es_out_t *out, const es_format_t *fmt)
+{
+ struct test_es_out_t *ctx = (struct test_es_out_t *) out;
+
+ if (fmt->i_group < 0)
+ return NULL;
+
+ es_out_id_t *id = malloc(sizeof (*id));
+ if (unlikely(id == NULL))
+ return NULL;
+
+ id->next = ctx->ids;
+ ctx->ids = id;
+
+ debug("[%p] Added ES\n", (void *)id);
+ return id;
+}
+
+static void EsOutCheckId(es_out_t *out, es_out_id_t *id)
+{
+ struct test_es_out_t *ctx = (struct test_es_out_t *) out;
+
+ for (es_out_id_t *ids = ctx->ids; ids != NULL; ids = ids->next)
+ if (ids == id)
+ return;
+
+ abort();
+}
+
+static int EsOutSend(es_out_t *out, es_out_id_t *id, block_t *block)
+{
+ //debug("[%p] Sent ES: %zu\n", (void *)idd, block->i_buffer);
+ EsOutCheckId(out, id);
+ block_Release(block);
+ return VLC_SUCCESS;
+}
+
+static void EsOutDelete(es_out_t *out, es_out_id_t *id)
+{
+ struct test_es_out_t *ctx = (struct test_es_out_t *) out;
+ es_out_id_t **pp = &ctx->ids;
+
+ while (*pp != id)
+ {
+ if (*pp == NULL)
+ abort();
+ pp = &((*pp)->next);
+ }
+
+ debug("[%p] Deleted ES\n", (void *)id);
+ *pp = id->next;
+ free(id);
+}
+
+static int EsOutControl(es_out_t *out, int query, va_list args)
+{
+ switch (query)
+ {
+ case ES_OUT_SET_ES:
+ break;
+ case ES_OUT_RESTART_ES:
+ abort();
+ case ES_OUT_SET_ES_DEFAULT:
+ case ES_OUT_SET_ES_STATE:
+ break;
+ case ES_OUT_GET_ES_STATE:
+ EsOutCheckId(out, va_arg(args, es_out_id_t *));
+ *va_arg(args, bool *) = true;
+ break;
+ case ES_OUT_SET_ES_CAT_POLICY:
+ break;
+ case ES_OUT_SET_GROUP:
+ abort();
+ case ES_OUT_SET_PCR:
+ case ES_OUT_SET_GROUP_PCR:
+ case ES_OUT_RESET_PCR:
+ case ES_OUT_SET_ES_FMT:
+ case ES_OUT_SET_NEXT_DISPLAY_TIME:
+ case ES_OUT_SET_GROUP_META:
+ case ES_OUT_SET_GROUP_EPG:
+ case ES_OUT_DEL_GROUP:
+ case ES_OUT_SET_ES_SCRAMBLED_STATE:
+ break;
+ case ES_OUT_GET_EMPTY:
+ *va_arg(args, bool *) = true;
+ break;
+ case ES_OUT_SET_META:
+ break;
+ case ES_OUT_GET_PCR_SYSTEM:
+ case ES_OUT_MODIFY_PCR_SYSTEM:
+ abort();
+ default:
+ return VLC_EGENERIC;
+ }
+ return VLC_SUCCESS;
+}
+
+static void EsOutDestroy(es_out_t *out)
+{
+ struct test_es_out_t *ctx = (struct test_es_out_t *)out;
+ es_out_id_t *id;
+
+ while ((id = ctx->ids) != NULL)
+ {
+ ctx->ids = id->next;
+ free(id);
+ }
+ free(ctx);
+}
+
+static es_out_t *test_es_out_create(vlc_object_t *parent)
+{
+ struct test_es_out_t *ctx = malloc(sizeof (*ctx));
+ if (ctx == NULL)
+ {
+ fprintf(stderr, "Error: cannot create ES output.\n");
+ return NULL;
+ }
+
+ ctx->ids = NULL;
+
+ es_out_t *out = &ctx->out;
+ out->pf_add = EsOutAdd;
+ out->pf_send = EsOutSend;
+ out->pf_del = EsOutDelete;
+ out->pf_control = EsOutControl;
+ out->pf_destroy = EsOutDestroy;
+ out->p_sys = (void *)parent;
+
+ return out;
+}
+
+static int demux_process_stream(const char *name, stream_t *s)
+{
+ if (name == NULL)
+ name = "any";
+
+ if (s == NULL)
+ return -1;
+
+ es_out_t *out = test_es_out_create(VLC_OBJECT(s));
+ if (out == NULL)
+ return -1;
+
+ demux_t *demux = demux_New(VLC_OBJECT(s), name, "", s, out);
+ if (demux == NULL)
+ {
+ es_out_Delete(out);
+ vlc_stream_Delete(s);
+ debug("Error: cannot create demultiplexer: %s\n", name);
+ return -1;
+ }
+
+ uintmax_t i = 0;
+ int val;
+
+ while ((val = demux_Demux(demux)) == VLC_DEMUXER_SUCCESS)
+ i++;
+
+ demux_Delete(demux);
+ es_out_Delete(out);
+
+ debug("Completed with %ju iteration(s).\n", i);
+
+ return val == VLC_DEMUXER_EOF ? 0 : -1;
+}
+
+static libvlc_instance_t *libvlc_create(void)
+{
+ const char *argv[] = {
+ NULL
+ };
+ unsigned argc = (sizeof (argv) / sizeof (*argv)) - 1;
+
+#ifdef TOP_BUILDDIR
+# ifndef HAVE_STATIC_MODULES
+ setenv("VLC_PLUGIN_PATH", TOP_BUILDDIR"/modules", 1);
+# endif
+ setenv("VLC_DATA_PATH", TOP_SRCDIR"/share", 1);
+#endif
+
+ libvlc_instance_t *vlc = libvlc_new(argc, argv);
+ if (vlc == NULL)
+ fprintf(stderr, "Error: cannot initialize LibVLC.\n");
+ return vlc;
+}
+
+int vlc_demux_process_url(const char *demux, const char *url)
+{
+ libvlc_instance_t *vlc = libvlc_create();
+ if (vlc == NULL)
+ return -1;
+
+ stream_t *s = vlc_access_NewMRL(VLC_OBJECT(vlc->p_libvlc_int), url);
+ if (s == NULL)
+ fprintf(stderr, "Error: cannot create input stream: %s\n", url);
+
+ int ret = demux_process_stream(demux, s);
+ libvlc_release(vlc);
+ return ret;
+}
+
+int vlc_demux_process_path(const char *demux, const char *path)
+{
+ char *url = vlc_path2uri(path, NULL);
+ if (url == NULL)
+ {
+ fprintf(stderr, "Error: cannot convert path to URL: %s\n", path);
+ return -1;
+ }
+
+ int ret = vlc_demux_process_url(demux, url);
+ free(url);
+ return ret;
+}
+
+int vlc_demux_process_memory(const char *demux,
+ const unsigned char *buf, size_t length)
+{
+ libvlc_instance_t *vlc = libvlc_create();
+ if (vlc == NULL)
+ return -1;
+
+ stream_t *s = vlc_stream_MemoryNew(VLC_OBJECT(vlc->p_libvlc_int),
+ (void *)buf, length, true);
+ if (s == NULL)
+ fprintf(stderr, "Error: cannot create input stream\n");
+
+ int ret = demux_process_stream(demux, s);
+ libvlc_release(vlc);
+ return ret;
+}
+
+#ifdef HAVE_STATIC_MODULES
+# include <vlc_plugin.h>
+
+typedef int (*vlc_plugin_cb)(int (*)(void *, void *, int, ...), void *);
+extern vlc_plugin_cb vlc_static_modules[];
+
+#define PLUGINS(f) \
+ f(filesystem) \
+ f(xml) \
+ f(aiff) \
+ f(asf) \
+ f(au) \
+ f(avi) \
+ f(caf) \
+ f(diracsys) \
+ f(es) \
+ f(flacsys) \
+ f(h26x) \
+ f(mjpeg) \
+ f(mkv) \
+ f(mp4) \
+ f(nsc) \
+ f(nsv) \
+ f(ps) \
+ f(pva) \
+ f(sap) \
+ f(smf) \
+ f(subtitle) \
+ PLUGIN_TS(f) \
+ f(tta) \
+ f(ttml) \
+ f(ty) \
+ f(voc) \
+ f(wav) \
+ f(xa) \
+ f(a52) \
+ f(dirac) \
+ f(dts) \
+ f(flac) \
+ f(h264) \
+ f(hevc) \
+ f(mlp) \
+ f(mpeg4audio) \
+ f(mpeg4video) \
+ f(mpegaudio) \
+ f(mpegvideo) \
+ f(vc1)
+#ifdef HAVE_DVBPSI
+# define PLUGIN_TS(f) f(ts)
+#else
+# define PLUGIN_TS(f)
+#endif
+
+#define DECL_PLUGIN(p) \
+ int vlc_entry__##p(int (*)(void *, void *, int, ...), void *);
+
+#define FUNC_PLUGIN(p) \
+ vlc_entry__##p,
+
+PLUGINS(DECL_PLUGIN)
+
+__attribute__((visibility("default")))
+vlc_plugin_cb vlc_static_modules[] = { PLUGINS(FUNC_PLUGIN) NULL };
+#endif /* HAVE_STATIC_MODULES */
diff --git a/test/src/input/demux-run.h b/test/src/input/demux-run.h
new file mode 100644
index 0000000000..e4c10f4f07
--- /dev/null
+++ b/test/src/input/demux-run.h
@@ -0,0 +1,31 @@
+/**
+ * @file demux-run.c
+ */
+/*****************************************************************************
+ * Copyright © 2016 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rémi Denis-Courmont reserves the right to redistribute this file under
+ * the terms of the GNU Lesser General Public License as published by the
+ * the Free Software Foundation; either version 2.1 or the License, or
+ * (at his option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+
+int vlc_demux_process_url(const char *demux, const char *url);
+int vlc_demux_process_path(const char *demux, const char *path);
+int vlc_demux_process_memory(const char *demux,
+ const unsigned char *buf, size_t length);
diff --git a/test/vlc-demux-libfuzzer.c b/test/vlc-demux-libfuzzer.c
new file mode 100644
index 0000000000..b9774ebad2
--- /dev/null
+++ b/test/vlc-demux-libfuzzer.c
@@ -0,0 +1,41 @@
+/**
+ * @file vlc-demux-test.c
+ */
+/*****************************************************************************
+ * Copyright © 2016 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rémi Denis-Courmont reserves the right to redistribute this file under
+ * the terms of the GNU Lesser General Public License as published by the
+ * the Free Software Foundation; either version 2.1 or the License, or
+ * (at his option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+#include "src/input/demux-run.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ vlc_demux_process_memory(getenv("VLC_DEMUX"), data, size);
+ return 0;
+}
diff --git a/test/vlc-demux-run.c b/test/vlc-demux-run.c
new file mode 100644
index 0000000000..334dbc618f
--- /dev/null
+++ b/test/vlc-demux-run.c
@@ -0,0 +1,52 @@
+/**
+ * @file vlc-demux-test.c
+ */
+/*****************************************************************************
+ * Copyright © 2016 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rémi Denis-Courmont reserves the right to redistribute this file under
+ * the terms of the GNU Lesser General Public License as published by the
+ * the Free Software Foundation; either version 2.1 or the License, or
+ * (at his option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include "src/input/demux-run.h"
+
+int main(int argc, char *argv[])
+{
+ const char *demux = NULL, *filename;
+
+ switch (argc)
+ {
+ case 3:
+ demux = argv[argc - 2];
+ /* fall through */
+ case 2:
+ filename = argv[argc - 1];
+ break;
+ default:
+ fprintf(stderr, "Usage: %s [demux] <filename>\n", argv[0]);
+ return 1;
+ }
+
+ return -vlc_demux_process_path(demux, filename);
+}
More information about the vlc-commits
mailing list