]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fuzz-bus-match: new fuzzer
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 4 Mar 2021 20:29:48 +0000 (21:29 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sat, 6 Mar 2021 08:32:18 +0000 (09:32 +0100)
This fuzzer is based on test-bus-match. Even the initial corpus is
derived entirely from it.

https://bugzilla.redhat.com/show_bug.cgi?id=1935084 shows an crash
in bus_match_parse(). I checked the coverage stats on oss-fuzz, and
sadly existing fuzzing did not cover this code at all.

src/libsystemd/meson.build
src/libsystemd/sd-bus/fuzz-bus-match.c [new file with mode: 0644]
test/fuzz/fuzz-bus-match/test.input [new file with mode: 0644]

index 2fe1978d02e63a7fe00b3e162045979c546faef5..ad50815a7b6ddd289207c9f872d9799458618477 100644 (file)
@@ -320,4 +320,6 @@ endif
 
 fuzzers += [
         [['src/libsystemd/sd-bus/fuzz-bus-message.c']],
+
+        [['src/libsystemd/sd-bus/fuzz-bus-match.c']],
 ]
diff --git a/src/libsystemd/sd-bus/fuzz-bus-match.c b/src/libsystemd/sd-bus/fuzz-bus-match.c
new file mode 100644 (file)
index 0000000..0585338
--- /dev/null
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "bus-internal.h"
+#include "bus-match.h"
+#include "env-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+        _cleanup_free_ char *out = NULL; /* out should be freed after g */
+        size_t out_size;
+        _cleanup_fclose_ FILE *g = NULL;
+        _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
+        int r;
+
+        /* We don't want to fill the logs with messages about parse errors.
+         * Disable most logging if not running standalone */
+        if (!getenv("SYSTEMD_LOG_LEVEL"))
+                log_set_max_level(LOG_CRIT);
+
+        r = sd_bus_new(&bus);
+        assert_se(r >= 0);
+
+        struct bus_match_node root = {
+                .type = BUS_MATCH_ROOT,
+        };
+
+        /* Note that we use the pointer to match_callback substructure, but the code
+         * uses container_of() to access outside of the passed-in type. */
+        sd_bus_slot slot = {
+                .type = BUS_MATCH_CALLBACK,
+                .match_callback = {},
+        };
+
+        if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0)
+                assert_se(g = open_memstream_unlocked(&out, &out_size));
+
+        for (size_t offset = 0; offset < size; ) {
+                _cleanup_free_ char *line = NULL;
+                char *end;
+
+                end = memchr((char*) data + offset, '\n', size - offset);
+
+                line = memdup_suffix0((char*) data + offset,
+                                      end ? end - (char*) data - offset : size - offset);
+                if (!line)
+                        return log_oom_debug();
+
+                offset = end ? (size_t) (end - (char*) data + 1) : size;
+
+                struct bus_match_component *components;
+                unsigned n_components;
+                r = bus_match_parse(line, &components, &n_components);
+                if (IN_SET(r, -EINVAL, -ENOMEM)) {
+                        log_debug_errno(r, "Failed to parse line: %m");
+                        continue;
+                }
+                assert_se(r >= 0); /* We only expect EINVAL and ENOMEM errors, or success. */
+
+                log_debug("Parsed %u components.", n_components);
+
+                _cleanup_free_ char *again = bus_match_to_string(components, n_components);
+                if (!again) {
+                        bus_match_parse_free(components, n_components);
+                        log_oom();
+                        break;
+                }
+
+                if (g)
+                        fprintf(g, "%s\n", again);
+
+                r = bus_match_add(&root, components, n_components, &slot.match_callback);
+                bus_match_parse_free(components, n_components);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to add match: %m");
+                        break;
+                }
+        }
+
+        bus_match_dump(g ?: stdout, &root, 0); /* We do this even on failure, to check consistency after error. */
+        bus_match_free(&root);
+
+        return 0;
+}
diff --git a/test/fuzz/fuzz-bus-match/test.input b/test/fuzz/fuzz-bus-match/test.input
new file mode 100644 (file)
index 0000000..92c02fc
--- /dev/null
@@ -0,0 +1,18 @@
+arg2='wal\'do',sender='foo',type='signal',interface='bar.x',
+arg2='wal\'do2',sender='foo',type='signal',interface='bar.x',
+arg3='test',sender='foo',type='signal',interface='bar.x',
+arg3='test',sender='foo',type='method_call',interface='bar.x',
+
+interface='quux.x'
+interface='bar.x'
+member='waldo',path='/foo/bar'
+path='/foo/bar'
+path_namespace='/foo'
+path_namespace='/foo/quux'
+arg1='two'
+member='waldo',arg2path='/prefix/'
+member=waldo,path='/foo/bar',arg3namespace='prefix'
+arg4has='pi'
+arg4has='pa'
+arg4has='po'
+arg4='pi'