]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemctl: use argv[0] not program_invocation_short_name for arg dispatch
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 15 Feb 2021 08:54:14 +0000 (09:54 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 15 Feb 2021 09:00:08 +0000 (10:00 +0100)
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.

src/systemctl/systemctl.c

index 16d0555c7ca89a76369ee164a7571e85633c7416..fc0d114fcb064ea08c93d886e54cd3ea5ba6deea 100644 (file)
@@ -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;