]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/exec-util.c
hwdb: add scancodes for AYANEO devices (#33378)
[thirdparty/systemd.git] / src / shared / exec-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <dirent.h>
4 #include <errno.h>
5 #include <sys/prctl.h>
6 #include <sys/types.h>
7 #include <unistd.h>
8 #include <stdio.h>
9
10 #include "alloc-util.h"
11 #include "conf-files.h"
12 #include "env-file.h"
13 #include "env-util.h"
14 #include "errno-util.h"
15 #include "escape.h"
16 #include "exec-util.h"
17 #include "fd-util.h"
18 #include "fileio.h"
19 #include "hashmap.h"
20 #include "macro.h"
21 #include "missing_syscall.h"
22 #include "path-util.h"
23 #include "process-util.h"
24 #include "serialize.h"
25 #include "set.h"
26 #include "signal-util.h"
27 #include "stat-util.h"
28 #include "string-table.h"
29 #include "string-util.h"
30 #include "strv.h"
31 #include "terminal-util.h"
32 #include "tmpfile-util.h"
33
34 #define EXIT_SKIP_REMAINING 77
35
36 /* Put this test here for a lack of better place */
37 assert_cc(EAGAIN == EWOULDBLOCK);
38
39 static int do_spawn(
40 const char *path,
41 char *argv[],
42 int stdout_fd,
43 bool set_systemd_exec_pid,
44 pid_t *ret_pid) {
45
46 int r;
47
48 assert(path);
49 assert(ret_pid);
50
51 if (null_or_empty_path(path) > 0) {
52 log_debug("%s is empty (a mask).", path);
53 return 0;
54 }
55
56 pid_t pid;
57 r = safe_fork_full(
58 "(direxec)",
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,
62 &pid);
63 if (r < 0)
64 return r;
65 if (r == 0) {
66 char *_argv[2];
67
68 if (set_systemd_exec_pid) {
69 r = setenv_systemd_exec_pid(false);
70 if (r < 0)
71 log_warning_errno(r, "Failed to set $SYSTEMD_EXEC_PID, ignoring: %m");
72 }
73
74 if (!argv) {
75 _argv[0] = (char*) path;
76 _argv[1] = NULL;
77 argv = _argv;
78 } else
79 argv[0] = (char*) path;
80
81 execv(path, argv);
82 log_error_errno(errno, "Failed to execute %s: %m", path);
83 _exit(EXIT_FAILURE);
84 }
85
86 *ret_pid = pid;
87 return 1;
88 }
89
90 static int do_execute(
91 char* const* paths,
92 const char *root,
93 usec_t timeout,
94 gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
95 void* const callback_args[_STDOUT_CONSUME_MAX],
96 int output_fd,
97 char *argv[],
98 char *envp[],
99 ExecDirFlags flags) {
100
101 _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
102 bool parallel_execution;
103 int r;
104
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.
107 *
108 * We attempt to perform parallel execution if configured by the user, however
109 * if `callbacks` is nonnull, execution must be serial.
110 */
111 parallel_execution = FLAGS_SET(flags, EXEC_DIR_PARALLEL) && !callbacks;
112
113 if (parallel_execution) {
114 pids = hashmap_new(NULL);
115 if (!pids)
116 return log_oom();
117 }
118
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(). */
121
122 if (timeout != USEC_INFINITY)
123 alarm(DIV_ROUND_UP(timeout, USEC_PER_SEC));
124
125 STRV_FOREACH(e, envp)
126 if (putenv(*e) != 0)
127 return log_error_errno(errno, "Failed to set environment variable: %m");
128
129 STRV_FOREACH(path, paths) {
130 _cleanup_free_ char *t = NULL;
131 _cleanup_close_ int fd = -EBADF;
132 pid_t pid;
133
134 t = path_join(root, *path);
135 if (!t)
136 return log_oom();
137
138 if (callbacks) {
139 _cleanup_free_ char *bn = NULL;
140
141 r = path_extract_filename(*path, &bn);
142 if (r < 0)
143 return log_error_errno(r, "Failed to extract filename from path '%s': %m", *path);
144
145 fd = open_serialization_fd(bn);
146 if (fd < 0)
147 return log_error_errno(fd, "Failed to open serialization file: %m");
148 }
149
150 if (DEBUG_LOGGING) {
151 _cleanup_free_ char *args = NULL;
152 if (argv)
153 args = quote_command_line(strv_skip(argv, 1), SHELL_ESCAPE_EMPTY);
154
155 log_debug("About to execute %s%s%s", t, argv ? " " : "", argv ? strnull(args) : "");
156 }
157
158 r = do_spawn(t, argv, fd, FLAGS_SET(flags, EXEC_DIR_SET_SYSTEMD_EXEC_PID), &pid);
159 if (r <= 0)
160 continue;
161
162 if (parallel_execution) {
163 r = hashmap_put(pids, PID_TO_PTR(pid), t);
164 if (r < 0)
165 return log_oom();
166 t = NULL;
167 } else {
168 bool skip_remaining = false;
169
170 r = wait_for_terminate_and_check(t, pid, WAIT_LOG_ABNORMAL);
171 if (r < 0)
172 return r;
173 if (r > 0) {
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);
179 else {
180 log_error("%s failed with exit status %i.", *path, r);
181 return r;
182 }
183 }
184
185 if (callbacks) {
186 if (lseek(fd, 0, SEEK_SET) < 0)
187 return log_error_errno(errno, "Failed to seek on serialization fd: %m");
188
189 r = callbacks[STDOUT_GENERATE](TAKE_FD(fd), callback_args[STDOUT_GENERATE]);
190 if (r < 0)
191 return log_error_errno(r, "Failed to process output from %s: %m", *path);
192 }
193
194 if (skip_remaining)
195 break;
196 }
197 }
198
199 if (callbacks) {
200 r = callbacks[STDOUT_COLLECT](output_fd, callback_args[STDOUT_COLLECT]);
201 if (r < 0)
202 return log_error_errno(r, "Callback two failed: %m");
203 }
204
205 while (!hashmap_isempty(pids)) {
206 _cleanup_free_ char *t = NULL;
207 pid_t pid;
208
209 pid = PTR_TO_PID(hashmap_first_key(pids));
210 assert(pid > 0);
211
212 t = hashmap_remove(pids, PID_TO_PTR(pid));
213 assert(t);
214
215 r = wait_for_terminate_and_check(t, pid, WAIT_LOG);
216 if (r < 0)
217 return r;
218 if (!FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS) && r > 0)
219 return r;
220 }
221
222 return 0;
223 }
224
225 int execute_strv(
226 const char *name,
227 char* const* paths,
228 const char *root,
229 usec_t timeout,
230 gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
231 void* const callback_args[_STDOUT_CONSUME_MAX],
232 char *argv[],
233 char *envp[],
234 ExecDirFlags flags) {
235
236 _cleanup_close_ int fd = -EBADF;
237 pid_t executor_pid;
238 int r;
239
240 assert(!FLAGS_SET(flags, EXEC_DIR_PARALLEL | EXEC_DIR_SKIP_REMAINING));
241
242 if (strv_isempty(paths))
243 return 0;
244
245 if (callbacks) {
246 assert(name);
247 assert(callback_args);
248 assert(callbacks[STDOUT_GENERATE]);
249 assert(callbacks[STDOUT_COLLECT]);
250 assert(callbacks[STDOUT_CONSUME]);
251
252 fd = open_serialization_fd(name);
253 if (fd < 0)
254 return log_error_errno(fd, "Failed to open serialization file: %m");
255 }
256
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. */
260
261 r = safe_fork("(sd-exec-strv)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_LOG, &executor_pid);
262 if (r < 0)
263 return r;
264 if (r == 0) {
265 r = do_execute(paths, root, timeout, callbacks, callback_args, fd, argv, envp, flags);
266 _exit(r < 0 ? EXIT_FAILURE : r);
267 }
268
269 r = wait_for_terminate_and_check("(sd-exec-strv)", executor_pid, 0);
270 if (r < 0)
271 return r;
272 if (!FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS) && r > 0)
273 return r;
274
275 if (!callbacks)
276 return 0;
277
278 if (lseek(fd, 0, SEEK_SET) < 0)
279 return log_error_errno(errno, "Failed to rewind serialization fd: %m");
280
281 r = callbacks[STDOUT_CONSUME](TAKE_FD(fd), callback_args[STDOUT_CONSUME]);
282 if (r < 0)
283 return log_error_errno(r, "Failed to parse returned data: %m");
284 return 0;
285 }
286
287 int execute_directories(
288 const char* const* directories,
289 usec_t timeout,
290 gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
291 void* const callback_args[_STDOUT_CONSUME_MAX],
292 char *argv[],
293 char *envp[],
294 ExecDirFlags flags) {
295
296 _cleanup_strv_free_ char **paths = NULL;
297 _cleanup_free_ char *name = NULL;
298 int r;
299
300 assert(!strv_isempty((char**) directories));
301
302 r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, directories);
303 if (r < 0)
304 return log_error_errno(r, "Failed to enumerate executables: %m");
305
306 if (strv_isempty(paths)) {
307 log_debug("No executables found.");
308 return 0;
309 }
310
311 if (callbacks) {
312 r = path_extract_filename(directories[0], &name);
313 if (r < 0)
314 return log_error_errno(r, "Failed to extract file name from '%s': %m", directories[0]);
315 }
316
317 return execute_strv(name, paths, NULL, timeout, callbacks, callback_args, argv, envp, flags);
318 }
319
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;
324 int r;
325
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.
328 *
329 * fd is always consumed, even on error.
330 */
331
332 f = fdopen(fd, "r");
333 if (!f) {
334 safe_close(fd);
335 return -errno;
336 }
337
338 r = load_env_file_pairs(f, NULL, &new);
339 if (r < 0)
340 return r;
341
342 STRV_FOREACH_PAIR(x, y, new) {
343 if (!env_name_is_valid(*x)) {
344 log_warning("Invalid variable assignment \"%s=...\", ignoring.", *x);
345 continue;
346 }
347
348 r = strv_env_assign(env, *x, *y);
349 if (r < 0)
350 return r;
351
352 if (setenv(*x, *y, true) < 0)
353 return -errno;
354 }
355
356 return 0;
357 }
358
359 static int gather_environment_collect(int fd, void *arg) {
360 _cleanup_fclose_ FILE *f = NULL;
361 char ***env = ASSERT_PTR(arg);
362 int r;
363
364 /* Write out a series of env=cescape(VAR=value) assignments to fd. */
365
366 f = fdopen(fd, "w");
367 if (!f) {
368 safe_close(fd);
369 return -errno;
370 }
371
372 r = serialize_strv(f, "env", *env);
373 if (r < 0)
374 return r;
375
376 r = fflush_and_check(f);
377 if (r < 0)
378 return r;
379
380 return 0;
381 }
382
383 static int gather_environment_consume(int fd, void *arg) {
384 _cleanup_fclose_ FILE *f = NULL;
385 char ***env = ASSERT_PTR(arg);
386 int r = 0;
387
388 /* Read a series of env=cescape(VAR=value) assignments from fd into env. */
389
390 f = fdopen(fd, "r");
391 if (!f) {
392 safe_close(fd);
393 return -errno;
394 }
395
396 for (;;) {
397 _cleanup_free_ char *line = NULL;
398 const char *v;
399 int k;
400
401 k = read_line(f, LONG_LINE_MAX, &line);
402 if (k < 0)
403 return k;
404 if (k == 0)
405 break;
406
407 v = startswith(line, "env=");
408 if (!v) {
409 log_debug("Serialization line \"%s\" unexpectedly didn't start with \"env=\".", line);
410 if (r == 0)
411 r = -EINVAL;
412
413 continue;
414 }
415
416 k = deserialize_environment(v, env);
417 if (k < 0) {
418 log_debug_errno(k, "Invalid serialization line \"%s\": %m", line);
419
420 if (r == 0)
421 r = k;
422 }
423 }
424
425 return r;
426 }
427
428 int exec_command_flags_from_strv(char **ex_opts, ExecCommandFlags *flags) {
429 ExecCommandFlags ex_flag, ret_flags = 0;
430
431 assert(flags);
432
433 STRV_FOREACH(opt, ex_opts) {
434 ex_flag = exec_command_flags_from_string(*opt);
435 if (ex_flag < 0)
436 return ex_flag;
437 ret_flags |= ex_flag;
438 }
439
440 *flags = ret_flags;
441
442 return 0;
443 }
444
445 int exec_command_flags_to_strv(ExecCommandFlags flags, char ***ex_opts) {
446 _cleanup_strv_free_ char **ret_opts = NULL;
447 ExecCommandFlags it = flags;
448 const char *str;
449 int r;
450
451 assert(ex_opts);
452
453 if (flags < 0)
454 return flags;
455
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);
459 if (!str)
460 return -EINVAL;
461
462 r = strv_extend(&ret_opts, str);
463 if (r < 0)
464 return r;
465 }
466
467 *ex_opts = TAKE_PTR(ret_opts);
468
469 return 0;
470 }
471
472 const gather_stdout_callback_t gather_environment[] = {
473 gather_environment_generate,
474 gather_environment_collect,
475 gather_environment_consume,
476 };
477
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 */
484 };
485
486 const char* exec_command_flags_to_string(ExecCommandFlags i) {
487 for (size_t idx = 0; idx < ELEMENTSOF(exec_command_strings); idx++)
488 if (i == (1 << idx))
489 return exec_command_strings[idx];
490
491 return NULL;
492 }
493
494 ExecCommandFlags exec_command_flags_from_string(const char *s) {
495 ssize_t idx;
496
497 idx = string_table_lookup(exec_command_strings, ELEMENTSOF(exec_command_strings), s);
498
499 if (idx < 0)
500 return _EXEC_COMMAND_FLAGS_INVALID;
501 else
502 return 1 << idx;
503 }
504
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)
508 return -EBADF;
509
510 /* Block any attempts on exploiting Linux' liberal argv[] handling, i.e. CVE-2021-4034 and suchlike */
511 if (isempty(executable) || strv_isempty(argv))
512 return -EINVAL;
513
514 #if ENABLE_FEXECVE
515
516 execveat(executable_fd, "", argv, envp, AT_EMPTY_PATH);
517
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().
520 *
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."
527 *
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.
531 */
532 #endif
533 execve(executable, argv, envp);
534 return -errno;
535 }
536
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;
539 size_t n, i;
540 va_list ap;
541 char **l;
542 int r;
543
544 assert(path);
545
546 /* Spawns a temporary TTY agent, making sure it goes away when we go away */
547
548 r = safe_fork_full(name,
549 NULL,
550 (int*) except, /* safe_fork_full only changes except if you pass in FORK_PACK_FDS, which we don't */
551 n_except,
552 FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_RLIMIT_NOFILE_SAFE,
553 ret_pid);
554 if (r < 0)
555 return r;
556 if (r > 0)
557 return 0;
558
559 /* In the child: */
560
561 stdout_is_tty = isatty(STDOUT_FILENO);
562 stderr_is_tty = isatty(STDERR_FILENO);
563
564 if (!stdout_is_tty || !stderr_is_tty) {
565 int fd;
566
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
570 * stdin around. */
571 fd = open("/dev/tty", O_WRONLY);
572 if (fd < 0) {
573 if (errno != ENXIO) {
574 log_error_errno(errno, "Failed to open /dev/tty: %m");
575 _exit(EXIT_FAILURE);
576 }
577
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. */
581 } else {
582 if (!stdout_is_tty && dup2(fd, STDOUT_FILENO) < 0) {
583 log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
584 _exit(EXIT_FAILURE);
585 }
586
587 if (!stderr_is_tty && dup2(fd, STDERR_FILENO) < 0) {
588 log_error_errno(errno, "Failed to dup2 /dev/tty: %m");
589 _exit(EXIT_FAILURE);
590 }
591
592 fd = safe_close_above_stdio(fd);
593 }
594 }
595
596 /* Count arguments */
597 va_start(ap, path);
598 for (n = 0; va_arg(ap, char*); n++)
599 ;
600 va_end(ap);
601
602 /* Allocate strv */
603 l = newa(char*, n + 1);
604
605 /* Fill in arguments */
606 va_start(ap, path);
607 for (i = 0; i <= n; i++)
608 l[i] = va_arg(ap, char*);
609 va_end(ap);
610
611 execv(path, l);
612 _exit(EXIT_FAILURE);
613 }