]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/exec-util.c
strv: make iterator in STRV_FOREACH() declaread in the loop
[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) {
de010b0b 256 char ***env = 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
267 assert(env);
268
269 f = fdopen(fd, "r");
270 if (!f) {
271 safe_close(fd);
272 return -errno;
273 }
274
aa8fbc74 275 r = load_env_file_pairs(f, NULL, &new);
3303d1b2
ZJS
276 if (r < 0)
277 return r;
278
279 STRV_FOREACH_PAIR(x, y, new) {
184d1904
ZJS
280 if (!env_name_is_valid(*x)) {
281 log_warning("Invalid variable assignment \"%s=...\", ignoring.", *x);
282 continue;
283 }
284
b230baae 285 r = strv_env_assign(env, *x, *y);
3303d1b2
ZJS
286 if (r < 0)
287 return r;
288
289 if (setenv(*x, *y, true) < 0)
290 return -errno;
291 }
292
b230baae 293 return 0;
3303d1b2
ZJS
294}
295
296static int gather_environment_collect(int fd, void *arg) {
3303d1b2 297 _cleanup_fclose_ FILE *f = NULL;
c93d527f 298 char ***env = arg;
3303d1b2
ZJS
299 int r;
300
301 /* Write out a series of env=cescape(VAR=value) assignments to fd. */
302
303 assert(env);
304
305 f = fdopen(fd, "w");
306 if (!f) {
307 safe_close(fd);
308 return -errno;
309 }
310
d68c645b 311 r = serialize_strv(f, "env", *env);
3303d1b2
ZJS
312 if (r < 0)
313 return r;
314
c93d527f
LP
315 r = fflush_and_check(f);
316 if (r < 0)
317 return r;
3303d1b2
ZJS
318
319 return 0;
320}
321
322static int gather_environment_consume(int fd, void *arg) {
3303d1b2 323 _cleanup_fclose_ FILE *f = NULL;
d68c645b
LP
324 char ***env = arg;
325 int r = 0;
3303d1b2
ZJS
326
327 /* Read a series of env=cescape(VAR=value) assignments from fd into env. */
328
329 assert(env);
330
e92aaed3 331 f = fdopen(fd, "r");
3303d1b2
ZJS
332 if (!f) {
333 safe_close(fd);
334 return -errno;
335 }
336
d68c645b
LP
337 for (;;) {
338 _cleanup_free_ char *line = NULL;
339 const char *v;
340 int k;
3303d1b2 341
d68c645b 342 k = read_line(f, LONG_LINE_MAX, &line);
3303d1b2 343 if (k < 0)
d68c645b
LP
344 return k;
345 if (k == 0)
346 break;
347
348 v = startswith(line, "env=");
349 if (!v) {
350 log_debug("Serialization line \"%s\" unexpectedly didn't start with \"env=\".", line);
351 if (r == 0)
352 r = -EINVAL;
353
354 continue;
355 }
356
357 k = deserialize_environment(v, env);
358 if (k < 0) {
359 log_debug_errno(k, "Invalid serialization line \"%s\": %m", line);
360
361 if (r == 0)
362 r = k;
363 }
3303d1b2
ZJS
364 }
365
366 return r;
367}
368
b3d59367
AZ
369int exec_command_flags_from_strv(char **ex_opts, ExecCommandFlags *flags) {
370 ExecCommandFlags ex_flag, ret_flags = 0;
b3d59367
AZ
371
372 assert(flags);
373
374 STRV_FOREACH(opt, ex_opts) {
375 ex_flag = exec_command_flags_from_string(*opt);
9de42a6a
BR
376 if (ex_flag < 0)
377 return ex_flag;
378 ret_flags |= ex_flag;
b3d59367
AZ
379 }
380
381 *flags = ret_flags;
382
383 return 0;
384}
385
386int exec_command_flags_to_strv(ExecCommandFlags flags, char ***ex_opts) {
387 _cleanup_strv_free_ char **ret_opts = NULL;
388 ExecCommandFlags it = flags;
389 const char *str;
390 int i, r;
391
392 assert(ex_opts);
393
9de42a6a
BR
394 if (flags < 0)
395 return flags;
396
b3d59367
AZ
397 for (i = 0; it != 0; it &= ~(1 << i), i++) {
398 if (FLAGS_SET(flags, (1 << i))) {
399 str = exec_command_flags_to_string(1 << i);
400 if (!str)
401 return -EINVAL;
402
403 r = strv_extend(&ret_opts, str);
404 if (r < 0)
405 return r;
406 }
407 }
408
409 *ex_opts = TAKE_PTR(ret_opts);
410
411 return 0;
412}
413
3303d1b2
ZJS
414const gather_stdout_callback_t gather_environment[] = {
415 gather_environment_generate,
416 gather_environment_collect,
417 gather_environment_consume,
418};
b3d59367
AZ
419
420static const char* const exec_command_strings[] = {
421 "ignore-failure", /* EXEC_COMMAND_IGNORE_FAILURE */
422 "privileged", /* EXEC_COMMAND_FULLY_PRIVILEGED */
423 "no-setuid", /* EXEC_COMMAND_NO_SETUID */
424 "ambient", /* EXEC_COMMAND_AMBIENT_MAGIC */
425 "no-env-expand", /* EXEC_COMMAND_NO_ENV_EXPAND */
426};
427
428const char* exec_command_flags_to_string(ExecCommandFlags i) {
429 size_t idx;
430
431 for (idx = 0; idx < ELEMENTSOF(exec_command_strings); idx++)
432 if (i == (1 << idx))
433 return exec_command_strings[idx];
434
435 return NULL;
436}
437
438ExecCommandFlags exec_command_flags_from_string(const char *s) {
439 ssize_t idx;
440
441 idx = string_table_lookup(exec_command_strings, ELEMENTSOF(exec_command_strings), s);
442
443 if (idx < 0)
444 return _EXEC_COMMAND_FLAGS_INVALID;
445 else
446 return 1 << idx;
447}
a6d9111c
ZJS
448
449int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]) {
69339ae9
LP
450 /* Refuse invalid fds, regardless if fexecve() use is enabled or not */
451 if (executable_fd < 0)
452 return -EBADF;
453
454 /* Block any attempts on exploiting Linux' liberal argv[] handling, i.e. CVE-2021-4034 and suchlike */
455 if (isempty(executable) || strv_isempty(argv))
456 return -EINVAL;
457
ceedbf81 458#if ENABLE_FEXECVE
69339ae9 459
8939eeae 460 execveat(executable_fd, "", argv, envp, AT_EMPTY_PATH);
3f51bbff
ZJS
461
462 if (IN_SET(errno, ENOSYS, ENOENT) || ERRNO_IS_PRIVILEGE(errno))
463 /* Old kernel or a script or an overzealous seccomp filter? Let's fall back to execve().
a6d9111c
ZJS
464 *
465 * fexecve(3): "If fd refers to a script (i.e., it is an executable text file that names a
466 * script interpreter with a first line that begins with the characters #!) and the
467 * close-on-exec flag has been set for fd, then fexecve() fails with the error ENOENT. This
468 * error occurs because, by the time the script interpreter is executed, fd has already been
469 * closed because of the close-on-exec flag. Thus, the close-on-exec flag can't be set on fd
470 * if it refers to a script."
471 *
472 * Unfortunately, if we unset close-on-exec, the script will be executed just fine, but (at
473 * least in case of bash) the script name, $0, will be shown as /dev/fd/nnn, which breaks
474 * scripts which make use of $0. Thus, let's fall back to execve() in this case.
475 */
ceedbf81 476#endif
a6d9111c
ZJS
477 execve(executable, argv, envp);
478 return -errno;
479}
3e24e8cd 480
c85cb3bc 481int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) {
3e24e8cd
ZJS
482 bool stdout_is_tty, stderr_is_tty;
483 size_t n, i;
484 va_list ap;
485 char **l;
486 int r;
487
488 assert(path);
489
490 /* Spawns a temporary TTY agent, making sure it goes away when we go away */
491
492 r = safe_fork_full(name,
493 except,
494 n_except,
495 FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG,
496 ret_pid);
497 if (r < 0)
498 return r;
499 if (r > 0)
500 return 0;
501
502 /* In the child: */
503
504 stdout_is_tty = isatty(STDOUT_FILENO);
505 stderr_is_tty = isatty(STDERR_FILENO);
506
507 if (!stdout_is_tty || !stderr_is_tty) {
508 int fd;
509
510 /* Detach from stdout/stderr and reopen /dev/tty for them. This is important to ensure that
511 * when systemctl is started via popen() or a similar call that expects to read EOF we
512 * actually do generate EOF and not delay this indefinitely by keeping an unused copy of
513 * stdin around. */
514 fd = open("/dev/tty", O_WRONLY);
515 if (fd < 0) {
b98416e1 516 if (errno != ENXIO) {
0bcf1679
LP
517 log_error_errno(errno, "Failed to open /dev/tty: %m");
518 _exit(EXIT_FAILURE);
519 }
3e24e8cd 520
0bcf1679
LP
521 /* If we get ENXIO here we have no controlling TTY even though stdout/stderr are
522 * connected to a TTY. That's a weird setup, but let's handle it gracefully: let's
523 * skip the forking of the agents, given the TTY setup is not in order. */
524 } else {
525 if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
526 log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
527 _exit(EXIT_FAILURE);
528 }
3e24e8cd 529
0bcf1679
LP
530 if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
531 log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
532 _exit(EXIT_FAILURE);
533 }
3e24e8cd 534
0bcf1679
LP
535 fd = safe_close_above_stdio(fd);
536 }
3e24e8cd
ZJS
537 }
538
539 (void) rlimit_nofile_safe();
540
541 /* Count arguments */
542 va_start(ap, path);
543 for (n = 0; va_arg(ap, char*); n++)
544 ;
545 va_end(ap);
546
547 /* Allocate strv */
548 l = newa(char*, n + 1);
549
550 /* Fill in arguments */
551 va_start(ap, path);
552 for (i = 0; i <= n; i++)
553 l[i] = va_arg(ap, char*);
554 va_end(ap);
555
556 execv(path, l);
557 _exit(EXIT_FAILURE);
558}