| /* 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; |
| |
| if (outside_size_range(size, 0, 65536)) |
| return 0; |
| |
| /* 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; |
| } |