]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fuzz: add initial fuzzing infrastructure
authorJonathan Rudenberg <jonathan@titanous.com>
Sun, 14 Jan 2018 00:51:07 +0000 (19:51 -0500)
committerJonathan Rudenberg <jonathan@titanous.com>
Wed, 17 Jan 2018 18:57:06 +0000 (13:57 -0500)
The fuzzers will be used by oss-fuzz to automatically and
continuously fuzz systemd.

This commit includes the build tooling necessary to build fuzz
targets, and a fuzzer for the DNS packet parser.

meson.build
meson_options.txt
scripts/oss-fuzz.sh [new file with mode: 0755]
src/fuzz/fuzz-dns-packet.c [new file with mode: 0644]
src/fuzz/fuzz-dns-packet.options [new file with mode: 0644]
src/fuzz/fuzz-main.c [new file with mode: 0644]
src/fuzz/fuzz.h [new file with mode: 0644]
src/fuzz/meson.build [new file with mode: 0644]
tools/meson-check-api-docs.sh [changed mode: 0644->0755]

index 5066ccf4323b032ad22bc92d5ae5eb1203f0c5d2..784a138f2ff6b396b8edfa6705779c7cfae3fe38 100644 (file)
@@ -268,6 +268,11 @@ if get_option('tests') != 'false'
         endif
 endif
 
+ossfuzz = get_option('oss-fuzz')
+if ossfuzz
+        fuzzing_engine = meson.get_compiler('cpp').find_library('FuzzingEngine')
+endif
+
 foreach arg : ['-Wextra',
                '-Werror=undef',
                '-Wlogical-op',
@@ -302,7 +307,6 @@ foreach arg : ['-Wextra',
                '-fvisibility=hidden',
                '-fstack-protector',
                '-fstack-protector-strong',
-               '-fPIE',
                '--param=ssp-buffer-size=4',
               ]
         if cc.has_argument(arg)
@@ -310,6 +314,14 @@ foreach arg : ['-Wextra',
         endif
 endforeach
 
+# the oss-fuzz fuzzers are not built with -fPIE, so don't
+# enable it when we are linking against them
+if not ossfuzz
+        if cc.has_argument('-fPIE')
+              add_project_arguments('-fPIE', language : 'c')
+        endif
+endif
+
 # "negative" arguments: gcc on purpose does not return an error for "-Wno-"
 # arguments, just emits a warnings. So test for the "positive" version instead.
 foreach arg : ['unused-parameter',
@@ -360,7 +372,7 @@ foreach arg : ['-Wl,-z,relro',
                            cc.cmd_array(), '-x', 'c', arg,
                            '-include', link_test_c).returncode() == 0
         message('Linking with @0@ supported: @1@'.format(arg, have ? 'yes' : 'no'))
-        if have
+        if have and (arg != '-pie' or not ossfuzz)
                 add_project_link_arguments(arg, language : 'c')
         endif
 endforeach
@@ -1178,6 +1190,7 @@ endforeach
 want_tests = get_option('tests')
 install_tests = get_option('install-tests')
 tests = []
+fuzzers = []
 
 conf.set10('SYSTEMD_SLOW_TESTS_DEFAULT', get_option('slow-tests'))
 
@@ -1303,6 +1316,7 @@ subdir('src/vconsole')
 subdir('src/boot/efi')
 
 subdir('src/test')
+subdir('src/fuzz')
 subdir('rules')
 subdir('test')
 
@@ -2457,6 +2471,39 @@ test('test-libudev-sym',
 
 ############################################################
 
+fuzzer_exes = []
+
+foreach tuple : fuzzers
+        sources = tuple[0]
+        link_with = tuple[1].length() > 0 ? tuple[1] : [libshared]
+        dependencies = tuple[2]
+        defs = tuple.length() >= 4 ? tuple[3] : []
+        incs = tuple.length() >= 5 ? tuple[4] : includes
+
+        if ossfuzz
+                dependencies += fuzzing_engine
+        else
+                sources += 'src/fuzz/fuzz-main.c'
+        endif
+
+        name = sources[0].split('/')[-1].split('.')[0]
+
+        fuzzer_exes += executable(
+                name,
+                sources,
+                include_directories : [incs, include_directories('src/fuzz')],
+                link_with : link_with,
+                dependencies : dependencies,
+                c_args : defs,
+                install : false)
+endforeach
+
+run_target('fuzzers',
+        depends : fuzzer_exes,
+        command : ['true'])
+
+############################################################
+
 make_directive_index_py = find_program('tools/make-directive-index.py')
 make_man_index_py = find_program('tools/make-man-index.py')
 xml_helper_py = find_program('tools/xml_helper.py')
index af8be576a10c012e8f8479a227a678d9ce27d080..9e7cad7471a7b39162e91198852a7e6594e3511a 100644 (file)
@@ -291,3 +291,6 @@ option('slow-tests', type : 'boolean', value : 'false',
        description : 'run the slow tests by default')
 option('install-tests', type : 'boolean', value : 'false',
        description : 'install test executables')
+
+option('oss-fuzz', type : 'boolean', value : 'false',
+       description : 'build against oss-fuzz')
diff --git a/scripts/oss-fuzz.sh b/scripts/oss-fuzz.sh
new file mode 100755 (executable)
index 0000000..b871d74
--- /dev/null
@@ -0,0 +1,36 @@
+#!/bin/bash
+# SPDX-License-Identifier: LGPL-2.1+
+#
+# Copyright 2017 Jonathan Rudenberg
+#
+# systemd 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.
+#
+# systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>.
+
+set -ex
+
+export LC_CTYPE=C.UTF-8
+
+meson $WORK -Doss-fuzz=true -Db_lundef=false -Dseccomp=false -Dlz4=false -Dlibiptc=false -Dlibidn=false
+ninja -C $WORK fuzzers
+
+# get DNS packet corpus
+df=$WORK/dns-fuzzing
+rm -rf $df
+git clone --depth 1 https://github.com/CZ-NIC/dns-fuzzing $df
+zip -jqr $OUT/fuzz-dns-packet_seed_corpus.zip $df/packet
+
+mkdir -p $OUT/src/shared
+mv $WORK/src/shared/libsystemd-shared-*.so $OUT/src/shared
+
+find $WORK -maxdepth 1 -type f -executable -name "fuzz-*" -exec mv {} $OUT \;
+mv $WORK/*.so src/fuzz/*.options $OUT
diff --git a/src/fuzz/fuzz-dns-packet.c b/src/fuzz/fuzz-dns-packet.c
new file mode 100644 (file)
index 0000000..3d8d79a
--- /dev/null
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/***
+  Copyright 2018 Jonathan Rudenberg
+
+  systemd 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.
+
+  systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "fuzz.h"
+#include "resolved-dns-packet.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
+        int r;
+
+        if (size > DNS_PACKET_SIZE_MAX)
+                return 0;
+
+        r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX);
+        if (r < 0)
+                return 0;
+        p->size = 0; /* by default append starts after the header, undo that */
+        dns_packet_append_blob(p, data, size, NULL);
+        if (size < DNS_PACKET_HEADER_SIZE) {
+                /* make sure we pad the packet back up to the minimum header size */
+                assert(p->allocated >= DNS_PACKET_HEADER_SIZE);
+                memzero(DNS_PACKET_DATA(p) + size, DNS_PACKET_HEADER_SIZE - size);
+                p->size = DNS_PACKET_HEADER_SIZE;
+        }
+        dns_packet_extract(p);
+
+        return 0;
+}
diff --git a/src/fuzz/fuzz-dns-packet.options b/src/fuzz/fuzz-dns-packet.options
new file mode 100644 (file)
index 0000000..0824b19
--- /dev/null
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 65535
diff --git a/src/fuzz/fuzz-main.c b/src/fuzz/fuzz-main.c
new file mode 100644 (file)
index 0000000..ca9abe9
--- /dev/null
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/***
+  Copyright 2018 Jonathan Rudenberg
+
+  systemd 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.
+
+  systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "alloc-util.h"
+#include "log.h"
+#include "fileio.h"
+#include "fuzz.h"
+
+/* This is a test driver for the systemd fuzzers that provides main function
+ * for regression testing outside of oss-fuzz (https://github.com/google/oss-fuzz)
+ *
+ * It reads files named on the command line and passes them one by one into the
+ * fuzzer that it is compiled into. */
+
+int main(int argc, char **argv) {
+        int i, r;
+        size_t size;
+        char *name;
+
+        log_set_max_level(LOG_DEBUG);
+        for (i = 1; i < argc; i++) {
+                _cleanup_free_ char *buf = NULL;
+
+                name = argv[i];
+                r = read_full_file(name, &buf, &size);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to open '%s': %m", name);
+                        return EXIT_FAILURE;
+                }
+                printf("%s... ", name);
+                fflush(stdout);
+                (void)LLVMFuzzerTestOneInput((uint8_t*)buf, size);
+                printf("ok\n");
+        }
+        return EXIT_SUCCESS;
+}
diff --git a/src/fuzz/fuzz.h b/src/fuzz/fuzz.h
new file mode 100644 (file)
index 0000000..5293c57
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/***
+  Copyright 2018 Jonathan Rudenberg
+
+  systemd 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.
+
+  systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stddef.h>
+#include <stdint.h>
+
+/* The entry point into the fuzzer */
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build
new file mode 100644 (file)
index 0000000..66cdf13
--- /dev/null
@@ -0,0 +1,25 @@
+# SPDX-License-Identifier: LGPL-2.1+
+# Copyright 2018 Jonathan Rudenberg
+#
+# systemd 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.
+#
+# systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>.
+
+fuzzers += [
+        [['src/fuzz/fuzz-dns-packet.c',
+          dns_type_headers],
+         [libsystemd_resolve_core,
+          libshared],
+         [libgcrypt,
+          libgpg_error,
+          libm]],
+]
old mode 100644 (file)
new mode 100755 (executable)