From: Zbigniew Jędrzejewski-Szmek Date: Mon, 15 Feb 2021 08:54:14 +0000 (+0100) Subject: systemctl: use argv[0] not program_invocation_short_name for arg dispatch X-Git-Tag: v248-rc1~122^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d41a9e4fc1e1bcdefc8d358da2744a97aac5820a;p=thirdparty%2Fsystemd.git systemctl: use argv[0] not program_invocation_short_name for arg dispatch The immediate motivation is to allow fuzz-systemctl-parse-argv to cover also the other code paths. p_i_s_n is not getting set (and it probably shouldn't), so the fuzzer would only cover the paths for ./systemctl, and not ./reboot, etc. Looking at argv[0] instead, which is passed as part of the fuzzer data, fixes that. But I think in general it's more correct to look at argv[0] here: after all we have all the information available through local variables and shouldn't go out of our way to look at a global. --- diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 16d0555c7ca..fc0d114fcb0 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -930,57 +930,53 @@ int systemctl_dispatch_parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - if (program_invocation_short_name) { - - if (strstr(program_invocation_short_name, "halt")) { - arg_action = ACTION_HALT; - return halt_parse_argv(argc, argv); - - } else if (strstr(program_invocation_short_name, "poweroff")) { - arg_action = ACTION_POWEROFF; - return halt_parse_argv(argc, argv); - - } else if (strstr(program_invocation_short_name, "reboot")) { - if (kexec_loaded()) - arg_action = ACTION_KEXEC; - else - arg_action = ACTION_REBOOT; - return halt_parse_argv(argc, argv); - - } else if (strstr(program_invocation_short_name, "shutdown")) { - arg_action = ACTION_POWEROFF; - return shutdown_parse_argv(argc, argv); - - } else if (strstr(program_invocation_short_name, "init")) { - - /* Matches invocations as "init" as well as "telinit", which are synonymous when run - * as PID != 1 on SysV. - * - * On SysV "telinit" was the official command to communicate with PID 1, but "init" would - * redirect itself to "telinit" if called with PID != 1. We follow the same logic here still, - * though we add one level of indirection, as we implement "telinit" in "systemctl". Hence, for - * us if you invoke "init" you get "systemd", but it will execve() "systemctl" immediately with - * argv[] unmodified if PID is != 1. If you invoke "telinit" you directly get "systemctl". In - * both cases we shall do the same thing, which is why we do strstr(p_i_s_n, "init") here, as a - * quick way to match both. - * - * Also see redirect_telinit() in src/core/main.c. */ - - if (sd_booted() > 0) { - 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. */ - - arg_action = ACTION_TELINIT; - return 1; - } - - } else if (strstr(program_invocation_short_name, "runlevel")) { - arg_action = ACTION_RUNLEVEL; - return runlevel_parse_argv(argc, argv); + if (strstr_ptr(argv[0], "halt")) { + arg_action = ACTION_HALT; + return halt_parse_argv(argc, argv); + + } else if (strstr_ptr(argv[0], "poweroff")) { + arg_action = ACTION_POWEROFF; + return halt_parse_argv(argc, argv); + + } else if (strstr_ptr(argv[0], "reboot")) { + if (kexec_loaded()) + arg_action = ACTION_KEXEC; + else + arg_action = ACTION_REBOOT; + return halt_parse_argv(argc, argv); + + } else if (strstr_ptr(argv[0], "shutdown")) { + arg_action = ACTION_POWEROFF; + return shutdown_parse_argv(argc, argv); + + } else if (strstr_ptr(argv[0], "init")) { + + /* Matches invocations as "init" as well as "telinit", which are synonymous when run + * as PID != 1 on SysV. + * + * On SysV "telinit" was the official command to communicate with PID 1, but "init" would + * redirect itself to "telinit" if called with PID != 1. We follow the same logic here still, + * though we add one level of indirection, as we implement "telinit" in "systemctl". Hence, + * for us if you invoke "init" you get "systemd", but it will execve() "systemctl" + * immediately with argv[] unmodified if PID is != 1. If you invoke "telinit" you directly + * get "systemctl". In both cases we shall do the same thing, which is why we do + * strstr_ptr(argv[0], "init") here, as a quick way to match both. + * + * Also see redirect_telinit() in src/core/main.c. */ + + if (sd_booted() > 0) { + 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. + */ + arg_action = ACTION_TELINIT; + return 1; } + + } else if (strstr_ptr(argv[0], "runlevel")) { + arg_action = ACTION_RUNLEVEL; + return runlevel_parse_argv(argc, argv); } arg_action = ACTION_SYSTEMCTL;