]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/exec-util.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / shared / exec-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
89711996
ZJS
2
3#include <dirent.h>
4#include <errno.h>
5#include <sys/prctl.h>
6#include <sys/types.h>
7#include <unistd.h>
c6e47247 8#include <stdio.h>
89711996
ZJS
9
10#include "alloc-util.h"
2e4cfe65 11#include "conf-files.h"
686d13b9 12#include "env-file.h"
c6e47247 13#include "env-util.h"
3f51bbff 14#include "errno-util.h"
89711996 15#include "exec-util.h"
c6e47247
ZJS
16#include "fd-util.h"
17#include "fileio.h"
89711996
ZJS
18#include "hashmap.h"
19#include "macro.h"
8939eeae 20#include "missing_syscall.h"
89711996 21#include "process-util.h"
595225af 22#include "rlimit-util.h"
d68c645b 23#include "serialize.h"
89711996
ZJS
24#include "set.h"
25#include "signal-util.h"
26#include "stat-util.h"
b3d59367 27#include "string-table.h"
89711996
ZJS
28#include "string-util.h"
29#include "strv.h"
c6e47247 30#include "terminal-util.h"
e4de7287 31#include "tmpfile-util.h"
89711996
ZJS
32#include "util.h"
33
34/* Put this test here for a lack of better place */
35assert_cc(EAGAIN == EWOULDBLOCK);
36
43f565c6 37static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid, bool set_systemd_exec_pid) {
cf55fc18 38 pid_t _pid;
4c253ed1 39 int r;
cf55fc18
ZJS
40
41 if (null_or_empty_path(path)) {
42 log_debug("%s is empty (a mask).", path);
43 return 0;
44 }
45
b6e1fff1 46 r = safe_fork("(direxec)", FORK_DEATHSIG|FORK_LOG, &_pid);
4c253ed1 47 if (r < 0)
b6e1fff1 48 return r;
4c253ed1 49 if (r == 0) {
cf55fc18
ZJS
50 char *_argv[2];
51
c6e47247 52 if (stdout_fd >= 0) {
aedec452 53 r = rearrange_stdio(STDIN_FILENO, TAKE_FD(stdout_fd), STDERR_FILENO);
2b33ab09 54 if (r < 0)
3554ef51 55 _exit(EXIT_FAILURE);
c6e47247
ZJS
56 }
57
595225af
LP
58 (void) rlimit_nofile_safe();
59
43f565c6
YW
60 if (set_systemd_exec_pid) {
61 r = setenv_systemd_exec_pid(false);
62 if (r < 0)
63 log_warning_errno(r, "Failed to set $SYSTEMD_EXEC_PID, ignoring: %m");
64 }
65
cf55fc18
ZJS
66 if (!argv) {
67 _argv[0] = (char*) path;
68 _argv[1] = NULL;
69 argv = _argv;
70 } else
71 argv[0] = (char*) path;
72
73 execv(path, argv);
74 log_error_errno(errno, "Failed to execute %s: %m", path);
75 _exit(EXIT_FAILURE);
76 }
77
cf55fc18
ZJS
78 *pid = _pid;
79 return 1;
80}
81
c6e47247
ZJS
82static int do_execute(
83 char **directories,
84 usec_t timeout,
85 gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
86 void* const callback_args[_STDOUT_CONSUME_MAX],
87 int output_fd,
78ec1bb4 88 char *argv[],
4b05f0c9
MK
89 char *envp[],
90 ExecDirFlags flags) {
c6e47247 91
89711996 92 _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
2e4cfe65 93 _cleanup_strv_free_ char **paths = NULL;
2e4cfe65 94 int r;
4b05f0c9 95 bool parallel_execution;
89711996 96
c6e47247
ZJS
97 /* We fork this all off from a child process so that we can somewhat cleanly make
98 * use of SIGALRM to set a time limit.
99 *
4b05f0c9
MK
100 * We attempt to perform parallel execution if configured by the user, however
101 * if `callbacks` is nonnull, execution must be serial.
c6e47247 102 */
4b05f0c9 103 parallel_execution = FLAGS_SET(flags, EXEC_DIR_PARALLEL) && !callbacks;
89711996 104
3e36211b 105 r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, (const char* const*) directories);
2e4cfe65 106 if (r < 0)
653d4695 107 return log_error_errno(r, "Failed to enumerate executables: %m");
2e4cfe65 108
4b05f0c9 109 if (parallel_execution) {
c6e47247
ZJS
110 pids = hashmap_new(NULL);
111 if (!pids)
112 return log_oom();
113 }
114
5238e957 115 /* Abort execution of this process after the timeout. We simply rely on SIGALRM as
c6e47247
ZJS
116 * default action terminating the process, and turn on alarm(). */
117
118 if (timeout != USEC_INFINITY)
be6b0c21 119 alarm(DIV_ROUND_UP(timeout, USEC_PER_SEC));
89711996 120
78ec1bb4 121 STRV_FOREACH(e, envp)
8f7329ac 122 if (putenv(*e) != 0)
ed689f78 123 return log_error_errno(errno, "Failed to set environment variable: %m");
78ec1bb4 124
2e4cfe65
ZJS
125 STRV_FOREACH(path, paths) {
126 _cleanup_free_ char *t = NULL;
c6e47247 127 _cleanup_close_ int fd = -1;
2e4cfe65 128 pid_t pid;
89711996 129
2e4cfe65
ZJS
130 t = strdup(*path);
131 if (!t)
132 return log_oom();
89711996 133
c6e47247
ZJS
134 if (callbacks) {
135 fd = open_serialization_fd(basename(*path));
136 if (fd < 0)
137 return log_error_errno(fd, "Failed to open serialization file: %m");
138 }
139
43f565c6 140 r = do_spawn(t, argv, fd, &pid, FLAGS_SET(flags, EXEC_DIR_SET_SYSTEMD_EXEC_PID));
2e4cfe65
ZJS
141 if (r <= 0)
142 continue;
89711996 143
4b05f0c9 144 if (parallel_execution) {
c6e47247
ZJS
145 r = hashmap_put(pids, PID_TO_PTR(pid), t);
146 if (r < 0)
147 return log_oom();
148 t = NULL;
149 } else {
7d4904fe 150 r = wait_for_terminate_and_check(t, pid, WAIT_LOG);
4b05f0c9
MK
151 if (FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS)) {
152 if (r < 0)
153 continue;
154 } else if (r > 0)
155 return r;
156
157 if (callbacks) {
158 if (lseek(fd, 0, SEEK_SET) < 0)
159 return log_error_errno(errno, "Failed to seek on serialization fd: %m");
160
161 r = callbacks[STDOUT_GENERATE](fd, callback_args[STDOUT_GENERATE]);
162 fd = -1;
163 if (r < 0)
164 return log_error_errno(r, "Failed to process output from %s: %m", *path);
165 }
c6e47247 166 }
89711996
ZJS
167 }
168
c6e47247
ZJS
169 if (callbacks) {
170 r = callbacks[STDOUT_COLLECT](output_fd, callback_args[STDOUT_COLLECT]);
171 if (r < 0)
172 return log_error_errno(r, "Callback two failed: %m");
173 }
89711996
ZJS
174
175 while (!hashmap_isempty(pids)) {
2e4cfe65 176 _cleanup_free_ char *t = NULL;
89711996
ZJS
177 pid_t pid;
178
179 pid = PTR_TO_PID(hashmap_first_key(pids));
180 assert(pid > 0);
181
2e4cfe65
ZJS
182 t = hashmap_remove(pids, PID_TO_PTR(pid));
183 assert(t);
89711996 184
4b05f0c9
MK
185 r = wait_for_terminate_and_check(t, pid, WAIT_LOG);
186 if (!FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS) && r > 0)
187 return r;
89711996
ZJS
188 }
189
190 return 0;
191}
192
c6e47247
ZJS
193int execute_directories(
194 const char* const* directories,
195 usec_t timeout,
196 gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
197 void* const callback_args[_STDOUT_CONSUME_MAX],
78ec1bb4 198 char *argv[],
4b05f0c9
MK
199 char *envp[],
200 ExecDirFlags flags) {
c6e47247 201
89711996 202 char **dirs = (char**) directories;
c6e47247 203 _cleanup_close_ int fd = -1;
1f5d1e02 204 char *name;
c6e47247 205 int r;
4b05f0c9 206 pid_t executor_pid;
89711996
ZJS
207
208 assert(!strv_isempty(dirs));
209
210 name = basename(dirs[0]);
211 assert(!isempty(name));
212
c6e47247
ZJS
213 if (callbacks) {
214 assert(callback_args);
215 assert(callbacks[STDOUT_GENERATE]);
216 assert(callbacks[STDOUT_COLLECT]);
217 assert(callbacks[STDOUT_CONSUME]);
218
219 fd = open_serialization_fd(name);
220 if (fd < 0)
221 return log_error_errno(fd, "Failed to open serialization file: %m");
222 }
223
224 /* Executes all binaries in the directories serially or in parallel and waits for
225 * them to finish. Optionally a timeout is applied. If a file with the same name
226 * exists in more than one directory, the earliest one wins. */
89711996 227
4b05f0c9 228 r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &executor_pid);
4c253ed1 229 if (r < 0)
b6e1fff1 230 return r;
4c253ed1 231 if (r == 0) {
4b05f0c9
MK
232 r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv, envp, flags);
233 _exit(r < 0 ? EXIT_FAILURE : r);
89711996
ZJS
234 }
235
4b05f0c9
MK
236 r = wait_for_terminate_and_check("(sd-executor)", executor_pid, 0);
237 if (r < 0)
238 return r;
239 if (!FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS) && r > 0)
240 return r;
241
c6e47247
ZJS
242 if (!callbacks)
243 return 0;
244
245 if (lseek(fd, 0, SEEK_SET) < 0)
246 return log_error_errno(errno, "Failed to rewind serialization fd: %m");
247
248 r = callbacks[STDOUT_CONSUME](fd, callback_args[STDOUT_CONSUME]);
249 fd = -1;
250 if (r < 0)
251 return log_error_errno(r, "Failed to parse returned data: %m");
252 return 0;
89711996 253}
3303d1b2
ZJS
254
255static int gather_environment_generate(int fd, void *arg) {
99534007 256 char ***env = ASSERT_PTR(arg);
3303d1b2 257 _cleanup_fclose_ FILE *f = NULL;
3f199740 258 _cleanup_strv_free_ char **new = NULL;
3303d1b2
ZJS
259 int r;
260
261 /* Read a series of VAR=value assignments from fd, use them to update the list of
262 * variables in env. Also update the exported environment.
263 *
264 * fd is always consumed, even on error.
265 */
266
3303d1b2
ZJS
267 f = fdopen(fd, "r");
268 if (!f) {
269 safe_close(fd);
270 return -errno;
271 }
272
aa8fbc74 273 r = load_env_file_pairs(f, NULL, &new);
3303d1b2
ZJS
274 if (r < 0)
275 return r;
276
277 STRV_FOREACH_PAIR(x, y, new) {
184d1904
ZJS
278 if (!env_name_is_valid(*x)) {
279 log_warning("Invalid variable assignment \"%s=...\", ignoring.", *x);
280 continue;
281 }
282
b230baae 283 r = strv_env_assign(env, *x, *y);
3303d1b2
ZJS
284 if (r < 0)
285 return r;
286
287 if (setenv(*x, *y, true) < 0)
288 return -errno;
289 }
290
b230baae 291 return 0;
3303d1b2
ZJS
292}
293
294static int gather_environment_collect(int fd, void *arg) {
3303d1b2 295 _cleanup_fclose_ FILE *f = NULL;
99534007 296 char ***env = ASSERT_PTR(arg);
3303d1b2
ZJS
297 int r;
298
299 /* Write out a series of env=cescape(VAR=value) assignments to fd. */
300
3303d1b2
ZJS
301 f = fdopen(fd, "w");
302 if (!f) {
303 safe_close(fd);
304 return -errno;
305 }
306
d68c645b 307 r = serialize_strv(f, "env", *env);
3303d1b2
ZJS
308 if (r < 0)
309 return r;
310
c93d527f
LP
311 r = fflush_and_check(f);
312 if (r < 0)
313 return r;
3303d1b2
ZJS
314
315 return 0;
316}
317
318static int gather_environment_consume(int fd, void *arg) {
3303d1b2 319 _cleanup_fclose_ FILE *f = NULL;
99534007 320 char ***env = ASSERT_PTR(arg);
d68c645b 321 int r = 0;
3303d1b2
ZJS
322
323 /* Read a series of env=cescape(VAR=value) assignments from fd into env. */
324
e92aaed3 325 f = fdopen(fd, "r");
3303d1b2
ZJS
326 if (!f) {
327 safe_close(fd);
328 return -errno;
329 }
330
d68c645b
LP
331 for (;;) {
332 _cleanup_free_ char *line = NULL;
333 const char *v;
334 int k;
3303d1b2 335
d68c645b 336 k = read_line(f, LONG_LINE_MAX, &line);
3303d1b2 337 if (k < 0)
d68c645b
LP
338 return k;
339 if (k == 0)
340 break;
341
342 v = startswith(line, "env=");
343 if (!v) {
344 log_debug("Serialization line \"%s\" unexpectedly didn't start with \"env=\".", line);
345 if (r == 0)
346 r = -EINVAL;
347
348 continue;
349 }
350
351 k = deserialize_environment(v, env);
352 if (k < 0) {
353 log_debug_errno(k, "Invalid serialization line \"%s\": %m", line);
354
355 if (r == 0)
356 r = k;
357 }
3303d1b2
ZJS
358 }
359
360 return r;
361}
362
b3d59367
AZ
363int exec_command_flags_from_strv(char **ex_opts, ExecCommandFlags *flags) {
364 ExecCommandFlags ex_flag, ret_flags = 0;
b3d59367
AZ
365
366 assert(flags);
367
368 STRV_FOREACH(opt, ex_opts) {
369 ex_flag = exec_command_flags_from_string(*opt);
9de42a6a
BR
370 if (ex_flag < 0)
371 return ex_flag;
372 ret_flags |= ex_flag;
b3d59367
AZ
373 }
374
375 *flags = ret_flags;
376
377 return 0;
378}
379
380int exec_command_flags_to_strv(ExecCommandFlags flags, char ***ex_opts) {
381 _cleanup_strv_free_ char **ret_opts = NULL;
382 ExecCommandFlags it = flags;
383 const char *str;
384 int i, r;
385
386 assert(ex_opts);
387
9de42a6a
BR
388 if (flags < 0)
389 return flags;
390
b3d59367
AZ
391 for (i = 0; it != 0; it &= ~(1 << i), i++) {
392 if (FLAGS_SET(flags, (1 << i))) {
393 str = exec_command_flags_to_string(1 << i);
394 if (!str)
395 return -EINVAL;
396
397 r = strv_extend(&ret_opts, str);
398 if (r < 0)
399 return r;
400 }
401 }
402
403 *ex_opts = TAKE_PTR(ret_opts);
404
405 return 0;
406}
407
3303d1b2
ZJS
408const gather_stdout_callback_t gather_environment[] = {
409 gather_environment_generate,
410 gather_environment_collect,
411 gather_environment_consume,
412};
b3d59367
AZ
413
414static const char* const exec_command_strings[] = {
415 "ignore-failure", /* EXEC_COMMAND_IGNORE_FAILURE */
416 "privileged", /* EXEC_COMMAND_FULLY_PRIVILEGED */
417 "no-setuid", /* EXEC_COMMAND_NO_SETUID */
418 "ambient", /* EXEC_COMMAND_AMBIENT_MAGIC */
419 "no-env-expand", /* EXEC_COMMAND_NO_ENV_EXPAND */
420};
421
422const char* exec_command_flags_to_string(ExecCommandFlags i) {
423 size_t idx;
424
425 for (idx = 0; idx < ELEMENTSOF(exec_command_strings); idx++)
426 if (i == (1 << idx))
427 return exec_command_strings[idx];
428
429 return NULL;
430}
431
432ExecCommandFlags exec_command_flags_from_string(const char *s) {
433 ssize_t idx;
434
435 idx = string_table_lookup(exec_command_strings, ELEMENTSOF(exec_command_strings), s);
436
437 if (idx < 0)
438 return _EXEC_COMMAND_FLAGS_INVALID;
439 else
440 return 1 << idx;
441}
a6d9111c
ZJS
442
443int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]) {
69339ae9
LP
444 /* Refuse invalid fds, regardless if fexecve() use is enabled or not */
445 if (executable_fd < 0)
446 return -EBADF;
447
448 /* Block any attempts on exploiting Linux' liberal argv[] handling, i.e. CVE-2021-4034 and suchlike */
449 if (isempty(executable) || strv_isempty(argv))
450 return -EINVAL;
451
ceedbf81 452#if ENABLE_FEXECVE
69339ae9 453
8939eeae 454 execveat(executable_fd, "", argv, envp, AT_EMPTY_PATH);
3f51bbff
ZJS
455
456 if (IN_SET(errno, ENOSYS, ENOENT) || ERRNO_IS_PRIVILEGE(errno))
457 /* Old kernel or a script or an overzealous seccomp filter? Let's fall back to execve().
a6d9111c
ZJS
458 *
459 * fexecve(3): "If fd refers to a script (i.e., it is an executable text file that names a
460 * script interpreter with a first line that begins with the characters #!) and the
461 * close-on-exec flag has been set for fd, then fexecve() fails with the error ENOENT. This
462 * error occurs because, by the time the script interpreter is executed, fd has already been
463 * closed because of the close-on-exec flag. Thus, the close-on-exec flag can't be set on fd
464 * if it refers to a script."
465 *
466 * Unfortunately, if we unset close-on-exec, the script will be executed just fine, but (at
467 * least in case of bash) the script name, $0, will be shown as /dev/fd/nnn, which breaks
468 * scripts which make use of $0. Thus, let's fall back to execve() in this case.
469 */
ceedbf81 470#endif
a6d9111c
ZJS
471 execve(executable, argv, envp);
472 return -errno;
473}
3e24e8cd 474
c85cb3bc 475int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) {
3e24e8cd
ZJS
476 bool stdout_is_tty, stderr_is_tty;
477 size_t n, i;
478 va_list ap;
479 char **l;
480 int r;
481
482 assert(path);
483
484 /* Spawns a temporary TTY agent, making sure it goes away when we go away */
485
486 r = safe_fork_full(name,
487 except,
488 n_except,
489 FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG,
490 ret_pid);
491 if (r < 0)
492 return r;
493 if (r > 0)
494 return 0;
495
496 /* In the child: */
497
498 stdout_is_tty = isatty(STDOUT_FILENO);
499 stderr_is_tty = isatty(STDERR_FILENO);
500
501 if (!stdout_is_tty || !stderr_is_tty) {
502 int fd;
503
504 /* Detach from stdout/stderr and reopen /dev/tty for them. This is important to ensure that
505 * when systemctl is started via popen() or a similar call that expects to read EOF we
506 * actually do generate EOF and not delay this indefinitely by keeping an unused copy of
507 * stdin around. */
508 fd = open("/dev/tty", O_WRONLY);
509 if (fd < 0) {
b98416e1 510 if (errno != ENXIO) {
0bcf1679
LP
511 log_error_errno(errno, "Failed to open /dev/tty: %m");
512 _exit(EXIT_FAILURE);
513 }
3e24e8cd 514
0bcf1679
LP
515 /* If we get ENXIO here we have no controlling TTY even though stdout/stderr are
516 * connected to a TTY. That's a weird setup, but let's handle it gracefully: let's
517 * skip the forking of the agents, given the TTY setup is not in order. */
518 } else {
519 if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
520 log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
521 _exit(EXIT_FAILURE);
522 }
3e24e8cd 523
0bcf1679
LP
524 if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
525 log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
526 _exit(EXIT_FAILURE);
527 }
3e24e8cd 528
0bcf1679
LP
529 fd = safe_close_above_stdio(fd);
530 }
3e24e8cd
ZJS
531 }
532
533 (void) rlimit_nofile_safe();
534
535 /* Count arguments */
536 va_start(ap, path);
537 for (n = 0; va_arg(ap, char*); n++)
538 ;
539 va_end(ap);
540
541 /* Allocate strv */
542 l = newa(char*, n + 1);
543
544 /* Fill in arguments */
545 va_start(ap, path);
546 for (i = 0; i <= n; i++)
547 l[i] = va_arg(ap, char*);
548 va_end(ap);
549
550 execv(path, l);
551 _exit(EXIT_FAILURE);
552}