1
0
mirror of https://github.com/systemd/systemd.git synced 2025-02-27 01:57:35 +03:00

Merge pull request #18506 from keszybz/fuzz-systemctl-parse-argv

Fuzzer for systemctl argline parsing
This commit is contained in:
Yu Watanabe 2021-02-11 00:29:22 +09:00 committed by GitHub
commit 9a67c080b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 96 additions and 23 deletions

View File

@ -510,7 +510,7 @@ static int manager_setup_signals(Manager *m) {
SIGCHLD, /* Child died */
SIGTERM, /* Reexecute daemon */
SIGHUP, /* Reload configuration */
SIGUSR1, /* systemd/upstart: reconnect to D-Bus */
SIGUSR1, /* systemd: reconnect to D-Bus */
SIGUSR2, /* systemd: dump status */
SIGINT, /* Kernel sends us this on control-alt-del */
SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */

View File

@ -38,18 +38,10 @@ int utmp_get_runlevel(int *runlevel, int *previous) {
* very new and not apply to the current script being executed. */
e = getenv("RUNLEVEL");
if (e && e[0] > 0) {
if (!isempty(e)) {
*runlevel = e[0];
if (previous) {
/* $PREVLEVEL seems to be an Upstart thing */
e = getenv("PREVLEVEL");
if (e && e[0] > 0)
*previous = e[0];
else
*previous = 0;
}
if (previous)
*previous = 0;
return 0;
}

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

@ -1,9 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h>
#include <unistd.h>
#include "alloc-util.h"
#include "pretty-print.h"
#include "rlimit-util.h"
#include "systemctl-compat-telinit.h"
#include "systemctl-daemon-reload.h"
#include "systemctl-start-unit.h"
@ -150,3 +152,11 @@ int reload_with_fallback(void) {
return 0;
}
int exec_telinit(char *argv[]) {
(void) rlimit_nofile_safe();
execv(TELINIT, argv);
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Couldn't find an alternative telinit implementation to spawn.");
}

View File

@ -4,3 +4,4 @@
int telinit_parse_argv(int argc, char *argv[]);
int start_with_fallback(void);
int reload_with_fallback(void);
int exec_telinit(char *argv[]);

View File

@ -425,7 +425,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "after", no_argument, NULL, ARG_AFTER },
{ "before", no_argument, NULL, ARG_BEFORE },
{ "show-types", no_argument, NULL, ARG_SHOW_TYPES },
{ "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */
{ "failed", no_argument, NULL, ARG_FAILED },
{ "full", no_argument, NULL, 'l' },
{ "job-mode", required_argument, NULL, ARG_JOB_MODE },
{ "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */
@ -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);
@ -970,14 +970,11 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = _ACTION_INVALID;
return telinit_parse_argv(argc, argv);
} else {
/* Hmm, so some other init system is running, we need to forward this request to
* it. For now we simply guess that it is Upstart. */
/* Hmm, so some other init system is running, we need to forward this request
* to it. */
(void) rlimit_nofile_safe();
execv(TELINIT, argv);
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Couldn't find an alternative telinit implementation to spawn.");
arg_action = ACTION_TELINIT;
return 1;
}
} else if (strstr(program_invocation_short_name, "runlevel")) {
@ -990,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 },
@ -1093,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;
@ -1143,6 +1141,10 @@ static int run(int argc, char *argv[]) {
r = runlevel_main();
break;
case ACTION_TELINIT:
r = exec_telinit(argv);
break;
case ACTION_EXIT:
case ACTION_SUSPEND:
case ACTION_HIBERNATE:
@ -1166,3 +1168,4 @@ finish:
}
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
#endif

View File

@ -29,6 +29,7 @@ enum action {
ACTION_RELOAD,
ACTION_REEXEC,
ACTION_RUNLEVEL,
ACTION_TELINIT,
ACTION_CANCEL_SHUTDOWN,
_ACTION_MAX,
_ACTION_INVALID = -1
@ -92,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[]);

View File

@ -3,12 +3,12 @@
#include "alloc-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "fuzz.h"
#include "rm-rf.h"
#include "string-util.h"
#include "strv.h"
#include "tests.h"
#include "tmpfile-util.h"
#include "fuzz.h"
#include "xdg-autostart-service.h"
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {

Binary file not shown.