]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fuzz-systemctl-parse-argv: a new fuzzer
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Sun, 7 Feb 2021 17:30:42 +0000 (18:30 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Tue, 9 Feb 2021 13:11:42 +0000 (14:11 +0100)
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 [new file with mode: 0644]
src/systemctl/meson.build
src/systemctl/systemctl.c
src/systemctl/systemctl.h
test/fuzz/fuzz-systemctl-parse-argv/help.input [new file with mode: 0644]

diff --git a/src/systemctl/fuzz-systemctl-parse-argv.c b/src/systemctl/fuzz-systemctl-parse-argv.c
new file mode 100644 (file)
index 0000000..f884917
--- /dev/null
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#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;
+}
index a6e254a14f696361078ab63d1998e8dd2c9100ff..38bf33d49a707946ffaa96f29ab8e37f6ccd1b18 100644 (file)
@@ -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']]]
index cb901881c965fa8959fe3e301c189aacfe153874..8c89646a777019974ea642df113c09089f8d7742 100644 (file)
@@ -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
index f7ee358ce1280afe9ff595d02cb32e4b2c5e109c..722853db2a6e62b9d4a32b34f8802a2abf09a4a3 100644 (file)
@@ -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 (file)
index 0000000..9562634
Binary files /dev/null and b/test/fuzz/fuzz-systemctl-parse-argv/help.input differ