1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
10 #include "alloc-util.h"
11 #include "conf-files.h"
14 #include "errno-util.h"
16 #include "exec-util.h"
21 #include "missing_syscall.h"
22 #include "path-util.h"
23 #include "process-util.h"
24 #include "serialize.h"
26 #include "signal-util.h"
27 #include "stat-util.h"
28 #include "string-table.h"
29 #include "string-util.h"
31 #include "terminal-util.h"
32 #include "tmpfile-util.h"
34 #define EXIT_SKIP_REMAINING 77
36 /* Put this test here for a lack of better place */
37 assert_cc(EAGAIN
== EWOULDBLOCK
);
43 bool set_systemd_exec_pid
,
51 if (null_or_empty_path(path
) > 0) {
52 log_debug("%s is empty (a mask).", path
);
59 (const int[]) { STDIN_FILENO
, stdout_fd
< 0 ? STDOUT_FILENO
: stdout_fd
, STDERR_FILENO
},
60 /* except_fds= */ NULL
, /* n_except_fds= */ 0,
61 FORK_DEATHSIG_SIGTERM
|FORK_LOG
|FORK_RLIMIT_NOFILE_SAFE
|FORK_REARRANGE_STDIO
|FORK_CLOSE_ALL_FDS
,
68 if (set_systemd_exec_pid
) {
69 r
= setenv_systemd_exec_pid(false);
71 log_warning_errno(r
, "Failed to set $SYSTEMD_EXEC_PID, ignoring: %m");
75 _argv
[0] = (char*) path
;
79 argv
[0] = (char*) path
;
82 log_error_errno(errno
, "Failed to execute %s: %m", path
);
90 static int do_execute(
94 gather_stdout_callback_t
const callbacks
[_STDOUT_CONSUME_MAX
],
95 void* const callback_args
[_STDOUT_CONSUME_MAX
],
101 _cleanup_hashmap_free_free_ Hashmap
*pids
= NULL
;
102 bool parallel_execution
;
105 /* We fork this all off from a child process so that we can somewhat cleanly make
106 * use of SIGALRM to set a time limit.
108 * We attempt to perform parallel execution if configured by the user, however
109 * if `callbacks` is nonnull, execution must be serial.
111 parallel_execution
= FLAGS_SET(flags
, EXEC_DIR_PARALLEL
) && !callbacks
;
113 if (parallel_execution
) {
114 pids
= hashmap_new(NULL
);
119 /* Abort execution of this process after the timeout. We simply rely on SIGALRM as
120 * default action terminating the process, and turn on alarm(). */
122 if (timeout
!= USEC_INFINITY
)
123 alarm(DIV_ROUND_UP(timeout
, USEC_PER_SEC
));
125 STRV_FOREACH(e
, envp
)
127 return log_error_errno(errno
, "Failed to set environment variable: %m");
129 STRV_FOREACH(path
, paths
) {
130 _cleanup_free_
char *t
= NULL
;
131 _cleanup_close_
int fd
= -EBADF
;
134 t
= path_join(root
, *path
);
139 _cleanup_free_
char *bn
= NULL
;
141 r
= path_extract_filename(*path
, &bn
);
143 return log_error_errno(r
, "Failed to extract filename from path '%s': %m", *path
);
145 fd
= open_serialization_fd(bn
);
147 return log_error_errno(fd
, "Failed to open serialization file: %m");
151 _cleanup_free_
char *args
= NULL
;
153 args
= quote_command_line(strv_skip(argv
, 1), SHELL_ESCAPE_EMPTY
);
155 log_debug("About to execute %s%s%s", t
, argv
? " " : "", argv
? strnull(args
) : "");
158 r
= do_spawn(t
, argv
, fd
, FLAGS_SET(flags
, EXEC_DIR_SET_SYSTEMD_EXEC_PID
), &pid
);
162 if (parallel_execution
) {
163 r
= hashmap_put(pids
, PID_TO_PTR(pid
), t
);
168 bool skip_remaining
= false;
170 r
= wait_for_terminate_and_check(t
, pid
, WAIT_LOG_ABNORMAL
);
174 if (FLAGS_SET(flags
, EXEC_DIR_SKIP_REMAINING
) && r
== EXIT_SKIP_REMAINING
) {
175 log_info("%s succeeded with exit status %i, not executing remaining executables.", *path
, r
);
176 skip_remaining
= true;
177 } else if (FLAGS_SET(flags
, EXEC_DIR_IGNORE_ERRORS
))
178 log_warning("%s failed with exit status %i, ignoring.", *path
, r
);
180 log_error("%s failed with exit status %i.", *path
, r
);
186 if (lseek(fd
, 0, SEEK_SET
) < 0)
187 return log_error_errno(errno
, "Failed to seek on serialization fd: %m");
189 r
= callbacks
[STDOUT_GENERATE
](TAKE_FD(fd
), callback_args
[STDOUT_GENERATE
]);
191 return log_error_errno(r
, "Failed to process output from %s: %m", *path
);
200 r
= callbacks
[STDOUT_COLLECT
](output_fd
, callback_args
[STDOUT_COLLECT
]);
202 return log_error_errno(r
, "Callback two failed: %m");
205 while (!hashmap_isempty(pids
)) {
206 _cleanup_free_
char *t
= NULL
;
209 pid
= PTR_TO_PID(hashmap_first_key(pids
));
212 t
= hashmap_remove(pids
, PID_TO_PTR(pid
));
215 r
= wait_for_terminate_and_check(t
, pid
, WAIT_LOG
);
218 if (!FLAGS_SET(flags
, EXEC_DIR_IGNORE_ERRORS
) && r
> 0)
230 gather_stdout_callback_t
const callbacks
[_STDOUT_CONSUME_MAX
],
231 void* const callback_args
[_STDOUT_CONSUME_MAX
],
234 ExecDirFlags flags
) {
236 _cleanup_close_
int fd
= -EBADF
;
240 assert(!FLAGS_SET(flags
, EXEC_DIR_PARALLEL
| EXEC_DIR_SKIP_REMAINING
));
242 if (strv_isempty(paths
))
247 assert(callback_args
);
248 assert(callbacks
[STDOUT_GENERATE
]);
249 assert(callbacks
[STDOUT_COLLECT
]);
250 assert(callbacks
[STDOUT_CONSUME
]);
252 fd
= open_serialization_fd(name
);
254 return log_error_errno(fd
, "Failed to open serialization file: %m");
257 /* Executes all binaries in the directories serially or in parallel and waits for
258 * them to finish. Optionally a timeout is applied. If a file with the same name
259 * exists in more than one directory, the earliest one wins. */
261 r
= safe_fork("(sd-exec-strv)", FORK_RESET_SIGNALS
|FORK_DEATHSIG_SIGTERM
|FORK_LOG
, &executor_pid
);
265 r
= do_execute(paths
, root
, timeout
, callbacks
, callback_args
, fd
, argv
, envp
, flags
);
266 _exit(r
< 0 ? EXIT_FAILURE
: r
);
269 r
= wait_for_terminate_and_check("(sd-exec-strv)", executor_pid
, 0);
272 if (!FLAGS_SET(flags
, EXEC_DIR_IGNORE_ERRORS
) && r
> 0)
278 if (lseek(fd
, 0, SEEK_SET
) < 0)
279 return log_error_errno(errno
, "Failed to rewind serialization fd: %m");
281 r
= callbacks
[STDOUT_CONSUME
](TAKE_FD(fd
), callback_args
[STDOUT_CONSUME
]);
283 return log_error_errno(r
, "Failed to parse returned data: %m");
287 int execute_directories(
288 const char* const* directories
,
290 gather_stdout_callback_t
const callbacks
[_STDOUT_CONSUME_MAX
],
291 void* const callback_args
[_STDOUT_CONSUME_MAX
],
294 ExecDirFlags flags
) {
296 _cleanup_strv_free_
char **paths
= NULL
;
297 _cleanup_free_
char *name
= NULL
;
300 assert(!strv_isempty((char**) directories
));
302 r
= conf_files_list_strv(&paths
, NULL
, NULL
, CONF_FILES_EXECUTABLE
|CONF_FILES_REGULAR
|CONF_FILES_FILTER_MASKED
, directories
);
304 return log_error_errno(r
, "Failed to enumerate executables: %m");
306 if (strv_isempty(paths
)) {
307 log_debug("No executables found.");
312 r
= path_extract_filename(directories
[0], &name
);
314 return log_error_errno(r
, "Failed to extract file name from '%s': %m", directories
[0]);
317 return execute_strv(name
, paths
, NULL
, timeout
, callbacks
, callback_args
, argv
, envp
, flags
);
320 static int gather_environment_generate(int fd
, void *arg
) {
321 char ***env
= ASSERT_PTR(arg
);
322 _cleanup_fclose_
FILE *f
= NULL
;
323 _cleanup_strv_free_
char **new = NULL
;
326 /* Read a series of VAR=value assignments from fd, use them to update the list of
327 * variables in env. Also update the exported environment.
329 * fd is always consumed, even on error.
338 r
= load_env_file_pairs(f
, NULL
, &new);
342 STRV_FOREACH_PAIR(x
, y
, new) {
343 if (!env_name_is_valid(*x
)) {
344 log_warning("Invalid variable assignment \"%s=...\", ignoring.", *x
);
348 r
= strv_env_assign(env
, *x
, *y
);
352 if (setenv(*x
, *y
, true) < 0)
359 static int gather_environment_collect(int fd
, void *arg
) {
360 _cleanup_fclose_
FILE *f
= NULL
;
361 char ***env
= ASSERT_PTR(arg
);
364 /* Write out a series of env=cescape(VAR=value) assignments to fd. */
372 r
= serialize_strv(f
, "env", *env
);
376 r
= fflush_and_check(f
);
383 static int gather_environment_consume(int fd
, void *arg
) {
384 _cleanup_fclose_
FILE *f
= NULL
;
385 char ***env
= ASSERT_PTR(arg
);
388 /* Read a series of env=cescape(VAR=value) assignments from fd into env. */
397 _cleanup_free_
char *line
= NULL
;
401 k
= read_line(f
, LONG_LINE_MAX
, &line
);
407 v
= startswith(line
, "env=");
409 log_debug("Serialization line \"%s\" unexpectedly didn't start with \"env=\".", line
);
416 k
= deserialize_environment(v
, env
);
418 log_debug_errno(k
, "Invalid serialization line \"%s\": %m", line
);
428 int exec_command_flags_from_strv(char **ex_opts
, ExecCommandFlags
*flags
) {
429 ExecCommandFlags ex_flag
, ret_flags
= 0;
433 STRV_FOREACH(opt
, ex_opts
) {
434 ex_flag
= exec_command_flags_from_string(*opt
);
437 ret_flags
|= ex_flag
;
445 int exec_command_flags_to_strv(ExecCommandFlags flags
, char ***ex_opts
) {
446 _cleanup_strv_free_
char **ret_opts
= NULL
;
447 ExecCommandFlags it
= flags
;
456 for (unsigned i
= 0; it
!= 0; it
&= ~(1 << i
), i
++)
457 if (FLAGS_SET(flags
, (1 << i
))) {
458 str
= exec_command_flags_to_string(1 << i
);
462 r
= strv_extend(&ret_opts
, str
);
467 *ex_opts
= TAKE_PTR(ret_opts
);
472 const gather_stdout_callback_t gather_environment
[] = {
473 gather_environment_generate
,
474 gather_environment_collect
,
475 gather_environment_consume
,
478 static const char* const exec_command_strings
[] = {
479 "ignore-failure", /* EXEC_COMMAND_IGNORE_FAILURE */
480 "privileged", /* EXEC_COMMAND_FULLY_PRIVILEGED */
481 "no-setuid", /* EXEC_COMMAND_NO_SETUID */
482 "ambient", /* EXEC_COMMAND_AMBIENT_MAGIC */
483 "no-env-expand", /* EXEC_COMMAND_NO_ENV_EXPAND */
486 const char* exec_command_flags_to_string(ExecCommandFlags i
) {
487 for (size_t idx
= 0; idx
< ELEMENTSOF(exec_command_strings
); idx
++)
489 return exec_command_strings
[idx
];
494 ExecCommandFlags
exec_command_flags_from_string(const char *s
) {
497 idx
= string_table_lookup(exec_command_strings
, ELEMENTSOF(exec_command_strings
), s
);
500 return _EXEC_COMMAND_FLAGS_INVALID
;
505 int fexecve_or_execve(int executable_fd
, const char *executable
, char *const argv
[], char *const envp
[]) {
506 /* Refuse invalid fds, regardless if fexecve() use is enabled or not */
507 if (executable_fd
< 0)
510 /* Block any attempts on exploiting Linux' liberal argv[] handling, i.e. CVE-2021-4034 and suchlike */
511 if (isempty(executable
) || strv_isempty(argv
))
516 execveat(executable_fd
, "", argv
, envp
, AT_EMPTY_PATH
);
518 if (IN_SET(errno
, ENOSYS
, ENOENT
) || ERRNO_IS_PRIVILEGE(errno
))
519 /* Old kernel or a script or an overzealous seccomp filter? Let's fall back to execve().
521 * fexecve(3): "If fd refers to a script (i.e., it is an executable text file that names a
522 * script interpreter with a first line that begins with the characters #!) and the
523 * close-on-exec flag has been set for fd, then fexecve() fails with the error ENOENT. This
524 * error occurs because, by the time the script interpreter is executed, fd has already been
525 * closed because of the close-on-exec flag. Thus, the close-on-exec flag can't be set on fd
526 * if it refers to a script."
528 * Unfortunately, if we unset close-on-exec, the script will be executed just fine, but (at
529 * least in case of bash) the script name, $0, will be shown as /dev/fd/nnn, which breaks
530 * scripts which make use of $0. Thus, let's fall back to execve() in this case.
533 execve(executable
, argv
, envp
);
537 int fork_agent(const char *name
, const int except
[], size_t n_except
, pid_t
*ret_pid
, const char *path
, ...) {
538 bool stdout_is_tty
, stderr_is_tty
;
546 /* Spawns a temporary TTY agent, making sure it goes away when we go away */
548 r
= safe_fork_full(name
,
550 (int*) except
, /* safe_fork_full only changes except if you pass in FORK_PACK_FDS, which we don't */
552 FORK_RESET_SIGNALS
|FORK_DEATHSIG_SIGTERM
|FORK_CLOSE_ALL_FDS
|FORK_REOPEN_LOG
|FORK_RLIMIT_NOFILE_SAFE
,
561 stdout_is_tty
= isatty(STDOUT_FILENO
);
562 stderr_is_tty
= isatty(STDERR_FILENO
);
564 if (!stdout_is_tty
|| !stderr_is_tty
) {
567 /* Detach from stdout/stderr and reopen /dev/tty for them. This is important to ensure that
568 * when systemctl is started via popen() or a similar call that expects to read EOF we
569 * actually do generate EOF and not delay this indefinitely by keeping an unused copy of
571 fd
= open("/dev/tty", O_WRONLY
);
573 if (errno
!= ENXIO
) {
574 log_error_errno(errno
, "Failed to open /dev/tty: %m");
578 /* If we get ENXIO here we have no controlling TTY even though stdout/stderr are
579 * connected to a TTY. That's a weird setup, but let's handle it gracefully: let's
580 * skip the forking of the agents, given the TTY setup is not in order. */
582 if (!stdout_is_tty
&& dup2(fd
, STDOUT_FILENO
) < 0) {
583 log_error_errno(errno
, "Failed to dup2 /dev/tty: %m");
587 if (!stderr_is_tty
&& dup2(fd
, STDERR_FILENO
) < 0) {
588 log_error_errno(errno
, "Failed to dup2 /dev/tty: %m");
592 fd
= safe_close_above_stdio(fd
);
596 /* Count arguments */
598 for (n
= 0; va_arg(ap
, char*); n
++)
603 l
= newa(char*, n
+ 1);
605 /* Fill in arguments */
607 for (i
= 0; i
<= n
; i
++)
608 l
[i
] = va_arg(ap
, char*);