From 5fd8782328bc06eeafe212a5431dbe50bed31474 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sun, 7 Feb 2021 18:30:42 +0100 Subject: [PATCH] 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. --- src/systemctl/fuzz-systemctl-parse-argv.c | 58 ++++++++++++++++++ src/systemctl/meson.build | 6 ++ src/systemctl/systemctl.c | 6 +- src/systemctl/systemctl.h | 2 + .../fuzz/fuzz-systemctl-parse-argv/help.input | Bin 0 -> 938 bytes 5 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/systemctl/fuzz-systemctl-parse-argv.c create mode 100644 test/fuzz/fuzz-systemctl-parse-argv/help.input 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 0000000000000000000000000000000000000000..95626348b0620c4c71b4260c8b093082f1d00df6 GIT binary patch literal 938 zc-n1JTW;Ji4AgxZBIp4Ov?v0kA5Ds6djMJHt{KasLrLrS_9bnj-5ULohC_nSf!+c1 z7$^O%D494Z%1bUdDySL7!K1}+F3qpkhnFvp&#xy3Ka?AN=qX|I?fL2S_50Jqi-V$c zSte}uoVob&$2fb6*f}sf2~Q|xaq!cDSHj2WAX-#4q-8-cRBh>sE4KCw%~X2maKhAK z3WQm?H*R6%PTeOf+Vc!We9AtQeWI1p#w_~kW3^17$1nh;o?0p_>LO(aiV^0X9awCp zOY+v%+kcqBW@|6#Z8gt;{SzP%3)Y+F&U znw!rKbP2$Z2luBVwM$*lcfcuHx^d`8cKPc^vT2#NYpA|hCpiduXK%Fm8|OtgHvj+t literal 0 Hc-jL100001 -- 2.47.3