X Tutup
Skip to content

Commit 5fd8782

Browse files
committed
fuzz-systemctl-parse-argv: a new fuzzer
Does what the name suggests. Obviously inspired by sudoers, but note that our tools are not supposed to be installed suid, so there is no privilege boundary to cross here.
1 parent 5bb920c commit 5fd8782

File tree

5 files changed

+70
-2
lines changed

5 files changed

+70
-2
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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 "stdio-util.h"
10+
#include "strv.h"
11+
#include "systemctl.h"
12+
13+
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
14+
_cleanup_strv_free_ char **argv = NULL;
15+
_cleanup_close_ int orig_stdout_fd = -1;
16+
int r;
17+
18+
/* We don't want to fill the logs with messages about parse errors.
19+
* Disable most logging if not running standalone */
20+
if (!getenv("SYSTEMD_LOG_LEVEL"))
21+
log_set_max_level(LOG_CRIT);
22+
23+
arg_pager_flags = PAGER_DISABLE; /* We shouldn't execute the pager */
24+
25+
argv = strv_parse_nulstr((const char *)data, size);
26+
if (!argv)
27+
return log_oom();
28+
29+
if (!argv[0])
30+
return 0; /* argv[0] should always be present, but may be zero-length. */
31+
32+
if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0) {
33+
orig_stdout_fd = fcntl(fileno(stdout), F_DUPFD_CLOEXEC, 3);
34+
if (orig_stdout_fd < 0)
35+
log_warning_errno(orig_stdout_fd, "Failed to duplicate fd 1: %m");
36+
else
37+
assert_se(freopen("/dev/null", "w", stdout));
38+
39+
opterr = 0; /* do not print errors */
40+
}
41+
42+
optind = 0; /* this tells the getopt machinery to reinitialize */
43+
44+
r = systemctl_dispatch_parse_argv(strv_length(argv), argv);
45+
if (r < 0)
46+
log_error_errno(r, "Failed to parse args: %m");
47+
else
48+
log_info(r == 0 ? "Done!" : "Action!");
49+
50+
if (orig_stdout_fd >= 0) {
51+
char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
52+
53+
xsprintf(path, "/proc/self/fd/%d", orig_stdout_fd);
54+
assert_se(freopen(path, "w", stdout));
55+
}
56+
57+
return 0;
58+
}

src/systemctl/meson.build

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,9 @@ else
8181
libshared_static,
8282
libbasic_gcrypt]
8383
endif
84+
85+
fuzzers += [
86+
[['src/systemctl/fuzz-systemctl-parse-argv.c',
87+
systemctl_sources],
88+
systemctl_link_with,
89+
[], [], ['-DFUZZ_SYSTEMCTL_PARSE_ARGV']]]

src/systemctl/systemctl.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -926,7 +926,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
926926
return 1;
927927
}
928928

929-
static int parse_argv(int argc, char *argv[]) {
929+
int systemctl_dispatch_parse_argv(int argc, char *argv[]) {
930930
assert(argc >= 0);
931931
assert(argv);
932932

@@ -987,6 +987,7 @@ static int parse_argv(int argc, char *argv[]) {
987987
return systemctl_parse_argv(argc, argv);
988988
}
989989

990+
#ifndef FUZZ_SYSTEMCTL_PARSE_ARGV
990991
static int systemctl_main(int argc, char *argv[]) {
991992
static const Verb verbs[] = {
992993
{ "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, list_units },
@@ -1090,7 +1091,7 @@ static int run(int argc, char *argv[]) {
10901091

10911092
sigbus_install();
10921093

1093-
r = parse_argv(argc, argv);
1094+
r = systemctl_dispatch_parse_argv(argc, argv);
10941095
if (r <= 0)
10951096
goto finish;
10961097

@@ -1167,3 +1168,4 @@ static int run(int argc, char *argv[]) {
11671168
}
11681169

11691170
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
1171+
#endif

src/systemctl/systemctl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,3 +93,5 @@ extern char **arg_clean_what;
9393
extern TimestampStyle arg_timestamp_style;
9494
extern bool arg_read_only;
9595
extern bool arg_mkdir;
96+
97+
int systemctl_dispatch_parse_argv(int argc, char *argv[]);
938 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)
X Tutup