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