[libsoup/wip/fuzzing: 1/5] Add basic fuzzing support




commit 46969e196a1b29120c5ae1fefa83df0152274e7b
Author: Patrick Griffis <pgriffis igalia com>
Date:   Tue Dec 15 17:42:40 2020 -0600

    Add basic fuzzing support

 .gitlab-ci.yml                    | 13 +++++++++++
 fuzzing/fuzz.h                    | 21 ++++++++++++++++++
 fuzzing/fuzz_cookie_parse.c       | 17 +++++++++++++++
 fuzzing/fuzz_cookie_parse.dict    |  9 ++++++++
 fuzzing/fuzz_decode_data_uri.c    | 19 ++++++++++++++++
 fuzzing/fuzz_decode_data_uri.dict |  5 +++++
 fuzzing/meson.build               | 46 +++++++++++++++++++++++++++++++++++++++
 meson.build                       |  7 +++---
 meson_options.txt                 |  6 +++++
 9 files changed, 140 insertions(+), 3 deletions(-)
---
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5f73e929..17d33977 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -58,6 +58,19 @@ fedora-asan:
     paths:
       - "_build/meson-logs/testlog.txt"
 
+fedora-fuzzing:
+  stage: build
+  allow_failure: true
+  variables:
+    CC: clang
+  script:
+    - meson _build -Dauto-features=enabled -Dfuzzing=enabled -Dintrospection=disabled -Dvapi=disabled
+    - meson test -C _build --suite=fuzzing --timeout-multiplier=10
+  artifacts:
+    when: on_failure
+    paths:
+      - _build/meson-logs/
+
 reference:
   stage: docs
   variables:
diff --git a/fuzzing/fuzz.h b/fuzzing/fuzz.h
new file mode 100644
index 00000000..0d380285
--- /dev/null
+++ b/fuzzing/fuzz.h
@@ -0,0 +1,21 @@
+#include "libsoup/soup.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_cookie_parse.c b/fuzzing/fuzz_cookie_parse.c
new file mode 100644
index 00000000..296b8d75
--- /dev/null
+++ b/fuzzing/fuzz_cookie_parse.c
@@ -0,0 +1,17 @@
+#include "fuzz.h"
+
+int
+LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
+{
+    // We only accept NUL terminated strings
+    if (!size || data[size - 1] != '\0')
+        return 0;
+
+    fuzz_set_logging_func ();
+
+    SoupCookie *cookie = soup_cookie_parse ((char*)data, NULL);
+
+    g_clear_pointer (&cookie, soup_cookie_free);
+
+    return 0;
+}
\ No newline at end of file
diff --git a/fuzzing/fuzz_cookie_parse.dict b/fuzzing/fuzz_cookie_parse.dict
new file mode 100644
index 00000000..bed45447
--- /dev/null
+++ b/fuzzing/fuzz_cookie_parse.dict
@@ -0,0 +1,9 @@
+"domain="
+"expires="
+"httponly"
+"max-age="
+"secure"
+"samesite="
+"path="
+"="
+";"
\ No newline at end of file
diff --git a/fuzzing/fuzz_decode_data_uri.c b/fuzzing/fuzz_decode_data_uri.c
new file mode 100644
index 00000000..97e0369f
--- /dev/null
+++ b/fuzzing/fuzz_decode_data_uri.c
@@ -0,0 +1,19 @@
+#include "fuzz.h"
+
+int
+LLVMFuzzerTestOneInput (const unsigned char *data, size_t size)
+{
+    GBytes *bytes;
+    char *data_uri;
+
+    fuzz_set_logging_func ();
+
+    data_uri = g_strdup_printf ("data:%.*s", (int)size, data);
+    // g_print("%s", data_uri);
+    bytes = soup_uri_decode_data_uri (data_uri, NULL);
+
+    g_clear_pointer (&bytes, g_bytes_unref);
+    g_free (data_uri);
+
+    return 0;
+}
\ No newline at end of file
diff --git a/fuzzing/fuzz_decode_data_uri.dict b/fuzzing/fuzz_decode_data_uri.dict
new file mode 100644
index 00000000..25fff80b
--- /dev/null
+++ b/fuzzing/fuzz_decode_data_uri.dict
@@ -0,0 +1,5 @@
+";base64,"
+","
+";"
+"text/plain"
+"text/plain;base64,"
\ No newline at end of file
diff --git a/fuzzing/meson.build b/fuzzing/meson.build
new file mode 100644
index 00000000..865bfcd3
--- /dev/null
+++ b/fuzzing/meson.build
@@ -0,0 +1,46 @@
+fs = import('fs')
+
+fuzz_targets = [
+  'fuzz_decode_data_uri',
+  'fuzz_cookie_parse',
+]
+
+fuzzing_args = '-fsanitize=fuzzer,address,undefined'
+have_fuzzing = cc.has_argument(fuzzing_args)
+fuzzing_feature = get_option('fuzzing')
+
+if not have_fuzzing and fuzzing_feature.enabled()
+  error('clang and libfuzzer are required for fuzzing')
+endif
+
+if have_fuzzing and (fuzzing_feature.enabled() or fuzzing_feature.auto())
+  foreach target : fuzz_targets
+    exe = executable(target, [target + '.c'],
+      c_args : [fuzzing_args, '-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'],
+      link_args : fuzzing_args,
+      dependencies : libsoup_dep,
+    )
+
+    extra_args = []
+    dict_file = join_paths(meson.current_source_dir(), target + '.dict')
+    if fs.exists(dict_file)
+      extra_args += '-dict=' + dict_file
+    endif
+
+    test(target, exe,
+      args: [
+        '-runs=500000',
+        '-jobs=16', # This will automatically limit itself to half your systems threads
+        '-artifact_prefix=meson-logs/' + target + '-',
+        '-print_final_stats=1',
+      ] + extra_args,
+      env: [
+        'ASAN_OPTIONS=fast_unwind_on_malloc=0',
+        'UBSAN_OPTIONS=print_stacktrace=1',
+      ],
+      suite: 'fuzzing',
+      timeout: 240,
+      priority: -1,
+    )
+  endforeach
+endif
\ No newline at end of file
diff --git a/meson.build b/meson.build
index 6564856c..a120a362 100644
--- a/meson.build
+++ b/meson.build
@@ -1,6 +1,6 @@
 project('libsoup', 'c',
         version: '2.91.0',
-        meson_version : '>=0.50',
+        meson_version : '>= 0.53',
         license : 'LGPL2',
         default_options : 'c_std=c99')
 
@@ -66,8 +66,9 @@ else
       '-Wno-missing-include-dirs',
   ]
 
-  if get_option('b_sanitize') == 'address'
-    test_cflags += '-fno-omit-frame-pointer'
+  if get_option('b_sanitize') == 'address' or get_option('b_sanitize') == 'address,undefined' or \
+     get_option('fuzzing').enabled()
+    test_cflags += ['-fno-omit-frame-pointer', '-fno-optimize-sibling-calls']
   endif
 
   common_flags += cc.get_supported_arguments(test_cflags)
diff --git a/meson_options.txt b/meson_options.txt
index 6eab71ac..3a7bae5c 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -70,3 +70,9 @@ option('sysprof',
   value: 'auto',
   description: 'enable sysprof-capture support for profiling'
 )
+
+option('fuzzing',
+  type: 'feature',
+  value: 'disabled',
+  description: 'enable fuzzing support'
+)
\ No newline at end of file


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