]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/core/execute.c
manager: switch service unit type over to using new handoff timestamping logic
[thirdparty/systemd.git] / src / core / execute.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <errno.h>
4#include <fcntl.h>
5#include <poll.h>
6#include <sys/file.h>
7#include <sys/mman.h>
8#include <sys/personality.h>
9#include <sys/prctl.h>
10#include <sys/shm.h>
11#include <sys/types.h>
12#include <sys/un.h>
13#include <unistd.h>
14#include <utmpx.h>
15
16#include <linux/fs.h> /* Must be included after <sys/mount.h> */
17
18#include "sd-messages.h"
19
20#include "af-list.h"
21#include "alloc-util.h"
22#include "async.h"
23#include "cap-list.h"
24#include "capability-util.h"
25#include "cgroup-setup.h"
26#include "constants.h"
27#include "cpu-set-util.h"
28#include "dev-setup.h"
29#include "env-file.h"
30#include "env-util.h"
31#include "errno-list.h"
32#include "escape.h"
33#include "exec-credential.h"
34#include "execute.h"
35#include "execute-serialize.h"
36#include "exit-status.h"
37#include "fd-util.h"
38#include "fileio.h"
39#include "format-util.h"
40#include "glob-util.h"
41#include "hexdecoct.h"
42#include "ioprio-util.h"
43#include "lock-util.h"
44#include "log.h"
45#include "macro.h"
46#include "manager.h"
47#include "manager-dump.h"
48#include "memory-util.h"
49#include "missing_fs.h"
50#include "missing_prctl.h"
51#include "mkdir-label.h"
52#include "namespace.h"
53#include "parse-util.h"
54#include "path-util.h"
55#include "process-util.h"
56#include "rlimit-util.h"
57#include "rm-rf.h"
58#include "seccomp-util.h"
59#include "securebits-util.h"
60#include "selinux-util.h"
61#include "serialize.h"
62#include "sort-util.h"
63#include "special.h"
64#include "stat-util.h"
65#include "string-table.h"
66#include "string-util.h"
67#include "strv.h"
68#include "syslog-util.h"
69#include "terminal-util.h"
70#include "tmpfile-util.h"
71#include "umask-util.h"
72#include "unit-serialize.h"
73#include "user-util.h"
74#include "utmp-wtmp.h"
75
76static bool is_terminal_input(ExecInput i) {
77 return IN_SET(i,
78 EXEC_INPUT_TTY,
79 EXEC_INPUT_TTY_FORCE,
80 EXEC_INPUT_TTY_FAIL);
81}
82
83static bool is_terminal_output(ExecOutput o) {
84 return IN_SET(o,
85 EXEC_OUTPUT_TTY,
86 EXEC_OUTPUT_KMSG_AND_CONSOLE,
87 EXEC_OUTPUT_JOURNAL_AND_CONSOLE);
88}
89
90const char *exec_context_tty_path(const ExecContext *context) {
91 assert(context);
92
93 if (context->stdio_as_fds)
94 return NULL;
95
96 if (context->tty_path)
97 return context->tty_path;
98
99 return "/dev/console";
100}
101
102static void exec_context_determine_tty_size(
103 const ExecContext *context,
104 const char *tty_path,
105 unsigned *ret_rows,
106 unsigned *ret_cols) {
107
108 unsigned rows, cols;
109
110 assert(context);
111 assert(ret_rows);
112 assert(ret_cols);
113
114 if (!tty_path)
115 tty_path = exec_context_tty_path(context);
116
117 rows = context->tty_rows;
118 cols = context->tty_cols;
119
120 if (tty_path && (rows == UINT_MAX || cols == UINT_MAX))
121 (void) proc_cmdline_tty_size(
122 tty_path,
123 rows == UINT_MAX ? &rows : NULL,
124 cols == UINT_MAX ? &cols : NULL);
125
126 *ret_rows = rows;
127 *ret_cols = cols;
128}
129
130int exec_context_apply_tty_size(
131 const ExecContext *context,
132 int tty_fd,
133 const char *tty_path) {
134
135 unsigned rows, cols;
136
137 exec_context_determine_tty_size(context, tty_path, &rows, &cols);
138
139 return terminal_set_size_fd(tty_fd, tty_path, rows, cols);
140 }
141
142void exec_context_tty_reset(const ExecContext *context, const ExecParameters *p) {
143 _cleanup_close_ int _fd = -EBADF, lock_fd = -EBADF;
144 int fd;
145
146 assert(context);
147
148 const char *path = exec_context_tty_path(context);
149
150 if (p && p->stdin_fd >= 0 && isatty_safe(p->stdin_fd))
151 fd = p->stdin_fd;
152 else if (path && (context->tty_path || is_terminal_input(context->std_input) ||
153 is_terminal_output(context->std_output) || is_terminal_output(context->std_error))) {
154 fd = _fd = open_terminal(path, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
155 if (fd < 0)
156 return (void) log_debug_errno(fd, "Failed to open terminal '%s', ignoring: %m", path);
157 } else
158 return; /* nothing to do */
159
160 /* Take a synchronization lock for the duration of the setup that we do here.
161 * systemd-vconsole-setup.service also takes the lock to avoid being interrupted. We open a new fd
162 * that will be closed automatically, and operate on it for convenience. */
163 lock_fd = lock_dev_console();
164 if (ERRNO_IS_NEG_PRIVILEGE(lock_fd))
165 log_debug_errno(lock_fd, "No privileges to lock /dev/console, proceeding without: %m");
166 else if (ERRNO_IS_NEG_DEVICE_ABSENT(lock_fd))
167 log_debug_errno(lock_fd, "Device /dev/console does not exist, proceeding without locking it: %m");
168 else if (lock_fd < 0)
169 return (void) log_debug_errno(lock_fd, "Failed to lock /dev/console: %m");
170
171 if (context->tty_vhangup)
172 (void) terminal_vhangup_fd(fd);
173
174 if (context->tty_reset)
175 (void) reset_terminal_fd(fd, /* switch_to_text= */ true);
176
177 (void) exec_context_apply_tty_size(context, fd, path);
178
179 if (context->tty_vt_disallocate && path)
180 (void) vt_disallocate(path);
181}
182
183bool exec_needs_network_namespace(const ExecContext *context) {
184 assert(context);
185
186 return context->private_network || context->network_namespace_path;
187}
188
189static bool exec_needs_ephemeral(const ExecContext *context) {
190 return (context->root_image || context->root_directory) && context->root_ephemeral;
191}
192
193bool exec_needs_ipc_namespace(const ExecContext *context) {
194 assert(context);
195
196 return context->private_ipc || context->ipc_namespace_path;
197}
198
199bool exec_needs_mount_namespace(
200 const ExecContext *context,
201 const ExecParameters *params,
202 const ExecRuntime *runtime) {
203
204 assert(context);
205
206 if (context->root_image)
207 return true;
208
209 if (!strv_isempty(context->read_write_paths) ||
210 !strv_isempty(context->read_only_paths) ||
211 !strv_isempty(context->inaccessible_paths) ||
212 !strv_isempty(context->exec_paths) ||
213 !strv_isempty(context->no_exec_paths))
214 return true;
215
216 if (context->n_bind_mounts > 0)
217 return true;
218
219 if (context->n_temporary_filesystems > 0)
220 return true;
221
222 if (context->n_mount_images > 0)
223 return true;
224
225 if (context->n_extension_images > 0)
226 return true;
227
228 if (!strv_isempty(context->extension_directories))
229 return true;
230
231 if (!IN_SET(context->mount_propagation_flag, 0, MS_SHARED))
232 return true;
233
234 if (context->private_tmp && runtime && runtime->shared && (runtime->shared->tmp_dir || runtime->shared->var_tmp_dir))
235 return true;
236
237 if (context->private_devices ||
238 context->private_mounts > 0 ||
239 (context->private_mounts < 0 && exec_needs_network_namespace(context)) ||
240 context->protect_system != PROTECT_SYSTEM_NO ||
241 context->protect_home != PROTECT_HOME_NO ||
242 context->protect_kernel_tunables ||
243 context->protect_kernel_modules ||
244 context->protect_kernel_logs ||
245 context->protect_control_groups ||
246 context->protect_proc != PROTECT_PROC_DEFAULT ||
247 context->proc_subset != PROC_SUBSET_ALL ||
248 exec_needs_ipc_namespace(context))
249 return true;
250
251 if (context->root_directory) {
252 if (exec_context_get_effective_mount_apivfs(context))
253 return true;
254
255 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
256 if (params && !params->prefix[t])
257 continue;
258
259 if (context->directories[t].n_items > 0)
260 return true;
261 }
262 }
263
264 if (context->dynamic_user &&
265 (context->directories[EXEC_DIRECTORY_STATE].n_items > 0 ||
266 context->directories[EXEC_DIRECTORY_CACHE].n_items > 0 ||
267 context->directories[EXEC_DIRECTORY_LOGS].n_items > 0))
268 return true;
269
270 if (context->log_namespace)
271 return true;
272
273 return false;
274}
275
276bool exec_directory_is_private(const ExecContext *context, ExecDirectoryType type) {
277 assert(context);
278
279 if (!context->dynamic_user)
280 return false;
281
282 if (type == EXEC_DIRECTORY_CONFIGURATION)
283 return false;
284
285 if (type == EXEC_DIRECTORY_RUNTIME && context->runtime_directory_preserve_mode == EXEC_PRESERVE_NO)
286 return false;
287
288 return true;
289}
290
291int exec_params_get_cgroup_path(
292 const ExecParameters *params,
293 const CGroupContext *c,
294 char **ret) {
295
296 const char *subgroup = NULL;
297 char *p;
298
299 assert(params);
300 assert(ret);
301
302 if (!params->cgroup_path)
303 return -EINVAL;
304
305 /* If we are called for a unit where cgroup delegation is on, and the payload created its own populated
306 * subcgroup (which we expect it to do, after all it asked for delegation), then we cannot place the control
307 * processes started after the main unit's process in the unit's main cgroup because it is now an inner one,
308 * and inner cgroups may not contain processes. Hence, if delegation is on, and this is a control process,
309 * let's use ".control" as subcgroup instead. Note that we do so only for ExecStartPost=, ExecReload=,
310 * ExecStop=, ExecStopPost=, i.e. for the commands where the main process is already forked. For ExecStartPre=
311 * this is not necessary, the cgroup is still empty. We distinguish these cases with the EXEC_CONTROL_CGROUP
312 * flag, which is only passed for the former statements, not for the latter. */
313
314 if (FLAGS_SET(params->flags, EXEC_CGROUP_DELEGATE) && (FLAGS_SET(params->flags, EXEC_CONTROL_CGROUP) || c->delegate_subgroup)) {
315 if (FLAGS_SET(params->flags, EXEC_IS_CONTROL))
316 subgroup = ".control";
317 else
318 subgroup = c->delegate_subgroup;
319 }
320
321 if (subgroup)
322 p = path_join(params->cgroup_path, subgroup);
323 else
324 p = strdup(params->cgroup_path);
325 if (!p)
326 return -ENOMEM;
327
328 *ret = p;
329 return !!subgroup;
330}
331
332bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c) {
333 assert(c);
334
335 return c->cpu_affinity_from_numa;
336}
337
338static void log_command_line(Unit *unit, const char *msg, const char *executable, char **argv) {
339 assert(unit);
340 assert(msg);
341 assert(executable);
342
343 if (!DEBUG_LOGGING)
344 return;
345
346 _cleanup_free_ char *cmdline = quote_command_line(argv, SHELL_ESCAPE_EMPTY);
347
348 log_unit_struct(unit, LOG_DEBUG,
349 "EXECUTABLE=%s", executable,
350 LOG_UNIT_MESSAGE(unit, "%s: %s", msg, strnull(cmdline)),
351 LOG_UNIT_INVOCATION_ID(unit));
352}
353
354static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***l);
355
356int exec_spawn(Unit *unit,
357 ExecCommand *command,
358 const ExecContext *context,
359 ExecParameters *params,
360 ExecRuntime *runtime,
361 const CGroupContext *cgroup_context,
362 PidRef *ret) {
363
364 char serialization_fd_number[DECIMAL_STR_MAX(int) + 1];
365 _cleanup_free_ char *subcgroup_path = NULL, *max_log_levels = NULL, *executor_path = NULL;
366 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
367 _cleanup_fdset_free_ FDSet *fdset = NULL;
368 _cleanup_fclose_ FILE *f = NULL;
369 int r;
370
371 assert(unit);
372 assert(unit->manager);
373 assert(unit->manager->executor_fd >= 0);
374 assert(command);
375 assert(context);
376 assert(params);
377 assert(!params->fds || FLAGS_SET(params->flags, EXEC_PASS_FDS));
378 assert(params->fds || (params->n_socket_fds + params->n_storage_fds == 0));
379 assert(!params->files_env); /* We fill this field, ensure it comes NULL-initialized to us */
380 assert(ret);
381
382 LOG_CONTEXT_PUSH_UNIT(unit);
383
384 r = exec_context_load_environment(unit, context, &params->files_env);
385 if (r < 0)
386 return log_unit_error_errno(unit, r, "Failed to load environment files: %m");
387
388 /* We won't know the real executable path until we create the mount namespace in the child, but we
389 want to log from the parent, so we use the possibly inaccurate path here. */
390 log_command_line(unit, "About to execute", command->path, command->argv);
391
392 if (params->cgroup_path) {
393 r = exec_params_get_cgroup_path(params, cgroup_context, &subcgroup_path);
394 if (r < 0)
395 return log_unit_error_errno(unit, r, "Failed to acquire subcgroup path: %m");
396 if (r > 0) {
397 /* If there's a subcgroup, then let's create it here now (the main cgroup was already
398 * realized by the unit logic) */
399
400 r = cg_create(SYSTEMD_CGROUP_CONTROLLER, subcgroup_path);
401 if (r < 0)
402 return log_unit_error_errno(unit, r, "Failed to create subcgroup '%s': %m", subcgroup_path);
403 }
404 }
405
406 /* In order to avoid copy-on-write traps and OOM-kills when pid1's memory.current is above the
407 * child's memory.max, serialize all the state needed to start the unit, and pass it to the
408 * systemd-executor binary. clone() with CLONE_VM + CLONE_VFORK will pause the parent until the exec
409 * and ensure all memory is shared. The child immediately execs the new binary so the delay should
410 * be minimal. If glibc 2.39 is available pidfd_spawn() is used in order to get a race-free pid fd
411 * and to clone directly into the target cgroup (if we booted with cgroupv2). */
412
413 r = open_serialization_file("sd-executor-state", &f);
414 if (r < 0)
415 return log_unit_error_errno(unit, r, "Failed to open serialization stream: %m");
416
417 fdset = fdset_new();
418 if (!fdset)
419 return log_oom();
420
421 r = exec_serialize_invocation(f, fdset, context, command, params, runtime, cgroup_context);
422 if (r < 0)
423 return log_unit_error_errno(unit, r, "Failed to serialize parameters: %m");
424
425 if (fseeko(f, 0, SEEK_SET) < 0)
426 return log_unit_error_errno(unit, errno, "Failed to reseek on serialization stream: %m");
427
428 r = fd_cloexec(fileno(f), false);
429 if (r < 0)
430 return log_unit_error_errno(unit, r, "Failed to set O_CLOEXEC on serialization fd: %m");
431
432 r = fdset_cloexec(fdset, false);
433 if (r < 0)
434 return log_unit_error_errno(unit, r, "Failed to set O_CLOEXEC on serialized fds: %m");
435
436 /* If LogLevelMax= is specified, then let's use the specified log level at the beginning of the
437 * executor process. To achieve that the specified log level is passed as an argument, rather than
438 * the one for the manager process. */
439 r = log_max_levels_to_string(context->log_level_max >= 0 ? context->log_level_max : log_get_max_level(), &max_log_levels);
440 if (r < 0)
441 return log_unit_error_errno(unit, r, "Failed to convert max log levels to string: %m");
442
443 r = fd_get_path(unit->manager->executor_fd, &executor_path);
444 if (r < 0)
445 return log_unit_error_errno(unit, r, "Failed to get executor path from fd: %m");
446
447 xsprintf(serialization_fd_number, "%i", fileno(f));
448
449 /* The executor binary is pinned, to avoid compatibility problems during upgrades. */
450 r = posix_spawn_wrapper(
451 FORMAT_PROC_FD_PATH(unit->manager->executor_fd),
452 STRV_MAKE(executor_path,
453 "--deserialize", serialization_fd_number,
454 "--log-level", max_log_levels,
455 "--log-target", log_target_to_string(manager_get_executor_log_target(unit->manager))),
456 environ,
457 cg_unified() > 0 ? subcgroup_path : NULL,
458 &pidref);
459 if (r == -EUCLEAN && subcgroup_path)
460 return log_unit_error_errno(unit, r,
461 "Failed to spawn process into cgroup '%s', because the cgroup "
462 "or one of its parents or siblings is in the threaded mode.",
463 subcgroup_path);
464 if (r < 0)
465 return log_unit_error_errno(unit, r, "Failed to spawn executor: %m");
466 /* We add the new process to the cgroup both in the child (so that we can be sure that no user code is ever
467 * executed outside of the cgroup) and in the parent (so that we can be sure that when we kill the cgroup the
468 * process will be killed too). */
469 if (r == 0 && subcgroup_path)
470 (void) cg_attach(SYSTEMD_CGROUP_CONTROLLER, subcgroup_path, pidref.pid);
471 /* r > 0: Already in the right cgroup thanks to CLONE_INTO_CGROUP */
472
473 log_unit_debug(unit, "Forked %s as " PID_FMT " (%s CLONE_INTO_CGROUP)",
474 command->path, pidref.pid, r > 0 ? "via" : "without");
475
476 exec_status_start(&command->exec_status, pidref.pid);
477
478 *ret = TAKE_PIDREF(pidref);
479 return 0;
480}
481
482void exec_context_init(ExecContext *c) {
483 assert(c);
484
485 /* When initializing a bool member to 'true', make sure to serialize in execute-serialize.c using
486 * serialize_bool() instead of serialize_bool_elide(). */
487
488 *c = (ExecContext) {
489 .umask = 0022,
490 .ioprio = IOPRIO_DEFAULT_CLASS_AND_PRIO,
491 .cpu_sched_policy = SCHED_OTHER,
492 .syslog_priority = LOG_DAEMON|LOG_INFO,
493 .syslog_level_prefix = true,
494 .ignore_sigpipe = true,
495 .timer_slack_nsec = NSEC_INFINITY,
496 .personality = PERSONALITY_INVALID,
497 .timeout_clean_usec = USEC_INFINITY,
498 .capability_bounding_set = CAP_MASK_UNSET,
499 .restrict_namespaces = NAMESPACE_FLAGS_INITIAL,
500 .log_level_max = -1,
501#if HAVE_SECCOMP
502 .syscall_errno = SECCOMP_ERROR_NUMBER_KILL,
503#endif
504 .tty_rows = UINT_MAX,
505 .tty_cols = UINT_MAX,
506 .private_mounts = -1,
507 .memory_ksm = -1,
508 .set_login_environment = -1,
509 };
510
511 FOREACH_ARRAY(d, c->directories, _EXEC_DIRECTORY_TYPE_MAX)
512 d->mode = 0755;
513
514 numa_policy_reset(&c->numa_policy);
515
516 assert_cc(NAMESPACE_FLAGS_INITIAL != NAMESPACE_FLAGS_ALL);
517}
518
519void exec_context_done(ExecContext *c) {
520 assert(c);
521
522 c->environment = strv_free(c->environment);
523 c->environment_files = strv_free(c->environment_files);
524 c->pass_environment = strv_free(c->pass_environment);
525 c->unset_environment = strv_free(c->unset_environment);
526
527 rlimit_free_all(c->rlimit);
528
529 for (size_t l = 0; l < 3; l++) {
530 c->stdio_fdname[l] = mfree(c->stdio_fdname[l]);
531 c->stdio_file[l] = mfree(c->stdio_file[l]);
532 }
533
534 c->working_directory = mfree(c->working_directory);
535 c->root_directory = mfree(c->root_directory);
536 c->root_image = mfree(c->root_image);
537 c->root_image_options = mount_options_free_all(c->root_image_options);
538 c->root_hash = mfree(c->root_hash);
539 c->root_hash_size = 0;
540 c->root_hash_path = mfree(c->root_hash_path);
541 c->root_hash_sig = mfree(c->root_hash_sig);
542 c->root_hash_sig_size = 0;
543 c->root_hash_sig_path = mfree(c->root_hash_sig_path);
544 c->root_verity = mfree(c->root_verity);
545 c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
546 c->extension_directories = strv_free(c->extension_directories);
547 c->tty_path = mfree(c->tty_path);
548 c->syslog_identifier = mfree(c->syslog_identifier);
549 c->user = mfree(c->user);
550 c->group = mfree(c->group);
551
552 c->supplementary_groups = strv_free(c->supplementary_groups);
553
554 c->pam_name = mfree(c->pam_name);
555
556 c->read_only_paths = strv_free(c->read_only_paths);
557 c->read_write_paths = strv_free(c->read_write_paths);
558 c->inaccessible_paths = strv_free(c->inaccessible_paths);
559 c->exec_paths = strv_free(c->exec_paths);
560 c->no_exec_paths = strv_free(c->no_exec_paths);
561 c->exec_search_path = strv_free(c->exec_search_path);
562
563 bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
564 c->bind_mounts = NULL;
565 c->n_bind_mounts = 0;
566 temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
567 c->temporary_filesystems = NULL;
568 c->n_temporary_filesystems = 0;
569 c->mount_images = mount_image_free_many(c->mount_images, &c->n_mount_images);
570
571 cpu_set_reset(&c->cpu_set);
572 numa_policy_reset(&c->numa_policy);
573
574 c->utmp_id = mfree(c->utmp_id);
575 c->selinux_context = mfree(c->selinux_context);
576 c->apparmor_profile = mfree(c->apparmor_profile);
577 c->smack_process_label = mfree(c->smack_process_label);
578
579 c->restrict_filesystems = set_free_free(c->restrict_filesystems);
580
581 c->syscall_filter = hashmap_free(c->syscall_filter);
582 c->syscall_archs = set_free(c->syscall_archs);
583 c->address_families = set_free(c->address_families);
584
585 FOREACH_ARRAY(d, c->directories, _EXEC_DIRECTORY_TYPE_MAX)
586 exec_directory_done(d);
587
588 c->log_level_max = -1;
589
590 exec_context_free_log_extra_fields(c);
591 c->log_filter_allowed_patterns = set_free_free(c->log_filter_allowed_patterns);
592 c->log_filter_denied_patterns = set_free_free(c->log_filter_denied_patterns);
593
594 c->log_ratelimit_interval_usec = 0;
595 c->log_ratelimit_burst = 0;
596
597 c->stdin_data = mfree(c->stdin_data);
598 c->stdin_data_size = 0;
599
600 c->network_namespace_path = mfree(c->network_namespace_path);
601 c->ipc_namespace_path = mfree(c->ipc_namespace_path);
602
603 c->log_namespace = mfree(c->log_namespace);
604
605 c->load_credentials = hashmap_free(c->load_credentials);
606 c->set_credentials = hashmap_free(c->set_credentials);
607 c->import_credentials = set_free_free(c->import_credentials);
608
609 c->root_image_policy = image_policy_free(c->root_image_policy);
610 c->mount_image_policy = image_policy_free(c->mount_image_policy);
611 c->extension_image_policy = image_policy_free(c->extension_image_policy);
612}
613
614int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) {
615 assert(c);
616
617 if (!runtime_prefix)
618 return 0;
619
620 FOREACH_ARRAY(i, c->directories[EXEC_DIRECTORY_RUNTIME].items, c->directories[EXEC_DIRECTORY_RUNTIME].n_items) {
621 _cleanup_free_ char *p = NULL;
622
623 if (exec_directory_is_private(c, EXEC_DIRECTORY_RUNTIME))
624 p = path_join(runtime_prefix, "private", i->path);
625 else
626 p = path_join(runtime_prefix, i->path);
627 if (!p)
628 return -ENOMEM;
629
630 /* We execute this synchronously, since we need to be sure this is gone when we start the
631 * service next. */
632 (void) rm_rf(p, REMOVE_ROOT);
633
634 STRV_FOREACH(symlink, i->symlinks) {
635 _cleanup_free_ char *symlink_abs = NULL;
636
637 if (exec_directory_is_private(c, EXEC_DIRECTORY_RUNTIME))
638 symlink_abs = path_join(runtime_prefix, "private", *symlink);
639 else
640 symlink_abs = path_join(runtime_prefix, *symlink);
641 if (!symlink_abs)
642 return -ENOMEM;
643
644 (void) unlink(symlink_abs);
645 }
646 }
647
648 return 0;
649}
650
651int exec_context_destroy_mount_ns_dir(Unit *u) {
652 _cleanup_free_ char *p = NULL;
653
654 if (!u || !MANAGER_IS_SYSTEM(u->manager))
655 return 0;
656
657 p = path_join("/run/systemd/propagate/", u->id);
658 if (!p)
659 return -ENOMEM;
660
661 /* This is only filled transiently (see mount_in_namespace()), should be empty or even non-existent*/
662 if (rmdir(p) < 0 && errno != ENOENT)
663 log_unit_debug_errno(u, errno, "Unable to remove propagation dir '%s', ignoring: %m", p);
664
665 return 0;
666}
667
668void exec_command_done(ExecCommand *c) {
669 assert(c);
670
671 c->path = mfree(c->path);
672 c->argv = strv_free(c->argv);
673}
674
675void exec_command_done_array(ExecCommand *c, size_t n) {
676 FOREACH_ARRAY(i, c, n)
677 exec_command_done(i);
678}
679
680ExecCommand* exec_command_free(ExecCommand *c) {
681 if (!c)
682 return NULL;
683
684 exec_command_done(c);
685 return mfree(c);
686}
687
688ExecCommand* exec_command_free_list(ExecCommand *c) {
689 ExecCommand *i;
690
691 while ((i = LIST_POP(command, c)))
692 exec_command_free(i);
693
694 return NULL;
695}
696
697void exec_command_free_array(ExecCommand **c, size_t n) {
698 FOREACH_ARRAY(i, c, n)
699 *i = exec_command_free_list(*i);
700}
701
702void exec_command_reset_status_array(ExecCommand *c, size_t n) {
703 FOREACH_ARRAY(i, c, n)
704 exec_status_reset(&i->exec_status);
705}
706
707void exec_command_reset_status_list_array(ExecCommand **c, size_t n) {
708 FOREACH_ARRAY(i, c, n)
709 LIST_FOREACH(command, z, *i)
710 exec_status_reset(&z->exec_status);
711}
712
713typedef struct InvalidEnvInfo {
714 const Unit *unit;
715 const char *path;
716} InvalidEnvInfo;
717
718static void invalid_env(const char *p, void *userdata) {
719 InvalidEnvInfo *info = userdata;
720
721 log_unit_error(info->unit, "Ignoring invalid environment assignment '%s': %s", p, info->path);
722}
723
724const char* exec_context_fdname(const ExecContext *c, int fd_index) {
725 assert(c);
726
727 switch (fd_index) {
728
729 case STDIN_FILENO:
730 if (c->std_input != EXEC_INPUT_NAMED_FD)
731 return NULL;
732
733 return c->stdio_fdname[STDIN_FILENO] ?: "stdin";
734
735 case STDOUT_FILENO:
736 if (c->std_output != EXEC_OUTPUT_NAMED_FD)
737 return NULL;
738
739 return c->stdio_fdname[STDOUT_FILENO] ?: "stdout";
740
741 case STDERR_FILENO:
742 if (c->std_error != EXEC_OUTPUT_NAMED_FD)
743 return NULL;
744
745 return c->stdio_fdname[STDERR_FILENO] ?: "stderr";
746
747 default:
748 return NULL;
749 }
750}
751
752static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***ret) {
753 _cleanup_strv_free_ char **v = NULL;
754 int r;
755
756 assert(c);
757 assert(ret);
758
759 STRV_FOREACH(i, c->environment_files) {
760 _cleanup_globfree_ glob_t pglob = {};
761 bool ignore = false;
762 char *fn = *i;
763
764 if (fn[0] == '-') {
765 ignore = true;
766 fn++;
767 }
768
769 if (!path_is_absolute(fn)) {
770 if (ignore)
771 continue;
772 return -EINVAL;
773 }
774
775 /* Filename supports globbing, take all matching files */
776 r = safe_glob(fn, 0, &pglob);
777 if (r < 0) {
778 if (ignore)
779 continue;
780 return r;
781 }
782
783 /* When we don't match anything, -ENOENT should be returned */
784 assert(pglob.gl_pathc > 0);
785
786 FOREACH_ARRAY(path, pglob.gl_pathv, pglob.gl_pathc) {
787 _cleanup_strv_free_ char **p = NULL;
788
789 r = load_env_file(NULL, *path, &p);
790 if (r < 0) {
791 if (ignore)
792 continue;
793 return r;
794 }
795
796 /* Log invalid environment variables with filename */
797 if (p) {
798 InvalidEnvInfo info = {
799 .unit = unit,
800 .path = *path,
801 };
802
803 p = strv_env_clean_with_callback(p, invalid_env, &info);
804 }
805
806 if (!v)
807 v = TAKE_PTR(p);
808 else {
809 char **m = strv_env_merge(v, p);
810 if (!m)
811 return -ENOMEM;
812
813 strv_free_and_replace(v, m);
814 }
815 }
816 }
817
818 *ret = TAKE_PTR(v);
819
820 return 0;
821}
822
823static bool tty_may_match_dev_console(const char *tty) {
824 _cleanup_free_ char *resolved = NULL;
825
826 if (!tty)
827 return true;
828
829 tty = skip_dev_prefix(tty);
830
831 /* trivial identity? */
832 if (streq(tty, "console"))
833 return true;
834
835 if (resolve_dev_console(&resolved) < 0)
836 return true; /* if we could not resolve, assume it may */
837
838 /* "tty0" means the active VC, so it may be the same sometimes */
839 return path_equal(resolved, tty) || (streq(resolved, "tty0") && tty_is_vc(tty));
840}
841
842static bool exec_context_may_touch_tty(const ExecContext *ec) {
843 assert(ec);
844
845 return ec->tty_reset ||
846 ec->tty_vhangup ||
847 ec->tty_vt_disallocate ||
848 is_terminal_input(ec->std_input) ||
849 is_terminal_output(ec->std_output) ||
850 is_terminal_output(ec->std_error);
851}
852
853bool exec_context_may_touch_console(const ExecContext *ec) {
854
855 return exec_context_may_touch_tty(ec) &&
856 tty_may_match_dev_console(exec_context_tty_path(ec));
857}
858
859static void strv_fprintf(FILE *f, char **l) {
860 assert(f);
861
862 STRV_FOREACH(g, l)
863 fprintf(f, " %s", *g);
864}
865
866static void strv_dump(FILE* f, const char *prefix, const char *name, char **strv) {
867 assert(f);
868 assert(prefix);
869 assert(name);
870
871 if (!strv_isempty(strv)) {
872 fprintf(f, "%s%s:", prefix, name);
873 strv_fprintf(f, strv);
874 fputs("\n", f);
875 }
876}
877
878void exec_params_dump(const ExecParameters *p, FILE* f, const char *prefix) {
879 assert(p);
880 assert(f);
881
882 prefix = strempty(prefix);
883
884 fprintf(f,
885 "%sRuntimeScope: %s\n"
886 "%sExecFlags: %u\n"
887 "%sSELinuxContextNetwork: %s\n"
888 "%sCgroupSupportedMask: %u\n"
889 "%sCgroupPath: %s\n"
890 "%sCrededentialsDirectory: %s\n"
891 "%sEncryptedCredentialsDirectory: %s\n"
892 "%sConfirmSpawn: %s\n"
893 "%sShallConfirmSpawn: %s\n"
894 "%sWatchdogUSec: " USEC_FMT "\n"
895 "%sNotifySocket: %s\n"
896 "%sFallbackSmackProcessLabel: %s\n",
897 prefix, runtime_scope_to_string(p->runtime_scope),
898 prefix, p->flags,
899 prefix, yes_no(p->selinux_context_net),
900 prefix, p->cgroup_supported,
901 prefix, p->cgroup_path,
902 prefix, strempty(p->received_credentials_directory),
903 prefix, strempty(p->received_encrypted_credentials_directory),
904 prefix, strempty(p->confirm_spawn),
905 prefix, yes_no(p->shall_confirm_spawn),
906 prefix, p->watchdog_usec,
907 prefix, strempty(p->notify_socket),
908 prefix, strempty(p->fallback_smack_process_label));
909
910 strv_dump(f, prefix, "FdNames", p->fd_names);
911 strv_dump(f, prefix, "Environment", p->environment);
912 strv_dump(f, prefix, "Prefix", p->prefix);
913
914 LIST_FOREACH(open_files, file, p->open_files)
915 fprintf(f, "%sOpenFile: %s %s", prefix, file->path, open_file_flags_to_string(file->flags));
916
917 strv_dump(f, prefix, "FilesEnv", p->files_env);
918}
919
920void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
921 int r;
922
923 assert(c);
924 assert(f);
925
926 prefix = strempty(prefix);
927
928 fprintf(f,
929 "%sUMask: %04o\n"
930 "%sWorkingDirectory: %s\n"
931 "%sRootDirectory: %s\n"
932 "%sRootEphemeral: %s\n"
933 "%sNonBlocking: %s\n"
934 "%sPrivateTmp: %s\n"
935 "%sPrivateDevices: %s\n"
936 "%sProtectKernelTunables: %s\n"
937 "%sProtectKernelModules: %s\n"
938 "%sProtectKernelLogs: %s\n"
939 "%sProtectClock: %s\n"
940 "%sProtectControlGroups: %s\n"
941 "%sPrivateNetwork: %s\n"
942 "%sPrivateUsers: %s\n"
943 "%sProtectHome: %s\n"
944 "%sProtectSystem: %s\n"
945 "%sMountAPIVFS: %s\n"
946 "%sIgnoreSIGPIPE: %s\n"
947 "%sMemoryDenyWriteExecute: %s\n"
948 "%sRestrictRealtime: %s\n"
949 "%sRestrictSUIDSGID: %s\n"
950 "%sKeyringMode: %s\n"
951 "%sProtectHostname: %s\n"
952 "%sProtectProc: %s\n"
953 "%sProcSubset: %s\n",
954 prefix, c->umask,
955 prefix, empty_to_root(c->working_directory),
956 prefix, empty_to_root(c->root_directory),
957 prefix, yes_no(c->root_ephemeral),
958 prefix, yes_no(c->non_blocking),
959 prefix, yes_no(c->private_tmp),
960 prefix, yes_no(c->private_devices),
961 prefix, yes_no(c->protect_kernel_tunables),
962 prefix, yes_no(c->protect_kernel_modules),
963 prefix, yes_no(c->protect_kernel_logs),
964 prefix, yes_no(c->protect_clock),
965 prefix, yes_no(c->protect_control_groups),
966 prefix, yes_no(c->private_network),
967 prefix, yes_no(c->private_users),
968 prefix, protect_home_to_string(c->protect_home),
969 prefix, protect_system_to_string(c->protect_system),
970 prefix, yes_no(exec_context_get_effective_mount_apivfs(c)),
971 prefix, yes_no(c->ignore_sigpipe),
972 prefix, yes_no(c->memory_deny_write_execute),
973 prefix, yes_no(c->restrict_realtime),
974 prefix, yes_no(c->restrict_suid_sgid),
975 prefix, exec_keyring_mode_to_string(c->keyring_mode),
976 prefix, yes_no(c->protect_hostname),
977 prefix, protect_proc_to_string(c->protect_proc),
978 prefix, proc_subset_to_string(c->proc_subset));
979
980 if (c->set_login_environment >= 0)
981 fprintf(f, "%sSetLoginEnvironment: %s\n", prefix, yes_no(c->set_login_environment > 0));
982
983 if (c->root_image)
984 fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
985
986 if (c->root_image_options) {
987 fprintf(f, "%sRootImageOptions:", prefix);
988 LIST_FOREACH(mount_options, o, c->root_image_options)
989 if (!isempty(o->options))
990 fprintf(f, " %s:%s",
991 partition_designator_to_string(o->partition_designator),
992 o->options);
993 fprintf(f, "\n");
994 }
995
996 if (c->root_hash) {
997 _cleanup_free_ char *encoded = NULL;
998 encoded = hexmem(c->root_hash, c->root_hash_size);
999 if (encoded)
1000 fprintf(f, "%sRootHash: %s\n", prefix, encoded);
1001 }
1002
1003 if (c->root_hash_path)
1004 fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
1005
1006 if (c->root_hash_sig) {
1007 _cleanup_free_ char *encoded = NULL;
1008 ssize_t len;
1009 len = base64mem(c->root_hash_sig, c->root_hash_sig_size, &encoded);
1010 if (len)
1011 fprintf(f, "%sRootHashSignature: base64:%s\n", prefix, encoded);
1012 }
1013
1014 if (c->root_hash_sig_path)
1015 fprintf(f, "%sRootHashSignature: %s\n", prefix, c->root_hash_sig_path);
1016
1017 if (c->root_verity)
1018 fprintf(f, "%sRootVerity: %s\n", prefix, c->root_verity);
1019
1020 STRV_FOREACH(e, c->environment)
1021 fprintf(f, "%sEnvironment: %s\n", prefix, *e);
1022
1023 STRV_FOREACH(e, c->environment_files)
1024 fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
1025
1026 STRV_FOREACH(e, c->pass_environment)
1027 fprintf(f, "%sPassEnvironment: %s\n", prefix, *e);
1028
1029 STRV_FOREACH(e, c->unset_environment)
1030 fprintf(f, "%sUnsetEnvironment: %s\n", prefix, *e);
1031
1032 fprintf(f, "%sRuntimeDirectoryPreserve: %s\n", prefix, exec_preserve_mode_to_string(c->runtime_directory_preserve_mode));
1033
1034 for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
1035 fprintf(f, "%s%sMode: %04o\n", prefix, exec_directory_type_to_string(dt), c->directories[dt].mode);
1036
1037 for (size_t i = 0; i < c->directories[dt].n_items; i++) {
1038 fprintf(f, "%s%s: %s\n", prefix, exec_directory_type_to_string(dt), c->directories[dt].items[i].path);
1039
1040 STRV_FOREACH(d, c->directories[dt].items[i].symlinks)
1041 fprintf(f, "%s%s: %s:%s\n", prefix, exec_directory_type_symlink_to_string(dt), c->directories[dt].items[i].path, *d);
1042 }
1043 }
1044
1045 fprintf(f, "%sTimeoutCleanSec: %s\n", prefix, FORMAT_TIMESPAN(c->timeout_clean_usec, USEC_PER_SEC));
1046
1047 if (c->memory_ksm >= 0)
1048 fprintf(f, "%sMemoryKSM: %s\n", prefix, yes_no(c->memory_ksm > 0));
1049
1050 if (c->nice_set)
1051 fprintf(f, "%sNice: %i\n", prefix, c->nice);
1052
1053 if (c->oom_score_adjust_set)
1054 fprintf(f, "%sOOMScoreAdjust: %i\n", prefix, c->oom_score_adjust);
1055
1056 if (c->coredump_filter_set)
1057 fprintf(f, "%sCoredumpFilter: 0x%"PRIx64"\n", prefix, c->coredump_filter);
1058
1059 for (unsigned i = 0; i < RLIM_NLIMITS; i++)
1060 if (c->rlimit[i]) {
1061 fprintf(f, "%sLimit%s: " RLIM_FMT "\n",
1062 prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
1063 fprintf(f, "%sLimit%sSoft: " RLIM_FMT "\n",
1064 prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur);
1065 }
1066
1067 if (c->ioprio_set) {
1068 _cleanup_free_ char *class_str = NULL;
1069
1070 r = ioprio_class_to_string_alloc(ioprio_prio_class(c->ioprio), &class_str);
1071 if (r >= 0)
1072 fprintf(f, "%sIOSchedulingClass: %s\n", prefix, class_str);
1073
1074 fprintf(f, "%sIOPriority: %d\n", prefix, ioprio_prio_data(c->ioprio));
1075 }
1076
1077 if (c->cpu_sched_set) {
1078 _cleanup_free_ char *policy_str = NULL;
1079
1080 r = sched_policy_to_string_alloc(c->cpu_sched_policy, &policy_str);
1081 if (r >= 0)
1082 fprintf(f, "%sCPUSchedulingPolicy: %s\n", prefix, policy_str);
1083
1084 fprintf(f,
1085 "%sCPUSchedulingPriority: %i\n"
1086 "%sCPUSchedulingResetOnFork: %s\n",
1087 prefix, c->cpu_sched_priority,
1088 prefix, yes_no(c->cpu_sched_reset_on_fork));
1089 }
1090
1091 if (c->cpu_set.set) {
1092 _cleanup_free_ char *affinity = NULL;
1093
1094 affinity = cpu_set_to_range_string(&c->cpu_set);
1095 fprintf(f, "%sCPUAffinity: %s\n", prefix, affinity);
1096 }
1097
1098 if (mpol_is_valid(numa_policy_get_type(&c->numa_policy))) {
1099 _cleanup_free_ char *nodes = NULL;
1100
1101 nodes = cpu_set_to_range_string(&c->numa_policy.nodes);
1102 fprintf(f, "%sNUMAPolicy: %s\n", prefix, mpol_to_string(numa_policy_get_type(&c->numa_policy)));
1103 fprintf(f, "%sNUMAMask: %s\n", prefix, strnull(nodes));
1104 }
1105
1106 if (c->timer_slack_nsec != NSEC_INFINITY)
1107 fprintf(f, "%sTimerSlackNSec: "NSEC_FMT "\n", prefix, c->timer_slack_nsec);
1108
1109 fprintf(f,
1110 "%sStandardInput: %s\n"
1111 "%sStandardOutput: %s\n"
1112 "%sStandardError: %s\n",
1113 prefix, exec_input_to_string(c->std_input),
1114 prefix, exec_output_to_string(c->std_output),
1115 prefix, exec_output_to_string(c->std_error));
1116
1117 if (c->std_input == EXEC_INPUT_NAMED_FD)
1118 fprintf(f, "%sStandardInputFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDIN_FILENO]);
1119 if (c->std_output == EXEC_OUTPUT_NAMED_FD)
1120 fprintf(f, "%sStandardOutputFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDOUT_FILENO]);
1121 if (c->std_error == EXEC_OUTPUT_NAMED_FD)
1122 fprintf(f, "%sStandardErrorFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDERR_FILENO]);
1123
1124 if (c->std_input == EXEC_INPUT_FILE)
1125 fprintf(f, "%sStandardInputFile: %s\n", prefix, c->stdio_file[STDIN_FILENO]);
1126 if (c->std_output == EXEC_OUTPUT_FILE)
1127 fprintf(f, "%sStandardOutputFile: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
1128 if (c->std_output == EXEC_OUTPUT_FILE_APPEND)
1129 fprintf(f, "%sStandardOutputFileToAppend: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
1130 if (c->std_output == EXEC_OUTPUT_FILE_TRUNCATE)
1131 fprintf(f, "%sStandardOutputFileToTruncate: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
1132 if (c->std_error == EXEC_OUTPUT_FILE)
1133 fprintf(f, "%sStandardErrorFile: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
1134 if (c->std_error == EXEC_OUTPUT_FILE_APPEND)
1135 fprintf(f, "%sStandardErrorFileToAppend: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
1136 if (c->std_error == EXEC_OUTPUT_FILE_TRUNCATE)
1137 fprintf(f, "%sStandardErrorFileToTruncate: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
1138
1139 if (c->tty_path)
1140 fprintf(f,
1141 "%sTTYPath: %s\n"
1142 "%sTTYReset: %s\n"
1143 "%sTTYVHangup: %s\n"
1144 "%sTTYVTDisallocate: %s\n"
1145 "%sTTYRows: %u\n"
1146 "%sTTYColumns: %u\n",
1147 prefix, c->tty_path,
1148 prefix, yes_no(c->tty_reset),
1149 prefix, yes_no(c->tty_vhangup),
1150 prefix, yes_no(c->tty_vt_disallocate),
1151 prefix, c->tty_rows,
1152 prefix, c->tty_cols);
1153
1154 if (IN_SET(c->std_output,
1155 EXEC_OUTPUT_KMSG,
1156 EXEC_OUTPUT_JOURNAL,
1157 EXEC_OUTPUT_KMSG_AND_CONSOLE,
1158 EXEC_OUTPUT_JOURNAL_AND_CONSOLE) ||
1159 IN_SET(c->std_error,
1160 EXEC_OUTPUT_KMSG,
1161 EXEC_OUTPUT_JOURNAL,
1162 EXEC_OUTPUT_KMSG_AND_CONSOLE,
1163 EXEC_OUTPUT_JOURNAL_AND_CONSOLE)) {
1164
1165 _cleanup_free_ char *fac_str = NULL, *lvl_str = NULL;
1166
1167 r = log_facility_unshifted_to_string_alloc(c->syslog_priority >> 3, &fac_str);
1168 if (r >= 0)
1169 fprintf(f, "%sSyslogFacility: %s\n", prefix, fac_str);
1170
1171 r = log_level_to_string_alloc(LOG_PRI(c->syslog_priority), &lvl_str);
1172 if (r >= 0)
1173 fprintf(f, "%sSyslogLevel: %s\n", prefix, lvl_str);
1174 }
1175
1176 if (c->log_level_max >= 0) {
1177 _cleanup_free_ char *t = NULL;
1178
1179 (void) log_level_to_string_alloc(c->log_level_max, &t);
1180
1181 fprintf(f, "%sLogLevelMax: %s\n", prefix, strna(t));
1182 }
1183
1184 if (c->log_ratelimit_interval_usec > 0)
1185 fprintf(f,
1186 "%sLogRateLimitIntervalSec: %s\n",
1187 prefix, FORMAT_TIMESPAN(c->log_ratelimit_interval_usec, USEC_PER_SEC));
1188
1189 if (c->log_ratelimit_burst > 0)
1190 fprintf(f, "%sLogRateLimitBurst: %u\n", prefix, c->log_ratelimit_burst);
1191
1192 if (!set_isempty(c->log_filter_allowed_patterns) || !set_isempty(c->log_filter_denied_patterns)) {
1193 fprintf(f, "%sLogFilterPatterns:", prefix);
1194
1195 char *pattern;
1196 SET_FOREACH(pattern, c->log_filter_allowed_patterns)
1197 fprintf(f, " %s", pattern);
1198 SET_FOREACH(pattern, c->log_filter_denied_patterns)
1199 fprintf(f, " ~%s", pattern);
1200 fputc('\n', f);
1201 }
1202
1203 FOREACH_ARRAY(field, c->log_extra_fields, c->n_log_extra_fields) {
1204 fprintf(f, "%sLogExtraFields: ", prefix);
1205 fwrite(field->iov_base, 1, field->iov_len, f);
1206 fputc('\n', f);
1207 }
1208
1209 if (c->log_namespace)
1210 fprintf(f, "%sLogNamespace: %s\n", prefix, c->log_namespace);
1211
1212 if (c->secure_bits) {
1213 _cleanup_free_ char *str = NULL;
1214
1215 r = secure_bits_to_string_alloc(c->secure_bits, &str);
1216 if (r >= 0)
1217 fprintf(f, "%sSecure Bits: %s\n", prefix, str);
1218 }
1219
1220 if (c->capability_bounding_set != CAP_MASK_UNSET) {
1221 _cleanup_free_ char *str = NULL;
1222
1223 r = capability_set_to_string(c->capability_bounding_set, &str);
1224 if (r >= 0)
1225 fprintf(f, "%sCapabilityBoundingSet: %s\n", prefix, str);
1226 }
1227
1228 if (c->capability_ambient_set != 0) {
1229 _cleanup_free_ char *str = NULL;
1230
1231 r = capability_set_to_string(c->capability_ambient_set, &str);
1232 if (r >= 0)
1233 fprintf(f, "%sAmbientCapabilities: %s\n", prefix, str);
1234 }
1235
1236 if (c->user)
1237 fprintf(f, "%sUser: %s\n", prefix, c->user);
1238 if (c->group)
1239 fprintf(f, "%sGroup: %s\n", prefix, c->group);
1240
1241 fprintf(f, "%sDynamicUser: %s\n", prefix, yes_no(c->dynamic_user));
1242
1243 strv_dump(f, prefix, "SupplementaryGroups", c->supplementary_groups);
1244
1245 if (c->pam_name)
1246 fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
1247
1248 strv_dump(f, prefix, "ReadWritePaths", c->read_write_paths);
1249 strv_dump(f, prefix, "ReadOnlyPaths", c->read_only_paths);
1250 strv_dump(f, prefix, "InaccessiblePaths", c->inaccessible_paths);
1251 strv_dump(f, prefix, "ExecPaths", c->exec_paths);
1252 strv_dump(f, prefix, "NoExecPaths", c->no_exec_paths);
1253 strv_dump(f, prefix, "ExecSearchPath", c->exec_search_path);
1254
1255 FOREACH_ARRAY(mount, c->bind_mounts, c->n_bind_mounts)
1256 fprintf(f, "%s%s: %s%s:%s:%s\n", prefix,
1257 mount->read_only ? "BindReadOnlyPaths" : "BindPaths",
1258 mount->ignore_enoent ? "-": "",
1259 mount->source,
1260 mount->destination,
1261 mount->recursive ? "rbind" : "norbind");
1262
1263 FOREACH_ARRAY(tmpfs, c->temporary_filesystems, c->n_temporary_filesystems)
1264 fprintf(f, "%sTemporaryFileSystem: %s%s%s\n", prefix,
1265 tmpfs->path,
1266 isempty(tmpfs->options) ? "" : ":",
1267 strempty(tmpfs->options));
1268
1269 if (c->utmp_id)
1270 fprintf(f,
1271 "%sUtmpIdentifier: %s\n",
1272 prefix, c->utmp_id);
1273
1274 if (c->selinux_context)
1275 fprintf(f,
1276 "%sSELinuxContext: %s%s\n",
1277 prefix, c->selinux_context_ignore ? "-" : "", c->selinux_context);
1278
1279 if (c->apparmor_profile)
1280 fprintf(f,
1281 "%sAppArmorProfile: %s%s\n",
1282 prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile);
1283
1284 if (c->smack_process_label)
1285 fprintf(f,
1286 "%sSmackProcessLabel: %s%s\n",
1287 prefix, c->smack_process_label_ignore ? "-" : "", c->smack_process_label);
1288
1289 if (c->personality != PERSONALITY_INVALID)
1290 fprintf(f,
1291 "%sPersonality: %s\n",
1292 prefix, strna(personality_to_string(c->personality)));
1293
1294 fprintf(f,
1295 "%sLockPersonality: %s\n",
1296 prefix, yes_no(c->lock_personality));
1297
1298 if (c->syscall_filter) {
1299 fprintf(f,
1300 "%sSystemCallFilter: ",
1301 prefix);
1302
1303 if (!c->syscall_allow_list)
1304 fputc('~', f);
1305
1306#if HAVE_SECCOMP
1307 void *id, *val;
1308 bool first = true;
1309 HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
1310 _cleanup_free_ char *name = NULL;
1311 const char *errno_name = NULL;
1312 int num = PTR_TO_INT(val);
1313
1314 if (first)
1315 first = false;
1316 else
1317 fputc(' ', f);
1318
1319 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
1320 fputs(strna(name), f);
1321
1322 if (num >= 0) {
1323 errno_name = seccomp_errno_or_action_to_string(num);
1324 if (errno_name)
1325 fprintf(f, ":%s", errno_name);
1326 else
1327 fprintf(f, ":%d", num);
1328 }
1329 }
1330#endif
1331
1332 fputc('\n', f);
1333 }
1334
1335 if (c->syscall_archs) {
1336 fprintf(f,
1337 "%sSystemCallArchitectures:",
1338 prefix);
1339
1340#if HAVE_SECCOMP
1341 void *id;
1342 SET_FOREACH(id, c->syscall_archs)
1343 fprintf(f, " %s", strna(seccomp_arch_to_string(PTR_TO_UINT32(id) - 1)));
1344#endif
1345 fputc('\n', f);
1346 }
1347
1348 if (exec_context_restrict_namespaces_set(c)) {
1349 _cleanup_free_ char *s = NULL;
1350
1351 r = namespace_flags_to_string(c->restrict_namespaces, &s);
1352 if (r >= 0)
1353 fprintf(f, "%sRestrictNamespaces: %s\n",
1354 prefix, strna(s));
1355 }
1356
1357#if HAVE_LIBBPF
1358 if (exec_context_restrict_filesystems_set(c)) {
1359 char *fs;
1360 SET_FOREACH(fs, c->restrict_filesystems)
1361 fprintf(f, "%sRestrictFileSystems: %s\n", prefix, fs);
1362 }
1363#endif
1364
1365 if (c->network_namespace_path)
1366 fprintf(f,
1367 "%sNetworkNamespacePath: %s\n",
1368 prefix, c->network_namespace_path);
1369
1370 if (c->syscall_errno > 0) {
1371 fprintf(f, "%sSystemCallErrorNumber: ", prefix);
1372
1373#if HAVE_SECCOMP
1374 const char *errno_name = seccomp_errno_or_action_to_string(c->syscall_errno);
1375 if (errno_name)
1376 fputs(errno_name, f);
1377 else
1378 fprintf(f, "%d", c->syscall_errno);
1379#endif
1380 fputc('\n', f);
1381 }
1382
1383 FOREACH_ARRAY(mount, c->mount_images, c->n_mount_images) {
1384 fprintf(f, "%sMountImages: %s%s:%s", prefix,
1385 mount->ignore_enoent ? "-": "",
1386 mount->source,
1387 mount->destination);
1388 LIST_FOREACH(mount_options, o, mount->mount_options)
1389 fprintf(f, ":%s:%s",
1390 partition_designator_to_string(o->partition_designator),
1391 strempty(o->options));
1392 fprintf(f, "\n");
1393 }
1394
1395 FOREACH_ARRAY(mount, c->extension_images, c->n_extension_images) {
1396 fprintf(f, "%sExtensionImages: %s%s", prefix,
1397 mount->ignore_enoent ? "-": "",
1398 mount->source);
1399 LIST_FOREACH(mount_options, o, mount->mount_options)
1400 fprintf(f, ":%s:%s",
1401 partition_designator_to_string(o->partition_designator),
1402 strempty(o->options));
1403 fprintf(f, "\n");
1404 }
1405
1406 strv_dump(f, prefix, "ExtensionDirectories", c->extension_directories);
1407}
1408
1409bool exec_context_maintains_privileges(const ExecContext *c) {
1410 assert(c);
1411
1412 /* Returns true if the process forked off would run under
1413 * an unchanged UID or as root. */
1414
1415 if (!c->user)
1416 return true;
1417
1418 if (STR_IN_SET(c->user, "root", "0"))
1419 return true;
1420
1421 return false;
1422}
1423
1424int exec_context_get_effective_ioprio(const ExecContext *c) {
1425 int p;
1426
1427 assert(c);
1428
1429 if (c->ioprio_set)
1430 return c->ioprio;
1431
1432 p = ioprio_get(IOPRIO_WHO_PROCESS, 0);
1433 if (p < 0)
1434 return IOPRIO_DEFAULT_CLASS_AND_PRIO;
1435
1436 return ioprio_normalize(p);
1437}
1438
1439bool exec_context_get_effective_mount_apivfs(const ExecContext *c) {
1440 assert(c);
1441
1442 /* Explicit setting wins */
1443 if (c->mount_apivfs_set)
1444 return c->mount_apivfs;
1445
1446 /* Default to "yes" if root directory or image are specified */
1447 if (exec_context_with_rootfs(c))
1448 return true;
1449
1450 return false;
1451}
1452
1453void exec_context_free_log_extra_fields(ExecContext *c) {
1454 assert(c);
1455
1456 FOREACH_ARRAY(field, c->log_extra_fields, c->n_log_extra_fields)
1457 free(field->iov_base);
1458
1459 c->log_extra_fields = mfree(c->log_extra_fields);
1460 c->n_log_extra_fields = 0;
1461}
1462
1463void exec_context_revert_tty(ExecContext *c) {
1464 _cleanup_close_ int fd = -EBADF;
1465 const char *path;
1466 struct stat st;
1467 int r;
1468
1469 assert(c);
1470
1471 /* First, reset the TTY (possibly kicking everybody else from the TTY) */
1472 exec_context_tty_reset(c, /* parameters= */ NULL);
1473
1474 /* And then undo what chown_terminal() did earlier. Note that we only do this if we have a path
1475 * configured. If the TTY was passed to us as file descriptor we assume the TTY is opened and managed
1476 * by whoever passed it to us and thus knows better when and how to chmod()/chown() it back. */
1477 if (!exec_context_may_touch_tty(c))
1478 return;
1479
1480 path = exec_context_tty_path(c);
1481 if (!path)
1482 return;
1483
1484 fd = open(path, O_PATH|O_CLOEXEC); /* Pin the inode */
1485 if (fd < 0)
1486 return (void) log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
1487 "Failed to open TTY inode of '%s' to adjust ownership/access mode, ignoring: %m",
1488 path);
1489
1490 if (fstat(fd, &st) < 0)
1491 return (void) log_warning_errno(errno, "Failed to stat TTY '%s', ignoring: %m", path);
1492
1493 /* Let's add a superficial check that we only do this for stuff that looks like a TTY. We only check
1494 * if things are a character device, since a proper check either means we'd have to open the TTY and
1495 * use isatty(), but we'd rather not do that since opening TTYs comes with all kinds of side-effects
1496 * and is slow. Or we'd have to hardcode dev_t major information, which we'd rather avoid. Why bother
1497 * with this at all? → https://github.com/systemd/systemd/issues/19213 */
1498 if (!S_ISCHR(st.st_mode))
1499 return log_warning("Configured TTY '%s' is not actually a character device, ignoring.", path);
1500
1501 r = fchmod_and_chown(fd, TTY_MODE, 0, TTY_GID);
1502 if (r < 0)
1503 log_warning_errno(r, "Failed to reset TTY ownership/access mode of %s to " UID_FMT ":" GID_FMT ", ignoring: %m", path, (uid_t) 0, (gid_t) TTY_GID);
1504}
1505
1506int exec_context_get_clean_directories(
1507 ExecContext *c,
1508 char **prefix,
1509 ExecCleanMask mask,
1510 char ***ret) {
1511
1512 _cleanup_strv_free_ char **l = NULL;
1513 int r;
1514
1515 assert(c);
1516 assert(prefix);
1517 assert(ret);
1518
1519 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
1520 if (!FLAGS_SET(mask, 1U << t))
1521 continue;
1522
1523 if (!prefix[t])
1524 continue;
1525
1526 FOREACH_ARRAY(i, c->directories[t].items, c->directories[t].n_items) {
1527 char *j;
1528
1529 j = path_join(prefix[t], i->path);
1530 if (!j)
1531 return -ENOMEM;
1532
1533 r = strv_consume(&l, j);
1534 if (r < 0)
1535 return r;
1536
1537 /* Also remove private directories unconditionally. */
1538 if (t != EXEC_DIRECTORY_CONFIGURATION) {
1539 j = path_join(prefix[t], "private", i->path);
1540 if (!j)
1541 return -ENOMEM;
1542
1543 r = strv_consume(&l, j);
1544 if (r < 0)
1545 return r;
1546 }
1547
1548 STRV_FOREACH(symlink, i->symlinks) {
1549 j = path_join(prefix[t], *symlink);
1550 if (!j)
1551 return -ENOMEM;
1552
1553 r = strv_consume(&l, j);
1554 if (r < 0)
1555 return r;
1556 }
1557 }
1558 }
1559
1560 *ret = TAKE_PTR(l);
1561 return 0;
1562}
1563
1564int exec_context_get_clean_mask(ExecContext *c, ExecCleanMask *ret) {
1565 ExecCleanMask mask = 0;
1566
1567 assert(c);
1568 assert(ret);
1569
1570 for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++)
1571 if (c->directories[t].n_items > 0)
1572 mask |= 1U << t;
1573
1574 *ret = mask;
1575 return 0;
1576}
1577
1578int exec_context_get_oom_score_adjust(const ExecContext *c) {
1579 int n = 0, r;
1580
1581 assert(c);
1582
1583 if (c->oom_score_adjust_set)
1584 return c->oom_score_adjust;
1585
1586 r = get_oom_score_adjust(&n);
1587 if (r < 0)
1588 log_debug_errno(r, "Failed to read /proc/self/oom_score_adj, ignoring: %m");
1589
1590 return n;
1591}
1592
1593uint64_t exec_context_get_coredump_filter(const ExecContext *c) {
1594 _cleanup_free_ char *t = NULL;
1595 uint64_t n = COREDUMP_FILTER_MASK_DEFAULT;
1596 int r;
1597
1598 assert(c);
1599
1600 if (c->coredump_filter_set)
1601 return c->coredump_filter;
1602
1603 r = read_one_line_file("/proc/self/coredump_filter", &t);
1604 if (r < 0)
1605 log_debug_errno(r, "Failed to read /proc/self/coredump_filter, ignoring: %m");
1606 else {
1607 r = safe_atoux64(t, &n);
1608 if (r < 0)
1609 log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/coredump_filter, ignoring: %m", t);
1610 }
1611
1612 return n;
1613}
1614
1615int exec_context_get_nice(const ExecContext *c) {
1616 int n;
1617
1618 assert(c);
1619
1620 if (c->nice_set)
1621 return c->nice;
1622
1623 errno = 0;
1624 n = getpriority(PRIO_PROCESS, 0);
1625 if (errno > 0) {
1626 log_debug_errno(errno, "Failed to get process nice value, ignoring: %m");
1627 n = 0;
1628 }
1629
1630 return n;
1631}
1632
1633int exec_context_get_cpu_sched_policy(const ExecContext *c) {
1634 int n;
1635
1636 assert(c);
1637
1638 if (c->cpu_sched_set)
1639 return c->cpu_sched_policy;
1640
1641 n = sched_getscheduler(0);
1642 if (n < 0)
1643 log_debug_errno(errno, "Failed to get scheduler policy, ignoring: %m");
1644
1645 return n < 0 ? SCHED_OTHER : n;
1646}
1647
1648int exec_context_get_cpu_sched_priority(const ExecContext *c) {
1649 struct sched_param p = {};
1650 int r;
1651
1652 assert(c);
1653
1654 if (c->cpu_sched_set)
1655 return c->cpu_sched_priority;
1656
1657 r = sched_getparam(0, &p);
1658 if (r < 0)
1659 log_debug_errno(errno, "Failed to get scheduler priority, ignoring: %m");
1660
1661 return r >= 0 ? p.sched_priority : 0;
1662}
1663
1664uint64_t exec_context_get_timer_slack_nsec(const ExecContext *c) {
1665 int r;
1666
1667 assert(c);
1668
1669 if (c->timer_slack_nsec != NSEC_INFINITY)
1670 return c->timer_slack_nsec;
1671
1672 r = prctl(PR_GET_TIMERSLACK);
1673 if (r < 0)
1674 log_debug_errno(r, "Failed to get timer slack, ignoring: %m");
1675
1676 return (uint64_t) MAX(r, 0);
1677}
1678
1679bool exec_context_get_set_login_environment(const ExecContext *c) {
1680 assert(c);
1681
1682 if (c->set_login_environment >= 0)
1683 return c->set_login_environment;
1684
1685 return c->user || c->dynamic_user || c->pam_name;
1686}
1687
1688char** exec_context_get_syscall_filter(const ExecContext *c) {
1689 _cleanup_strv_free_ char **l = NULL;
1690
1691 assert(c);
1692
1693#if HAVE_SECCOMP
1694 void *id, *val;
1695 HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
1696 _cleanup_free_ char *name = NULL;
1697 const char *e = NULL;
1698 char *s;
1699 int num = PTR_TO_INT(val);
1700
1701 if (c->syscall_allow_list && num >= 0)
1702 /* syscall with num >= 0 in allow-list is denied. */
1703 continue;
1704
1705 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
1706 if (!name)
1707 continue;
1708
1709 if (num >= 0) {
1710 e = seccomp_errno_or_action_to_string(num);
1711 if (e) {
1712 s = strjoin(name, ":", e);
1713 if (!s)
1714 return NULL;
1715 } else {
1716 if (asprintf(&s, "%s:%d", name, num) < 0)
1717 return NULL;
1718 }
1719 } else
1720 s = TAKE_PTR(name);
1721
1722 if (strv_consume(&l, s) < 0)
1723 return NULL;
1724 }
1725
1726 strv_sort(l);
1727#endif
1728
1729 return l ? TAKE_PTR(l) : strv_new(NULL);
1730}
1731
1732char** exec_context_get_syscall_archs(const ExecContext *c) {
1733 _cleanup_strv_free_ char **l = NULL;
1734
1735 assert(c);
1736
1737#if HAVE_SECCOMP
1738 void *id;
1739 SET_FOREACH(id, c->syscall_archs) {
1740 const char *name;
1741
1742 name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
1743 if (!name)
1744 continue;
1745
1746 if (strv_extend(&l, name) < 0)
1747 return NULL;
1748 }
1749
1750 strv_sort(l);
1751#endif
1752
1753 return l ? TAKE_PTR(l) : strv_new(NULL);
1754}
1755
1756char** exec_context_get_syscall_log(const ExecContext *c) {
1757 _cleanup_strv_free_ char **l = NULL;
1758
1759 assert(c);
1760
1761#if HAVE_SECCOMP
1762 void *id, *val;
1763 HASHMAP_FOREACH_KEY(val, id, c->syscall_log) {
1764 char *name = NULL;
1765
1766 name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
1767 if (!name)
1768 continue;
1769
1770 if (strv_consume(&l, name) < 0)
1771 return NULL;
1772 }
1773
1774 strv_sort(l);
1775#endif
1776
1777 return l ? TAKE_PTR(l) : strv_new(NULL);
1778}
1779
1780char** exec_context_get_address_families(const ExecContext *c) {
1781 _cleanup_strv_free_ char **l = NULL;
1782 void *af;
1783
1784 assert(c);
1785
1786 SET_FOREACH(af, c->address_families) {
1787 const char *name;
1788
1789 name = af_to_name(PTR_TO_INT(af));
1790 if (!name)
1791 continue;
1792
1793 if (strv_extend(&l, name) < 0)
1794 return NULL;
1795 }
1796
1797 strv_sort(l);
1798
1799 return l ? TAKE_PTR(l) : strv_new(NULL);
1800}
1801
1802char** exec_context_get_restrict_filesystems(const ExecContext *c) {
1803 _cleanup_strv_free_ char **l = NULL;
1804
1805 assert(c);
1806
1807#if HAVE_LIBBPF
1808 l = set_get_strv(c->restrict_filesystems);
1809 if (!l)
1810 return NULL;
1811
1812 strv_sort(l);
1813#endif
1814
1815 return l ? TAKE_PTR(l) : strv_new(NULL);
1816}
1817
1818void exec_status_start(ExecStatus *s, pid_t pid) {
1819 assert(s);
1820
1821 *s = (ExecStatus) {
1822 .pid = pid,
1823 };
1824
1825 dual_timestamp_now(&s->start_timestamp);
1826}
1827
1828void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int code, int status) {
1829 assert(s);
1830
1831 if (s->pid != pid)
1832 *s = (ExecStatus) {
1833 .pid = pid,
1834 };
1835
1836 dual_timestamp_now(&s->exit_timestamp);
1837
1838 s->code = code;
1839 s->status = status;
1840
1841 if (context && context->utmp_id)
1842 (void) utmp_put_dead_process(context->utmp_id, pid, code, status);
1843}
1844
1845void exec_status_handoff(ExecStatus *s, const struct ucred *ucred, const dual_timestamp *ts) {
1846 assert(s);
1847 assert(ucred);
1848 assert(ts);
1849
1850 if (ucred->pid != s->pid)
1851 *s = (ExecStatus) {
1852 .pid = ucred->pid,
1853 };
1854
1855 s->handoff_timestamp = *ts;
1856}
1857
1858void exec_status_reset(ExecStatus *s) {
1859 assert(s);
1860
1861 *s = (ExecStatus) {};
1862}
1863
1864void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix) {
1865 assert(s);
1866 assert(f);
1867
1868 if (s->pid <= 0)
1869 return;
1870
1871 prefix = strempty(prefix);
1872
1873 fprintf(f,
1874 "%sPID: "PID_FMT"\n",
1875 prefix, s->pid);
1876
1877 if (dual_timestamp_is_set(&s->start_timestamp))
1878 fprintf(f,
1879 "%sStart Timestamp: %s\n",
1880 prefix, FORMAT_TIMESTAMP(s->start_timestamp.realtime));
1881
1882 if (dual_timestamp_is_set(&s->handoff_timestamp))
1883 fprintf(f,
1884 "%sHandoff Timestamp: %s\n",
1885 prefix, FORMAT_TIMESTAMP(s->handoff_timestamp.realtime));
1886
1887 if (dual_timestamp_is_set(&s->exit_timestamp))
1888 fprintf(f,
1889 "%sExit Timestamp: %s\n"
1890 "%sExit Code: %s\n"
1891 "%sExit Status: %i\n",
1892 prefix, FORMAT_TIMESTAMP(s->exit_timestamp.realtime),
1893 prefix, sigchld_code_to_string(s->code),
1894 prefix, s->status);
1895}
1896
1897void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
1898 _cleanup_free_ char *cmd = NULL;
1899 const char *prefix2;
1900
1901 assert(c);
1902 assert(f);
1903
1904 prefix = strempty(prefix);
1905 prefix2 = strjoina(prefix, "\t");
1906
1907 cmd = quote_command_line(c->argv, SHELL_ESCAPE_EMPTY);
1908
1909 fprintf(f,
1910 "%sCommand Line: %s\n",
1911 prefix, strnull(cmd));
1912
1913 exec_status_dump(&c->exec_status, f, prefix2);
1914}
1915
1916void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
1917 assert(f);
1918
1919 prefix = strempty(prefix);
1920
1921 LIST_FOREACH(command, i, c)
1922 exec_command_dump(i, f, prefix);
1923}
1924
1925void exec_command_append_list(ExecCommand **l, ExecCommand *e) {
1926 ExecCommand *end;
1927
1928 assert(l);
1929 assert(e);
1930
1931 if (*l) {
1932 /* It's kind of important, that we keep the order here */
1933 end = LIST_FIND_TAIL(command, *l);
1934 LIST_INSERT_AFTER(command, *l, end, e);
1935 } else
1936 *l = e;
1937}
1938
1939int exec_command_set(ExecCommand *c, const char *path, ...) {
1940 va_list ap;
1941 char **l, *p;
1942
1943 assert(c);
1944 assert(path);
1945
1946 va_start(ap, path);
1947 l = strv_new_ap(path, ap);
1948 va_end(ap);
1949
1950 if (!l)
1951 return -ENOMEM;
1952
1953 p = strdup(path);
1954 if (!p) {
1955 strv_free(l);
1956 return -ENOMEM;
1957 }
1958
1959 free_and_replace(c->path, p);
1960
1961 return strv_free_and_replace(c->argv, l);
1962}
1963
1964int exec_command_append(ExecCommand *c, const char *path, ...) {
1965 _cleanup_strv_free_ char **l = NULL;
1966 va_list ap;
1967 int r;
1968
1969 assert(c);
1970 assert(path);
1971
1972 va_start(ap, path);
1973 l = strv_new_ap(path, ap);
1974 va_end(ap);
1975
1976 if (!l)
1977 return -ENOMEM;
1978
1979 r = strv_extend_strv(&c->argv, l, false);
1980 if (r < 0)
1981 return r;
1982
1983 return 0;
1984}
1985
1986static char *destroy_tree(char *path) {
1987 if (!path)
1988 return NULL;
1989
1990 if (!path_equal(path, RUN_SYSTEMD_EMPTY)) {
1991 log_debug("Spawning process to nuke '%s'", path);
1992
1993 (void) asynchronous_rm_rf(path, REMOVE_ROOT|REMOVE_SUBVOLUME|REMOVE_PHYSICAL);
1994 }
1995
1996 return mfree(path);
1997}
1998
1999void exec_shared_runtime_done(ExecSharedRuntime *rt) {
2000 assert(rt);
2001
2002 if (rt->manager)
2003 (void) hashmap_remove(rt->manager->exec_shared_runtime_by_id, rt->id);
2004
2005 rt->id = mfree(rt->id);
2006 rt->tmp_dir = mfree(rt->tmp_dir);
2007 rt->var_tmp_dir = mfree(rt->var_tmp_dir);
2008 safe_close_pair(rt->netns_storage_socket);
2009 safe_close_pair(rt->ipcns_storage_socket);
2010}
2011
2012static ExecSharedRuntime* exec_shared_runtime_free(ExecSharedRuntime *rt) {
2013 if (!rt)
2014 return NULL;
2015
2016 exec_shared_runtime_done(rt);
2017 return mfree(rt);
2018}
2019
2020DEFINE_TRIVIAL_UNREF_FUNC(ExecSharedRuntime, exec_shared_runtime, exec_shared_runtime_free);
2021DEFINE_TRIVIAL_CLEANUP_FUNC(ExecSharedRuntime*, exec_shared_runtime_free);
2022
2023ExecSharedRuntime* exec_shared_runtime_destroy(ExecSharedRuntime *rt) {
2024 if (!rt)
2025 return NULL;
2026
2027 assert(rt->n_ref > 0);
2028 rt->n_ref--;
2029
2030 if (rt->n_ref > 0)
2031 return NULL;
2032
2033 rt->tmp_dir = destroy_tree(rt->tmp_dir);
2034 rt->var_tmp_dir = destroy_tree(rt->var_tmp_dir);
2035
2036 return exec_shared_runtime_free(rt);
2037}
2038
2039static int exec_shared_runtime_allocate(ExecSharedRuntime **ret, const char *id) {
2040 _cleanup_free_ char *id_copy = NULL;
2041 ExecSharedRuntime *n;
2042
2043 assert(ret);
2044
2045 id_copy = strdup(id);
2046 if (!id_copy)
2047 return -ENOMEM;
2048
2049 n = new(ExecSharedRuntime, 1);
2050 if (!n)
2051 return -ENOMEM;
2052
2053 *n = (ExecSharedRuntime) {
2054 .id = TAKE_PTR(id_copy),
2055 .netns_storage_socket = EBADF_PAIR,
2056 .ipcns_storage_socket = EBADF_PAIR,
2057 };
2058
2059 *ret = n;
2060 return 0;
2061}
2062
2063static int exec_shared_runtime_add(
2064 Manager *m,
2065 const char *id,
2066 char **tmp_dir,
2067 char **var_tmp_dir,
2068 int netns_storage_socket[2],
2069 int ipcns_storage_socket[2],
2070 ExecSharedRuntime **ret) {
2071
2072 _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt = NULL;
2073 int r;
2074
2075 assert(m);
2076 assert(id);
2077
2078 /* tmp_dir, var_tmp_dir, {net,ipc}ns_storage_socket fds are donated on success */
2079
2080 r = exec_shared_runtime_allocate(&rt, id);
2081 if (r < 0)
2082 return r;
2083
2084 r = hashmap_ensure_put(&m->exec_shared_runtime_by_id, &string_hash_ops, rt->id, rt);
2085 if (r < 0)
2086 return r;
2087
2088 assert(!!rt->tmp_dir == !!rt->var_tmp_dir); /* We require both to be set together */
2089 rt->tmp_dir = TAKE_PTR(*tmp_dir);
2090 rt->var_tmp_dir = TAKE_PTR(*var_tmp_dir);
2091
2092 if (netns_storage_socket) {
2093 rt->netns_storage_socket[0] = TAKE_FD(netns_storage_socket[0]);
2094 rt->netns_storage_socket[1] = TAKE_FD(netns_storage_socket[1]);
2095 }
2096
2097 if (ipcns_storage_socket) {
2098 rt->ipcns_storage_socket[0] = TAKE_FD(ipcns_storage_socket[0]);
2099 rt->ipcns_storage_socket[1] = TAKE_FD(ipcns_storage_socket[1]);
2100 }
2101
2102 rt->manager = m;
2103
2104 if (ret)
2105 *ret = rt;
2106 /* do not remove created ExecSharedRuntime object when the operation succeeds. */
2107 TAKE_PTR(rt);
2108 return 0;
2109}
2110
2111static int exec_shared_runtime_make(
2112 Manager *m,
2113 const ExecContext *c,
2114 const char *id,
2115 ExecSharedRuntime **ret) {
2116
2117 _cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
2118 _cleanup_close_pair_ int netns_storage_socket[2] = EBADF_PAIR, ipcns_storage_socket[2] = EBADF_PAIR;
2119 int r;
2120
2121 assert(m);
2122 assert(c);
2123 assert(id);
2124
2125 /* It is not necessary to create ExecSharedRuntime object. */
2126 if (!exec_needs_network_namespace(c) && !exec_needs_ipc_namespace(c) && !c->private_tmp) {
2127 *ret = NULL;
2128 return 0;
2129 }
2130
2131 if (c->private_tmp &&
2132 !(prefixed_path_strv_contains(c->inaccessible_paths, "/tmp") &&
2133 (prefixed_path_strv_contains(c->inaccessible_paths, "/var/tmp") ||
2134 prefixed_path_strv_contains(c->inaccessible_paths, "/var")))) {
2135 r = setup_tmp_dirs(id, &tmp_dir, &var_tmp_dir);
2136 if (r < 0)
2137 return r;
2138 }
2139
2140 if (exec_needs_network_namespace(c))
2141 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, netns_storage_socket) < 0)
2142 return -errno;
2143
2144 if (exec_needs_ipc_namespace(c))
2145 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ipcns_storage_socket) < 0)
2146 return -errno;
2147
2148 r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ipcns_storage_socket, ret);
2149 if (r < 0)
2150 return r;
2151
2152 return 1;
2153}
2154
2155int exec_shared_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool create, ExecSharedRuntime **ret) {
2156 ExecSharedRuntime *rt;
2157 int r;
2158
2159 assert(m);
2160 assert(id);
2161 assert(ret);
2162
2163 rt = hashmap_get(m->exec_shared_runtime_by_id, id);
2164 if (rt)
2165 /* We already have an ExecSharedRuntime object, let's increase the ref count and reuse it */
2166 goto ref;
2167
2168 if (!create) {
2169 *ret = NULL;
2170 return 0;
2171 }
2172
2173 /* If not found, then create a new object. */
2174 r = exec_shared_runtime_make(m, c, id, &rt);
2175 if (r < 0)
2176 return r;
2177 if (r == 0) {
2178 /* When r == 0, it is not necessary to create ExecSharedRuntime object. */
2179 *ret = NULL;
2180 return 0;
2181 }
2182
2183ref:
2184 /* increment reference counter. */
2185 rt->n_ref++;
2186 *ret = rt;
2187 return 1;
2188}
2189
2190int exec_shared_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
2191 ExecSharedRuntime *rt;
2192
2193 assert(m);
2194 assert(f);
2195 assert(fds);
2196
2197 HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
2198 fprintf(f, "exec-runtime=%s", rt->id);
2199
2200 if (rt->tmp_dir)
2201 fprintf(f, " tmp-dir=%s", rt->tmp_dir);
2202
2203 if (rt->var_tmp_dir)
2204 fprintf(f, " var-tmp-dir=%s", rt->var_tmp_dir);
2205
2206 if (rt->netns_storage_socket[0] >= 0) {
2207 int copy;
2208
2209 copy = fdset_put_dup(fds, rt->netns_storage_socket[0]);
2210 if (copy < 0)
2211 return copy;
2212
2213 fprintf(f, " netns-socket-0=%i", copy);
2214 }
2215
2216 if (rt->netns_storage_socket[1] >= 0) {
2217 int copy;
2218
2219 copy = fdset_put_dup(fds, rt->netns_storage_socket[1]);
2220 if (copy < 0)
2221 return copy;
2222
2223 fprintf(f, " netns-socket-1=%i", copy);
2224 }
2225
2226 if (rt->ipcns_storage_socket[0] >= 0) {
2227 int copy;
2228
2229 copy = fdset_put_dup(fds, rt->ipcns_storage_socket[0]);
2230 if (copy < 0)
2231 return copy;
2232
2233 fprintf(f, " ipcns-socket-0=%i", copy);
2234 }
2235
2236 if (rt->ipcns_storage_socket[1] >= 0) {
2237 int copy;
2238
2239 copy = fdset_put_dup(fds, rt->ipcns_storage_socket[1]);
2240 if (copy < 0)
2241 return copy;
2242
2243 fprintf(f, " ipcns-socket-1=%i", copy);
2244 }
2245
2246 fputc('\n', f);
2247 }
2248
2249 return 0;
2250}
2251
2252int exec_shared_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds) {
2253 _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt_create = NULL;
2254 ExecSharedRuntime *rt = NULL;
2255 int r;
2256
2257 /* This is for the migration from old (v237 or earlier) deserialization text.
2258 * Due to the bug #7790, this may not work with the units that use JoinsNamespaceOf=.
2259 * Even if the ExecSharedRuntime object originally created by the other unit, we cannot judge
2260 * so or not from the serialized text, then we always creates a new object owned by this. */
2261
2262 assert(u);
2263 assert(key);
2264 assert(value);
2265
2266 /* Manager manages ExecSharedRuntime objects by the unit id.
2267 * So, we omit the serialized text when the unit does not have id (yet?)... */
2268 if (isempty(u->id)) {
2269 log_unit_debug(u, "Invocation ID not found. Dropping runtime parameter.");
2270 return 0;
2271 }
2272
2273 if (u->manager) {
2274 if (hashmap_ensure_allocated(&u->manager->exec_shared_runtime_by_id, &string_hash_ops) < 0)
2275 return log_oom();
2276
2277 rt = hashmap_get(u->manager->exec_shared_runtime_by_id, u->id);
2278 }
2279 if (!rt) {
2280 if (exec_shared_runtime_allocate(&rt_create, u->id) < 0)
2281 return log_oom();
2282
2283 rt = rt_create;
2284 }
2285
2286 if (streq(key, "tmp-dir")) {
2287 if (free_and_strdup_warn(&rt->tmp_dir, value) < 0)
2288 return -ENOMEM;
2289
2290 } else if (streq(key, "var-tmp-dir")) {
2291 if (free_and_strdup_warn(&rt->var_tmp_dir, value) < 0)
2292 return -ENOMEM;
2293
2294 } else if (streq(key, "netns-socket-0")) {
2295
2296 safe_close(rt->netns_storage_socket[0]);
2297 rt->netns_storage_socket[0] = deserialize_fd(fds, value);
2298 if (rt->netns_storage_socket[0] < 0)
2299 return 0;
2300
2301 } else if (streq(key, "netns-socket-1")) {
2302
2303 safe_close(rt->netns_storage_socket[1]);
2304 rt->netns_storage_socket[1] = deserialize_fd(fds, value);
2305 if (rt->netns_storage_socket[1] < 0)
2306 return 0;
2307 } else
2308 return 0;
2309
2310 /* If the object is newly created, then put it to the hashmap which manages ExecSharedRuntime objects. */
2311 if (rt_create && u->manager) {
2312 r = hashmap_put(u->manager->exec_shared_runtime_by_id, rt_create->id, rt_create);
2313 if (r < 0) {
2314 log_unit_debug_errno(u, r, "Failed to put runtime parameter to manager's storage: %m");
2315 return 0;
2316 }
2317
2318 rt_create->manager = u->manager;
2319
2320 /* Avoid cleanup */
2321 TAKE_PTR(rt_create);
2322 }
2323
2324 return 1;
2325}
2326
2327int exec_shared_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
2328 _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
2329 char *id = NULL;
2330 int r, netns_fdpair[] = {-1, -1}, ipcns_fdpair[] = {-1, -1};
2331 const char *p, *v = ASSERT_PTR(value);
2332 size_t n;
2333
2334 assert(m);
2335 assert(fds);
2336
2337 n = strcspn(v, " ");
2338 id = strndupa_safe(v, n);
2339 if (v[n] != ' ')
2340 goto finalize;
2341 p = v + n + 1;
2342
2343 v = startswith(p, "tmp-dir=");
2344 if (v) {
2345 n = strcspn(v, " ");
2346 tmp_dir = strndup(v, n);
2347 if (!tmp_dir)
2348 return log_oom();
2349 if (v[n] != ' ')
2350 goto finalize;
2351 p = v + n + 1;
2352 }
2353
2354 v = startswith(p, "var-tmp-dir=");
2355 if (v) {
2356 n = strcspn(v, " ");
2357 var_tmp_dir = strndup(v, n);
2358 if (!var_tmp_dir)
2359 return log_oom();
2360 if (v[n] != ' ')
2361 goto finalize;
2362 p = v + n + 1;
2363 }
2364
2365 v = startswith(p, "netns-socket-0=");
2366 if (v) {
2367 char *buf;
2368
2369 n = strcspn(v, " ");
2370 buf = strndupa_safe(v, n);
2371
2372 netns_fdpair[0] = deserialize_fd(fds, buf);
2373 if (netns_fdpair[0] < 0)
2374 return netns_fdpair[0];
2375 if (v[n] != ' ')
2376 goto finalize;
2377 p = v + n + 1;
2378 }
2379
2380 v = startswith(p, "netns-socket-1=");
2381 if (v) {
2382 char *buf;
2383
2384 n = strcspn(v, " ");
2385 buf = strndupa_safe(v, n);
2386
2387 netns_fdpair[1] = deserialize_fd(fds, buf);
2388 if (netns_fdpair[1] < 0)
2389 return netns_fdpair[1];
2390 if (v[n] != ' ')
2391 goto finalize;
2392 p = v + n + 1;
2393 }
2394
2395 v = startswith(p, "ipcns-socket-0=");
2396 if (v) {
2397 char *buf;
2398
2399 n = strcspn(v, " ");
2400 buf = strndupa_safe(v, n);
2401
2402 ipcns_fdpair[0] = deserialize_fd(fds, buf);
2403 if (ipcns_fdpair[0] < 0)
2404 return ipcns_fdpair[0];
2405 if (v[n] != ' ')
2406 goto finalize;
2407 p = v + n + 1;
2408 }
2409
2410 v = startswith(p, "ipcns-socket-1=");
2411 if (v) {
2412 char *buf;
2413
2414 n = strcspn(v, " ");
2415 buf = strndupa_safe(v, n);
2416
2417 ipcns_fdpair[1] = deserialize_fd(fds, buf);
2418 if (ipcns_fdpair[1] < 0)
2419 return ipcns_fdpair[1];
2420 }
2421
2422finalize:
2423 r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_fdpair, ipcns_fdpair, NULL);
2424 if (r < 0)
2425 return log_debug_errno(r, "Failed to add exec-runtime: %m");
2426 return 0;
2427}
2428
2429void exec_shared_runtime_vacuum(Manager *m) {
2430 ExecSharedRuntime *rt;
2431
2432 assert(m);
2433
2434 /* Free unreferenced ExecSharedRuntime objects. This is used after manager deserialization process. */
2435
2436 HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
2437 if (rt->n_ref > 0)
2438 continue;
2439
2440 (void) exec_shared_runtime_free(rt);
2441 }
2442}
2443
2444int exec_runtime_make(
2445 const Unit *unit,
2446 const ExecContext *context,
2447 ExecSharedRuntime *shared,
2448 DynamicCreds *creds,
2449 ExecRuntime **ret) {
2450 _cleanup_close_pair_ int ephemeral_storage_socket[2] = EBADF_PAIR;
2451 _cleanup_free_ char *ephemeral = NULL;
2452 _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
2453 int r;
2454
2455 assert(unit);
2456 assert(context);
2457 assert(ret);
2458
2459 if (!shared && !creds && !exec_needs_ephemeral(context)) {
2460 *ret = NULL;
2461 return 0;
2462 }
2463
2464 if (exec_needs_ephemeral(context)) {
2465 r = mkdir_p("/var/lib/systemd/ephemeral-trees", 0755);
2466 if (r < 0)
2467 return r;
2468
2469 r = tempfn_random_child("/var/lib/systemd/ephemeral-trees", unit->id, &ephemeral);
2470 if (r < 0)
2471 return r;
2472
2473 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ephemeral_storage_socket) < 0)
2474 return -errno;
2475 }
2476
2477 rt = new(ExecRuntime, 1);
2478 if (!rt)
2479 return -ENOMEM;
2480
2481 *rt = (ExecRuntime) {
2482 .shared = shared,
2483 .dynamic_creds = creds,
2484 .ephemeral_copy = TAKE_PTR(ephemeral),
2485 .ephemeral_storage_socket[0] = TAKE_FD(ephemeral_storage_socket[0]),
2486 .ephemeral_storage_socket[1] = TAKE_FD(ephemeral_storage_socket[1]),
2487 };
2488
2489 *ret = TAKE_PTR(rt);
2490 return 1;
2491}
2492
2493ExecRuntime* exec_runtime_free(ExecRuntime *rt) {
2494 if (!rt)
2495 return NULL;
2496
2497 exec_shared_runtime_unref(rt->shared);
2498 dynamic_creds_unref(rt->dynamic_creds);
2499
2500 rt->ephemeral_copy = destroy_tree(rt->ephemeral_copy);
2501
2502 safe_close_pair(rt->ephemeral_storage_socket);
2503 return mfree(rt);
2504}
2505
2506ExecRuntime* exec_runtime_destroy(ExecRuntime *rt) {
2507 if (!rt)
2508 return NULL;
2509
2510 rt->shared = exec_shared_runtime_destroy(rt->shared);
2511 rt->dynamic_creds = dynamic_creds_destroy(rt->dynamic_creds);
2512 return exec_runtime_free(rt);
2513}
2514
2515void exec_runtime_clear(ExecRuntime *rt) {
2516 if (!rt)
2517 return;
2518
2519 safe_close_pair(rt->ephemeral_storage_socket);
2520 rt->ephemeral_copy = mfree(rt->ephemeral_copy);
2521}
2522
2523void exec_params_shallow_clear(ExecParameters *p) {
2524 if (!p)
2525 return;
2526
2527 /* This is called on the PID1 side, as many of the struct's FDs are only borrowed, and actually
2528 * owned by the manager or other objects, and reused across multiple units. */
2529
2530 p->environment = strv_free(p->environment);
2531 p->fd_names = strv_free(p->fd_names);
2532 p->files_env = strv_free(p->files_env);
2533 p->fds = mfree(p->fds);
2534 p->exec_fd = safe_close(p->exec_fd);
2535 p->user_lookup_fd = -EBADF;
2536 p->bpf_restrict_fs_map_fd = -EBADF;
2537 p->unit_id = mfree(p->unit_id);
2538 p->invocation_id = SD_ID128_NULL;
2539 p->invocation_id_string[0] = '\0';
2540 p->confirm_spawn = mfree(p->confirm_spawn);
2541}
2542
2543void exec_params_deep_clear(ExecParameters *p) {
2544 if (!p)
2545 return;
2546
2547 /* This is called on the sd-executor side, where everything received is owned by the process and has
2548 * to be fully cleaned up to make sanitizers and analyzers happy, as opposed as the shallow clean
2549 * function above. */
2550
2551 close_many_unset(p->fds, p->n_socket_fds + p->n_storage_fds);
2552
2553 p->cgroup_path = mfree(p->cgroup_path);
2554
2555 if (p->prefix) {
2556 free_many_charp(p->prefix, _EXEC_DIRECTORY_TYPE_MAX);
2557 p->prefix = mfree(p->prefix);
2558 }
2559
2560 p->received_credentials_directory = mfree(p->received_credentials_directory);
2561 p->received_encrypted_credentials_directory = mfree(p->received_encrypted_credentials_directory);
2562
2563 if (p->idle_pipe) {
2564 close_many_and_free(p->idle_pipe, 4);
2565 p->idle_pipe = NULL;
2566 }
2567
2568 p->stdin_fd = safe_close(p->stdin_fd);
2569 p->stdout_fd = safe_close(p->stdout_fd);
2570 p->stderr_fd = safe_close(p->stderr_fd);
2571
2572 p->notify_socket = mfree(p->notify_socket);
2573
2574 open_file_free_many(&p->open_files);
2575
2576 p->fallback_smack_process_label = mfree(p->fallback_smack_process_label);
2577
2578 exec_params_shallow_clear(p);
2579}
2580
2581void exec_directory_done(ExecDirectory *d) {
2582 if (!d)
2583 return;
2584
2585 FOREACH_ARRAY(i, d->items, d->n_items) {
2586 free(i->path);
2587 strv_free(i->symlinks);
2588 }
2589
2590 d->items = mfree(d->items);
2591 d->n_items = 0;
2592 d->mode = 0755;
2593}
2594
2595static ExecDirectoryItem *exec_directory_find(ExecDirectory *d, const char *path) {
2596 assert(d);
2597 assert(path);
2598
2599 FOREACH_ARRAY(i, d->items, d->n_items)
2600 if (path_equal(i->path, path))
2601 return i;
2602
2603 return NULL;
2604}
2605
2606int exec_directory_add(ExecDirectory *d, const char *path, const char *symlink) {
2607 _cleanup_strv_free_ char **s = NULL;
2608 _cleanup_free_ char *p = NULL;
2609 ExecDirectoryItem *existing;
2610 int r;
2611
2612 assert(d);
2613 assert(path);
2614
2615 existing = exec_directory_find(d, path);
2616 if (existing) {
2617 r = strv_extend(&existing->symlinks, symlink);
2618 if (r < 0)
2619 return r;
2620
2621 return 0; /* existing item is updated */
2622 }
2623
2624 p = strdup(path);
2625 if (!p)
2626 return -ENOMEM;
2627
2628 if (symlink) {
2629 s = strv_new(symlink);
2630 if (!s)
2631 return -ENOMEM;
2632 }
2633
2634 if (!GREEDY_REALLOC(d->items, d->n_items + 1))
2635 return -ENOMEM;
2636
2637 d->items[d->n_items++] = (ExecDirectoryItem) {
2638 .path = TAKE_PTR(p),
2639 .symlinks = TAKE_PTR(s),
2640 };
2641
2642 return 1; /* new item is added */
2643}
2644
2645static int exec_directory_item_compare_func(const ExecDirectoryItem *a, const ExecDirectoryItem *b) {
2646 assert(a);
2647 assert(b);
2648
2649 return path_compare(a->path, b->path);
2650}
2651
2652void exec_directory_sort(ExecDirectory *d) {
2653 assert(d);
2654
2655 /* Sort the exec directories to make always parent directories processed at first in
2656 * setup_exec_directory(), e.g., even if StateDirectory=foo/bar foo, we need to create foo at first,
2657 * then foo/bar. Also, set .only_create flag if one of the parent directories is contained in the
2658 * list. See also comments in setup_exec_directory() and issue #24783. */
2659
2660 if (d->n_items <= 1)
2661 return;
2662
2663 typesafe_qsort(d->items, d->n_items, exec_directory_item_compare_func);
2664
2665 for (size_t i = 1; i < d->n_items; i++)
2666 for (size_t j = 0; j < i; j++)
2667 if (path_startswith(d->items[i].path, d->items[j].path)) {
2668 d->items[i].only_create = true;
2669 break;
2670 }
2671}
2672
2673ExecCleanMask exec_clean_mask_from_string(const char *s) {
2674 ExecDirectoryType t;
2675
2676 assert(s);
2677
2678 if (streq(s, "all"))
2679 return EXEC_CLEAN_ALL;
2680 if (streq(s, "fdstore"))
2681 return EXEC_CLEAN_FDSTORE;
2682
2683 t = exec_resource_type_from_string(s);
2684 if (t < 0)
2685 return (ExecCleanMask) t;
2686
2687 return 1U << t;
2688}
2689
2690static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
2691 [EXEC_INPUT_NULL] = "null",
2692 [EXEC_INPUT_TTY] = "tty",
2693 [EXEC_INPUT_TTY_FORCE] = "tty-force",
2694 [EXEC_INPUT_TTY_FAIL] = "tty-fail",
2695 [EXEC_INPUT_SOCKET] = "socket",
2696 [EXEC_INPUT_NAMED_FD] = "fd",
2697 [EXEC_INPUT_DATA] = "data",
2698 [EXEC_INPUT_FILE] = "file",
2699};
2700
2701DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
2702
2703static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
2704 [EXEC_OUTPUT_INHERIT] = "inherit",
2705 [EXEC_OUTPUT_NULL] = "null",
2706 [EXEC_OUTPUT_TTY] = "tty",
2707 [EXEC_OUTPUT_KMSG] = "kmsg",
2708 [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
2709 [EXEC_OUTPUT_JOURNAL] = "journal",
2710 [EXEC_OUTPUT_JOURNAL_AND_CONSOLE] = "journal+console",
2711 [EXEC_OUTPUT_SOCKET] = "socket",
2712 [EXEC_OUTPUT_NAMED_FD] = "fd",
2713 [EXEC_OUTPUT_FILE] = "file",
2714 [EXEC_OUTPUT_FILE_APPEND] = "append",
2715 [EXEC_OUTPUT_FILE_TRUNCATE] = "truncate",
2716};
2717
2718DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
2719
2720static const char* const exec_utmp_mode_table[_EXEC_UTMP_MODE_MAX] = {
2721 [EXEC_UTMP_INIT] = "init",
2722 [EXEC_UTMP_LOGIN] = "login",
2723 [EXEC_UTMP_USER] = "user",
2724};
2725
2726DEFINE_STRING_TABLE_LOOKUP(exec_utmp_mode, ExecUtmpMode);
2727
2728static const char* const exec_preserve_mode_table[_EXEC_PRESERVE_MODE_MAX] = {
2729 [EXEC_PRESERVE_NO] = "no",
2730 [EXEC_PRESERVE_YES] = "yes",
2731 [EXEC_PRESERVE_RESTART] = "restart",
2732};
2733
2734DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode, ExecPreserveMode, EXEC_PRESERVE_YES);
2735
2736/* This table maps ExecDirectoryType to the setting it is configured with in the unit */
2737static const char* const exec_directory_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2738 [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectory",
2739 [EXEC_DIRECTORY_STATE] = "StateDirectory",
2740 [EXEC_DIRECTORY_CACHE] = "CacheDirectory",
2741 [EXEC_DIRECTORY_LOGS] = "LogsDirectory",
2742 [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectory",
2743};
2744
2745DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
2746
2747/* This table maps ExecDirectoryType to the symlink setting it is configured with in the unit */
2748static const char* const exec_directory_type_symlink_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2749 [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectorySymlink",
2750 [EXEC_DIRECTORY_STATE] = "StateDirectorySymlink",
2751 [EXEC_DIRECTORY_CACHE] = "CacheDirectorySymlink",
2752 [EXEC_DIRECTORY_LOGS] = "LogsDirectorySymlink",
2753 [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectorySymlink",
2754};
2755
2756DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_symlink, ExecDirectoryType);
2757
2758static const char* const exec_directory_type_mode_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2759 [EXEC_DIRECTORY_RUNTIME] = "RuntimeDirectoryMode",
2760 [EXEC_DIRECTORY_STATE] = "StateDirectoryMode",
2761 [EXEC_DIRECTORY_CACHE] = "CacheDirectoryMode",
2762 [EXEC_DIRECTORY_LOGS] = "LogsDirectoryMode",
2763 [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectoryMode",
2764};
2765
2766DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_mode, ExecDirectoryType);
2767
2768/* And this table maps ExecDirectoryType too, but to a generic term identifying the type of resource. This
2769 * one is supposed to be generic enough to be used for unit types that don't use ExecContext and per-unit
2770 * directories, specifically .timer units with their timestamp touch file. */
2771static const char* const exec_resource_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2772 [EXEC_DIRECTORY_RUNTIME] = "runtime",
2773 [EXEC_DIRECTORY_STATE] = "state",
2774 [EXEC_DIRECTORY_CACHE] = "cache",
2775 [EXEC_DIRECTORY_LOGS] = "logs",
2776 [EXEC_DIRECTORY_CONFIGURATION] = "configuration",
2777};
2778
2779DEFINE_STRING_TABLE_LOOKUP(exec_resource_type, ExecDirectoryType);
2780
2781static const char* const exec_keyring_mode_table[_EXEC_KEYRING_MODE_MAX] = {
2782 [EXEC_KEYRING_INHERIT] = "inherit",
2783 [EXEC_KEYRING_PRIVATE] = "private",
2784 [EXEC_KEYRING_SHARED] = "shared",
2785};
2786
2787DEFINE_STRING_TABLE_LOOKUP(exec_keyring_mode, ExecKeyringMode);