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