diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2021-03-04 21:29:48 +0100 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2021-03-06 09:32:18 +0100 |
commit | 84f11eda20e99f8496731a19dda41bffe862b99c (patch) | |
tree | 8abab30631ac39deeb7173829a5a3e6df77b61ef | |
parent | test-bus-match: small modernization (diff) | |
download | systemd-84f11eda20e99f8496731a19dda41bffe862b99c.tar.xz systemd-84f11eda20e99f8496731a19dda41bffe862b99c.zip |
fuzz-bus-match: new fuzzer
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.
-rw-r--r-- | src/libsystemd/meson.build | 2 | ||||
-rw-r--r-- | src/libsystemd/sd-bus/fuzz-bus-match.c | 86 | ||||
-rw-r--r-- | test/fuzz/fuzz-bus-match/test.input | 18 |
3 files changed, 106 insertions, 0 deletions
diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build index 2fe1978d02..ad50815a7b 100644 --- a/src/libsystemd/meson.build +++ b/src/libsystemd/meson.build @@ -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 index 0000000000..0585338e28 --- /dev/null +++ b/src/libsystemd/sd-bus/fuzz-bus-match.c @@ -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 index 0000000000..92c02fc75a --- /dev/null +++ b/test/fuzz/fuzz-bus-match/test.input @@ -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' |