/src/systemd/src/core/fuzz-execute-serialize.c
Line | Count | Source |
1 | | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2 | | /* Notes on how to run the fuzzer manually: |
3 | | * 1) Build the fuzzers with LLVM's libFuzzer and ASan+UBSan: |
4 | | * $ CC=clang CXX=clang++ meson build-libfuzz -Db_sanitize=address,undefined -Dllvm-fuzz=true -Db_lundef=false |
5 | | * |
6 | | * 2) Collect some valid inputs: |
7 | | * |
8 | | * OUT=test/fuzz/fuzz-execute-serialize/initial |
9 | | * for section in context command parameters runtime cgroup; do |
10 | | * awk "match(\$0, /startswith\\(.+, \"(exec-${section}-[^\"]+=)\"/, m) { print m[1]; }" \ |
11 | | * src/core/execute-serialize.c >>"$OUT" |
12 | | * # Each "section" is delimited by an empty line |
13 | | * echo >>"$OUT" |
14 | | * done |
15 | | * |
16 | | * 3) Run the fuzzer: |
17 | | * $ build-libfuzz/fuzz-execute-serialize test/fuzz/fuzz-execute-serialize |
18 | | */ |
19 | | |
20 | | #include <stdio.h> |
21 | | #include <stdlib.h> |
22 | | |
23 | | #include "cgroup.h" |
24 | | #include "dynamic-user.h" |
25 | | #include "execute-serialize.h" |
26 | | #include "execute.h" |
27 | | #include "fd-util.h" |
28 | | #include "fdset.h" |
29 | | #include "fuzz.h" |
30 | | |
31 | 14.0k | static void exec_fuzz_one(FILE *f, FDSet *fdset) { |
32 | 14.0k | _cleanup_(exec_params_deep_clear) ExecParameters params = EXEC_PARAMETERS_INIT(/* flags= */ 0); |
33 | 14.0k | _cleanup_(exec_context_done) ExecContext exec_context = {}; |
34 | 14.0k | _cleanup_(cgroup_context_done) CGroupContext cgroup_context = {}; |
35 | 14.0k | DynamicCreds dynamic_creds = {}; |
36 | 14.0k | ExecCommand command = {}; |
37 | 14.0k | ExecSharedRuntime shared = { |
38 | 14.0k | .userns_storage_socket = EBADF_PAIR, |
39 | 14.0k | .netns_storage_socket = EBADF_PAIR, |
40 | 14.0k | .ipcns_storage_socket = EBADF_PAIR, |
41 | 14.0k | }; |
42 | 14.0k | ExecRuntime runtime = { |
43 | 14.0k | .ephemeral_storage_socket = EBADF_PAIR, |
44 | 14.0k | .shared = &shared, |
45 | 14.0k | .dynamic_creds = &dynamic_creds, |
46 | 14.0k | }; |
47 | | |
48 | 14.0k | exec_context_init(&exec_context); |
49 | 14.0k | cgroup_context_init(&cgroup_context); |
50 | | |
51 | 14.0k | (void) exec_deserialize_invocation(f, fdset, &exec_context, &command, ¶ms, &runtime, &cgroup_context); |
52 | 14.0k | exec_context.private_var_tmp = PRIVATE_TMP_DISCONNECTED; /* The deserialization in the above may set an invalid value. */ |
53 | 14.0k | (void) exec_serialize_invocation(f, fdset, &exec_context, &command, ¶ms, &runtime, &cgroup_context); |
54 | 14.0k | (void) exec_deserialize_invocation(f, fdset, &exec_context, &command, ¶ms, &runtime, &cgroup_context); |
55 | | |
56 | | /* We definitely didn't provide valid FDs during deserialization, so |
57 | | * wipe the FDs before exec_params_serialized_clear() kicks in, otherwise |
58 | | * we'll hit the assert in safe_close() */ |
59 | 14.0k | params.stdin_fd = -EBADF; |
60 | 14.0k | params.stdout_fd = -EBADF; |
61 | 14.0k | params.stderr_fd = -EBADF; |
62 | 14.0k | params.root_directory_fd = -EBADF; |
63 | 14.0k | params.exec_fd = -EBADF; |
64 | 14.0k | params.user_lookup_fd = -EBADF; |
65 | 14.0k | params.bpf_restrict_fs_map_fd = -EBADF; |
66 | 14.0k | if (!params.fds) |
67 | 13.9k | params.n_socket_fds = params.n_stashed_fds = 0; |
68 | 4.43M | for (size_t i = 0; params.fds && i < params.n_socket_fds + params.n_stashed_fds; i++) |
69 | 4.41M | params.fds[i] = -EBADF; |
70 | | |
71 | 14.0k | exec_command_done_array(&command, /* n= */ 1); |
72 | 14.0k | exec_shared_runtime_done(&shared); |
73 | 14.0k | if (dynamic_creds.group != dynamic_creds.user) |
74 | 0 | dynamic_user_free(dynamic_creds.group); |
75 | 14.0k | dynamic_user_free(dynamic_creds.user); |
76 | 14.0k | free(runtime.ephemeral_copy); |
77 | 14.0k | safe_close_pair(runtime.ephemeral_storage_socket); |
78 | 14.0k | } |
79 | | |
80 | 14.0k | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
81 | 14.0k | _cleanup_fclose_ FILE *f = NULL; |
82 | 14.0k | _cleanup_fdset_free_ FDSet *fdset = NULL; |
83 | | |
84 | 14.0k | if (outside_size_range(size, 0, 128 * 1024)) |
85 | 5 | return 0; |
86 | | |
87 | 14.0k | fuzz_setup_logging(); |
88 | | |
89 | 14.0k | assert_se(fdset = fdset_new()); |
90 | 14.0k | assert_se(f = data_to_file(data, size)); |
91 | | |
92 | 14.0k | exec_fuzz_one(f, fdset); |
93 | | |
94 | 14.0k | return 0; |
95 | 14.0k | } |