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:
commit
9a67c080b0
@ -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) */
|
||||
|
@ -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;
|
||||
}
|
||||
|
58
src/systemctl/fuzz-systemctl-parse-argv.c
Normal file
58
src/systemctl/fuzz-systemctl-parse-argv.c
Normal 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;
|
||||
}
|
@ -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']]]
|
||||
|
@ -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.");
|
||||
}
|
||||
|
@ -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[]);
|
||||
|
@ -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
|
||||
|
@ -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[]);
|
||||
|
@ -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) {
|
||||
|
BIN
test/fuzz/fuzz-systemctl-parse-argv/help.input
Normal file
BIN
test/fuzz/fuzz-systemctl-parse-argv/help.input
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user