Files
systemd/src/fuzz/fuzz-bootspec.c
Lennart Poettering f1b622a00c varlink,json: introduce new varlink_dispatch() helper
varlink_dispatch() is a simple wrapper around json_dispatch() that
returns clean, standards-compliant InvalidParameter error back to
clients, if the specified JSON cannot be parsed properly.

For this json_dispatch() is extended to return the offending field's
name. Because it already has quite a few parameters, I then renamed
json_dispatch() to json_dispatch_full() and made json_dispatch() a
wrapper around it that passes the new argument as NULL. While doing so I
figured we should also get rid of the bad= argument in the short
wrapper, since it's only used in the OCI code.

To simplify the OCI code this adds a second wrapper oci_dispatch()
around json_dispatch_full(), that fills in bad= the way we want.

Net result: instead of one json_dispatch() call there are now:

1. json_dispatch_full() for the fully feature mother of all dispathers.
2. json_dispatch() for the simpler version that you want to use most of
   the time.
3. varlink_dispatch() that generates nice Varlink errors
4. oci_dispatch() that does the OCI specific error handling

And that's all there is.
2023-11-02 01:19:21 +00:00

124 lines
4.1 KiB
C

/* 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 int json_dispatch_loader(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
BootConfig *config = ASSERT_PTR(userdata);
_cleanup_strv_free_ char **entries = NULL;
int r;
r = json_dispatch_strv(name, variant, flags, &entries);
if (r < 0)
return r;
(void) boot_config_augment_from_loader(config, entries, false);
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 },
{ "loader", JSON_VARIANT_ARRAY, json_dispatch_loader, 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;
if (outside_size_range(size, 0, 65536))
return 0;
fuzz_setup_logging();
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, 0, &config);
if (r < 0)
return 0;
assert_se(boot_config_finalize(&config) >= 0);
(void) boot_config_select_special_entries(&config, /* skip_efivars= */ false);
_cleanup_close_ int orig_stdout_fd = -EBADF;
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;
}