From: Zbigniew Jędrzejewski-Szmek Date: Sun, 7 Feb 2021 17:30:42 +0000 (+0100) Subject: fuzz-systemctl-parse-argv: a new fuzzer X-Git-Tag: v248-rc1~170^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5fd8782328bc06eeafe212a5431dbe50bed31474;p=thirdparty%2Fsystemd.git 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. --- diff --git a/src/systemctl/fuzz-systemctl-parse-argv.c b/src/systemctl/fuzz-systemctl-parse-argv.c new file mode 100644 index 00000000000..f884917e17f --- /dev/null +++ b/src/systemctl/fuzz-systemctl-parse-argv.c @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include + +#include "env-util.h" +#include "fd-util.h" +#include "fuzz.h" +#include "stdio-util.h" +#include "strv.h" +#include "systemctl.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + _cleanup_strv_free_ char **argv = NULL; + _cleanup_close_ int orig_stdout_fd = -1; + int r; + + /* We don't want to fill the logs with messages about parse errors. + * Disable most logging if not running standalone */ + if (!getenv("SYSTEMD_LOG_LEVEL")) + log_set_max_level(LOG_CRIT); + + arg_pager_flags = PAGER_DISABLE; /* We shouldn't execute the pager */ + + argv = strv_parse_nulstr((const char *)data, size); + if (!argv) + return log_oom(); + + if (!argv[0]) + return 0; /* argv[0] should always be present, but may be zero-length. */ + + if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0) { + orig_stdout_fd = fcntl(fileno(stdout), F_DUPFD_CLOEXEC, 3); + if (orig_stdout_fd < 0) + log_warning_errno(orig_stdout_fd, "Failed to duplicate fd 1: %m"); + else + assert_se(freopen("/dev/null", "w", stdout)); + + opterr = 0; /* do not print errors */ + } + + optind = 0; /* this tells the getopt machinery to reinitialize */ + + r = systemctl_dispatch_parse_argv(strv_length(argv), argv); + if (r < 0) + log_error_errno(r, "Failed to parse args: %m"); + else + log_info(r == 0 ? "Done!" : "Action!"); + + if (orig_stdout_fd >= 0) { + char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + + xsprintf(path, "/proc/self/fd/%d", orig_stdout_fd); + assert_se(freopen(path, "w", stdout)); + } + + return 0; +} diff --git a/src/systemctl/meson.build b/src/systemctl/meson.build index a6e254a14f6..38bf33d49a7 100644 --- a/src/systemctl/meson.build +++ b/src/systemctl/meson.build @@ -81,3 +81,9 @@ else libshared_static, libbasic_gcrypt] endif + +fuzzers += [ + [['src/systemctl/fuzz-systemctl-parse-argv.c', + systemctl_sources], + systemctl_link_with, + [], [], ['-DFUZZ_SYSTEMCTL_PARSE_ARGV']]] diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index cb901881c96..8c89646a777 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -926,7 +926,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { return 1; } -static int parse_argv(int argc, char *argv[]) { +int systemctl_dispatch_parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); @@ -987,6 +987,7 @@ static int parse_argv(int argc, char *argv[]) { return systemctl_parse_argv(argc, argv); } +#ifndef FUZZ_SYSTEMCTL_PARSE_ARGV static int systemctl_main(int argc, char *argv[]) { static const Verb verbs[] = { { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, list_units }, @@ -1090,7 +1091,7 @@ static int run(int argc, char *argv[]) { sigbus_install(); - r = parse_argv(argc, argv); + r = systemctl_dispatch_parse_argv(argc, argv); if (r <= 0) goto finish; @@ -1167,3 +1168,4 @@ finish: } DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run); +#endif diff --git a/src/systemctl/systemctl.h b/src/systemctl/systemctl.h index f7ee358ce12..722853db2a6 100644 --- a/src/systemctl/systemctl.h +++ b/src/systemctl/systemctl.h @@ -93,3 +93,5 @@ extern char **arg_clean_what; extern TimestampStyle arg_timestamp_style; extern bool arg_read_only; extern bool arg_mkdir; + +int systemctl_dispatch_parse_argv(int argc, char *argv[]); diff --git a/test/fuzz/fuzz-systemctl-parse-argv/help.input b/test/fuzz/fuzz-systemctl-parse-argv/help.input new file mode 100644 index 00000000000..95626348b06 Binary files /dev/null and b/test/fuzz/fuzz-systemctl-parse-argv/help.input differ