]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/fuzz/fuzz-bootspec.c
varlink,json: introduce new varlink_dispatch() helper
[thirdparty/systemd.git] / src / fuzz / fuzz-bootspec.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <string.h>
4
5 #include "bootspec.h"
6 #include "env-util.h"
7 #include "escape.h"
8 #include "fuzz.h"
9 #include "fd-util.h"
10 #include "json.h"
11
12 static int json_dispatch_config(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
13 BootConfig *config = ASSERT_PTR(userdata);
14
15 const char *s = json_variant_string(variant);
16 if (!s)
17 return -EINVAL;
18
19 _cleanup_fclose_ FILE *f = NULL;
20 assert_se(f = data_to_file((const uint8_t*) s, strlen(s)));
21
22 (void) boot_loader_read_conf(config, f, "memstream");
23 return 0;
24 }
25
26 static int json_dispatch_entries(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
27 BootConfig *config = ASSERT_PTR(userdata);
28 JsonVariant *entry;
29
30 JSON_VARIANT_ARRAY_FOREACH(entry, variant) {
31 if (!json_variant_is_array(entry) ||
32 json_variant_elements(entry) < 1)
33 return -EINVAL;
34
35 JsonVariant *v;
36 const char *id = NULL, *raw = NULL;
37 _cleanup_free_ char *data = NULL;
38 ssize_t len = -ENODATA;
39
40 v = json_variant_by_index(entry, 0);
41 if (v)
42 id = json_variant_string(v);
43 if (!id)
44 continue;
45
46 v = json_variant_by_index(entry, 1);
47 if (v)
48 raw = json_variant_string(v);
49 if (raw)
50 len = cunescape(raw, UNESCAPE_RELAX | UNESCAPE_ACCEPT_NUL, &data);
51 if (len >= 0) {
52 _cleanup_fclose_ FILE *f = NULL;
53 assert_se(f = data_to_file((const uint8_t*) data, len));
54
55 assert_se(boot_config_load_type1(config, f, "/", "/entries", id) != -ENOMEM);
56 }
57 }
58
59 return 0;
60 }
61
62 static int json_dispatch_loader(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
63 BootConfig *config = ASSERT_PTR(userdata);
64 _cleanup_strv_free_ char **entries = NULL;
65 int r;
66
67 r = json_dispatch_strv(name, variant, flags, &entries);
68 if (r < 0)
69 return r;
70
71 (void) boot_config_augment_from_loader(config, entries, false);
72 return 0;
73 }
74
75 static const JsonDispatch data_dispatch[] = {
76 { "config", JSON_VARIANT_STRING, json_dispatch_config, 0, 0 },
77 { "entries", JSON_VARIANT_ARRAY, json_dispatch_entries, 0, 0 },
78 { "loader", JSON_VARIANT_ARRAY, json_dispatch_loader, 0, 0 },
79 {}
80 };
81
82 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
83 _cleanup_free_ const char *datadup = NULL;
84 _cleanup_(boot_config_free) BootConfig config = BOOT_CONFIG_NULL;
85 int r;
86
87 if (outside_size_range(size, 0, 65536))
88 return 0;
89
90 fuzz_setup_logging();
91
92 assert_se(datadup = memdup_suffix0(data, size));
93
94 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
95 r = json_parse(datadup, 0, &v, NULL, NULL);
96 if (r < 0)
97 return 0;
98
99 r = json_dispatch(v, data_dispatch, 0, &config);
100 if (r < 0)
101 return 0;
102
103 assert_se(boot_config_finalize(&config) >= 0);
104
105 (void) boot_config_select_special_entries(&config, /* skip_efivars= */ false);
106
107 _cleanup_close_ int orig_stdout_fd = -EBADF;
108 if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0) {
109 orig_stdout_fd = fcntl(fileno(stdout), F_DUPFD_CLOEXEC, 3);
110 if (orig_stdout_fd < 0)
111 log_warning_errno(orig_stdout_fd, "Failed to duplicate fd 1: %m");
112 else
113 assert_se(freopen("/dev/null", "w", stdout));
114 }
115
116 (void) show_boot_entries(&config, JSON_FORMAT_OFF);
117 (void) show_boot_entries(&config, JSON_FORMAT_PRETTY);
118
119 if (orig_stdout_fd >= 0)
120 assert_se(freopen(FORMAT_PROC_FD_PATH(orig_stdout_fd), "w", stdout));
121
122 return 0;
123 }