1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include "alloc-util.h"
9 #include "conf-files.h"
12 #include "errno-util.h"
14 #include "exec-util.h"
19 #include "path-util.h"
20 #include "process-util.h"
21 #include "serialize.h"
22 #include "stat-util.h"
23 #include "string-table.h"
24 #include "string-util.h"
26 #include "terminal-util.h"
27 #include "time-util.h"
29 #define EXIT_SKIP_REMAINING 77
31 /* Put this test here for a lack of better place */
32 assert_cc(EAGAIN
== EWOULDBLOCK
);
38 bool set_systemd_exec_pid
,
46 if (null_or_empty_path(path
) > 0) {
47 log_debug("%s is masked, skipping.", path
);
54 (const int[]) { STDIN_FILENO
, stdout_fd
< 0 ? STDOUT_FILENO
: stdout_fd
, STDERR_FILENO
},
55 /* except_fds= */ NULL
, /* n_except_fds= */ 0,
56 FORK_DEATHSIG_SIGTERM
|FORK_LOG
|FORK_RLIMIT_NOFILE_SAFE
|FORK_REARRANGE_STDIO
|FORK_CLOSE_ALL_FDS
,
63 if (set_systemd_exec_pid
) {
64 r
= setenv_systemd_exec_pid(false);
66 log_warning_errno(r
, "Failed to set $SYSTEMD_EXEC_PID, ignoring: %m");
70 _argv
[0] = (char*) path
;
74 argv
[0] = (char*) path
;
77 log_error_errno(errno
, "Failed to execute %s: %m", path
);
85 static int do_execute(
89 gather_stdout_callback_t
const callbacks
[_STDOUT_CONSUME_MAX
],
90 void * const callback_args
[_STDOUT_CONSUME_MAX
],
96 _cleanup_hashmap_free_ Hashmap
*pids
= NULL
;
97 bool parallel_execution
;
100 /* We fork this all off from a child process so that we can somewhat cleanly make use of SIGALRM
101 * to set a time limit.
103 * We attempt to perform parallel execution if configured by the user, however if `callbacks` is nonnull,
104 * execution must be serial.
107 assert(!strv_isempty(paths
));
109 parallel_execution
= FLAGS_SET(flags
, EXEC_DIR_PARALLEL
) && !callbacks
;
111 /* Abort execution of this process after the timeout. We simply rely on SIGALRM as
112 * default action terminating the process, and turn on alarm(). */
114 if (timeout
!= USEC_INFINITY
)
115 alarm(DIV_ROUND_UP(timeout
, USEC_PER_SEC
));
117 STRV_FOREACH(e
, envp
)
119 return log_error_errno(errno
, "Failed to set environment variable: %m");
121 STRV_FOREACH(path
, paths
) {
122 _cleanup_free_
char *t
= NULL
;
123 _cleanup_close_
int fd
= -EBADF
;
126 t
= path_join(root
, *path
);
131 _cleanup_free_
char *bn
= NULL
;
133 r
= path_extract_filename(*path
, &bn
);
135 return log_error_errno(r
, "Failed to extract filename from path '%s': %m", *path
);
137 fd
= open_serialization_fd(bn
);
139 return log_error_errno(fd
, "Failed to open serialization file: %m");
143 _cleanup_free_
char *s
= NULL
;
145 char **args
= strv_skip(argv
, 1);
147 s
= quote_command_line(args
, SHELL_ESCAPE_EMPTY
);
149 log_debug("About to execute %s%s%s", t
, args
? " " : "", args
? strnull(s
) : "");
152 if (FLAGS_SET(flags
, EXEC_DIR_WARN_WORLD_WRITABLE
)) {
157 log_warning_errno(errno
, "Failed to stat '%s', ignoring: %m", t
);
158 else if (S_ISREG(st
.st_mode
) && (st
.st_mode
& 0002))
159 log_warning("'%s' is marked world-writable, which is a security risk as it "
160 "is executed with privileges. Please remove world writability "
161 "permission bits. Proceeding anyway.", t
);
164 r
= do_spawn(t
, argv
, fd
, FLAGS_SET(flags
, EXEC_DIR_SET_SYSTEMD_EXEC_PID
), &pid
);
168 if (parallel_execution
) {
169 r
= hashmap_ensure_put(&pids
, &trivial_hash_ops_value_free
, PID_TO_PTR(pid
), t
);
174 bool skip_remaining
= false;
176 r
= wait_for_terminate_and_check(t
, pid
, WAIT_LOG_ABNORMAL
);
180 if (FLAGS_SET(flags
, EXEC_DIR_SKIP_REMAINING
) && r
== EXIT_SKIP_REMAINING
) {
181 log_info("%s succeeded with exit status %i, not executing remaining executables.", *path
, r
);
182 skip_remaining
= true;
183 } else if (FLAGS_SET(flags
, EXEC_DIR_IGNORE_ERRORS
))
184 log_warning("%s failed with exit status %i, ignoring.", *path
, r
);
186 log_error("%s failed with exit status %i.", *path
, r
);
192 r
= finish_serialization_fd(fd
);
194 return log_error_errno(r
, "Failed to finish serialization fd: %m");
196 r
= callbacks
[STDOUT_GENERATE
](TAKE_FD(fd
), callback_args
[STDOUT_GENERATE
]);
198 return log_error_errno(r
, "Failed to process output from %s: %m", *path
);
207 r
= callbacks
[STDOUT_COLLECT
](output_fd
, callback_args
[STDOUT_COLLECT
]);
209 return log_error_errno(r
, "Callback two failed: %m");
212 while (!hashmap_isempty(pids
)) {
213 _cleanup_free_
char *t
= NULL
;
217 t
= ASSERT_PTR(hashmap_steal_first_key_and_value(pids
, &p
));
221 r
= wait_for_terminate_and_check(t
, pid
, WAIT_LOG
);
224 if (!FLAGS_SET(flags
, EXEC_DIR_IGNORE_ERRORS
) && r
> 0)
236 gather_stdout_callback_t
const callbacks
[_STDOUT_CONSUME_MAX
],
237 void * const callback_args
[_STDOUT_CONSUME_MAX
],
240 ExecDirFlags flags
) {
242 _cleanup_close_
int fd
= -EBADF
;
246 assert(!FLAGS_SET(flags
, EXEC_DIR_PARALLEL
| EXEC_DIR_SKIP_REMAINING
));
248 if (strv_isempty(paths
))
253 assert(callbacks
[STDOUT_GENERATE
]);
254 assert(callbacks
[STDOUT_COLLECT
]);
255 assert(callbacks
[STDOUT_CONSUME
]);
256 assert(callback_args
);
258 fd
= open_serialization_fd(name
);
260 return log_error_errno(fd
, "Failed to open serialization file: %m");
263 /* Executes all binaries in the directories serially or in parallel and waits for
264 * them to finish. Optionally a timeout is applied. If a file with the same name
265 * exists in more than one directory, the earliest one wins. */
267 r
= safe_fork("(sd-exec-strv)", FORK_RESET_SIGNALS
|FORK_DEATHSIG_SIGTERM
|FORK_LOG
, &executor_pid
);
271 r
= do_execute(paths
, root
, timeout
, callbacks
, callback_args
, fd
, argv
, envp
, flags
);
272 _exit(r
< 0 ? EXIT_FAILURE
: r
);
275 r
= wait_for_terminate_and_check("(sd-exec-strv)", executor_pid
, 0);
278 if (!FLAGS_SET(flags
, EXEC_DIR_IGNORE_ERRORS
) && r
> 0)
284 r
= finish_serialization_fd(fd
);
286 return log_error_errno(r
, "Failed to finish serialization fd: %m");
288 r
= callbacks
[STDOUT_CONSUME
](TAKE_FD(fd
), callback_args
[STDOUT_CONSUME
]);
290 return log_error_errno(r
, "Failed to parse returned data: %m");
295 int execute_directories(
296 const char * const *directories
,
298 gather_stdout_callback_t
const callbacks
[_STDOUT_CONSUME_MAX
],
299 void * const callback_args
[_STDOUT_CONSUME_MAX
],
302 ExecDirFlags flags
) {
304 _cleanup_strv_free_
char **paths
= NULL
;
305 _cleanup_free_
char *name
= NULL
;
308 assert(!strv_isempty((char* const*) directories
));
310 r
= conf_files_list_strv(
314 CONF_FILES_EXECUTABLE
|CONF_FILES_REGULAR
|CONF_FILES_FILTER_MASKED
,
317 return log_error_errno(r
, "Failed to enumerate executables: %m");
319 if (strv_isempty(paths
)) {
320 log_debug("No executables found.");
325 r
= path_extract_filename(directories
[0], &name
);
327 return log_error_errno(r
, "Failed to extract file name from '%s': %m", directories
[0]);
330 return execute_strv(name
, paths
, /* root = */ NULL
, timeout
, callbacks
, callback_args
, argv
, envp
, flags
);
333 static int gather_environment_generate(int fd
, void *arg
) {
334 char ***env
= ASSERT_PTR(arg
);
335 _cleanup_fclose_
FILE *f
= NULL
;
336 _cleanup_strv_free_
char **new = NULL
;
339 /* Read a series of VAR=value assignments from fd, use them to update the list of variables in env.
340 * Also update the exported environment.
342 * fd is always consumed, even on error.
353 r
= load_env_file_pairs(f
, NULL
, &new);
357 STRV_FOREACH_PAIR(x
, y
, new) {
358 if (!env_name_is_valid(*x
)) {
359 log_warning("Invalid variable assignment \"%s=...\", ignoring.", *x
);
363 r
= strv_env_assign(env
, *x
, *y
);
367 if (setenv(*x
, *y
, /* overwrite = */ true) < 0)
374 static int gather_environment_collect(int fd
, void *arg
) {
375 char ***env
= ASSERT_PTR(arg
);
376 _cleanup_fclose_
FILE *f
= NULL
;
379 /* Write out a series of env=cescape(VAR=value) assignments to fd. */
389 r
= serialize_strv(f
, "env", *env
);
393 r
= fflush_and_check(f
);
400 static int gather_environment_consume(int fd
, void *arg
) {
401 char ***env
= ASSERT_PTR(arg
);
402 _cleanup_fclose_
FILE *f
= NULL
;
405 /* Read a series of env=cescape(VAR=value) assignments from fd into env. */
416 _cleanup_free_
char *line
= NULL
;
419 r
= read_line(f
, LONG_LINE_MAX
, &line
);
425 v
= startswith(line
, "env=");
427 RET_GATHER(ret
, log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
428 "Serialization line unexpectedly didn't start with \"env=\", ignoring: %s",
433 r
= deserialize_environment(v
, env
);
435 RET_GATHER(ret
, log_debug_errno(r
, "Failed to deserialize line \"%s\": %m", line
));
439 const gather_stdout_callback_t gather_environment
[_STDOUT_CONSUME_MAX
] = {
440 gather_environment_generate
,
441 gather_environment_collect
,
442 gather_environment_consume
,
445 int exec_command_flags_from_strv(char * const *ex_opts
, ExecCommandFlags
*ret
) {
446 ExecCommandFlags flags
= 0;
450 STRV_FOREACH(opt
, ex_opts
) {
451 ExecCommandFlags fl
= exec_command_flags_from_string(*opt
);
463 int exec_command_flags_to_strv(ExecCommandFlags flags
, char ***ret
) {
464 _cleanup_strv_free_
char **opts
= NULL
;
470 BIT_FOREACH(i
, flags
) {
471 const char *s
= exec_command_flags_to_string(1 << i
);
475 r
= strv_extend(&opts
, s
);
480 *ret
= TAKE_PTR(opts
);
485 static const char* const exec_command_strings
[] = {
486 "ignore-failure", /* EXEC_COMMAND_IGNORE_FAILURE */
487 "privileged", /* EXEC_COMMAND_FULLY_PRIVILEGED */
488 "no-setuid", /* EXEC_COMMAND_NO_SETUID */
489 "no-env-expand", /* EXEC_COMMAND_NO_ENV_EXPAND */
490 "via-shell", /* EXEC_COMMAND_VIA_SHELL */
493 assert_cc((1 << ELEMENTSOF(exec_command_strings
)) - 1 == _EXEC_COMMAND_FLAGS_ALL
);
495 const char* exec_command_flags_to_string(ExecCommandFlags i
) {
496 for (size_t idx
= 0; idx
< ELEMENTSOF(exec_command_strings
); idx
++)
498 return exec_command_strings
[idx
];
503 ExecCommandFlags
exec_command_flags_from_string(const char *s
) {
506 if (streq(s
, "ambient")) /* Compatibility with ambient hack, removed in v258, map to no bits set */
509 idx
= string_table_lookup_from_string(exec_command_strings
, ELEMENTSOF(exec_command_strings
), s
);
511 return _EXEC_COMMAND_FLAGS_INVALID
;
516 int fexecve_or_execve(int executable_fd
, const char *executable
, char *const argv
[], char *const envp
[]) {
517 /* Refuse invalid fds, regardless if fexecve() use is enabled or not */
518 if (executable_fd
< 0)
521 /* Block any attempts on exploiting Linux' liberal argv[] handling, i.e. CVE-2021-4034 and suchlike */
522 if (isempty(executable
) || strv_isempty(argv
))
527 execveat(executable_fd
, "", argv
, envp
, AT_EMPTY_PATH
);
529 if (IN_SET(errno
, ENOSYS
, ENOENT
) || ERRNO_IS_PRIVILEGE(errno
))
530 /* Old kernel or a script or an overzealous seccomp filter? Let's fall back to execve().
532 * fexecve(3): "If fd refers to a script (i.e., it is an executable text file that names a
533 * script interpreter with a first line that begins with the characters #!) and the
534 * close-on-exec flag has been set for fd, then fexecve() fails with the error ENOENT. This
535 * error occurs because, by the time the script interpreter is executed, fd has already been
536 * closed because of the close-on-exec flag. Thus, the close-on-exec flag can't be set on fd
537 * if it refers to a script."
539 * Unfortunately, if we unset close-on-exec, the script will be executed just fine, but (at
540 * least in case of bash) the script name, $0, will be shown as /dev/fd/nnn, which breaks
541 * scripts which make use of $0. Thus, let's fall back to execve() in this case.
544 execve(executable
, argv
, envp
);
548 int shall_fork_agent(void) {
551 /* Check if we have a controlling terminal. If not (ENXIO here), we aren't actually invoked
552 * interactively on a terminal, hence fail. */
553 r
= get_ctty_devnr(0, NULL
);
559 if (!is_main_thread())
565 int _fork_agent(const char *name
, char * const *argv
, const int except
[], size_t n_except
, pid_t
*ret_pid
) {
568 assert(!strv_isempty(argv
));
570 /* Spawns a temporary TTY agent, making sure it goes away when we go away */
572 r
= safe_fork_full(name
,
574 (int*) except
, /* safe_fork_full only changes except if you pass in FORK_PACK_FDS, which we don't */
576 FORK_RESET_SIGNALS
|FORK_DEATHSIG_SIGTERM
|FORK_CLOSE_ALL_FDS
|FORK_REOPEN_LOG
|FORK_RLIMIT_NOFILE_SAFE
,
585 bool stdin_is_tty
= isatty_safe(STDIN_FILENO
),
586 stdout_is_tty
= isatty_safe(STDOUT_FILENO
),
587 stderr_is_tty
= isatty_safe(STDERR_FILENO
);
589 if (!stdin_is_tty
|| !stdout_is_tty
|| !stderr_is_tty
) {
592 /* Detach from stdin/stdout/stderr and reopen /dev/tty for them. This is important to ensure
593 * that when systemctl is started via popen() or a similar call that expects to read EOF we
594 * actually do generate EOF and not delay this indefinitely by keeping an unused copy of
596 fd
= open_terminal("/dev/tty", stdin_is_tty
? O_WRONLY
: (stdout_is_tty
&& stderr_is_tty
) ? O_RDONLY
: O_RDWR
);
598 log_error_errno(fd
, "Failed to open %s: %m", "/dev/tty");
602 if (!stdin_is_tty
&& dup2(fd
, STDIN_FILENO
) < 0) {
603 log_error_errno(errno
, "Failed to dup2 /dev/tty to STDIN: %m");
607 if (!stdout_is_tty
&& dup2(fd
, STDOUT_FILENO
) < 0) {
608 log_error_errno(errno
, "Failed to dup2 /dev/tty to STDOUT: %m");
612 if (!stderr_is_tty
&& dup2(fd
, STDERR_FILENO
) < 0) {
613 log_error_errno(errno
, "Failed to dup2 /dev/tty to STDERR: %m");
617 fd
= safe_close_above_stdio(fd
);
620 /* Count arguments */
621 execv(argv
[0], argv
);
623 /* Let's treat missing agent binary as a graceful issue (in order to support splitting out the Polkit
624 * or password agents into separate, optional distro packages), and not complain loudly. */
625 log_full_errno(errno
== ENOENT
? LOG_DEBUG
: LOG_ERR
, errno
,
626 "Failed to execute %s: %m", argv
[0]);