diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2022-05-05 19:04:01 +0200 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2022-05-08 17:58:00 +0200 |
commit | 1409ce6ed2e7e741e61bc326dbed856cb4eaf97c (patch) | |
tree | 2d4ef7737dd60d6f7422886e7a262662843f5cea | |
parent | a847b539de828bf7e877cf0f8a014a8360d32a79 (diff) | |
download | systemd-1409ce6ed2e7e741e61bc326dbed856cb4eaf97c.tar.gz |
Add fuzzer for the bootspec parser
-rw-r--r-- | src/fuzz/fuzz-bootspec-gen.py | 18 | ||||
-rw-r--r-- | src/fuzz/fuzz-bootspec.c | 108 | ||||
-rw-r--r-- | src/fuzz/meson.build | 2 | ||||
-rw-r--r-- | test/fuzz/fuzz-bootspec/sample1 | 17 |
4 files changed, 145 insertions, 0 deletions
diff --git a/src/fuzz/fuzz-bootspec-gen.py b/src/fuzz/fuzz-bootspec-gen.py new file mode 100644 index 0000000000..aaacbbe7f5 --- /dev/null +++ b/src/fuzz/fuzz-bootspec-gen.py @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +"""Generate sample input for fuzz-bootspec""" + +import json +import os +import sys + +config = open(sys.argv[1]).read() +entries = [(os.path.basename(name), open(name).read()) + for name in sys.argv[2:]] + +data = { + 'config': config, + 'entries': entries, +} + +print(json.dumps(data, indent=4)) diff --git a/src/fuzz/fuzz-bootspec.c b/src/fuzz/fuzz-bootspec.c new file mode 100644 index 0000000000..9907457450 --- /dev/null +++ b/src/fuzz/fuzz-bootspec.c @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include <string.h> + +#include "bootspec.h" +#include "env-util.h" +#include "escape.h" +#include "fuzz.h" +#include "fd-util.h" +#include "json.h" + +static int json_dispatch_config(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { + BootConfig *config = ASSERT_PTR(userdata); + + const char *s = json_variant_string(variant); + if (!s) + return -EINVAL; + + _cleanup_fclose_ FILE *f = NULL; + assert_se(f = data_to_file((const uint8_t*) s, strlen(s))); + + (void) boot_loader_read_conf(config, f, "memstream"); + return 0; +} + +static int json_dispatch_entries(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { + BootConfig *config = ASSERT_PTR(userdata); + JsonVariant *entry; + + JSON_VARIANT_ARRAY_FOREACH(entry, variant) { + if (!json_variant_is_array(entry) || + json_variant_elements(entry) < 1) + return -EINVAL; + + JsonVariant *v; + const char *id = NULL, *raw = NULL; + _cleanup_free_ char *data = NULL; + ssize_t len = -ENODATA; + + v = json_variant_by_index(entry, 0); + if (v) + id = json_variant_string(v); + if (!id) + continue; + + v = json_variant_by_index(entry, 1); + if (v) + raw = json_variant_string(v); + if (raw) + len = cunescape(raw, UNESCAPE_RELAX | UNESCAPE_ACCEPT_NUL, &data); + if (len >= 0) { + _cleanup_fclose_ FILE *f = NULL; + assert_se(f = data_to_file((const uint8_t*) data, len)); + + assert_se(boot_config_load_type1(config, f, "/", "/entries", id) != -ENOMEM); + } + } + + return 0; +} + +static const JsonDispatch data_dispatch[] = { + { "config", JSON_VARIANT_STRING, json_dispatch_config, 0, 0 }, + { "entries", JSON_VARIANT_ARRAY, json_dispatch_entries, 0, 0 }, + {} +}; + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + _cleanup_free_ const char *datadup = NULL; + _cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL; + int r; + + /* Disable most logging if not running standalone */ + if (!getenv("SYSTEMD_LOG_LEVEL")) + log_set_max_level(LOG_CRIT); + + assert_se(datadup = memdup_suffix0(data, size)); + + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + r = json_parse(datadup, 0, &v, NULL, NULL); + if (r < 0) + return 0; + + r = json_dispatch(v, data_dispatch, NULL, 0, &config); + if (r < 0) + return 0; + + assert_se(boot_config_finalize(&config) >= 0); + + (void) boot_config_select_special_entries(&config); + + _cleanup_close_ int orig_stdout_fd = -1; + if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0) { + orig_stdout_fd = fcntl(fileno(stdout), F_DUPFD_CLOEXEC, 3); + if (orig_stdout_fd < 0) + log_warning_errno(orig_stdout_fd, "Failed to duplicate fd 1: %m"); + else + assert_se(freopen("/dev/null", "w", stdout)); + } + + (void) show_boot_entries(&config, JSON_FORMAT_OFF); + (void) show_boot_entries(&config, JSON_FORMAT_PRETTY); + + if (orig_stdout_fd >= 0) + assert_se(freopen(FORMAT_PROC_FD_PATH(orig_stdout_fd), "w", stdout)); + + return 0; +} diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build index b92fb95e8a..6f36536f1b 100644 --- a/src/fuzz/meson.build +++ b/src/fuzz/meson.build @@ -1,6 +1,8 @@ # SPDX-License-Identifier: LGPL-2.1-or-later fuzzers += [ + [files('fuzz-bootspec.c')], + [files('fuzz-bus-label.c')], [files('fuzz-calendarspec.c')], diff --git a/test/fuzz/fuzz-bootspec/sample1 b/test/fuzz/fuzz-bootspec/sample1 new file mode 100644 index 0000000000..319c5530ab --- /dev/null +++ b/test/fuzz/fuzz-bootspec/sample1 @@ -0,0 +1,17 @@ +{ + "config": "timeout 3\nconsole-mode 2\n# default 08a5690afeedfeedaaac0a5d2e3cf6b0-*\n# default auto-reboot-to-firmware-setup\n", + "entries": [ + [ + "08a5690afeedfeedaaac0a5d2e3cf6b0-5.15.14-200.fc35.x86_64.conf", + "title Fedora Linux 35 (Workstation Edition)\nversion 5.15.14-200.fc35.x86_64\nmachine-id 08a5690afeedfeedaaac0a5d2e3cf6b0\noptions root=/dev/mapper/fedora_krowka-root rw rd.lvm.lv=fedora_krowka/root rd.luks.uuid=luks-2d9b648a-15b1-4204-988b-ec085089f8ce rd.lvm.lv=fedora_krowka/swap LANG=en_US.UTF-8 selinux=0 resume=/dev/mapper/fedora_krowka-swap systemd.show-status systemd.unit-status-format=name quiet\nlinux /08a5690afeedfeedaaac0a5d2e3cf6b0/5.15.14-200.fc35.x86_64/linux\ninitrd /08a5690afeedfeedaaac0a5d2e3cf6b0/5.15.14-200.fc35.x86_64/initrd\n" + ], + [ + "08a5690afeedfeedaaac0a5d2e3cf6b0-5.17.0-0.rc5.102.fc36.x86_64.conf", + "title Fedora Linux 36 (Workstation Edition Prerelease)\nversion 5.17.0-0.rc5.102.fc36.x86_64\nmachine-id 08a5690afeedfeedaaac0a5d2e3cf6b0\noptions root=/dev/mapper/fedora_krowka-root rw rd.lvm.lv=fedora_krowka/root rd.luks.uuid=luks-2d9b648a-15b1-4204-988b-ec085089f8ce rd.lvm.lv=fedora_krowka/swap LANG=en_US.UTF-8 selinux=0 resume=/dev/mapper/fedora_krowka-swap systemd.show-status systemd.unit-status-format=name quiet\nlinux /08a5690afeedfeedaaac0a5d2e3cf6b0/5.17.0-0.rc5.102.fc36.x86_64/linux\ninitrd /08a5690afeedfeedaaac0a5d2e3cf6b0/5.17.0-0.rc5.102.fc36.x86_64/initrd\n" + ], + [ + "listing.conf", + "title Title\nversion 3.7.2-201.fc18.x86_64\nmachine-id 4098b3f648d74c13b1f04ccfba7798e8\nsort-key 666\nlinux /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux\ninitrd /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd\nefi /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/efi\noptions one two three four\ndevicetree 6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.armv7hl/tegra20-paz00.dtb\ndevicetree-overlay /6a9857a393724b7a981ebb5b8495b9ea/overlays/overlay_A.dtbo /6a9857a393724b7a981ebb5b8495b9ea/overlays/overlay_B.dtbo\narchitecture IA32\narchitecture x64\narchitecture IA64\narchitecture ARM\narchitecture AA64\n" + ] + ] +} |