]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/systemctl/fuzz-systemctl-parse-argv.c
tree-wide: use -EBADF for fd initialization
[thirdparty/systemd.git] / src / systemctl / fuzz-systemctl-parse-argv.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <stdio.h>
4 #include <unistd.h>
5
6 #include "env-util.h"
7 #include "fd-util.h"
8 #include "fuzz.h"
9 #include "nulstr-util.h"
10 #include "selinux-util.h"
11 #include "static-destruct.h"
12 #include "stdio-util.h"
13 #include "strv.h"
14 #include "systemctl.h"
15 #include "systemctl-util.h"
16
17 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
18 _cleanup_strv_free_ char **argv = NULL;
19 _cleanup_close_ int orig_stdout_fd = -EBADF;
20 int r;
21
22 if (size > 16*1024)
23 return 0; /* See the comment below about the limit for strv_length(). */
24
25 /* We don't want to fill the logs with messages about parse errors.
26 * Disable most logging if not running standalone */
27 if (!getenv("SYSTEMD_LOG_LEVEL"))
28 log_set_max_level(LOG_CRIT);
29
30 arg_pager_flags = PAGER_DISABLE; /* We shouldn't execute the pager */
31
32 argv = strv_parse_nulstr((const char *)data, size);
33 if (!argv)
34 return log_oom();
35
36 if (!argv[0])
37 return 0; /* argv[0] should always be present, but may be zero-length. */
38 if (strv_length(argv) > 1024)
39 return 0; /* oss-fuzz reports timeouts which are caused by appending to a very long strv.
40 * The code is indeed not very efficient, but it's designed for normal command-line
41 * use, where we don't expect more than a dozen of entries. The fact that it is
42 * slow with ~100k entries is not particularly interesting. Let's just refuse such
43 * long command lines. */
44
45 if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0) {
46 orig_stdout_fd = fcntl(fileno(stdout), F_DUPFD_CLOEXEC, 3);
47 if (orig_stdout_fd < 0)
48 log_warning_errno(orig_stdout_fd, "Failed to duplicate fd 1: %m");
49 else
50 assert_se(freopen("/dev/null", "w", stdout));
51
52 opterr = 0; /* do not print errors */
53 }
54
55 optind = 0; /* this tells the getopt machinery to reinitialize */
56
57 r = systemctl_dispatch_parse_argv(strv_length(argv), argv);
58 if (r < 0)
59 log_error_errno(r, "Failed to parse args: %m");
60 else
61 log_info(r == 0 ? "Done!" : "Action!");
62
63 if (orig_stdout_fd >= 0)
64 assert_se(freopen(FORMAT_PROC_FD_PATH(orig_stdout_fd), "w", stdout));
65
66 release_busses(); /* We open the bus for communication with logind.
67 * It needs to be closed to avoid apparent leaks. */
68
69 mac_selinux_finish();
70
71 /* Call static destructors to do global state cleanup. We do it here, and not in fuzz-main.c so that
72 * any global state is destroyed between fuzzer runs. */
73 static_destruct();
74
75 return 0;
76 }