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.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2021-02-07 18:30:42 +01:00
parent 5bb920ce27
commit 5fd8782328
5 changed files with 70 additions and 2 deletions

View file

@ -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;
}

View 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']]]

View 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

View 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[]);

Binary file not shown.