[glib: 1/2] Integrate oss-fuzz targets



commit a2c09f57f6f491630ea949f38c4bfec95c47ef90
Author: pdknsk <pdknsk gmail com>
Date:   Thu Oct 11 00:02:03 2018 +0000

    Integrate oss-fuzz targets

 fuzzing/README.md              | 49 ++++++++++++++++++++++++++++++++++++++++++
 fuzzing/driver.c               | 32 +++++++++++++++++++++++++++
 fuzzing/fuzz.h                 | 22 +++++++++++++++++++
 fuzzing/fuzz_bookmark.c        | 15 +++++++++++++
 fuzzing/fuzz_bookmark.corpus   |  1 +
 fuzzing/fuzz_dbus_message.c    | 28 ++++++++++++++++++++++++
 fuzzing/fuzz_key.c             | 16 ++++++++++++++
 fuzzing/fuzz_key.corpus        |  2 ++
 fuzzing/fuzz_variant_binary.c  | 21 ++++++++++++++++++
 fuzzing/fuzz_variant_text.c    | 21 ++++++++++++++++++
 fuzzing/fuzz_variant_text.dict | 32 +++++++++++++++++++++++++++
 fuzzing/meson.build            | 28 ++++++++++++++++++++++++
 meson.build                    |  1 +
 13 files changed, 268 insertions(+)
---
diff --git a/fuzzing/README.md b/fuzzing/README.md
new file mode 100644
index 000000000..bcf32b51a
--- /dev/null
+++ b/fuzzing/README.md
@@ -0,0 +1,49 @@
+Fuzz targets used by [oss-fuzz](https://github.com/google/oss-fuzz/).
+
+## How to add new targets
+
+Add **fuzz_target_name.c** and edit `meson.build` accordingly.
+
+New targets are picked up by oss-fuzz automatically within a day. Targets must not be renamed once added.
+
+Add (optional) **fuzz_target_name.dict** containing keywords and magic bytes.
+
+Add (optional) **fuzz_target_name.corpus** with file names on separate lines. Wildcards `?`, `*` and `**` 
are supported. Examples below.
+
+```bash
+glib/*  # all files in directory glib
+glib/** # all files in directory glib and sub-directories
+**.xbel # all files ending with .xbel in the repository
+```
+
+Recommended reading: [Fuzz Target](https://llvm.org/docs/LibFuzzer.html#fuzz-target), 
[Dictionaries](https://llvm.org/docs/LibFuzzer.html#dictionaries), 
[Corpus](https://llvm.org/docs/LibFuzzer.html#corpus)
+
+## How to reproduce oss-fuzz bugs locally
+
+Build with at least the following flags, choosing a sanitizer as needed. A somewhat recent version of 
[clang](http://clang.llvm.org/) is recommended.
+
+```bash
+$ CC=clang CXX=clang++ meson DIR -Db_sanitize=<address|undefined> -Db_lundef=false
+```
+
+Afterwards run the affected target against the provided test case.
+
+```bash
+$ DIR/fuzzing/fuzz_target_name FILE
+```
+
+#### FAQs
+
+###### What about Memory Sanitizer (MSAN)?
+
+Correct MSAN instrumentation is [difficult to 
achieve](https://clang.llvm.org/docs/MemorySanitizer.html#handling-external-code) locally, so false positives 
are very likely to mask the actual bug.
+
+If need be, [you can still 
reproduce](https://github.com/google/oss-fuzz/blob/master/docs/reproducing.md#building-using-docker) those 
bugs with the oss-fuzz provided docker images.
+
+###### There are no file/function names in the stack trace.
+
+`llvm-symbolizer` must be in `PATH`.
+
+###### UndefinedBehavior Sanitizer (UBSAN) doesn't provide a stack trace.
+
+Set environment variable `UBSAN_OPTIONS` to `print_stacktrace=1` prior to running the target.
diff --git a/fuzzing/driver.c b/fuzzing/driver.c
new file mode 100644
index 000000000..99e965ba6
--- /dev/null
+++ b/fuzzing/driver.c
@@ -0,0 +1,32 @@
+/* Simpler gnu89 version of StandaloneFuzzTargetMain.c from LLVM */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern int LLVMFuzzerTestOneInput (const unsigned char *data, size_t size);
+
+int
+main (int argc, char **argv)
+{
+  FILE *f;
+  size_t n_read, len;
+  unsigned char *buf;
+
+  if (argc < 2)
+    return 1;
+
+  f = fopen (argv[1], "r");
+  assert (f);
+  fseek (f, 0, SEEK_END);
+  len = ftell (f);
+  fseek (f, 0, SEEK_SET);
+  buf = (unsigned char*) malloc (len);
+  n_read = fread (buf, 1, len, f);
+  assert (n_read == len);
+  LLVMFuzzerTestOneInput (buf, len);
+
+  free (buf);
+  printf ("Done!\n");
+  return 0;
+}
diff --git a/fuzzing/fuzz.h b/fuzzing/fuzz.h
new file mode 100644
index 000000000..4a879984c
--- /dev/null
+++ b/fuzzing/fuzz.h
@@ -0,0 +1,22 @@
+#include "gio/gio.h"
+#include "glib/glib.h"
+
+int LLVMFuzzerTestOneInput (const unsigned char *data, size_t size);
+
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+static GLogWriterOutput
+empty_logging_func (GLogLevelFlags log_level, const GLogField *fields,
+                    gsize n_fields, gpointer user_data)
+{
+  return G_LOG_WRITER_HANDLED;
+}
+#endif
+
+/* Disables logging for oss-fuzz. Must be used with each target. */
+static void
+fuzz_set_logging_func (void)
+{
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+  g_log_set_writer_func (empty_logging_func, NULL, NULL);
+#endif
+}
diff --git a/fuzzing/fuzz_bookmark.c b/fuzzing/fuzz_bookmark.c
new file mode 100644
index 000000000..4f257fd0c
--- /dev/null
+++ b/fuzzing/fuzz_bookmark.c
@@ -0,0 +1,15 @@
+#include "fuzz.h"
+
+int
+LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
+{
+  GBookmarkFile *bookmark = NULL;
+
+  fuzz_set_logging_func ();
+
+  bookmark = g_bookmark_file_new ();
+  g_bookmark_file_load_from_data (bookmark, (const gchar*) data, size, NULL);
+
+  g_bookmark_file_free (bookmark);
+  return 0;
+}
diff --git a/fuzzing/fuzz_bookmark.corpus b/fuzzing/fuzz_bookmark.corpus
new file mode 100644
index 000000000..5c78bc930
--- /dev/null
+++ b/fuzzing/fuzz_bookmark.corpus
@@ -0,0 +1 @@
+glib/tests/**.xbel
diff --git a/fuzzing/fuzz_dbus_message.c b/fuzzing/fuzz_dbus_message.c
new file mode 100644
index 000000000..bccb2ba3e
--- /dev/null
+++ b/fuzzing/fuzz_dbus_message.c
@@ -0,0 +1,28 @@
+#include "fuzz.h"
+
+const static GDBusCapabilityFlags flags = G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING;
+
+int
+LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
+{
+  gssize bytes;
+  GDBusMessage *msg = NULL;
+  guchar *blob = NULL;
+  gsize msg_size;
+
+  fuzz_set_logging_func ();
+
+  bytes = g_dbus_message_bytes_needed ((guchar*) data, size, NULL);
+  if (bytes <= 0)
+    return 0;
+
+  msg = g_dbus_message_new_from_blob ((guchar*) data, size, flags, NULL);
+  if (msg == NULL)
+    return 0;
+
+  blob = g_dbus_message_to_blob (msg, &msg_size, flags, NULL);
+
+  g_free (blob);
+  g_object_unref (msg);
+  return 0;
+}
diff --git a/fuzzing/fuzz_key.c b/fuzzing/fuzz_key.c
new file mode 100644
index 000000000..8d0edc5fa
--- /dev/null
+++ b/fuzzing/fuzz_key.c
@@ -0,0 +1,16 @@
+#include "fuzz.h"
+
+int
+LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
+{
+  GKeyFile *key = NULL;
+
+  fuzz_set_logging_func ();
+
+  key = g_key_file_new ();
+  g_key_file_load_from_data (key, (const gchar*) data, size, G_KEY_FILE_NONE,
+                             NULL);
+
+  g_key_file_free (key);
+  return 0;
+}
diff --git a/fuzzing/fuzz_key.corpus b/fuzzing/fuzz_key.corpus
new file mode 100644
index 000000000..5a1cb4166
--- /dev/null
+++ b/fuzzing/fuzz_key.corpus
@@ -0,0 +1,2 @@
+glib/tests/**.ini
+gio/tests/**.desktop
diff --git a/fuzzing/fuzz_variant_binary.c b/fuzzing/fuzz_variant_binary.c
new file mode 100644
index 000000000..995718c23
--- /dev/null
+++ b/fuzzing/fuzz_variant_binary.c
@@ -0,0 +1,21 @@
+#include "fuzz.h"
+
+int
+LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
+{
+  GVariant *variant = NULL, *normal_variant = NULL;
+
+  fuzz_set_logging_func ();
+
+  variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size, FALSE,
+                                     NULL, NULL);
+  if (variant == NULL)
+    return 0;
+
+  normal_variant = g_variant_take_ref (g_variant_get_normal_form (variant));
+  g_variant_get_data (variant);
+
+  g_variant_unref (normal_variant);
+  g_variant_unref (variant);
+  return 0;
+}
diff --git a/fuzzing/fuzz_variant_text.c b/fuzzing/fuzz_variant_text.c
new file mode 100644
index 000000000..a79790949
--- /dev/null
+++ b/fuzzing/fuzz_variant_text.c
@@ -0,0 +1,21 @@
+#include "fuzz.h"
+
+int
+LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
+{
+  const gchar *gdata = (const gchar*) data;
+  GVariant *variant = NULL;
+  gchar *text = NULL;
+
+  fuzz_set_logging_func ();
+
+  variant = g_variant_parse (NULL, gdata, gdata + size, NULL, NULL);
+  if (variant == NULL)
+    return 0;
+
+  text = g_variant_print (variant, TRUE);
+
+  g_free (text);
+  g_variant_unref (variant);
+  return 0;
+}
diff --git a/fuzzing/fuzz_variant_text.dict b/fuzzing/fuzz_variant_text.dict
new file mode 100644
index 000000000..a0e528400
--- /dev/null
+++ b/fuzzing/fuzz_variant_text.dict
@@ -0,0 +1,32 @@
+"'"
+"\""
+"("
+")"
+"<"
+">"
+"["
+"]"
+"{"
+"}"
+"*"
+"?"
+"@"
+"b'"
+"b\""
+"boolean"
+"byte"
+"double"
+"false"
+"handle"
+"int16"
+"int32"
+"int64"
+"just"
+"nothing"
+"objectpath"
+"signature"
+"string"
+"true"
+"uint16"
+"uint32"
+"uint64"
diff --git a/fuzzing/meson.build b/fuzzing/meson.build
new file mode 100644
index 000000000..16878fedf
--- /dev/null
+++ b/fuzzing/meson.build
@@ -0,0 +1,28 @@
+fuzz_targets = [
+  'fuzz_bookmark',
+  'fuzz_dbus_message',
+  'fuzz_key',
+  'fuzz_variant_binary',
+  'fuzz_variant_text',
+]
+
+deps = [libgmodule_dep, libgio_dep, libglib_dep, libgobject_dep]
+
+extra_sources = []
+extra_c_args = cc.get_supported_arguments('-Werror=unused-function')
+
+# Links in a static library provided by oss-fuzz, else a standalone driver.
+# https://github.com/google/oss-fuzz/blob/master/docs/new_project_guide.md#buildsh-script-environment
+fuzzing_engine = cxx.find_library('FuzzingEngine', required : false)
+if fuzzing_engine.found()
+  deps += fuzzing_engine
+else
+  extra_sources += 'driver.c'
+endif
+
+foreach target_name : fuzz_targets
+  exe = executable(target_name, [extra_sources, target_name + '.c'],
+    c_args : extra_c_args,
+    dependencies : deps,
+  )
+endforeach
diff --git a/meson.build b/meson.build
index dd5bd8f3f..d562e8e87 100644
--- a/meson.build
+++ b/meson.build
@@ -1980,6 +1980,7 @@ subdir('gio')
 if xgettext.found()
   subdir('po')
 endif
+subdir('fuzzing')
 subdir('tests')
 
 # Install glib-gettextize executable, if a UNIX-style shell is found


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]