Coverage Report

Created: 2026-01-22 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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, &params, &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, &params, &runtime, &cgroup_context);
54
14.0k
        (void) exec_deserialize_invocation(f, fdset, &exec_context, &command, &params, &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
}