• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 19315930715

12 Nov 2025 11:39PM UTC coverage: 72.251% (-0.2%) from 72.412%
19315930715

push

github

bluca
mkosi: update debian commit reference to efdd7a637

* efdd7a6377 Install new file for upstream build
* 9ebdc6099e d/rules: enable 10-systemd-logind-root-ignore-inhibitors.rules.example on Ubuntu
* 1255cc7663 initramfs-tools: only skip chzdev rules if zdev_early=0
* 4675b281ee d/t/boot-and-services: skip apparmor test on armhf
* 214d6e37b2 d/t/boot-and-services: run transient unit to check syslog messages
* f4e196aa26 d/t/boot-and-services: tweak test_rsyslog regex
* dbd366a43e Install new files for upstream build
* bb7f8ef532 Install new files for upstream build
* efa7cee8a7 Install new file for upstream build
* 95aa1d1685 Install new file for upstream build
* b770f0f01b kernel-install: skip 55-initrd.install when an initrd generator is configured
* af8d1e3134 Update changelog for 258.1-2 release
* 2d0e73cd14 d/libnss-systemd.postinst: Ensure module is enabled for all four databases

306471 of 424176 relevant lines covered (72.25%)

1239443.53 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.28
/src/core/execute.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <fcntl.h>
4
#include <poll.h>
5
#include <sys/mman.h>
6
#include <sys/mount.h>
7
#include <sys/prctl.h>
8
#include <sys/socket.h>
9
#include <sys/stat.h>
10
#include <unistd.h>
11

12
#include "af-list.h"
13
#include "alloc-util.h"
14
#include "async.h"
15
#include "bitfield.h"
16
#include "capability-list.h"
17
#include "capability-util.h"
18
#include "cgroup-setup.h"
19
#include "coredump-util.h"
20
#include "cpu-set-util.h"
21
#include "dissect-image.h"
22
#include "dynamic-user.h"
23
#include "env-file.h"
24
#include "env-util.h"
25
#include "escape.h"
26
#include "execute.h"
27
#include "execute-serialize.h"
28
#include "fd-util.h"
29
#include "fdset.h"
30
#include "fileio.h"
31
#include "format-util.h"
32
#include "fs-util.h"
33
#include "glob-util.h"
34
#include "hexdecoct.h"
35
#include "image-policy.h"
36
#include "io-util.h"
37
#include "ioprio-util.h"
38
#include "log.h"
39
#include "manager.h"
40
#include "mkdir.h"
41
#include "namespace-util.h"
42
#include "namespace.h"
43
#include "nsflags.h"
44
#include "open-file.h"
45
#include "ordered-set.h"
46
#include "osc-context.h"
47
#include "parse-util.h"
48
#include "path-util.h"
49
#include "pidref.h"
50
#include "process-util.h"
51
#include "rlimit-util.h"
52
#include "rm-rf.h"
53
#include "seccomp-util.h"
54
#include "securebits-util.h"
55
#include "serialize.h"
56
#include "set.h"
57
#include "sort-util.h"
58
#include "string-table.h"
59
#include "string-util.h"
60
#include "strv.h"
61
#include "syslog-util.h"
62
#include "terminal-util.h"
63
#include "tmpfile-util.h"
64
#include "utmp-wtmp.h"
65
#include "vpick.h"
66

67
const char* exec_context_tty_path(const ExecContext *context) {
12,308✔
68
        assert(context);
12,308✔
69

70
        if (context->stdio_as_fds)
12,308✔
71
                return NULL;
72

73
        if (context->tty_path)
11,633✔
74
                return context->tty_path;
483✔
75

76
        return "/dev/console";
77
}
78

79
int exec_context_apply_tty_size(
1,032✔
80
                const ExecContext *context,
81
                int input_fd,
82
                int output_fd,
83
                const char *tty_path) {
84

85
        unsigned rows, cols;
1,032✔
86
        int r;
1,032✔
87

88
        assert(context);
1,032✔
89
        assert(input_fd >= 0);
1,032✔
90
        assert(output_fd >= 0);
1,032✔
91

92
        if (!isatty_safe(output_fd))
1,032✔
93
                return 0;
1,032✔
94

95
        if (!tty_path)
516✔
96
                tty_path = exec_context_tty_path(context);
261✔
97

98
        /* Preferably use explicitly configured data */
99
        rows = context->tty_rows;
516✔
100
        cols = context->tty_cols;
516✔
101

102
        /* Fill in data from kernel command line if anything is unspecified */
103
        if (tty_path && (rows == UINT_MAX || cols == UINT_MAX))
516✔
104
                (void) proc_cmdline_tty_size(
474✔
105
                                tty_path,
106
                                rows == UINT_MAX ? &rows : NULL,
107
                                cols == UINT_MAX ? &cols : NULL);
108

109
        /* If we got nothing so far and we are talking to a physical device, then let's query dimensions from
110
         * the ANSI terminal driver. Note that we will not bother with this in case terminal reset via ansi
111
         * sequences is not enabled, as the DSR logic relies on ANSI sequences after all, and if we shall not
112
         * use those during initialization we need to skip it. */
113
        if (rows == UINT_MAX && cols == UINT_MAX &&
657✔
114
            exec_context_shall_ansi_seq_reset(context) &&
244✔
115
            isatty_safe(input_fd)) {
103✔
116
                r = terminal_get_size_by_dsr(input_fd, output_fd, &rows, &cols);
103✔
117
                if (r < 0)
103✔
118
                        log_debug_errno(r, "Failed to get terminal size by DSR, ignoring: %m");
103✔
119
        }
120

121
        return terminal_set_size_fd(output_fd, tty_path, rows, cols);
516✔
122
}
123

124
void exec_context_tty_reset(const ExecContext *context, const ExecParameters *parameters, sd_id128_t invocation_id) {
11,346✔
125
        _cleanup_close_ int _fd = -EBADF, lock_fd = -EBADF;
22,692✔
126
        int fd, r;
11,346✔
127

128
        assert(context);
11,346✔
129

130
        /* Note that this is potentially a "destructive" reset of a TTY device. It's about getting rid of the
131
         * remains of previous uses of the TTY. It's *not* about getting things set up for coming uses. We'll
132
         * potentially invalidate the TTY here through hangups or VT disallocations, and hence do not keep a
133
         * continuous fd open. */
134

135
        const char *path = exec_context_tty_path(context);
11,346✔
136

137
        if (parameters && parameters->stdout_fd >= 0 && isatty_safe(parameters->stdout_fd))
11,346✔
138
                fd = parameters->stdout_fd;
21✔
139
        else if (path && exec_context_has_tty(context)) {
11,325✔
140
                fd = _fd = open_terminal(path, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
255✔
141
                if (fd < 0)
255✔
142
                        return (void) log_debug_errno(fd, "Failed to open terminal '%s', ignoring: %m", path);
×
143
        } else
144
                return;   /* nothing to do */
145

146
        /* Take a synchronization lock for the duration of the setup that we do here.
147
         * systemd-vconsole-setup.service also takes the lock to avoid being interrupted. We open a new fd
148
         * that will be closed automatically, and operate on it for convenience. */
149
        lock_fd = lock_dev_console();
276✔
150
        if (ERRNO_IS_NEG_PRIVILEGE(lock_fd))
276✔
151
                log_debug_errno(lock_fd, "No privileges to lock /dev/console, proceeding without lock: %m");
×
152
        else if (ERRNO_IS_NEG_DEVICE_ABSENT(lock_fd))
276✔
153
                log_debug_errno(lock_fd, "Device /dev/console does not exist, proceeding without lock: %m");
×
154
        else if (lock_fd < 0)
276✔
155
                log_warning_errno(lock_fd, "Failed to lock /dev/console, proceeding without lock: %m");
×
156

157
        if (context->tty_reset)
276✔
158
                (void) terminal_reset_defensive(
217✔
159
                                fd,
160
                                TERMINAL_RESET_SWITCH_TO_TEXT |
161
                                (exec_context_shall_ansi_seq_reset(context) ? TERMINAL_RESET_FORCE_ANSI_SEQ : TERMINAL_RESET_AVOID_ANSI_SEQ));
214✔
162

163
        r = exec_context_apply_tty_size(context, fd, fd, path);
276✔
164
        if (r < 0)
276✔
165
                log_debug_errno(r, "Failed to configure TTY dimensions, ignoring: %m");
×
166

167
        if (!sd_id128_is_null(invocation_id) && exec_context_shall_ansi_seq_reset(context)) {
517✔
168
                sd_id128_t context_id;
21✔
169

170
                r = osc_context_id_from_invocation_id(invocation_id, &context_id);
21✔
171
                if (r < 0)
21✔
172
                        log_debug_errno(r, "Failed to derive context ID from invocation ID, ignoring: %m");
21✔
173
                else {
174
                        _cleanup_free_ char *seq = NULL;
21✔
175

176
                        r = osc_context_close(context_id, &seq);
21✔
177
                        if (r < 0)
21✔
178
                                log_debug_errno(r, "Failed to acquire OSC close sequence, ignoring: %m");
×
179
                        else
180
                                (void) loop_write(fd, seq, SIZE_MAX);
21✔
181
                }
182
        }
183

184
        if (context->tty_vhangup)
276✔
185
                (void) terminal_vhangup_fd(fd);
99✔
186

187
        /* We don't need the fd anymore now, and it potentially points to a hungup TTY anyway, let's close it
188
         * hence. */
189
        _fd = safe_close(_fd);
276✔
190

191
        if (context->tty_vt_disallocate && path)
276✔
192
                (void) vt_disallocate(path);
51✔
193
}
194

195
bool exec_needs_network_namespace(const ExecContext *context) {
57,356✔
196
        assert(context);
57,356✔
197

198
        return context->private_network || context->network_namespace_path;
57,356✔
199
}
200

201
static bool exec_needs_ephemeral(const ExecContext *context) {
5,540✔
202
        return (context->root_image || context->root_directory) && context->root_ephemeral;
5,540✔
203
}
204

205
bool exec_needs_ipc_namespace(const ExecContext *context) {
52,198✔
206
        assert(context);
52,198✔
207

208
        return context->private_ipc || context->ipc_namespace_path;
52,198✔
209
}
210

211
static bool needs_cgroup_namespace(ProtectControlGroups i) {
129,067✔
212
        return IN_SET(i, PROTECT_CONTROL_GROUPS_PRIVATE, PROTECT_CONTROL_GROUPS_STRICT);
129,067✔
213
}
214

215
ProtectControlGroups exec_get_protect_control_groups(const ExecContext *context) {
79,631✔
216
        assert(context);
79,631✔
217

218
        /* If cgroup namespace is configured via ProtectControlGroups=private or strict but we can't actually
219
         * use cgroup namespace, we ignore the setting and do not unshare the namespace.
220
         * ProtectControlGroups=private and strict get downgraded to no and yes respectively. This ensures
221
         * that strict always gets a read-only mount of /sys/fs/cgroup/. */
222
        if (needs_cgroup_namespace(context->protect_control_groups) && !namespace_type_supported(NAMESPACE_CGROUP)) {
79,631✔
223
                if (context->protect_control_groups == PROTECT_CONTROL_GROUPS_PRIVATE)
×
224
                        return PROTECT_CONTROL_GROUPS_NO;
225
                if (context->protect_control_groups == PROTECT_CONTROL_GROUPS_STRICT)
×
226
                        return PROTECT_CONTROL_GROUPS_YES;
227
        }
228
        return context->protect_control_groups;
79,631✔
229
}
230

231
bool exec_needs_cgroup_namespace(const ExecContext *context) {
49,436✔
232
        assert(context);
49,436✔
233

234
        return needs_cgroup_namespace(exec_get_protect_control_groups(context));
49,436✔
235
}
236

237
bool exec_needs_cgroup_mount(const ExecContext *context) {
26,224✔
238
        assert(context);
26,224✔
239

240
        return exec_get_protect_control_groups(context) != PROTECT_CONTROL_GROUPS_NO;
26,224✔
241
}
242

243
bool exec_is_cgroup_mount_read_only(const ExecContext *context) {
1,986✔
244
        assert(context);
1,986✔
245

246
        return IN_SET(exec_get_protect_control_groups(context), PROTECT_CONTROL_GROUPS_YES, PROTECT_CONTROL_GROUPS_STRICT);
1,986✔
247
}
248

249
bool exec_needs_pid_namespace(const ExecContext *context, const ExecParameters *params) {
85,218✔
250
        assert(context);
85,218✔
251

252
        /* PID namespaces don't really make sense for control processes so let's not use them for those. */
253
        if (params && FLAGS_SET(params->flags, EXEC_IS_CONTROL))
85,218✔
254
                return false;
255

256
        return context->private_pids != PRIVATE_PIDS_NO && namespace_type_supported(NAMESPACE_PID);
76,150✔
257
}
258

259
bool exec_needs_mount_namespace(
31,089✔
260
                const ExecContext *context,
261
                const ExecParameters *params,
262
                const ExecRuntime *runtime) {
263

264
        assert(context);
31,089✔
265

266
        if (context->root_image)
31,089✔
267
                return true;
268

269
        if (context->root_directory_as_fd)
31,039✔
270
                return true;
271

272
        if (!strv_isempty(context->read_write_paths) ||
31,039✔
273
            !strv_isempty(context->read_only_paths) ||
28,908✔
274
            !strv_isempty(context->inaccessible_paths) ||
28,895✔
275
            !strv_isempty(context->exec_paths) ||
28,870✔
276
            !strv_isempty(context->no_exec_paths))
28,870✔
277
                return true;
278

279
        if (context->n_bind_mounts > 0)
28,870✔
280
                return true;
281

282
        if (context->n_temporary_filesystems > 0)
28,813✔
283
                return true;
284

285
        if (context->n_mount_images > 0)
28,654✔
286
                return true;
287

288
        if (context->n_extension_images > 0)
28,631✔
289
                return true;
290

291
        if (!strv_isempty(context->extension_directories))
28,602✔
292
                return true;
293

294
        if (!IN_SET(context->mount_propagation_flag, 0, MS_SHARED))
28,597✔
295
                return true;
296

297
        if (context->private_tmp == PRIVATE_TMP_DISCONNECTED)
28,597✔
298
                return true;
299

300
        if (context->private_tmp == PRIVATE_TMP_CONNECTED && runtime && runtime->shared && (runtime->shared->tmp_dir || runtime->shared->var_tmp_dir))
27,966✔
301
                return true;
302

303
        if (context->private_devices ||
27,463✔
304
            context->private_mounts > 0 ||
27,097✔
305
            (context->private_mounts < 0 && exec_needs_network_namespace(context)) ||
26,617✔
306
            context->protect_system != PROTECT_SYSTEM_NO ||
26,582✔
307
            context->protect_home != PROTECT_HOME_NO ||
26,582✔
308
            context->protect_kernel_tunables ||
26,582✔
309
            context->protect_kernel_modules ||
26,582✔
310
            context->protect_kernel_logs ||
49,829✔
311
            exec_needs_cgroup_mount(context) ||
24,913✔
312
            context->protect_proc != PROTECT_PROC_DEFAULT ||
24,895✔
313
            context->proc_subset != PROC_SUBSET_ALL ||
24,847✔
314
            context->private_bpf != PRIVATE_BPF_NO ||
49,676✔
315
            exec_needs_ipc_namespace(context) ||
49,676✔
316
            exec_needs_pid_namespace(context, params))
24,838✔
317
                return true;
2,660✔
318

319
        if (context->root_directory) {
24,803✔
320
                if (exec_context_get_effective_mount_apivfs(context))
5✔
321
                        return true;
322

323
                for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
×
324
                        if (params && !params->prefix[t])
×
325
                                continue;
×
326

327
                        if (context->directories[t].n_items > 0)
×
328
                                return true;
329
                }
330
        }
331

332
        if (context->dynamic_user &&
24,798✔
333
            (context->directories[EXEC_DIRECTORY_STATE].n_items > 0 ||
×
334
             context->directories[EXEC_DIRECTORY_CACHE].n_items > 0 ||
×
335
             context->directories[EXEC_DIRECTORY_LOGS].n_items > 0))
×
336
                return true;
337

338
        if (exec_context_get_effective_bind_log_sockets(context))
24,798✔
339
                return true;
340

341
        for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++)
148,420✔
342
                FOREACH_ARRAY(i, context->directories[t].items, context->directories[t].n_items)
128,446✔
343
                        if (FLAGS_SET(i->flags, EXEC_DIRECTORY_READ_ONLY))
4,818✔
344
                                return true;
345

346
        return false;
347
}
348

349
const char* exec_get_private_notify_socket_path(const ExecContext *context, const ExecParameters *params, bool needs_sandboxing) {
3,847✔
350
        assert(context);
3,847✔
351
        assert(params);
3,847✔
352

353
        if (!params->notify_socket)
3,847✔
354
                return NULL;
355

356
        if (!needs_sandboxing)
3,161✔
357
                return NULL;
358

359
        if (!context->root_directory && !context->root_image && !context->root_directory_as_fd)
3,161✔
360
                return NULL;
361

362
        if (!exec_context_get_effective_mount_apivfs(context))
×
363
                return NULL;
364

365
        if (!FLAGS_SET(params->flags, EXEC_APPLY_CHROOT))
×
366
                return NULL;
×
367

368
        return "/run/host/notify";
369
}
370

371
int exec_log_level_max_with_exec_params(const ExecContext *context, const ExecParameters *params) {
19,886✔
372
        assert(params);
19,886✔
373

374
        if (params->debug_invocation)
19,886✔
375
                return LOG_DEBUG;
376

377
        return exec_log_level_max(context);
19,882✔
378
}
379

380
int exec_log_level_max(const ExecContext *context) {
19,928✔
381
        assert(context);
19,928✔
382
        return context->log_level_max < 0 ? log_get_max_level() : context->log_level_max;
19,928✔
383
}
384

385
bool exec_directory_is_private(const ExecContext *context, ExecDirectoryType type) {
9,866✔
386
        assert(context);
9,866✔
387

388
        if (!context->dynamic_user)
9,866✔
389
                return false;
390

391
        if (!EXEC_DIRECTORY_TYPE_SHALL_CHOWN(type))
104✔
392
                return false;
393

394
        if (type == EXEC_DIRECTORY_RUNTIME && context->runtime_directory_preserve_mode == EXEC_PRESERVE_NO)
98✔
395
                return false;
14✔
396

397
        return true;
398
}
399

400
int exec_params_needs_control_subcgroup(const ExecParameters *params) {
2,157✔
401
        /* Keep this in sync with exec_params_get_cgroup_path(). */
402
        return FLAGS_SET(params->flags, EXEC_CGROUP_DELEGATE|EXEC_CONTROL_CGROUP|EXEC_IS_CONTROL);
2,157✔
403
}
404

405
int exec_params_get_cgroup_path(
10,653✔
406
                const ExecParameters *params,
407
                const CGroupContext *c,
408
                const char *prefix,
409
                char **ret) {
410

411
        const char *subgroup = NULL;
10,653✔
412
        char *p;
10,653✔
413

414
        assert(params);
10,653✔
415
        assert(c);
10,653✔
416
        assert(ret);
10,653✔
417

418
        /* If we are called for a unit where cgroup delegation is on, and the payload created its own populated
419
         * subcgroup (which we expect it to do, after all it asked for delegation), then we cannot place the control
420
         * processes started after the main unit's process in the unit's main cgroup because it is now an inner one,
421
         * and inner cgroups may not contain processes. Hence, if delegation is on, and this is a control process,
422
         * let's use ".control" as subcgroup instead. Note that we do so only for ExecStartPost=, ExecReload=,
423
         * ExecStop=, ExecStopPost=, i.e. for the commands where the main process is already forked. For ExecStartPre=
424
         * this is not necessary, the cgroup is still empty. We distinguish these cases with the EXEC_CONTROL_CGROUP
425
         * flag, which is only passed for the former statements, not for the latter. */
426

427
        /* Keep this in sync with exec_params_needs_control_subcgroup(). */
428
        if (FLAGS_SET(params->flags, EXEC_CGROUP_DELEGATE) && (FLAGS_SET(params->flags, EXEC_CONTROL_CGROUP) || c->delegate_subgroup)) {
10,653✔
429
                if (FLAGS_SET(params->flags, EXEC_IS_CONTROL))
714✔
430
                        subgroup = ".control";
431
                else
432
                        subgroup = c->delegate_subgroup;
662✔
433
        }
434

435
        if (subgroup)
662✔
436
                p = path_join(prefix, subgroup);
714✔
437
        else
438
                p = strdup(strempty(prefix));
9,947✔
439
        if (!p)
10,653✔
440
                return -ENOMEM;
441

442
        *ret = p;
10,653✔
443
        return !!subgroup;
10,653✔
444
}
445

446
bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c) {
1,490✔
447
        assert(c);
1,490✔
448

449
        return c->cpu_affinity_from_numa;
1,490✔
450
}
451

452
static void log_command_line(Unit *unit, const char *msg, const char *executable, char **argv) {
2,127✔
453
        assert(unit);
2,127✔
454
        assert(msg);
2,127✔
455
        assert(executable);
2,127✔
456

457
        if (!DEBUG_LOGGING)
2,127✔
458
                return;
2,127✔
459

460
        _cleanup_free_ char *cmdline = quote_command_line(argv, SHELL_ESCAPE_EMPTY);
4,254✔
461

462
        log_unit_struct(unit, LOG_DEBUG,
2,127✔
463
                        LOG_ITEM("EXECUTABLE=%s", executable),
464
                        LOG_UNIT_MESSAGE(unit, "%s: %s", msg, strnull(cmdline)),
465
                        LOG_UNIT_INVOCATION_ID(unit));
466
}
467

468
static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***l);
469

470
int exec_spawn(
2,127✔
471
                Unit *unit,
472
                ExecCommand *command,
473
                const ExecContext *context,
474
                ExecParameters *params,
475
                ExecRuntime *runtime,
476
                const CGroupContext *cgroup_context,
477
                PidRef *ret) {
478

479
        _cleanup_free_ char *subcgroup_path = NULL, *max_log_levels = NULL;
2,127✔
480
        _cleanup_fdset_free_ FDSet *fdset = NULL;
×
481
        _cleanup_fclose_ FILE *f = NULL;
2,127✔
482
        int r;
2,127✔
483

484
        assert(unit);
2,127✔
485
        assert(unit->manager);
2,127✔
486
        assert(unit->manager->executor_fd >= 0);
2,127✔
487
        assert(unit->manager->executor_path);
2,127✔
488
        assert(command);
2,127✔
489
        assert(context);
2,127✔
490
        assert(params);
2,127✔
491
        assert(params->fds || (params->n_socket_fds + params->n_stashed_fds == 0 && !params->fd_names));
2,127✔
492
        assert(params->n_stashed_fds == 0 || FLAGS_SET(params->flags, EXEC_PASS_FDS));
2,127✔
493
        assert(!params->files_env); /* We fill this field, ensure it comes NULL-initialized to us */
2,127✔
494
        assert(ret);
2,127✔
495

496
        LOG_CONTEXT_PUSH_UNIT(unit);
4,254✔
497

498
        r = exec_context_load_environment(unit, context, &params->files_env);
2,127✔
499
        if (r < 0)
2,127✔
500
                return log_unit_error_errno(unit, r, "Failed to load environment files: %m");
×
501

502
        /* We won't know the real executable path until we create the mount namespace in the child, but we
503
           want to log from the parent, so we use the possibly inaccurate path here. */
504
        log_command_line(unit, "About to execute", command->path, command->argv);
2,127✔
505

506
        /* We cannot spawn the main service process into the subcgroup as it might need to unshare the cgroup
507
         * namespace first if one is configured to make sure the root of the cgroup namespace is the service
508
         * cgroup and not the subcgroup. However, when running control commands on a live service, the
509
         * commands have to be spawned inside a subcgroup, otherwise we violate the no inner processes rule
510
         * of cgroupv2 as the main service process might already have enabled controllers by writing to
511
         * cgroup.subtree_control. */
512

513
        const char *cgtarget;
2,127✔
514
        if (exec_params_needs_control_subcgroup(params)) {
2,127✔
515
                r = exec_params_get_cgroup_path(params, cgroup_context, params->cgroup_path, &subcgroup_path);
4✔
516
                if (r < 0)
4✔
517
                        return log_unit_error_errno(unit, r, "Failed to acquire subcgroup path: %m");
×
518
                if (r > 0) {
4✔
519
                        /* If there's a subcgroup, then let's create it here now (the main cgroup was already
520
                         * realized by the unit logic) */
521

522
                        r = cg_create(subcgroup_path);
4✔
523
                        if (r < 0)
4✔
524
                                return log_unit_error_errno(unit, r, "Failed to create subcgroup '%s': %m", subcgroup_path);
×
525
                }
526

527
                cgtarget = subcgroup_path;
4✔
528
        } else
529
                cgtarget = params->cgroup_path;
2,123✔
530

531
        /* In order to avoid copy-on-write traps and OOM-kills when pid1's memory.current is above the
532
         * child's memory.max, serialize all the state needed to start the unit, and pass it to the
533
         * systemd-executor binary. clone() with CLONE_VM + CLONE_VFORK will pause the parent until the exec
534
         * and ensure all memory is shared. The child immediately execs the new binary so the delay should
535
         * be minimal. If glibc 2.39 is available pidfd_spawn() is used in order to get a race-free pid fd
536
         * and to clone directly into the target cgroup (if we booted with cgroupv2). */
537

538
        r = open_serialization_file("sd-executor-state", &f);
2,127✔
539
        if (r < 0)
2,127✔
540
                return log_unit_error_errno(unit, r, "Failed to open serialization stream: %m");
×
541

542
        fdset = fdset_new();
2,127✔
543
        if (!fdset)
2,127✔
544
                return log_oom();
×
545

546
        r = exec_serialize_invocation(f, fdset, context, command, params, runtime, cgroup_context);
2,127✔
547
        if (r < 0)
2,127✔
548
                return log_unit_error_errno(unit, r, "Failed to serialize parameters: %m");
×
549

550
        r = finish_serialization_file(f);
2,127✔
551
        if (r < 0)
2,127✔
552
                return log_unit_error_errno(unit, r, "Failed to finish serialization stream: %m");
×
553

554
        r = fd_cloexec(fileno(f), false);
2,127✔
555
        if (r < 0)
2,127✔
556
                return log_unit_error_errno(unit, r, "Failed to set O_CLOEXEC on serialization fd: %m");
×
557

558
        r = fdset_cloexec(fdset, false);
2,127✔
559
        if (r < 0)
2,127✔
560
                return log_unit_error_errno(unit, r, "Failed to set O_CLOEXEC on serialized fds: %m");
×
561

562
        /* If LogLevelMax= is specified, then let's use the specified log level at the beginning of the
563
         * executor process. To achieve that the specified log level is passed as an argument, rather than
564
         * the one for the manager process. */
565
        r = log_max_levels_to_string(context->log_level_max >= 0 ? context->log_level_max : log_get_max_level(), &max_log_levels);
2,127✔
566
        if (r < 0)
2,127✔
567
                return log_unit_error_errno(unit, r, "Failed to convert max log levels to string: %m");
×
568

569
        char serialization_fd_number[DECIMAL_STR_MAX(int)];
2,127✔
570
        xsprintf(serialization_fd_number, "%i", fileno(f));
2,127✔
571

572
        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
2,127✔
573
        dual_timestamp start_timestamp;
2,127✔
574

575
        /* Restore the original ambient capability set the manager was started with to pass it to
576
         * sd-executor. */
577
        r = capability_ambient_set_apply(unit->manager->saved_ambient_set, /* also_inherit= */ false);
2,127✔
578
        if (r < 0)
2,127✔
579
                return log_unit_error_errno(unit, r, "Failed to apply the starting ambient set: %m");
×
580

581
        /* Record the start timestamp before we fork so that it is guaranteed to be earlier than the
582
         * handoff timestamp. */
583
        dual_timestamp_now(&start_timestamp);
2,127✔
584

585
        /* The executor binary is pinned, to avoid compatibility problems during upgrades. */
586
        r = posix_spawn_wrapper(
2,127✔
587
                        FORMAT_PROC_FD_PATH(unit->manager->executor_fd),
2,127✔
588
                        STRV_MAKE(unit->manager->executor_path,
2,127✔
589
                                  "--deserialize", serialization_fd_number,
590
                                  "--log-level", max_log_levels,
591
                                  "--log-target", log_target_to_string(manager_get_executor_log_target(unit->manager))),
592
                        environ,
593
                        cgtarget,
594
                        &pidref);
595

596
        /* Drop the ambient set again, so no processes other than sd-executore spawned from the manager inherit it. */
597
        (void) capability_ambient_set_apply(0, /* also_inherit= */ false);
2,127✔
598

599
        if (r == -EUCLEAN && cgtarget)
2,127✔
600
                return log_unit_error_errno(unit, r,
×
601
                                            "Failed to spawn process into cgroup '%s', because the cgroup "
602
                                            "or one of its parents or siblings is in the threaded mode.",
603
                                            cgtarget);
604
        if (r < 0)
2,127✔
605
                return log_unit_error_errno(unit, r, "Failed to spawn executor: %m");
×
606
        /* We add the new process to the cgroup both in the child (so that we can be sure that no user code is ever
607
         * executed outside of the cgroup) and in the parent (so that we can be sure that when we kill the cgroup the
608
         * process will be killed too). */
609
        if (r == 0 && cgtarget)
2,127✔
610
                (void) cg_attach(cgtarget, pidref.pid);
×
611
        /* r > 0: Already in the right cgroup thanks to CLONE_INTO_CGROUP */
612

613
        log_unit_debug(unit, "Forked %s as " PID_FMT " (%s CLONE_INTO_CGROUP)",
2,127✔
614
                       command->path, pidref.pid, r > 0 ? "via" : "without");
615

616
        exec_status_start(&command->exec_status, pidref.pid, &start_timestamp);
2,127✔
617

618
        *ret = TAKE_PIDREF(pidref);
2,127✔
619
        return 0;
2,127✔
620
}
621

622
void exec_context_init(ExecContext *c) {
58,358✔
623
        assert(c);
58,358✔
624

625
        /* When initializing a bool member to 'true', make sure to serialize in execute-serialize.c using
626
         * serialize_bool() instead of serialize_bool_elide(). */
627

628
        *c = (ExecContext) {
58,358✔
629
                .umask = 0022,
630
                .ioprio = IOPRIO_DEFAULT_CLASS_AND_PRIO,
58,358✔
631
                .cpu_sched_policy = SCHED_OTHER,
632
                .syslog_priority = LOG_DAEMON|LOG_INFO,
633
                .syslog_level_prefix = true,
634
                .ignore_sigpipe = true,
635
                .timer_slack_nsec = NSEC_INFINITY,
636
                .personality = PERSONALITY_INVALID,
637
                .timeout_clean_usec = USEC_INFINITY,
638
                .capability_bounding_set = CAP_MASK_ALL,
639
                .restrict_namespaces = NAMESPACE_FLAGS_INITIAL,
640
                .delegate_namespaces = NAMESPACE_FLAGS_INITIAL,
641
                .log_level_max = -1,
642
#if HAVE_SECCOMP
643
                .syscall_errno = SECCOMP_ERROR_NUMBER_KILL,
644
#endif
645
                .tty_rows = UINT_MAX,
646
                .tty_cols = UINT_MAX,
647
                .private_mounts = -1,
648
                .mount_apivfs = -1,
649
                .bind_log_sockets = -1,
650
                .memory_ksm = -1,
651
                .private_var_tmp = _PRIVATE_TMP_INVALID,
652
                .set_login_environment = -1,
653
        };
654

655
        FOREACH_ARRAY(d, c->directories, _EXEC_DIRECTORY_TYPE_MAX)
350,148✔
656
                d->mode = 0755;
291,790✔
657

658
        numa_policy_reset(&c->numa_policy);
58,358✔
659

660
        assert_cc(NAMESPACE_FLAGS_INITIAL != NAMESPACE_FLAGS_ALL);
58,358✔
661
}
58,358✔
662

663
void exec_context_done(ExecContext *c) {
48,448✔
664
        assert(c);
48,448✔
665

666
        c->environment = strv_free(c->environment);
48,448✔
667
        c->environment_files = strv_free(c->environment_files);
48,448✔
668
        c->pass_environment = strv_free(c->pass_environment);
48,448✔
669
        c->unset_environment = strv_free(c->unset_environment);
48,448✔
670

671
        rlimit_free_all(c->rlimit);
48,448✔
672

673
        for (size_t l = 0; l < 3; l++) {
193,792✔
674
                c->stdio_fdname[l] = mfree(c->stdio_fdname[l]);
145,344✔
675
                c->stdio_file[l] = mfree(c->stdio_file[l]);
145,344✔
676
        }
677

678
        c->working_directory = mfree(c->working_directory);
48,448✔
679
        c->root_directory = mfree(c->root_directory);
48,448✔
680
        c->root_image = mfree(c->root_image);
48,448✔
681
        c->root_image_options = mount_options_free_all(c->root_image_options);
48,448✔
682
        c->root_hash = mfree(c->root_hash);
48,448✔
683
        c->root_hash_size = 0;
48,448✔
684
        c->root_hash_path = mfree(c->root_hash_path);
48,448✔
685
        c->root_hash_sig = mfree(c->root_hash_sig);
48,448✔
686
        c->root_hash_sig_size = 0;
48,448✔
687
        c->root_hash_sig_path = mfree(c->root_hash_sig_path);
48,448✔
688
        c->root_verity = mfree(c->root_verity);
48,448✔
689
        c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
48,448✔
690
        c->extension_directories = strv_free(c->extension_directories);
48,448✔
691
        c->tty_path = mfree(c->tty_path);
48,448✔
692
        c->syslog_identifier = mfree(c->syslog_identifier);
48,448✔
693
        c->user = mfree(c->user);
48,448✔
694
        c->group = mfree(c->group);
48,448✔
695

696
        c->supplementary_groups = strv_free(c->supplementary_groups);
48,448✔
697

698
        c->pam_name = mfree(c->pam_name);
48,448✔
699

700
        c->read_only_paths = strv_free(c->read_only_paths);
48,448✔
701
        c->read_write_paths = strv_free(c->read_write_paths);
48,448✔
702
        c->inaccessible_paths = strv_free(c->inaccessible_paths);
48,448✔
703
        c->exec_paths = strv_free(c->exec_paths);
48,448✔
704
        c->no_exec_paths = strv_free(c->no_exec_paths);
48,448✔
705
        c->exec_search_path = strv_free(c->exec_search_path);
48,448✔
706

707
        bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
48,448✔
708
        c->bind_mounts = NULL;
48,448✔
709
        c->n_bind_mounts = 0;
48,448✔
710
        temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
48,448✔
711
        c->temporary_filesystems = NULL;
48,448✔
712
        c->n_temporary_filesystems = 0;
48,448✔
713
        c->mount_images = mount_image_free_many(c->mount_images, &c->n_mount_images);
48,448✔
714

715
        cpu_set_done(&c->cpu_set);
48,448✔
716
        numa_policy_reset(&c->numa_policy);
48,448✔
717

718
        c->utmp_id = mfree(c->utmp_id);
48,448✔
719
        c->selinux_context = mfree(c->selinux_context);
48,448✔
720
        c->apparmor_profile = mfree(c->apparmor_profile);
48,448✔
721
        c->smack_process_label = mfree(c->smack_process_label);
48,448✔
722

723
        c->restrict_filesystems = set_free(c->restrict_filesystems);
48,448✔
724

725
        c->syscall_filter = hashmap_free(c->syscall_filter);
48,448✔
726
        c->syscall_archs = set_free(c->syscall_archs);
48,448✔
727
        c->syscall_log = hashmap_free(c->syscall_log);
48,448✔
728
        c->address_families = set_free(c->address_families);
48,448✔
729

730
        FOREACH_ARRAY(d, c->directories, _EXEC_DIRECTORY_TYPE_MAX)
290,688✔
731
                exec_directory_done(d);
242,240✔
732

733
        c->log_level_max = -1;
48,448✔
734

735
        exec_context_free_log_extra_fields(c);
48,448✔
736
        c->log_filter_allowed_patterns = set_free(c->log_filter_allowed_patterns);
48,448✔
737
        c->log_filter_denied_patterns = set_free(c->log_filter_denied_patterns);
48,448✔
738

739
        c->log_ratelimit = (RateLimit) {};
48,448✔
740

741
        c->stdin_data = mfree(c->stdin_data);
48,448✔
742
        c->stdin_data_size = 0;
48,448✔
743

744
        c->user_namespace_path = mfree(c->user_namespace_path);
48,448✔
745
        c->network_namespace_path = mfree(c->network_namespace_path);
48,448✔
746
        c->ipc_namespace_path = mfree(c->ipc_namespace_path);
48,448✔
747

748
        c->log_namespace = mfree(c->log_namespace);
48,448✔
749

750
        c->load_credentials = hashmap_free(c->load_credentials);
48,448✔
751
        c->set_credentials = hashmap_free(c->set_credentials);
48,448✔
752
        c->import_credentials = ordered_set_free(c->import_credentials);
48,448✔
753

754
        c->root_image_policy = image_policy_free(c->root_image_policy);
48,448✔
755
        c->mount_image_policy = image_policy_free(c->mount_image_policy);
48,448✔
756
        c->extension_image_policy = image_policy_free(c->extension_image_policy);
48,448✔
757

758
        c->private_hostname = mfree(c->private_hostname);
48,448✔
759
}
48,448✔
760

761
int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) {
5,764✔
762
        assert(c);
5,764✔
763

764
        if (!runtime_prefix)
5,764✔
765
                return 0;
766

767
        FOREACH_ARRAY(i, c->directories[EXEC_DIRECTORY_RUNTIME].items, c->directories[EXEC_DIRECTORY_RUNTIME].n_items) {
5,765✔
768
                _cleanup_free_ char *p = NULL;
1✔
769

770
                if (exec_directory_is_private(c, EXEC_DIRECTORY_RUNTIME))
1✔
771
                        p = path_join(runtime_prefix, "private", i->path);
×
772
                else
773
                        p = path_join(runtime_prefix, i->path);
1✔
774
                if (!p)
1✔
775
                        return -ENOMEM;
776

777
                /* We execute this synchronously, since we need to be sure this is gone when we start the
778
                 * service next. */
779
                (void) rm_rf(p, REMOVE_ROOT);
1✔
780

781
                STRV_FOREACH(symlink, i->symlinks) {
1✔
782
                        _cleanup_free_ char *symlink_abs = NULL;
×
783

784
                        if (exec_directory_is_private(c, EXEC_DIRECTORY_RUNTIME))
×
785
                                symlink_abs = path_join(runtime_prefix, "private", *symlink);
×
786
                        else
787
                                symlink_abs = path_join(runtime_prefix, *symlink);
×
788
                        if (!symlink_abs)
×
789
                                return -ENOMEM;
×
790

791
                        (void) unlink(symlink_abs);
×
792
                }
793
        }
794

795
        return 0;
796
}
797

798
int exec_context_destroy_mount_ns_dir(Unit *u) {
12,176✔
799
        _cleanup_free_ char *p = NULL;
12,176✔
800

801
        if (!u || !MANAGER_IS_SYSTEM(u->manager))
12,176✔
802
                return 0;
803

804
        p = path_join("/run/systemd/propagate/", u->id);
2,202✔
805
        if (!p)
2,202✔
806
                return -ENOMEM;
807

808
        /* This is only filled transiently (see mount_in_namespace()), should be empty or even non-existent. */
809
        if (rmdir(p) < 0 && errno != ENOENT)
2,202✔
810
                log_unit_debug_errno(u, errno, "Unable to remove propagation dir '%s', ignoring: %m", p);
×
811

812
        return 0;
813
}
814

815
void exec_command_done(ExecCommand *c) {
102,620✔
816
        assert(c);
102,620✔
817

818
        c->path = mfree(c->path);
102,620✔
819
        c->argv = strv_free(c->argv);
102,620✔
820
}
102,620✔
821

822
void exec_command_done_array(ExecCommand *c, size_t n) {
28,772✔
823
        FOREACH_ARRAY(i, c, n)
115,086✔
824
                exec_command_done(i);
86,314✔
825
}
28,772✔
826

827
ExecCommand* exec_command_free(ExecCommand *c) {
16,274✔
828
        if (!c)
16,274✔
829
                return NULL;
830

831
        exec_command_done(c);
16,274✔
832
        return mfree(c);
16,274✔
833
}
834

835
ExecCommand* exec_command_free_list(ExecCommand *c) {
138,640✔
836
        ExecCommand *i;
138,640✔
837

838
        while ((i = LIST_POP(command, c)))
154,914✔
839
                exec_command_free(i);
16,274✔
840

841
        return NULL;
138,640✔
842
}
843

844
void exec_command_free_array(ExecCommand **c, size_t n) {
19,644✔
845
        FOREACH_ARRAY(i, c, n)
158,268✔
846
                *i = exec_command_free_list(*i);
138,624✔
847
}
19,644✔
848

849
void exec_command_reset_status_array(ExecCommand *c, size_t n) {
7,427✔
850
        FOREACH_ARRAY(i, c, n)
29,707✔
851
                exec_status_reset(&i->exec_status);
22,280✔
852
}
7,427✔
853

854
void exec_command_reset_status_list_array(ExecCommand **c, size_t n) {
4,967✔
855
        FOREACH_ARRAY(i, c, n)
35,265✔
856
                LIST_FOREACH(command, z, *i)
32,361✔
857
                        exec_status_reset(&z->exec_status);
2,063✔
858
}
4,967✔
859

860
typedef struct InvalidEnvInfo {
861
        const Unit *unit;
862
        const char *path;
863
} InvalidEnvInfo;
864

865
static void invalid_env(const char *p, void *userdata) {
×
866
        InvalidEnvInfo *info = userdata;
×
867

868
        log_unit_error(info->unit, "Ignoring invalid environment assignment '%s': %s", p, info->path);
×
869
}
×
870

871
const char* exec_context_fdname(const ExecContext *c, int fd_index) {
34,299✔
872
        assert(c);
34,299✔
873

874
        switch (fd_index) {
34,299✔
875

876
        case STDIN_FILENO:
11,433✔
877
                if (c->std_input != EXEC_INPUT_NAMED_FD)
11,433✔
878
                        return NULL;
879

880
                return c->stdio_fdname[STDIN_FILENO] ?: "stdin";
×
881

882
        case STDOUT_FILENO:
11,433✔
883
                if (c->std_output != EXEC_OUTPUT_NAMED_FD)
11,433✔
884
                        return NULL;
885

886
                return c->stdio_fdname[STDOUT_FILENO] ?: "stdout";
×
887

888
        case STDERR_FILENO:
11,433✔
889
                if (c->std_error != EXEC_OUTPUT_NAMED_FD)
11,433✔
890
                        return NULL;
891

892
                return c->stdio_fdname[STDERR_FILENO] ?: "stderr";
×
893

894
        default:
895
                return NULL;
896
        }
897
}
898

899
static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***ret) {
2,127✔
900
        _cleanup_strv_free_ char **v = NULL;
2,127✔
901
        int r;
2,127✔
902

903
        assert(c);
2,127✔
904
        assert(ret);
2,127✔
905

906
        STRV_FOREACH(i, c->environment_files) {
2,129✔
907
                _cleanup_strv_free_ char **paths = NULL;
2✔
908
                bool ignore = false;
2✔
909
                char *fn = *i;
2✔
910

911
                if (fn[0] == '-') {
2✔
912
                        ignore = true;
1✔
913
                        fn++;
1✔
914
                }
915

916
                if (!path_is_absolute(fn)) {
2✔
917
                        if (ignore)
×
918
                                continue;
×
919
                        return -EINVAL;
920
                }
921

922
                /* Filename supports globbing, take all matching files */
923
                r = safe_glob(fn, /* flags = */ 0, &paths);
2✔
924
                if (r < 0) {
2✔
925
                        if (ignore)
1✔
926
                                continue;
1✔
927
                        return r;
928
                }
929

930
                /* When we don't match anything, -ENOENT should be returned */
931
                assert(!strv_isempty(paths));
1✔
932

933
                STRV_FOREACH(path, paths) {
2✔
934
                        _cleanup_strv_free_ char **p = NULL;
1✔
935

936
                        r = load_env_file(NULL, *path, &p);
1✔
937
                        if (r < 0) {
1✔
938
                                if (ignore)
×
939
                                        continue;
×
940
                                return r;
941
                        }
942

943
                        /* Log invalid environment variables with filename */
944
                        if (p) {
1✔
945
                                InvalidEnvInfo info = {
1✔
946
                                        .unit = unit,
947
                                        .path = *path,
1✔
948
                                };
949

950
                                strv_env_clean_with_callback(p, invalid_env, &info);
1✔
951
                        }
952

953
                        if (!v)
1✔
954
                                v = TAKE_PTR(p);
1✔
955
                        else {
956
                                char **m = strv_env_merge(v, p);
×
957
                                if (!m)
×
958
                                        return -ENOMEM;
×
959

960
                                strv_free_and_replace(v, m);
×
961
                        }
962
                }
963
        }
964

965
        *ret = TAKE_PTR(v);
2,127✔
966

967
        return 0;
2,127✔
968
}
969

970
static bool tty_may_match_dev_console(const char *tty) {
223✔
971
        _cleanup_free_ char *resolved = NULL;
223✔
972

973
        if (!tty)
223✔
974
                return true;
975

976
        tty = skip_dev_prefix(tty);
223✔
977

978
        /* trivial identity? */
979
        if (streq(tty, "console"))
223✔
980
                return true;
981

982
        if (resolve_dev_console(&resolved) < 0)
39✔
983
                return true; /* if we could not resolve, assume it may */
984

985
        /* "tty0" means the active VC, so it may be the same sometimes */
986
        return path_equal(skip_dev_prefix(resolved), tty) || (streq(skip_dev_prefix(resolved), "tty0") && tty_is_vc(tty));
39✔
987
}
988

989
static bool exec_context_may_touch_tty(const ExecContext *ec) {
23,504✔
990
        assert(ec);
23,504✔
991

992
        return ec->tty_reset ||
46,799✔
993
                ec->tty_vhangup ||
23,295✔
994
                ec->tty_vt_disallocate ||
23,295✔
995
                exec_input_is_terminal(ec->std_input) ||
23,295✔
996
                ec->std_output == EXEC_OUTPUT_TTY ||
46,799✔
997
                ec->std_error == EXEC_OUTPUT_TTY;
23,246✔
998
}
999

1000
bool exec_context_may_touch_console(const ExecContext *ec) {
22,100✔
1001

1002
        return exec_context_may_touch_tty(ec) &&
22,323✔
1003
               tty_may_match_dev_console(exec_context_tty_path(ec));
223✔
1004
}
1005

1006
bool exec_context_shall_ansi_seq_reset(const ExecContext *c) {
1,146✔
1007
        assert(c);
1,146✔
1008

1009
        /* Determines whether ANSI sequences shall be used during any terminal initialisation:
1010
         *
1011
         * 1. If the reset logic is enabled at all, this is an immediate no.
1012
         *
1013
         * 2. If $TERM is set to anything other than "dumb", it's a yes.
1014
         */
1015

1016
        if (!c->tty_reset)
1,146✔
1017
                return false;
1018

1019
        /* FIXME:
1020
         * On invocation, we generate $TERM based on settings for StandardOutput= and friends and the kernel
1021
         * command line options, or propagate $TERM from the service manager. See setup_term_environment(). */
1022
        return !streq_ptr(strv_env_get(c->environment, "TERM"), "dumb");
537✔
1023
}
1024

1025
static void strv_fprintf(FILE *f, char **l) {
×
1026
        assert(f);
×
1027

1028
        STRV_FOREACH(g, l)
×
1029
                fprintf(f, " %s", *g);
×
1030
}
×
1031

1032
static void strv_dump(FILE* f, const char *prefix, const char *name, char **strv) {
1,776✔
1033
        assert(f);
1,776✔
1034
        assert(prefix);
1,776✔
1035
        assert(name);
1,776✔
1036

1037
        if (!strv_isempty(strv)) {
1,776✔
1038
                fprintf(f, "%s%s:", prefix, name);
×
1039
                strv_fprintf(f, strv);
×
1040
                fputs("\n", f);
×
1041
        }
1042
}
1,776✔
1043

1044
void exec_params_dump(const ExecParameters *p, FILE* f, const char *prefix) {
×
1045
        assert(p);
×
1046
        assert(f);
×
1047

1048
        prefix = strempty(prefix);
×
1049

1050
        fprintf(f,
×
1051
                "%sRuntimeScope: %s\n"
1052
                "%sExecFlags: %u\n"
1053
                "%sSELinuxContextNetwork: %s\n"
1054
                "%sCgroupPath: %s\n"
1055
                "%sCrededentialsDirectory: %s\n"
1056
                "%sEncryptedCredentialsDirectory: %s\n"
1057
                "%sConfirmSpawn: %s\n"
1058
                "%sShallConfirmSpawn: %s\n"
1059
                "%sWatchdogUSec: " USEC_FMT "\n"
1060
                "%sNotifySocket: %s\n"
1061
                "%sDebugInvocation: %s\n"
1062
                "%sFallbackSmackProcessLabel: %s\n",
1063
                prefix, runtime_scope_to_string(p->runtime_scope),
×
1064
                prefix, p->flags,
×
1065
                prefix, yes_no(p->selinux_context_net),
×
1066
                prefix, p->cgroup_path,
×
1067
                prefix, strempty(p->received_credentials_directory),
×
1068
                prefix, strempty(p->received_encrypted_credentials_directory),
×
1069
                prefix, strempty(p->confirm_spawn),
×
1070
                prefix, yes_no(p->shall_confirm_spawn),
×
1071
                prefix, p->watchdog_usec,
×
1072
                prefix, strempty(p->notify_socket),
×
1073
                prefix, yes_no(p->debug_invocation),
×
1074
                prefix, strempty(p->fallback_smack_process_label));
×
1075

1076
        strv_dump(f, prefix, "FdNames", p->fd_names);
×
1077
        strv_dump(f, prefix, "Environment", p->environment);
×
1078
        strv_dump(f, prefix, "Prefix", p->prefix);
×
1079

1080
        LIST_FOREACH(open_files, file, p->open_files)
×
1081
                fprintf(f, "%sOpenFile: %s %s", prefix, file->path, open_file_flags_to_string(file->flags));
×
1082

1083
        strv_dump(f, prefix, "FilesEnv", p->files_env);
×
1084
}
×
1085

1086
void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
222✔
1087
        int r;
222✔
1088

1089
        assert(c);
222✔
1090
        assert(f);
222✔
1091

1092
        prefix = strempty(prefix);
222✔
1093

1094
        fprintf(f,
222✔
1095
                "%sUMask: %04o\n"
1096
                "%sWorkingDirectory: %s\n"
1097
                "%sRootDirectory: %s\n"
1098
                "%sRootEphemeral: %s\n"
1099
                "%sNonBlocking: %s\n"
1100
                "%sPrivateTmp: %s\n"
1101
                "%sPrivateDevices: %s\n"
1102
                "%sProtectKernelTunables: %s\n"
1103
                "%sProtectKernelModules: %s\n"
1104
                "%sProtectKernelLogs: %s\n"
1105
                "%sProtectClock: %s\n"
1106
                "%sProtectControlGroups: %s\n"
1107
                "%sPrivateNetwork: %s\n"
1108
                "%sPrivateUsers: %s\n"
1109
                "%sPrivatePIDs: %s\n"
1110
                "%sProtectHome: %s\n"
1111
                "%sProtectSystem: %s\n"
1112
                "%sMountAPIVFS: %s\n"
1113
                "%sBindLogSockets: %s\n"
1114
                "%sIgnoreSIGPIPE: %s\n"
1115
                "%sMemoryDenyWriteExecute: %s\n"
1116
                "%sRestrictRealtime: %s\n"
1117
                "%sRestrictSUIDSGID: %s\n"
1118
                "%sKeyringMode: %s\n"
1119
                "%sProtectHostname: %s%s%s\n"
1120
                "%sProtectProc: %s\n"
1121
                "%sProcSubset: %s\n"
1122
                "%sPrivateBPF: %s\n",
1123
                prefix, c->umask,
222✔
1124
                prefix, empty_to_root(c->working_directory),
222✔
1125
                prefix, empty_to_root(c->root_directory),
222✔
1126
                prefix, yes_no(c->root_ephemeral),
222✔
1127
                prefix, yes_no(c->non_blocking),
222✔
1128
                prefix, private_tmp_to_string(c->private_tmp),
222✔
1129
                prefix, yes_no(c->private_devices),
222✔
1130
                prefix, yes_no(c->protect_kernel_tunables),
222✔
1131
                prefix, yes_no(c->protect_kernel_modules),
222✔
1132
                prefix, yes_no(c->protect_kernel_logs),
222✔
1133
                prefix, yes_no(c->protect_clock),
222✔
1134
                prefix, protect_control_groups_to_string(c->protect_control_groups),
222✔
1135
                prefix, yes_no(c->private_network),
222✔
1136
                prefix, private_users_to_string(c->private_users),
222✔
1137
                prefix, private_pids_to_string(c->private_pids),
222✔
1138
                prefix, protect_home_to_string(c->protect_home),
222✔
1139
                prefix, protect_system_to_string(c->protect_system),
222✔
1140
                prefix, yes_no(exec_context_get_effective_mount_apivfs(c)),
222✔
1141
                prefix, yes_no(exec_context_get_effective_bind_log_sockets(c)),
222✔
1142
                prefix, yes_no(c->ignore_sigpipe),
222✔
1143
                prefix, yes_no(c->memory_deny_write_execute),
222✔
1144
                prefix, yes_no(c->restrict_realtime),
222✔
1145
                prefix, yes_no(c->restrict_suid_sgid),
222✔
1146
                prefix, exec_keyring_mode_to_string(c->keyring_mode),
222✔
1147
                prefix, protect_hostname_to_string(c->protect_hostname), c->private_hostname ? ":" : "", strempty(c->private_hostname),
444✔
1148
                prefix, protect_proc_to_string(c->protect_proc),
222✔
1149
                prefix, proc_subset_to_string(c->proc_subset),
222✔
1150
                prefix, private_bpf_to_string(c->private_bpf));
222✔
1151

1152
        if (c->private_bpf == PRIVATE_BPF_YES) {
222✔
1153
                _cleanup_free_ char
×
1154
                        *commands = bpf_delegate_commands_to_string(c->bpf_delegate_commands),
×
1155
                        *maps = bpf_delegate_maps_to_string(c->bpf_delegate_maps),
×
1156
                        *programs = bpf_delegate_programs_to_string(c->bpf_delegate_programs),
×
1157
                        *attachments = bpf_delegate_attachments_to_string(c->bpf_delegate_attachments);
×
1158

1159
                fprintf(f, "%sBPFDelegateCommands: %s\n", prefix, strna(commands));
×
1160
                fprintf(f, "%sBPFDelegateMaps: %s\n", prefix, strna(maps));
×
1161
                fprintf(f, "%sBPFDelegatePrograms: %s\n", prefix, strna(programs));
×
1162
                fprintf(f, "%sBPFDelegateAttachments: %s\n", prefix, strna(attachments));
×
1163
        }
1164

1165
        if (c->set_login_environment >= 0)
222✔
1166
                fprintf(f, "%sSetLoginEnvironment: %s\n", prefix, yes_no(c->set_login_environment > 0));
2✔
1167

1168
        if (c->root_image)
222✔
1169
                fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
×
1170

1171
        if (c->root_image_options) {
222✔
1172
                fprintf(f, "%sRootImageOptions:", prefix);
×
1173
                LIST_FOREACH(mount_options, o, c->root_image_options)
×
1174
                        if (!isempty(o->options))
×
1175
                                fprintf(f, " %s:%s",
×
1176
                                        partition_designator_to_string(o->partition_designator),
1177
                                        o->options);
1178
                fprintf(f, "\n");
×
1179
        }
1180

1181
        if (c->root_hash) {
222✔
1182
                _cleanup_free_ char *encoded = NULL;
×
1183
                encoded = hexmem(c->root_hash, c->root_hash_size);
×
1184
                if (encoded)
×
1185
                        fprintf(f, "%sRootHash: %s\n", prefix, encoded);
×
1186
        }
1187

1188
        if (c->root_hash_path)
222✔
1189
                fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
×
1190

1191
        if (c->root_hash_sig) {
222✔
1192
                _cleanup_free_ char *encoded = NULL;
×
1193
                ssize_t len;
×
1194
                len = base64mem(c->root_hash_sig, c->root_hash_sig_size, &encoded);
×
1195
                if (len)
×
1196
                        fprintf(f, "%sRootHashSignature: base64:%s\n", prefix, encoded);
×
1197
        }
1198

1199
        if (c->root_hash_sig_path)
222✔
1200
                fprintf(f, "%sRootHashSignature: %s\n", prefix, c->root_hash_sig_path);
×
1201

1202
        if (c->root_verity)
222✔
1203
                fprintf(f, "%sRootVerity: %s\n", prefix, c->root_verity);
×
1204

1205
        STRV_FOREACH(e, c->environment)
222✔
1206
                fprintf(f, "%sEnvironment: %s\n", prefix, *e);
×
1207

1208
        STRV_FOREACH(e, c->environment_files)
222✔
1209
                fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
×
1210

1211
        STRV_FOREACH(e, c->pass_environment)
232✔
1212
                fprintf(f, "%sPassEnvironment: %s\n", prefix, *e);
10✔
1213

1214
        STRV_FOREACH(e, c->unset_environment)
222✔
1215
                fprintf(f, "%sUnsetEnvironment: %s\n", prefix, *e);
×
1216

1217
        fprintf(f, "%sRuntimeDirectoryPreserve: %s\n", prefix, exec_preserve_mode_to_string(c->runtime_directory_preserve_mode));
222✔
1218

1219
        for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
1,332✔
1220
                fprintf(f, "%s%sMode: %04o\n", prefix, exec_directory_type_to_string(dt), c->directories[dt].mode);
1,110✔
1221

1222
                for (size_t i = 0; i < c->directories[dt].n_items; i++) {
1,120✔
1223
                        fprintf(f,
10✔
1224
                                "%s%s: %s%s\n",
1225
                                prefix,
1226
                                exec_directory_type_to_string(dt),
1227
                                c->directories[dt].items[i].path,
1228
                                FLAGS_SET(c->directories[dt].items[i].flags, EXEC_DIRECTORY_READ_ONLY) ? " (ro)" : "");
10✔
1229

1230
                        STRV_FOREACH(d, c->directories[dt].items[i].symlinks)
10✔
1231
                                fprintf(f, "%s%s: %s:%s\n", prefix, exec_directory_type_symlink_to_string(dt), c->directories[dt].items[i].path, *d);
×
1232
                }
1233
        }
1234

1235
        fprintf(f, "%sTimeoutCleanSec: %s\n", prefix, FORMAT_TIMESPAN(c->timeout_clean_usec, USEC_PER_SEC));
222✔
1236

1237
        if (c->memory_ksm >= 0)
222✔
1238
                fprintf(f, "%sMemoryKSM: %s\n", prefix, yes_no(c->memory_ksm > 0));
2✔
1239

1240
        if (c->nice_set)
222✔
1241
                fprintf(f, "%sNice: %i\n", prefix, c->nice);
×
1242

1243
        if (c->oom_score_adjust_set)
222✔
1244
                fprintf(f, "%sOOMScoreAdjust: %i\n", prefix, c->oom_score_adjust);
10✔
1245

1246
        if (c->coredump_filter_set)
222✔
1247
                fprintf(f, "%sCoredumpFilter: 0x%"PRIx64"\n", prefix, c->coredump_filter);
×
1248

1249
        for (unsigned i = 0; i < RLIM_NLIMITS; i++)
3,774✔
1250
                if (c->rlimit[i]) {
3,552✔
1251
                        fprintf(f, "%sLimit%s: " RLIM_FMT "\n",
20✔
1252
                                prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
1253
                        fprintf(f, "%sLimit%sSoft: " RLIM_FMT "\n",
20✔
1254
                                prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur);
20✔
1255
                }
1256

1257
        if (c->ioprio_is_set) {
222✔
1258
                _cleanup_free_ char *class_str = NULL;
×
1259

1260
                r = ioprio_class_to_string_alloc(ioprio_prio_class(c->ioprio), &class_str);
×
1261
                if (r >= 0)
×
1262
                        fprintf(f, "%sIOSchedulingClass: %s\n", prefix, class_str);
×
1263

1264
                fprintf(f, "%sIOPriority: %d\n", prefix, ioprio_prio_data(c->ioprio));
×
1265
        }
1266

1267
        if (c->cpu_sched_set) {
222✔
1268
                _cleanup_free_ char *policy_str = NULL;
×
1269

1270
                r = sched_policy_to_string_alloc(c->cpu_sched_policy, &policy_str);
×
1271
                if (r >= 0)
×
1272
                        fprintf(f, "%sCPUSchedulingPolicy: %s\n", prefix, policy_str);
×
1273

1274
                fprintf(f,
×
1275
                        "%sCPUSchedulingPriority: %i\n"
1276
                        "%sCPUSchedulingResetOnFork: %s\n",
1277
                        prefix, c->cpu_sched_priority,
×
1278
                        prefix, yes_no(c->cpu_sched_reset_on_fork));
×
1279
        }
1280

1281
        if (c->cpu_set.set) {
222✔
1282
                _cleanup_free_ char *affinity = NULL;
×
1283

1284
                affinity = cpu_set_to_range_string(&c->cpu_set);
×
1285
                fprintf(f, "%sCPUAffinity: %s\n", prefix, affinity);
×
1286
        }
1287

1288
        if (mpol_is_valid(numa_policy_get_type(&c->numa_policy))) {
222✔
1289
                _cleanup_free_ char *nodes = NULL;
1✔
1290

1291
                nodes = cpu_set_to_range_string(&c->numa_policy.nodes);
1✔
1292
                fprintf(f, "%sNUMAPolicy: %s\n", prefix, mpol_to_string(numa_policy_get_type(&c->numa_policy)));
1✔
1293
                fprintf(f, "%sNUMAMask: %s\n", prefix, strnull(nodes));
1✔
1294
        }
1295

1296
        if (c->timer_slack_nsec != NSEC_INFINITY)
222✔
1297
                fprintf(f, "%sTimerSlackNSec: "NSEC_FMT "\n", prefix, c->timer_slack_nsec);
1✔
1298

1299
        fprintf(f,
222✔
1300
                "%sStandardInput: %s\n"
1301
                "%sStandardOutput: %s\n"
1302
                "%sStandardError: %s\n",
1303
                prefix, exec_input_to_string(c->std_input),
222✔
1304
                prefix, exec_output_to_string(c->std_output),
222✔
1305
                prefix, exec_output_to_string(c->std_error));
222✔
1306

1307
        if (c->std_input == EXEC_INPUT_NAMED_FD)
222✔
1308
                fprintf(f, "%sStandardInputFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDIN_FILENO]);
×
1309
        if (c->std_output == EXEC_OUTPUT_NAMED_FD)
222✔
1310
                fprintf(f, "%sStandardOutputFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDOUT_FILENO]);
×
1311
        if (c->std_error == EXEC_OUTPUT_NAMED_FD)
222✔
1312
                fprintf(f, "%sStandardErrorFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDERR_FILENO]);
×
1313

1314
        if (c->std_input == EXEC_INPUT_FILE)
222✔
1315
                fprintf(f, "%sStandardInputFile: %s\n", prefix, c->stdio_file[STDIN_FILENO]);
×
1316
        if (c->std_output == EXEC_OUTPUT_FILE)
222✔
1317
                fprintf(f, "%sStandardOutputFile: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
×
1318
        if (c->std_output == EXEC_OUTPUT_FILE_APPEND)
222✔
1319
                fprintf(f, "%sStandardOutputFileToAppend: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
×
1320
        if (c->std_output == EXEC_OUTPUT_FILE_TRUNCATE)
222✔
1321
                fprintf(f, "%sStandardOutputFileToTruncate: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
×
1322
        if (c->std_error == EXEC_OUTPUT_FILE)
222✔
1323
                fprintf(f, "%sStandardErrorFile: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
×
1324
        if (c->std_error == EXEC_OUTPUT_FILE_APPEND)
222✔
1325
                fprintf(f, "%sStandardErrorFileToAppend: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
×
1326
        if (c->std_error == EXEC_OUTPUT_FILE_TRUNCATE)
222✔
1327
                fprintf(f, "%sStandardErrorFileToTruncate: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
×
1328

1329
        if (c->tty_path)
222✔
1330
                fprintf(f,
×
1331
                        "%sTTYPath: %s\n"
1332
                        "%sTTYReset: %s\n"
1333
                        "%sTTYVHangup: %s\n"
1334
                        "%sTTYVTDisallocate: %s\n"
1335
                        "%sTTYRows: %u\n"
1336
                        "%sTTYColumns: %u\n",
1337
                        prefix, c->tty_path,
1338
                        prefix, yes_no(c->tty_reset),
×
1339
                        prefix, yes_no(c->tty_vhangup),
×
1340
                        prefix, yes_no(c->tty_vt_disallocate),
×
1341
                        prefix, c->tty_rows,
×
1342
                        prefix, c->tty_cols);
×
1343

1344
        if (IN_SET(c->std_output,
222✔
1345
                   EXEC_OUTPUT_KMSG,
1346
                   EXEC_OUTPUT_JOURNAL,
1347
                   EXEC_OUTPUT_KMSG_AND_CONSOLE,
1348
                   EXEC_OUTPUT_JOURNAL_AND_CONSOLE) ||
1349
            IN_SET(c->std_error,
17✔
1350
                   EXEC_OUTPUT_KMSG,
1351
                   EXEC_OUTPUT_JOURNAL,
1352
                   EXEC_OUTPUT_KMSG_AND_CONSOLE,
1353
                   EXEC_OUTPUT_JOURNAL_AND_CONSOLE)) {
1354

1355
                _cleanup_free_ char *fac_str = NULL, *lvl_str = NULL;
205✔
1356

1357
                r = log_facility_unshifted_to_string_alloc(c->syslog_priority >> 3, &fac_str);
205✔
1358
                if (r >= 0)
205✔
1359
                        fprintf(f, "%sSyslogFacility: %s\n", prefix, fac_str);
205✔
1360

1361
                r = log_level_to_string_alloc(LOG_PRI(c->syslog_priority), &lvl_str);
205✔
1362
                if (r >= 0)
205✔
1363
                        fprintf(f, "%sSyslogLevel: %s\n", prefix, lvl_str);
205✔
1364
        }
1365

1366
        if (c->log_level_max >= 0) {
222✔
1367
                _cleanup_free_ char *t = NULL;
1✔
1368

1369
                (void) log_level_to_string_alloc(c->log_level_max, &t);
1✔
1370

1371
                fprintf(f, "%sLogLevelMax: %s\n", prefix, strna(t));
1✔
1372
        }
1373

1374
        if (c->log_ratelimit.interval > 0)
222✔
1375
                fprintf(f,
×
1376
                        "%sLogRateLimitIntervalSec: %s\n",
1377
                        prefix, FORMAT_TIMESPAN(c->log_ratelimit.interval, USEC_PER_SEC));
×
1378

1379
        if (c->log_ratelimit.burst > 0)
222✔
1380
                fprintf(f, "%sLogRateLimitBurst: %u\n", prefix, c->log_ratelimit.burst);
×
1381

1382
        if (!set_isempty(c->log_filter_allowed_patterns) || !set_isempty(c->log_filter_denied_patterns)) {
222✔
1383
                fprintf(f, "%sLogFilterPatterns:", prefix);
×
1384

1385
                char *pattern;
×
1386
                SET_FOREACH(pattern, c->log_filter_allowed_patterns)
×
1387
                        fprintf(f, " %s", pattern);
×
1388
                SET_FOREACH(pattern, c->log_filter_denied_patterns)
×
1389
                        fprintf(f, " ~%s", pattern);
×
1390
                fputc('\n', f);
×
1391
        }
1392

1393
        FOREACH_ARRAY(field, c->log_extra_fields, c->n_log_extra_fields) {
226✔
1394
                fprintf(f, "%sLogExtraFields: ", prefix);
4✔
1395
                fwrite(field->iov_base, 1, field->iov_len, f);
4✔
1396
                fputc('\n', f);
4✔
1397
        }
1398

1399
        if (c->log_namespace)
222✔
1400
                fprintf(f, "%sLogNamespace: %s\n", prefix, c->log_namespace);
×
1401

1402
        if (c->secure_bits) {
222✔
1403
                _cleanup_free_ char *str = NULL;
×
1404

1405
                r = secure_bits_to_string_alloc(c->secure_bits, &str);
×
1406
                if (r >= 0)
×
1407
                        fprintf(f, "%sSecure Bits: %s\n", prefix, str);
×
1408
        }
1409

1410
        if (c->capability_bounding_set != CAP_MASK_UNSET) {
222✔
1411
                _cleanup_free_ char *str = NULL;
222✔
1412

1413
                r = capability_set_to_string(c->capability_bounding_set, &str);
222✔
1414
                if (r >= 0)
222✔
1415
                        fprintf(f, "%sCapabilityBoundingSet: %s\n", prefix, str);
222✔
1416
        }
1417

1418
        if (c->capability_ambient_set != 0) {
222✔
1419
                _cleanup_free_ char *str = NULL;
×
1420

1421
                r = capability_set_to_string(c->capability_ambient_set, &str);
×
1422
                if (r >= 0)
×
1423
                        fprintf(f, "%sAmbientCapabilities: %s\n", prefix, str);
×
1424
        }
1425

1426
        if (c->user)
222✔
1427
                fprintf(f, "%sUser: %s\n", prefix, c->user);
1✔
1428
        if (c->group)
222✔
1429
                fprintf(f, "%sGroup: %s\n", prefix, c->group);
1✔
1430

1431
        fprintf(f, "%sDynamicUser: %s\n", prefix, yes_no(c->dynamic_user));
443✔
1432

1433
        strv_dump(f, prefix, "SupplementaryGroups", c->supplementary_groups);
222✔
1434

1435
        if (c->pam_name)
222✔
1436
                fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
×
1437

1438
        strv_dump(f, prefix, "ReadWritePaths", c->read_write_paths);
222✔
1439
        strv_dump(f, prefix, "ReadOnlyPaths", c->read_only_paths);
222✔
1440
        strv_dump(f, prefix, "InaccessiblePaths", c->inaccessible_paths);
222✔
1441
        strv_dump(f, prefix, "ExecPaths", c->exec_paths);
222✔
1442
        strv_dump(f, prefix, "NoExecPaths", c->no_exec_paths);
222✔
1443
        strv_dump(f, prefix, "ExecSearchPath", c->exec_search_path);
222✔
1444

1445
        FOREACH_ARRAY(mount, c->bind_mounts, c->n_bind_mounts)
226✔
1446
                fprintf(f, "%s%s: %s%s:%s:%s\n", prefix,
4✔
1447
                        mount->read_only ? "BindReadOnlyPaths" : "BindPaths",
4✔
1448
                        mount->ignore_enoent ? "-": "",
4✔
1449
                        mount->source,
1450
                        mount->destination,
1451
                        mount->recursive ? "rbind" : "norbind");
4✔
1452

1453
        FOREACH_ARRAY(tmpfs, c->temporary_filesystems, c->n_temporary_filesystems)
222✔
1454
                fprintf(f, "%sTemporaryFileSystem: %s%s%s\n", prefix,
×
1455
                        tmpfs->path,
1456
                        isempty(tmpfs->options) ? "" : ":",
×
1457
                        strempty(tmpfs->options));
×
1458

1459
        if (c->utmp_id)
222✔
1460
                fprintf(f,
×
1461
                        "%sUtmpIdentifier: %s\n",
1462
                        prefix, c->utmp_id);
1463

1464
        if (c->selinux_context)
222✔
1465
                fprintf(f,
×
1466
                        "%sSELinuxContext: %s%s\n",
1467
                        prefix, c->selinux_context_ignore ? "-" : "", c->selinux_context);
×
1468

1469
        if (c->apparmor_profile)
222✔
1470
                fprintf(f,
×
1471
                        "%sAppArmorProfile: %s%s\n",
1472
                        prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile);
×
1473

1474
        if (c->smack_process_label)
222✔
1475
                fprintf(f,
×
1476
                        "%sSmackProcessLabel: %s%s\n",
1477
                        prefix, c->smack_process_label_ignore ? "-" : "", c->smack_process_label);
×
1478

1479
        if (c->personality != PERSONALITY_INVALID)
222✔
1480
                fprintf(f,
1✔
1481
                        "%sPersonality: %s\n",
1482
                        prefix, strna(personality_to_string(c->personality)));
1483

1484
        fprintf(f,
222✔
1485
                "%sLockPersonality: %s\n",
1486
                prefix, yes_no(c->lock_personality));
222✔
1487

1488
        if (c->syscall_filter) {
222✔
1489
                fprintf(f,
11✔
1490
                        "%sSystemCallFilter: ",
1491
                        prefix);
1492

1493
                if (!c->syscall_allow_list)
11✔
1494
                        fputc('~', f);
×
1495

1496
#if HAVE_SECCOMP
1497
                if (dlopen_libseccomp() >= 0) {
11✔
1498
                        void *id, *val;
11✔
1499
                        bool first = true;
11✔
1500
                        HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
4,279✔
1501
                                _cleanup_free_ char *name = NULL;
4,268✔
1502
                                const char *errno_name = NULL;
4,268✔
1503
                                int num = PTR_TO_INT(val);
4,268✔
1504

1505
                                if (first)
4,268✔
1506
                                        first = false;
1507
                                else
1508
                                        fputc(' ', f);
4,257✔
1509

1510
                                name = sym_seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
4,268✔
1511
                                fputs(strna(name), f);
4,268✔
1512

1513
                                if (num >= 0) {
4,268✔
1514
                                        errno_name = seccomp_errno_or_action_to_string(num);
×
1515
                                        if (errno_name)
×
1516
                                                fprintf(f, ":%s", errno_name);
×
1517
                                        else
1518
                                                fprintf(f, ":%d", num);
×
1519
                                }
1520
                        }
1521
                }
1522
#endif
1523

1524
                fputc('\n', f);
11✔
1525
        }
1526

1527
        if (c->syscall_archs) {
222✔
1528
                fprintf(f,
11✔
1529
                        "%sSystemCallArchitectures:",
1530
                        prefix);
1531

1532
#if HAVE_SECCOMP
1533
                void *id;
11✔
1534
                SET_FOREACH(id, c->syscall_archs)
22✔
1535
                        fprintf(f, " %s", strna(seccomp_arch_to_string(PTR_TO_UINT32(id) - 1)));
11✔
1536
#endif
1537
                fputc('\n', f);
11✔
1538
        }
1539

1540
        if (exec_context_restrict_namespaces_set(c)) {
222✔
1541
                _cleanup_free_ char *s = NULL;
12✔
1542

1543
                r = namespace_flags_to_string(c->restrict_namespaces, &s);
12✔
1544
                if (r >= 0)
12✔
1545
                        fprintf(f, "%sRestrictNamespaces: %s\n",
12✔
1546
                                prefix, strna(s));
1547
        }
1548

1549
#if HAVE_LIBBPF
1550
        if (exec_context_restrict_filesystems_set(c)) {
222✔
1551
                char *fs;
×
1552
                SET_FOREACH(fs, c->restrict_filesystems)
×
1553
                        fprintf(f, "%sRestrictFileSystems: %s\n", prefix, fs);
×
1554
        }
1555
#endif
1556

1557
        if (c->user_namespace_path)
222✔
1558
                fprintf(f,
×
1559
                        "%sUserNamespacePath: %s\n",
1560
                        prefix, c->user_namespace_path);
1561

1562
        if (c->network_namespace_path)
222✔
1563
                fprintf(f,
×
1564
                        "%sNetworkNamespacePath: %s\n",
1565
                        prefix, c->network_namespace_path);
1566

1567
        if (c->syscall_errno > 0) {
222✔
1568
                fprintf(f, "%sSystemCallErrorNumber: ", prefix);
221✔
1569

1570
#if HAVE_SECCOMP
1571
                const char *errno_name = seccomp_errno_or_action_to_string(c->syscall_errno);
221✔
1572
                if (errno_name)
221✔
1573
                        fputs(errno_name, f);
221✔
1574
                else
1575
                        fprintf(f, "%d", c->syscall_errno);
×
1576
#endif
1577
                fputc('\n', f);
221✔
1578
        }
1579

1580
        FOREACH_ARRAY(mount, c->mount_images, c->n_mount_images) {
222✔
1581
                fprintf(f, "%sMountImages: %s%s:%s", prefix,
×
1582
                        mount->ignore_enoent ? "-": "",
×
1583
                        mount->source,
1584
                        mount->destination);
1585
                LIST_FOREACH(mount_options, o, mount->mount_options)
×
1586
                        fprintf(f, ":%s:%s",
×
1587
                                partition_designator_to_string(o->partition_designator),
1588
                                strempty(o->options));
×
1589
                fprintf(f, "\n");
×
1590
        }
1591

1592
        FOREACH_ARRAY(mount, c->extension_images, c->n_extension_images) {
222✔
1593
                fprintf(f, "%sExtensionImages: %s%s", prefix,
×
1594
                        mount->ignore_enoent ? "-": "",
×
1595
                        mount->source);
1596
                LIST_FOREACH(mount_options, o, mount->mount_options)
×
1597
                        fprintf(f, ":%s:%s",
×
1598
                                partition_designator_to_string(o->partition_designator),
1599
                                strempty(o->options));
×
1600
                fprintf(f, "\n");
×
1601
        }
1602

1603
        strv_dump(f, prefix, "ExtensionDirectories", c->extension_directories);
222✔
1604
}
222✔
1605

1606
bool exec_context_maintains_privileges(const ExecContext *c) {
×
1607
        assert(c);
×
1608

1609
        /* Returns true if the process forked off would run under
1610
         * an unchanged UID or as root. */
1611

1612
        if (!c->user)
×
1613
                return true;
1614

1615
        if (STR_IN_SET(c->user, "root", "0"))
×
1616
                return true;
×
1617

1618
        return false;
×
1619
}
1620

1621
int exec_context_get_effective_ioprio(const ExecContext *c) {
2,980✔
1622
        int p;
2,980✔
1623

1624
        assert(c);
2,980✔
1625

1626
        if (c->ioprio_is_set)
2,980✔
1627
                return c->ioprio;
14✔
1628

1629
        p = ioprio_get(IOPRIO_WHO_PROCESS, 0);
2,966✔
1630
        if (p < 0)
2,966✔
1631
                return IOPRIO_DEFAULT_CLASS_AND_PRIO;
1632

1633
        return ioprio_normalize(p);
2,966✔
1634
}
1635

1636
bool exec_context_get_effective_mount_apivfs(const ExecContext *c) {
34,172✔
1637
        assert(c);
34,172✔
1638

1639
        /* Explicit setting wins */
1640
        if (c->mount_apivfs >= 0)
34,172✔
1641
                return c->mount_apivfs > 0;
119✔
1642

1643
        /* Default to "yes" if root directory or image are specified */
1644
        if (exec_context_with_rootfs(c))
34,053✔
1645
                return true;
140✔
1646

1647
        return false;
1648
}
1649

1650
bool exec_context_get_effective_bind_log_sockets(const ExecContext *c) {
28,495✔
1651
        assert(c);
28,495✔
1652

1653
        /* If log namespace is specified, "/run/systemd/journal.namespace/" would be bind mounted to
1654
         * "/run/systemd/journal/", which effectively means BindLogSockets=yes */
1655
        if (c->log_namespace)
28,495✔
1656
                return true;
1657

1658
        if (c->bind_log_sockets >= 0)
28,487✔
1659
                return c->bind_log_sockets > 0;
2✔
1660

1661
        if (exec_context_get_effective_mount_apivfs(c))
28,485✔
1662
                return true;
1663

1664
        /* When PrivateDevices=yes, /dev/log gets symlinked to /run/systemd/journal/dev-log */
1665
        if (exec_context_with_rootfs(c) && c->private_devices)
28,376✔
1666
                return true;
×
1667

1668
        return false;
1669
}
1670

1671
void exec_context_free_log_extra_fields(ExecContext *c) {
48,450✔
1672
        assert(c);
48,450✔
1673

1674
        FOREACH_ARRAY(field, c->log_extra_fields, c->n_log_extra_fields)
48,455✔
1675
                free(field->iov_base);
5✔
1676

1677
        c->log_extra_fields = mfree(c->log_extra_fields);
48,450✔
1678
        c->n_log_extra_fields = 0;
48,450✔
1679
}
48,450✔
1680

1681
void exec_context_revert_tty(ExecContext *c, sd_id128_t invocation_id) {
1,404✔
1682
        _cleanup_close_ int fd = -EBADF;
1,404✔
1683
        const char *path;
1,404✔
1684
        struct stat st;
1,404✔
1685
        int r;
1,404✔
1686

1687
        assert(c);
1,404✔
1688

1689
        /* First, reset the TTY (possibly kicking everybody else from the TTY) */
1690
        exec_context_tty_reset(c, /* parameters= */ NULL, invocation_id);
1,404✔
1691

1692
        /* And then undo what chown_terminal() did earlier. Note that we only do this if we have a path
1693
         * configured. If the TTY was passed to us as file descriptor we assume the TTY is opened and managed
1694
         * by whoever passed it to us and thus knows better when and how to chmod()/chown() it back. */
1695
        if (!exec_context_may_touch_tty(c))
1,404✔
1696
                return;
1697

1698
        path = exec_context_tty_path(c);
35✔
1699
        if (!path)
35✔
1700
                return;
1701

1702
        fd = open(path, O_PATH|O_CLOEXEC); /* Pin the inode */
35✔
1703
        if (fd < 0)
35✔
1704
                return (void) log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
×
1705
                                             "Failed to open TTY inode of '%s' to adjust ownership/access mode, ignoring: %m",
1706
                                             path);
1707

1708
        if (fstat(fd, &st) < 0)
35✔
1709
                return (void) log_warning_errno(errno, "Failed to stat TTY '%s', ignoring: %m", path);
×
1710

1711
        /* Let's add a superficial check that we only do this for stuff that looks like a TTY. We only check
1712
         * if things are a character device, since a proper check either means we'd have to open the TTY and
1713
         * use isatty(), but we'd rather not do that since opening TTYs comes with all kinds of side-effects
1714
         * and is slow. Or we'd have to hardcode dev_t major information, which we'd rather avoid. Why bother
1715
         * with this at all? → https://github.com/systemd/systemd/issues/19213 */
1716
        if (!S_ISCHR(st.st_mode))
35✔
1717
                return log_warning("Configured TTY '%s' is not actually a character device, ignoring.", path);
×
1718

1719
        r = fchmod_and_chown(fd, TTY_MODE, 0, TTY_GID);
35✔
1720
        if (r < 0)
35✔
1721
                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);
35✔
1722
}
1723

1724
int exec_context_get_clean_directories(
×
1725
                ExecContext *c,
1726
                char **prefix,
1727
                ExecCleanMask mask,
1728
                char ***ret) {
1729

1730
        _cleanup_strv_free_ char **l = NULL;
×
1731
        int r;
×
1732

1733
        assert(c);
×
1734
        assert(prefix);
×
1735
        assert(ret);
×
1736

1737
        for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
×
1738
                if (!BIT_SET(mask, t))
×
1739
                        continue;
×
1740

1741
                if (!prefix[t])
×
1742
                        continue;
×
1743

1744
                FOREACH_ARRAY(i, c->directories[t].items, c->directories[t].n_items) {
×
1745
                        char *j;
×
1746

1747
                        j = path_join(prefix[t], i->path);
×
1748
                        if (!j)
×
1749
                                return -ENOMEM;
1750

1751
                        r = strv_consume(&l, j);
×
1752
                        if (r < 0)
×
1753
                                return r;
1754

1755
                        /* Also remove private directories unconditionally. */
1756
                        if (EXEC_DIRECTORY_TYPE_SHALL_CHOWN(t)) {
×
1757
                                j = path_join(prefix[t], "private", i->path);
×
1758
                                if (!j)
×
1759
                                        return -ENOMEM;
1760

1761
                                r = strv_consume(&l, j);
×
1762
                                if (r < 0)
×
1763
                                        return r;
1764
                        }
1765

1766
                        STRV_FOREACH(symlink, i->symlinks) {
×
1767
                                j = path_join(prefix[t], *symlink);
×
1768
                                if (!j)
×
1769
                                        return -ENOMEM;
1770

1771
                                r = strv_consume(&l, j);
×
1772
                                if (r < 0)
×
1773
                                        return r;
1774
                        }
1775
                }
1776
        }
1777

1778
        *ret = TAKE_PTR(l);
×
1779
        return 0;
×
1780
}
1781

1782
int exec_context_get_clean_mask(ExecContext *c, ExecCleanMask *ret) {
1,474✔
1783
        ExecCleanMask mask = 0;
1,474✔
1784

1785
        assert(c);
1,474✔
1786
        assert(ret);
1,474✔
1787

1788
        for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++)
8,844✔
1789
                if (c->directories[t].n_items > 0)
7,370✔
1790
                        mask |= 1U << t;
250✔
1791

1792
        *ret = mask;
1,474✔
1793
        return 0;
1,474✔
1794
}
1795

1796
int exec_context_get_oom_score_adjust(const ExecContext *c) {
1,490✔
1797
        int n = 0, r;
1,490✔
1798

1799
        assert(c);
1,490✔
1800

1801
        if (c->oom_score_adjust_set)
1,490✔
1802
                return c->oom_score_adjust;
573✔
1803

1804
        r = get_oom_score_adjust(&n);
917✔
1805
        if (r < 0)
917✔
1806
                log_debug_errno(r, "Failed to read /proc/self/oom_score_adj, ignoring: %m");
×
1807

1808
        return n;
917✔
1809
}
1810

1811
uint64_t exec_context_get_coredump_filter(const ExecContext *c) {
1,490✔
1812
        _cleanup_free_ char *t = NULL;
1,490✔
1813
        uint64_t n = COREDUMP_FILTER_MASK_DEFAULT;
1,490✔
1814
        int r;
1,490✔
1815

1816
        assert(c);
1,490✔
1817

1818
        if (c->coredump_filter_set)
1,490✔
1819
                return c->coredump_filter;
×
1820

1821
        r = read_one_line_file("/proc/self/coredump_filter", &t);
1,490✔
1822
        if (r < 0)
1,490✔
1823
                log_debug_errno(r, "Failed to read /proc/self/coredump_filter, ignoring: %m");
×
1824
        else {
1825
                r = safe_atoux64(t, &n);
1,490✔
1826
                if (r < 0)
1,490✔
1827
                        log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/coredump_filter, ignoring: %m", t);
×
1828
        }
1829

1830
        return n;
1,490✔
1831
}
1832

1833
int exec_context_get_nice(const ExecContext *c) {
1,490✔
1834
        int n;
1,490✔
1835

1836
        assert(c);
1,490✔
1837

1838
        if (c->nice_set)
1,490✔
1839
                return c->nice;
4✔
1840

1841
        errno = 0;
1,486✔
1842
        n = getpriority(PRIO_PROCESS, 0);
1,486✔
1843
        if (errno > 0) {
1,486✔
1844
                log_debug_errno(errno, "Failed to get process nice value, ignoring: %m");
×
1845
                n = 0;
1846
        }
1847

1848
        return n;
1849
}
1850

1851
int exec_context_get_cpu_sched_policy(const ExecContext *c) {
1,490✔
1852
        int n;
1,490✔
1853

1854
        assert(c);
1,490✔
1855

1856
        if (c->cpu_sched_set)
1,490✔
1857
                return c->cpu_sched_policy;
×
1858

1859
        n = sched_getscheduler(0);
1,490✔
1860
        if (n < 0)
1,490✔
1861
                log_debug_errno(errno, "Failed to get scheduler policy, ignoring: %m");
×
1862

1863
        return n < 0 ? SCHED_OTHER : n;
1,490✔
1864
}
1865

1866
int exec_context_get_cpu_sched_priority(const ExecContext *c) {
1,490✔
1867
        struct sched_param p = {};
1,490✔
1868
        int r;
1,490✔
1869

1870
        assert(c);
1,490✔
1871

1872
        if (c->cpu_sched_set)
1,490✔
1873
                return c->cpu_sched_priority;
×
1874

1875
        r = sched_getparam(0, &p);
1,490✔
1876
        if (r < 0)
1,490✔
1877
                log_debug_errno(errno, "Failed to get scheduler priority, ignoring: %m");
×
1878

1879
        return r >= 0 ? p.sched_priority : 0;
1,490✔
1880
}
1881

1882
uint64_t exec_context_get_timer_slack_nsec(const ExecContext *c) {
1,490✔
1883
        int r;
1,490✔
1884

1885
        assert(c);
1,490✔
1886

1887
        if (c->timer_slack_nsec != NSEC_INFINITY)
1,490✔
1888
                return c->timer_slack_nsec;
1889

1890
        r = prctl(PR_GET_TIMERSLACK);
1,490✔
1891
        if (r < 0)
1,490✔
1892
                log_debug_errno(r, "Failed to get timer slack, ignoring: %m");
×
1893

1894
        return (uint64_t) MAX(r, 0);
1,490✔
1895
}
1896

1897
bool exec_context_get_set_login_environment(const ExecContext *c) {
11,381✔
1898
        assert(c);
11,381✔
1899

1900
        if (c->set_login_environment >= 0)
11,381✔
1901
                return c->set_login_environment;
×
1902

1903
        return c->user || c->dynamic_user || c->pam_name;
20,517✔
1904
}
1905

1906
char** exec_context_get_syscall_filter(const ExecContext *c) {
1,490✔
1907
        _cleanup_strv_free_ char **l = NULL;
1,490✔
1908

1909
        assert(c);
1,490✔
1910

1911
#if HAVE_SECCOMP
1912
        if (dlopen_libseccomp() < 0)
1,490✔
1913
                return strv_new(NULL);
×
1914

1915
        void *id, *val;
1,490✔
1916
        HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
12,416✔
1917
                _cleanup_free_ char *name = NULL;
10,926✔
1918
                const char *e = NULL;
10,926✔
1919
                char *s;
10,926✔
1920
                int num = PTR_TO_INT(val);
10,926✔
1921

1922
                if (c->syscall_allow_list && num >= 0)
10,926✔
1923
                        /* syscall with num >= 0 in allow-list is denied. */
1924
                        continue;
×
1925

1926
                name = sym_seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
10,926✔
1927
                if (!name)
10,926✔
1928
                        continue;
×
1929

1930
                if (num >= 0) {
10,926✔
1931
                        e = seccomp_errno_or_action_to_string(num);
×
1932
                        if (e) {
×
1933
                                s = strjoin(name, ":", e);
×
1934
                                if (!s)
×
1935
                                        return NULL;
1936
                        } else {
1937
                                if (asprintf(&s, "%s:%d", name, num) < 0)
×
1938
                                        return NULL;
1939
                        }
1940
                } else
1941
                        s = TAKE_PTR(name);
10,926✔
1942

1943
                if (strv_consume(&l, s) < 0)
10,926✔
1944
                        return NULL;
1945
        }
1946

1947
        strv_sort(l);
1,490✔
1948
#endif
1949

1950
        return l ? TAKE_PTR(l) : strv_new(NULL);
1,490✔
1951
}
1952

1953
char** exec_context_get_syscall_archs(const ExecContext *c) {
1,490✔
1954
        _cleanup_strv_free_ char **l = NULL;
1,490✔
1955

1956
        assert(c);
1,490✔
1957

1958
#if HAVE_SECCOMP
1959
        void *id;
1,490✔
1960
        SET_FOREACH(id, c->syscall_archs) {
1,522✔
1961
                const char *name;
32✔
1962

1963
                name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
32✔
1964
                if (!name)
32✔
1965
                        continue;
×
1966

1967
                if (strv_extend(&l, name) < 0)
32✔
1968
                        return NULL;
×
1969
        }
1970

1971
        strv_sort(l);
1,490✔
1972
#endif
1973

1974
        return l ? TAKE_PTR(l) : strv_new(NULL);
1,490✔
1975
}
1976

1977
char** exec_context_get_syscall_log(const ExecContext *c) {
1,490✔
1978
        _cleanup_strv_free_ char **l = NULL;
1,490✔
1979

1980
        assert(c);
1,490✔
1981

1982
#if HAVE_SECCOMP
1983
        if (dlopen_libseccomp() < 0)
1,490✔
1984
                return strv_new(NULL);
×
1985

1986
        void *id, *val;
1,490✔
1987
        HASHMAP_FOREACH_KEY(val, id, c->syscall_log) {
1,490✔
1988
                char *name = NULL;
×
1989

1990
                name = sym_seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
×
1991
                if (!name)
×
1992
                        continue;
×
1993

1994
                if (strv_consume(&l, name) < 0)
×
1995
                        return NULL;
×
1996
        }
1997

1998
        strv_sort(l);
1,490✔
1999
#endif
2000

2001
        return l ? TAKE_PTR(l) : strv_new(NULL);
1,490✔
2002
}
2003

2004
char** exec_context_get_address_families(const ExecContext *c) {
1,490✔
2005
        _cleanup_strv_free_ char **l = NULL;
1,490✔
2006
        void *af;
1,490✔
2007

2008
        assert(c);
1,490✔
2009

2010
        SET_FOREACH(af, c->address_families) {
1,591✔
2011
                const char *name;
101✔
2012

2013
                name = af_to_name(PTR_TO_INT(af));
101✔
2014
                if (!name)
101✔
2015
                        continue;
×
2016

2017
                if (strv_extend(&l, name) < 0)
101✔
2018
                        return NULL;
×
2019
        }
2020

2021
        strv_sort(l);
1,490✔
2022

2023
        return l ? TAKE_PTR(l) : strv_new(NULL);
1,490✔
2024
}
2025

2026
char** exec_context_get_restrict_filesystems(const ExecContext *c) {
1,490✔
2027
        assert(c);
1,490✔
2028

2029
#if HAVE_LIBBPF
2030
        char **l = set_get_strv(c->restrict_filesystems);
1,490✔
2031
        if (!l)
1,490✔
2032
                return NULL;
2033

2034
        return strv_sort(l);
1,490✔
2035
#else
2036
        return strv_new(NULL);
2037
#endif
2038
}
2039

2040
bool exec_context_restrict_namespaces_set(const ExecContext *c) {
13,235✔
2041
        assert(c);
13,235✔
2042

2043
        return (c->restrict_namespaces & NAMESPACE_FLAGS_ALL) != NAMESPACE_FLAGS_ALL;
13,235✔
2044
}
2045

2046
bool exec_context_restrict_filesystems_set(const ExecContext *c) {
14,382✔
2047
        assert(c);
14,382✔
2048

2049
        return c->restrict_filesystems_allow_list ||
14,382✔
2050
          !set_isempty(c->restrict_filesystems);
14,382✔
2051
}
2052

2053
bool exec_context_with_rootfs(const ExecContext *c) {
62,684✔
2054
        assert(c);
62,684✔
2055

2056
        /* Checks if RootDirectory=, RootImage= or RootDirectoryFileDescriptor= are used */
2057

2058
        return !empty_or_root(c->root_directory) || c->root_image || c->root_directory_as_fd;
62,684✔
2059
}
2060

2061
int exec_context_has_vpicked_extensions(const ExecContext *context) {
4✔
2062
        int r;
4✔
2063

2064
        assert(context);
4✔
2065

2066
        FOREACH_ARRAY(mi, context->extension_images, context->n_extension_images) {
4✔
2067
                r = path_uses_vpick(mi->source);
×
2068
                if (r != 0)
×
2069
                        return r;
2070
        }
2071
        STRV_FOREACH(ed, context->extension_directories) {
4✔
2072
                r = path_uses_vpick(*ed);
×
2073
                if (r != 0)
×
2074
                        return r;
2075
        }
2076

2077
        return 0;
2078
}
2079

2080
void exec_status_start(ExecStatus *s, pid_t pid, const dual_timestamp *ts) {
4,221✔
2081
        assert(s);
4,221✔
2082

2083
        *s = (ExecStatus) {
4,221✔
2084
                .pid = pid,
2085
        };
2086

2087
        if (ts)
4,221✔
2088
                s->start_timestamp = *ts;
4,221✔
2089
        else
2090
                dual_timestamp_now(&s->start_timestamp);
×
2091
}
4,221✔
2092

2093
void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int code, int status) {
1,959✔
2094
        assert(s);
1,959✔
2095

2096
        if (s->pid != pid)
1,959✔
2097
                *s = (ExecStatus) {
4✔
2098
                        .pid = pid,
2099
                };
2100

2101
        dual_timestamp_now(&s->exit_timestamp);
1,959✔
2102

2103
        s->code = code;
1,959✔
2104
        s->status = status;
1,959✔
2105

2106
        if (context && context->utmp_id)
1,959✔
2107
                (void) utmp_put_dead_process(context->utmp_id, pid, code, status);
14✔
2108
}
1,959✔
2109

2110
void exec_status_handoff(ExecStatus *s, const struct ucred *ucred, const dual_timestamp *ts) {
7,348✔
2111
        assert(s);
7,348✔
2112
        assert(ucred);
7,348✔
2113
        assert(ts);
7,348✔
2114

2115
        if (ucred->pid != s->pid)
7,348✔
2116
                *s = (ExecStatus) {
7✔
2117
                        .pid = ucred->pid,
2118
                };
2119

2120
        s->handoff_timestamp = *ts;
7,348✔
2121
}
7,348✔
2122

2123
void exec_status_reset(ExecStatus *s) {
26,164✔
2124
        assert(s);
26,164✔
2125

2126
        *s = (ExecStatus) {};
26,164✔
2127
}
26,164✔
2128

2129
void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix) {
98✔
2130
        assert(s);
98✔
2131
        assert(f);
98✔
2132

2133
        if (s->pid <= 0)
98✔
2134
                return;
2135

2136
        prefix = strempty(prefix);
10✔
2137

2138
        fprintf(f,
10✔
2139
                "%sPID: "PID_FMT"\n",
2140
                prefix, s->pid);
2141

2142
        if (dual_timestamp_is_set(&s->start_timestamp))
10✔
2143
                fprintf(f,
10✔
2144
                        "%sStart Timestamp: %s\n",
2145
                        prefix, FORMAT_TIMESTAMP_STYLE(s->start_timestamp.realtime, TIMESTAMP_US));
10✔
2146

2147
        if (dual_timestamp_is_set(&s->handoff_timestamp) && dual_timestamp_is_set(&s->start_timestamp) &&
10✔
2148
            s->handoff_timestamp.monotonic > s->start_timestamp.monotonic)
10✔
2149
                fprintf(f,
10✔
2150
                        "%sHandoff Timestamp: %s since start\n",
2151
                        prefix,
2152
                        FORMAT_TIMESPAN(usec_sub_unsigned(s->handoff_timestamp.monotonic, s->start_timestamp.monotonic), 1));
20✔
2153
        else
2154
                fprintf(f,
×
2155
                        "%sHandoff Timestamp: %s\n",
2156
                        prefix, FORMAT_TIMESTAMP_STYLE(s->handoff_timestamp.realtime, TIMESTAMP_US));
×
2157

2158
        if (dual_timestamp_is_set(&s->exit_timestamp)) {
10✔
2159

2160
                if (dual_timestamp_is_set(&s->handoff_timestamp) && s->exit_timestamp.monotonic > s->handoff_timestamp.monotonic)
×
2161
                        fprintf(f,
×
2162
                                "%sExit Timestamp: %s since handoff\n",
2163
                                prefix,
2164
                                FORMAT_TIMESPAN(usec_sub_unsigned(s->exit_timestamp.monotonic, s->handoff_timestamp.monotonic), 1));
×
2165
                else if (dual_timestamp_is_set(&s->start_timestamp) && s->exit_timestamp.monotonic > s->start_timestamp.monotonic)
×
2166
                        fprintf(f,
×
2167
                                "%sExit Timestamp: %s since start\n",
2168
                                prefix,
2169
                                FORMAT_TIMESPAN(usec_sub_unsigned(s->exit_timestamp.monotonic, s->start_timestamp.monotonic), 1));
×
2170
                else
2171
                        fprintf(f,
×
2172
                                "%sExit Timestamp: %s\n",
2173
                                prefix, FORMAT_TIMESTAMP_STYLE(s->exit_timestamp.realtime, TIMESTAMP_US));
×
2174

2175
                fprintf(f,
×
2176
                        "%sExit Code: %s\n"
2177
                        "%sExit Status: %i\n",
2178
                        prefix, sigchld_code_to_string(s->code),
×
2179
                        prefix, s->status);
×
2180
        }
2181
}
2182

2183
void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
98✔
2184
        _cleanup_free_ char *cmd = NULL;
196✔
2185
        const char *prefix2;
98✔
2186

2187
        assert(c);
98✔
2188
        assert(f);
98✔
2189

2190
        prefix = strempty(prefix);
98✔
2191
        prefix2 = strjoina(prefix, "\t");
490✔
2192

2193
        cmd = quote_command_line(c->argv, SHELL_ESCAPE_EMPTY);
98✔
2194

2195
        fprintf(f,
98✔
2196
                "%sCommand Line: %s\n",
2197
                prefix, strnull(cmd));
2198

2199
        exec_status_dump(&c->exec_status, f, prefix2);
98✔
2200
}
98✔
2201

2202
void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
95✔
2203
        assert(f);
95✔
2204

2205
        prefix = strempty(prefix);
95✔
2206

2207
        LIST_FOREACH(command, i, c)
193✔
2208
                exec_command_dump(i, f, prefix);
98✔
2209
}
95✔
2210

2211
void exec_command_append_list(ExecCommand **l, ExecCommand *e) {
16,274✔
2212
        ExecCommand *end;
16,274✔
2213

2214
        assert(l);
16,274✔
2215
        assert(e);
16,274✔
2216

2217
        if (*l) {
16,274✔
2218
                /* It's kind of important, that we keep the order here */
2219
                end = LIST_FIND_TAIL(command, *l);
363✔
2220
                LIST_INSERT_AFTER(command, *l, end, e);
126✔
2221
        } else
2222
                *l = e;
16,148✔
2223
}
16,274✔
2224

2225
int exec_command_set(ExecCommand *c, const char *path, ...) {
188✔
2226
        va_list ap;
188✔
2227
        char **l, *p;
188✔
2228

2229
        assert(c);
188✔
2230
        assert(path);
188✔
2231

2232
        va_start(ap, path);
188✔
2233
        l = strv_new_ap(path, ap);
188✔
2234
        va_end(ap);
188✔
2235

2236
        if (!l)
188✔
2237
                return -ENOMEM;
188✔
2238

2239
        p = strdup(path);
188✔
2240
        if (!p) {
188✔
2241
                strv_free(l);
×
2242
                return -ENOMEM;
×
2243
        }
2244

2245
        free_and_replace(c->path, p);
188✔
2246

2247
        return strv_free_and_replace(c->argv, l);
188✔
2248
}
2249

2250
int exec_command_append(ExecCommand *c, const char *path, ...) {
277✔
2251
        char **l;
277✔
2252
        va_list ap;
277✔
2253
        int r;
277✔
2254

2255
        assert(c);
277✔
2256
        assert(path);
277✔
2257

2258
        va_start(ap, path);
277✔
2259
        l = strv_new_ap(path, ap);
277✔
2260
        va_end(ap);
277✔
2261

2262
        if (!l)
277✔
2263
                return -ENOMEM;
277✔
2264

2265
        r = strv_extend_strv_consume(&c->argv, l, /* filter_duplicates = */ false);
277✔
2266
        if (r < 0)
277✔
2267
                return r;
×
2268

2269
        return 0;
2270
}
2271

2272
static char *destroy_tree(char *path) {
251✔
2273
        if (!path)
251✔
2274
                return NULL;
2275

2276
        if (!path_equal(path, RUN_SYSTEMD_EMPTY)) {
88✔
2277
                log_debug("Spawning process to nuke '%s'", path);
88✔
2278

2279
                (void) asynchronous_rm_rf(path, REMOVE_ROOT|REMOVE_SUBVOLUME|REMOVE_PHYSICAL);
88✔
2280
        }
2281

2282
        return mfree(path);
88✔
2283
}
2284

2285
void exec_shared_runtime_done(ExecSharedRuntime *rt) {
95,233✔
2286
        assert(rt);
95,233✔
2287

2288
        if (rt->manager)
95,233✔
2289
                (void) hashmap_remove(rt->manager->exec_shared_runtime_by_id, rt->id);
150✔
2290

2291
        rt->id = mfree(rt->id);
95,233✔
2292
        rt->tmp_dir = mfree(rt->tmp_dir);
95,233✔
2293
        rt->var_tmp_dir = mfree(rt->var_tmp_dir);
95,233✔
2294
        safe_close_pair(rt->userns_storage_socket);
95,233✔
2295
        safe_close_pair(rt->netns_storage_socket);
95,233✔
2296
        safe_close_pair(rt->ipcns_storage_socket);
95,233✔
2297
}
95,233✔
2298

2299
static ExecSharedRuntime* exec_shared_runtime_free(ExecSharedRuntime *rt) {
95,201✔
2300
        if (!rt)
95,201✔
2301
                return NULL;
2302

2303
        exec_shared_runtime_done(rt);
95,201✔
2304
        return mfree(rt);
95,201✔
2305
}
2306

2307
DEFINE_TRIVIAL_UNREF_FUNC(ExecSharedRuntime, exec_shared_runtime, exec_shared_runtime_free);
151✔
2308
DEFINE_TRIVIAL_CLEANUP_FUNC(ExecSharedRuntime*, exec_shared_runtime_free);
97,673✔
2309

2310
ExecSharedRuntime* exec_shared_runtime_destroy(ExecSharedRuntime *rt) {
51✔
2311
        if (!rt)
51✔
2312
                return NULL;
2313

2314
        assert(rt->n_ref > 0);
50✔
2315
        rt->n_ref--;
50✔
2316

2317
        if (rt->n_ref > 0)
50✔
2318
                return NULL;
2319

2320
        rt->tmp_dir = destroy_tree(rt->tmp_dir);
50✔
2321
        rt->var_tmp_dir = destroy_tree(rt->var_tmp_dir);
50✔
2322

2323
        return exec_shared_runtime_free(rt);
50✔
2324
}
2325

2326
static int exec_shared_runtime_allocate(ExecSharedRuntime **ret, const char *id) {
95,201✔
2327
        _cleanup_free_ char *id_copy = NULL;
190,402✔
2328
        ExecSharedRuntime *n;
95,201✔
2329

2330
        assert(ret);
95,201✔
2331

2332
        id_copy = strdup(id);
95,201✔
2333
        if (!id_copy)
95,201✔
2334
                return -ENOMEM;
2335

2336
        n = new(ExecSharedRuntime, 1);
95,201✔
2337
        if (!n)
95,201✔
2338
                return -ENOMEM;
2339

2340
        *n = (ExecSharedRuntime) {
95,201✔
2341
                .id = TAKE_PTR(id_copy),
95,201✔
2342
                .userns_storage_socket = EBADF_PAIR,
2343
                .netns_storage_socket = EBADF_PAIR,
2344
                .ipcns_storage_socket = EBADF_PAIR,
2345
        };
2346

2347
        *ret = n;
95,201✔
2348
        return 0;
95,201✔
2349
}
2350

2351
static int exec_shared_runtime_add(
150✔
2352
                Manager *m,
2353
                const char *id,
2354
                char **tmp_dir,
2355
                char **var_tmp_dir,
2356
                int userns_storage_socket[2],
2357
                int netns_storage_socket[2],
2358
                int ipcns_storage_socket[2],
2359
                ExecSharedRuntime **ret) {
2360

2361
        _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt = NULL;
150✔
2362
        int r;
150✔
2363

2364
        assert(m);
150✔
2365
        assert(id);
150✔
2366

2367
        /* tmp_dir, var_tmp_dir, {net,ipc}ns_storage_socket fds are donated on success */
2368

2369
        r = exec_shared_runtime_allocate(&rt, id);
150✔
2370
        if (r < 0)
150✔
2371
                return r;
2372

2373
        r = hashmap_ensure_put(&m->exec_shared_runtime_by_id, &string_hash_ops, rt->id, rt);
150✔
2374
        if (r < 0)
150✔
2375
                return r;
2376

2377
        assert(!!rt->tmp_dir == !!rt->var_tmp_dir); /* We require both to be set together */
150✔
2378
        rt->tmp_dir = TAKE_PTR(*tmp_dir);
150✔
2379
        rt->var_tmp_dir = TAKE_PTR(*var_tmp_dir);
150✔
2380

2381
        if (userns_storage_socket) {
150✔
2382
                rt->userns_storage_socket[0] = TAKE_FD(userns_storage_socket[0]);
150✔
2383
                rt->userns_storage_socket[1] = TAKE_FD(userns_storage_socket[1]);
150✔
2384
        }
2385

2386
        if (netns_storage_socket) {
150✔
2387
                rt->netns_storage_socket[0] = TAKE_FD(netns_storage_socket[0]);
150✔
2388
                rt->netns_storage_socket[1] = TAKE_FD(netns_storage_socket[1]);
150✔
2389
        }
2390

2391
        if (ipcns_storage_socket) {
150✔
2392
                rt->ipcns_storage_socket[0] = TAKE_FD(ipcns_storage_socket[0]);
150✔
2393
                rt->ipcns_storage_socket[1] = TAKE_FD(ipcns_storage_socket[1]);
150✔
2394
        }
2395

2396
        rt->manager = m;
150✔
2397

2398
        if (ret)
150✔
2399
                *ret = rt;
71✔
2400
        /* do not remove created ExecSharedRuntime object when the operation succeeds. */
2401
        TAKE_PTR(rt);
150✔
2402
        return 0;
150✔
2403
}
2404

2405
static int exec_shared_runtime_make(
5,461✔
2406
                Manager *m,
2407
                const ExecContext *c,
2408
                const char *id,
2409
                ExecSharedRuntime **ret) {
2410

2411
        _cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
5,461✔
2412
        _cleanup_close_pair_ int userns_storage_socket[2] = EBADF_PAIR, netns_storage_socket[2] = EBADF_PAIR, ipcns_storage_socket[2] = EBADF_PAIR;
16,383✔
2413
        int r;
5,461✔
2414

2415
        assert(m);
5,461✔
2416
        assert(c);
5,461✔
2417
        assert(id);
5,461✔
2418

2419
        /* It is not necessary to create ExecSharedRuntime object. */
2420
        if (!exec_needs_network_namespace(c) && !exec_needs_ipc_namespace(c) && c->private_tmp != PRIVATE_TMP_CONNECTED) {
5,461✔
2421
                *ret = NULL;
5,390✔
2422
                return 0;
5,390✔
2423
        }
2424

2425
        if (c->private_tmp == PRIVATE_TMP_CONNECTED &&
136✔
2426
            !(prefixed_path_strv_contains(c->inaccessible_paths, "/tmp") &&
65✔
2427
              (prefixed_path_strv_contains(c->inaccessible_paths, "/var/tmp") ||
×
2428
               prefixed_path_strv_contains(c->inaccessible_paths, "/var")))) {
×
2429
                r = setup_tmp_dirs(id, &tmp_dir, &var_tmp_dir);
65✔
2430
                if (r < 0)
65✔
2431
                        return r;
2432
        }
2433

2434
        if (c->user_namespace_path)
71✔
2435
                if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, userns_storage_socket) < 0)
×
2436
                        return -errno;
×
2437

2438
        if (exec_needs_network_namespace(c))
71✔
2439
                if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, netns_storage_socket) < 0)
7✔
2440
                        return -errno;
×
2441

2442
        if (exec_needs_ipc_namespace(c))
71✔
2443
                if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ipcns_storage_socket) < 0)
2✔
2444
                        return -errno;
×
2445

2446
        r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, userns_storage_socket, netns_storage_socket, ipcns_storage_socket, ret);
71✔
2447
        if (r < 0)
71✔
2448
                return r;
×
2449

2450
        return 1;
2451
}
2452

2453
int exec_shared_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool create, ExecSharedRuntime **ret) {
5,540✔
2454
        ExecSharedRuntime *rt;
5,540✔
2455
        int r;
5,540✔
2456

2457
        assert(m);
5,540✔
2458
        assert(id);
5,540✔
2459
        assert(ret);
5,540✔
2460

2461
        rt = hashmap_get(m->exec_shared_runtime_by_id, id);
5,540✔
2462
        if (rt)
5,540✔
2463
                /* We already have an ExecSharedRuntime object, let's increase the ref count and reuse it */
2464
                goto ref;
79✔
2465

2466
        if (!create) {
5,461✔
2467
                *ret = NULL;
×
2468
                return 0;
×
2469
        }
2470

2471
        /* If not found, then create a new object. */
2472
        r = exec_shared_runtime_make(m, c, id, &rt);
5,461✔
2473
        if (r < 0)
5,461✔
2474
                return r;
2475
        if (r == 0) {
5,461✔
2476
                /* When r == 0, it is not necessary to create ExecSharedRuntime object. */
2477
                *ret = NULL;
5,390✔
2478
                return 0;
5,390✔
2479
        }
2480

2481
ref:
71✔
2482
        /* increment reference counter. */
2483
        rt->n_ref++;
150✔
2484
        *ret = rt;
150✔
2485
        return 1;
150✔
2486
}
2487

2488
int exec_shared_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
63✔
2489
        ExecSharedRuntime *rt;
63✔
2490

2491
        assert(m);
63✔
2492
        assert(f);
63✔
2493
        assert(fds);
63✔
2494

2495
        HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
163✔
2496
                fprintf(f, "exec-runtime=%s", rt->id);
100✔
2497

2498
                if (rt->tmp_dir)
100✔
2499
                        fprintf(f, " tmp-dir=%s", rt->tmp_dir);
100✔
2500

2501
                if (rt->var_tmp_dir)
100✔
2502
                        fprintf(f, " var-tmp-dir=%s", rt->var_tmp_dir);
100✔
2503

2504
                if (rt->userns_storage_socket[0] >= 0) {
100✔
2505
                        int copy;
×
2506

2507
                        copy = fdset_put_dup(fds, rt->userns_storage_socket[0]);
×
2508
                        if (copy < 0)
×
2509
                                return copy;
×
2510

2511
                        fprintf(f, " userns-socket-0=%i", copy);
×
2512
                }
2513

2514
                if (rt->userns_storage_socket[1] >= 0) {
100✔
2515
                        int copy;
×
2516

2517
                        copy = fdset_put_dup(fds, rt->userns_storage_socket[1]);
×
2518
                        if (copy < 0)
×
2519
                                return copy;
2520

2521
                        fprintf(f, " userns-socket-1=%i", copy);
×
2522
                }
2523

2524
                if (rt->netns_storage_socket[0] >= 0) {
100✔
2525
                        int copy;
2✔
2526

2527
                        copy = fdset_put_dup(fds, rt->netns_storage_socket[0]);
2✔
2528
                        if (copy < 0)
2✔
2529
                                return copy;
2530

2531
                        fprintf(f, " netns-socket-0=%i", copy);
2✔
2532
                }
2533

2534
                if (rt->netns_storage_socket[1] >= 0) {
100✔
2535
                        int copy;
2✔
2536

2537
                        copy = fdset_put_dup(fds, rt->netns_storage_socket[1]);
2✔
2538
                        if (copy < 0)
2✔
2539
                                return copy;
2540

2541
                        fprintf(f, " netns-socket-1=%i", copy);
2✔
2542
                }
2543

2544
                if (rt->ipcns_storage_socket[0] >= 0) {
100✔
2545
                        int copy;
×
2546

2547
                        copy = fdset_put_dup(fds, rt->ipcns_storage_socket[0]);
×
2548
                        if (copy < 0)
×
2549
                                return copy;
2550

2551
                        fprintf(f, " ipcns-socket-0=%i", copy);
×
2552
                }
2553

2554
                if (rt->ipcns_storage_socket[1] >= 0) {
100✔
2555
                        int copy;
×
2556

2557
                        copy = fdset_put_dup(fds, rt->ipcns_storage_socket[1]);
×
2558
                        if (copy < 0)
×
2559
                                return copy;
2560

2561
                        fprintf(f, " ipcns-socket-1=%i", copy);
×
2562
                }
2563

2564
                fputc('\n', f);
100✔
2565
        }
2566

2567
        return 0;
63✔
2568
}
2569

2570
int exec_shared_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds) {
97,523✔
2571
        _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt_create = NULL;
97,523✔
2572
        ExecSharedRuntime *rt = NULL;
97,523✔
2573
        int r;
97,523✔
2574

2575
        /* This is for the migration from old (v237 or earlier) deserialization text.
2576
         * Due to the bug #7790, this may not work with the units that use JoinsNamespaceOf=.
2577
         * Even if the ExecSharedRuntime object originally created by the other unit, we cannot judge
2578
         * so or not from the serialized text, then we always creates a new object owned by this. */
2579

2580
        assert(u);
97,523✔
2581
        assert(key);
97,523✔
2582
        assert(value);
97,523✔
2583

2584
        /* Manager manages ExecSharedRuntime objects by the unit id.
2585
         * So, we omit the serialized text when the unit does not have id (yet?)... */
2586
        if (isempty(u->id)) {
97,523✔
2587
                log_unit_debug(u, "Invocation ID not found. Dropping runtime parameter.");
×
2588
                return 0;
×
2589
        }
2590

2591
        if (u->manager) {
97,523✔
2592
                if (hashmap_ensure_allocated(&u->manager->exec_shared_runtime_by_id, &string_hash_ops) < 0)
97,523✔
2593
                        return log_oom();
×
2594

2595
                rt = hashmap_get(u->manager->exec_shared_runtime_by_id, u->id);
97,523✔
2596
        }
2597
        if (!rt) {
97,523✔
2598
                if (exec_shared_runtime_allocate(&rt_create, u->id) < 0)
95,051✔
2599
                        return log_oom();
×
2600

2601
                rt = rt_create;
95,051✔
2602
        }
2603

2604
        if (streq(key, "tmp-dir")) {
97,523✔
2605
                if (free_and_strdup_warn(&rt->tmp_dir, value) < 0)
×
2606
                        return -ENOMEM;
2607

2608
        } else if (streq(key, "var-tmp-dir")) {
97,523✔
2609
                if (free_and_strdup_warn(&rt->var_tmp_dir, value) < 0)
×
2610
                        return -ENOMEM;
2611

2612
        } else if (streq(key, "netns-socket-0")) {
97,523✔
2613

2614
                safe_close(rt->netns_storage_socket[0]);
×
2615
                rt->netns_storage_socket[0] = deserialize_fd(fds, value);
×
2616
                if (rt->netns_storage_socket[0] < 0)
×
2617
                        return 0;
2618

2619
        } else if (streq(key, "netns-socket-1")) {
97,523✔
2620

2621
                safe_close(rt->netns_storage_socket[1]);
×
2622
                rt->netns_storage_socket[1] = deserialize_fd(fds, value);
×
2623
                if (rt->netns_storage_socket[1] < 0)
×
2624
                        return 0;
2625
        } else
2626
                return 0;
2627

2628
        /* If the object is newly created, then put it to the hashmap which manages ExecSharedRuntime objects. */
2629
        if (rt_create && u->manager) {
×
2630
                r = hashmap_put(u->manager->exec_shared_runtime_by_id, rt_create->id, rt_create);
×
2631
                if (r < 0) {
×
2632
                        log_unit_debug_errno(u, r, "Failed to put runtime parameter to manager's storage: %m");
×
2633
                        return 0;
×
2634
                }
2635

2636
                rt_create->manager = u->manager;
×
2637

2638
                /* Avoid cleanup */
2639
                TAKE_PTR(rt_create);
×
2640
        }
2641

2642
        return 1;
2643
}
2644

2645
int exec_shared_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
79✔
2646
        _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
79✔
2647
        char *id = NULL;
79✔
2648
        int r, userns_fdpair[] = {-1, -1}, netns_fdpair[] = {-1, -1}, ipcns_fdpair[] = {-1, -1};
79✔
2649
        const char *p, *v = ASSERT_PTR(value);
79✔
2650
        size_t n;
79✔
2651

2652
        assert(m);
79✔
2653
        assert(fds);
79✔
2654

2655
        n = strcspn(v, " ");
79✔
2656
        id = strndupa_safe(v, n);
79✔
2657
        if (v[n] != ' ')
79✔
2658
                goto finalize;
×
2659
        p = v + n + 1;
79✔
2660

2661
        v = startswith(p, "tmp-dir=");
79✔
2662
        if (v) {
79✔
2663
                n = strcspn(v, " ");
79✔
2664
                tmp_dir = strndup(v, n);
79✔
2665
                if (!tmp_dir)
79✔
2666
                        return log_oom();
×
2667
                if (v[n] != ' ')
79✔
2668
                        goto finalize;
×
2669
                p = v + n + 1;
79✔
2670
        }
2671

2672
        v = startswith(p, "var-tmp-dir=");
79✔
2673
        if (v) {
79✔
2674
                n = strcspn(v, " ");
79✔
2675
                var_tmp_dir = strndup(v, n);
79✔
2676
                if (!var_tmp_dir)
79✔
2677
                        return log_oom();
×
2678
                if (v[n] != ' ')
79✔
2679
                        goto finalize;
78✔
2680
                p = v + n + 1;
1✔
2681
        }
2682

2683
        v = startswith(p, "userns-socket-0=");
1✔
2684
        if (v) {
1✔
2685
                char *buf;
×
2686

2687
                n = strcspn(v, " ");
×
2688
                buf = strndupa_safe(v, n);
×
2689

2690
                userns_fdpair[0] = deserialize_fd(fds, buf);
×
2691
                if (userns_fdpair[0] < 0)
×
2692
                        return userns_fdpair[0];
2693
                if (v[n] != ' ')
×
2694
                        goto finalize;
×
2695
                p = v + n + 1;
×
2696
        }
2697

2698
        v = startswith(p, "userns-socket-1=");
1✔
2699
        if (v) {
1✔
2700
                char *buf;
×
2701

2702
                n = strcspn(v, " ");
×
2703
                buf = strndupa_safe(v, n);
×
2704

2705
                userns_fdpair[1] = deserialize_fd(fds, buf);
×
2706
                if (userns_fdpair[1] < 0)
×
2707
                        return userns_fdpair[1];
2708
                if (v[n] != ' ')
×
2709
                        goto finalize;
×
2710
                p = v + n + 1;
×
2711
        }
2712

2713
        v = startswith(p, "netns-socket-0=");
1✔
2714
        if (v) {
1✔
2715
                char *buf;
1✔
2716

2717
                n = strcspn(v, " ");
1✔
2718
                buf = strndupa_safe(v, n);
1✔
2719

2720
                netns_fdpair[0] = deserialize_fd(fds, buf);
1✔
2721
                if (netns_fdpair[0] < 0)
1✔
2722
                        return netns_fdpair[0];
2723
                if (v[n] != ' ')
1✔
2724
                        goto finalize;
×
2725
                p = v + n + 1;
1✔
2726
        }
2727

2728
        v = startswith(p, "netns-socket-1=");
1✔
2729
        if (v) {
1✔
2730
                char *buf;
1✔
2731

2732
                n = strcspn(v, " ");
1✔
2733
                buf = strndupa_safe(v, n);
1✔
2734

2735
                netns_fdpair[1] = deserialize_fd(fds, buf);
1✔
2736
                if (netns_fdpair[1] < 0)
1✔
2737
                        return netns_fdpair[1];
2738
                if (v[n] != ' ')
1✔
2739
                        goto finalize;
1✔
2740
                p = v + n + 1;
×
2741
        }
2742

2743
        v = startswith(p, "ipcns-socket-0=");
×
2744
        if (v) {
×
2745
                char *buf;
×
2746

2747
                n = strcspn(v, " ");
×
2748
                buf = strndupa_safe(v, n);
×
2749

2750
                ipcns_fdpair[0] = deserialize_fd(fds, buf);
×
2751
                if (ipcns_fdpair[0] < 0)
×
2752
                        return ipcns_fdpair[0];
2753
                if (v[n] != ' ')
×
2754
                        goto finalize;
×
2755
                p = v + n + 1;
×
2756
        }
2757

2758
        v = startswith(p, "ipcns-socket-1=");
×
2759
        if (v) {
×
2760
                char *buf;
×
2761

2762
                n = strcspn(v, " ");
×
2763
                buf = strndupa_safe(v, n);
×
2764

2765
                ipcns_fdpair[1] = deserialize_fd(fds, buf);
×
2766
                if (ipcns_fdpair[1] < 0)
×
2767
                        return ipcns_fdpair[1];
2768
        }
2769

2770
finalize:
×
2771
        r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, userns_fdpair, netns_fdpair, ipcns_fdpair, NULL);
79✔
2772
        if (r < 0)
79✔
2773
                return log_debug_errno(r, "Failed to add exec-runtime: %m");
×
2774
        return 0;
2775
}
2776

2777
void exec_shared_runtime_vacuum(Manager *m) {
1,506✔
2778
        ExecSharedRuntime *rt;
1,506✔
2779

2780
        assert(m);
1,506✔
2781

2782
        /* Free unreferenced ExecSharedRuntime objects. This is used after manager deserialization process. */
2783

2784
        HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
1,585✔
2785
                if (rt->n_ref > 0)
79✔
2786
                        continue;
79✔
2787

2788
                (void) exec_shared_runtime_free(rt);
×
2789
        }
2790
}
1,506✔
2791

2792
int exec_runtime_make(
5,540✔
2793
                const Unit *unit,
2794
                const ExecContext *context,
2795
                ExecSharedRuntime *shared,
2796
                DynamicCreds *creds,
2797
                ExecRuntime **ret) {
2798
        _cleanup_close_pair_ int ephemeral_storage_socket[2] = EBADF_PAIR;
5,540✔
2799
        _cleanup_free_ char *ephemeral = NULL;
5,540✔
2800
        _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
5,540✔
2801
        int r;
5,540✔
2802

2803
        assert(unit);
5,540✔
2804
        assert(context);
5,540✔
2805
        assert(ret);
5,540✔
2806

2807
        if (!shared && !creds && !exec_needs_ephemeral(context)) {
5,540✔
2808
                *ret = NULL;
5,389✔
2809
                return 0;
5,389✔
2810
        }
2811

2812
        if (exec_needs_ephemeral(context)) {
151✔
2813
                r = mkdir_p("/var/lib/systemd/ephemeral-trees", 0755);
×
2814
                if (r < 0)
×
2815
                        return r;
2816

2817
                r = tempfn_random_child("/var/lib/systemd/ephemeral-trees", unit->id, &ephemeral);
×
2818
                if (r < 0)
×
2819
                        return r;
2820

2821
                if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ephemeral_storage_socket) < 0)
×
2822
                        return -errno;
×
2823
        }
2824

2825
        rt = new(ExecRuntime, 1);
151✔
2826
        if (!rt)
151✔
2827
                return -ENOMEM;
2828

2829
        *rt = (ExecRuntime) {
151✔
2830
                .shared = shared,
2831
                .dynamic_creds = creds,
2832
                .ephemeral_copy = TAKE_PTR(ephemeral),
151✔
2833
                .ephemeral_storage_socket[0] = TAKE_FD(ephemeral_storage_socket[0]),
151✔
2834
                .ephemeral_storage_socket[1] = TAKE_FD(ephemeral_storage_socket[1]),
151✔
2835
        };
2836

2837
        *ret = TAKE_PTR(rt);
151✔
2838
        return 1;
151✔
2839
}
2840

2841
ExecRuntime* exec_runtime_free(ExecRuntime *rt) {
48,467✔
2842
        if (!rt)
48,467✔
2843
                return NULL;
2844

2845
        exec_shared_runtime_unref(rt->shared);
151✔
2846
        dynamic_creds_unref(rt->dynamic_creds);
151✔
2847

2848
        rt->ephemeral_copy = destroy_tree(rt->ephemeral_copy);
151✔
2849

2850
        safe_close_pair(rt->ephemeral_storage_socket);
151✔
2851
        return mfree(rt);
151✔
2852
}
2853

2854
ExecRuntime* exec_runtime_destroy(ExecRuntime *rt) {
5,825✔
2855
        if (!rt)
5,825✔
2856
                return NULL;
2857

2858
        rt->shared = exec_shared_runtime_destroy(rt->shared);
51✔
2859
        rt->dynamic_creds = dynamic_creds_destroy(rt->dynamic_creds);
51✔
2860
        return exec_runtime_free(rt);
51✔
2861
}
2862

2863
void exec_runtime_clear(ExecRuntime *rt) {
32✔
2864
        if (!rt)
32✔
2865
                return;
2866

2867
        safe_close_pair(rt->ephemeral_storage_socket);
32✔
2868
        rt->ephemeral_copy = mfree(rt->ephemeral_copy);
32✔
2869
}
2870

2871
void exec_params_shallow_clear(ExecParameters *p) {
2,159✔
2872
        if (!p)
2,159✔
2873
                return;
2874

2875
        /* This is called on the PID1 side, as many of the struct's FDs are only borrowed, and actually
2876
         * owned by the manager or other objects, and reused across multiple units. */
2877

2878
        p->environment = strv_free(p->environment);
2,159✔
2879
        p->fd_names = strv_free(p->fd_names);
2,159✔
2880
        p->files_env = strv_free(p->files_env);
2,159✔
2881
        p->fds = mfree(p->fds);
2,159✔
2882
        p->exec_fd = safe_close(p->exec_fd);
2,159✔
2883
        p->user_lookup_fd = -EBADF;
2,159✔
2884
        p->bpf_restrict_fs_map_fd = -EBADF;
2,159✔
2885
        p->unit_id = mfree(p->unit_id);
2,159✔
2886
        p->invocation_id = SD_ID128_NULL;
2,159✔
2887
        p->invocation_id_string[0] = '\0';
2,159✔
2888
        p->confirm_spawn = mfree(p->confirm_spawn);
2,159✔
2889
}
2890

2891
void exec_params_deep_clear(ExecParameters *p) {
32✔
2892
        if (!p)
32✔
2893
                return;
2894

2895
        /* This is called on the sd-executor side, where everything received is owned by the process and has
2896
         * to be fully cleaned up to make sanitizers and analyzers happy, as opposed as the shallow clean
2897
         * function above. */
2898

2899
        close_many_unset(p->fds, p->n_socket_fds + p->n_stashed_fds);
32✔
2900

2901
        p->cgroup_path = mfree(p->cgroup_path);
32✔
2902

2903
        if (p->prefix) {
32✔
2904
                free_many_charp(p->prefix, _EXEC_DIRECTORY_TYPE_MAX);
32✔
2905
                p->prefix = mfree(p->prefix);
32✔
2906
        }
2907

2908
        p->received_credentials_directory = mfree(p->received_credentials_directory);
32✔
2909
        p->received_encrypted_credentials_directory = mfree(p->received_encrypted_credentials_directory);
32✔
2910

2911
        if (p->idle_pipe) {
32✔
2912
                close_many_and_free(p->idle_pipe, 4);
×
2913
                p->idle_pipe = NULL;
×
2914
        }
2915

2916
        p->stdin_fd = safe_close(p->stdin_fd);
32✔
2917
        p->stdout_fd = safe_close(p->stdout_fd);
32✔
2918
        p->stderr_fd = safe_close(p->stderr_fd);
32✔
2919
        p->root_directory_fd = safe_close(p->root_directory_fd);
32✔
2920

2921
        p->notify_socket = mfree(p->notify_socket);
32✔
2922

2923
        open_file_free_many(&p->open_files);
32✔
2924

2925
        p->fallback_smack_process_label = mfree(p->fallback_smack_process_label);
32✔
2926

2927
        exec_params_shallow_clear(p);
32✔
2928
}
2929

2930
void exec_directory_done(ExecDirectory *d) {
242,240✔
2931
        if (!d)
242,240✔
2932
                return;
2933

2934
        FOREACH_ARRAY(i, d->items, d->n_items) {
243,735✔
2935
                free(i->path);
1,495✔
2936
                strv_free(i->symlinks);
1,495✔
2937
        }
2938

2939
        d->items = mfree(d->items);
242,240✔
2940
        d->n_items = 0;
242,240✔
2941
        d->mode = 0755;
242,240✔
2942
}
2943

2944
static ExecDirectoryItem *exec_directory_find(ExecDirectory *d, const char *path) {
4,419✔
2945
        assert(d);
4,419✔
2946
        assert(path);
4,419✔
2947

2948
        FOREACH_ARRAY(i, d->items, d->n_items)
6,753✔
2949
                if (path_equal(i->path, path))
2,349✔
2950
                        return i;
2951

2952
        return NULL;
2953
}
2954

2955
int exec_directory_add(ExecDirectory *d, const char *path, const char *symlink, ExecDirectoryFlags flags) {
4,419✔
2956
        _cleanup_strv_free_ char **s = NULL;
×
2957
        _cleanup_free_ char *p = NULL;
4,419✔
2958
        ExecDirectoryItem *existing;
4,419✔
2959
        int r;
4,419✔
2960

2961
        assert(d);
4,419✔
2962
        assert(path);
4,419✔
2963

2964
        existing = exec_directory_find(d, path);
4,419✔
2965
        if (existing) {
4,419✔
2966
                r = strv_extend(&existing->symlinks, symlink);
15✔
2967
                if (r < 0)
15✔
2968
                        return r;
2969

2970
                existing->flags |= flags;
15✔
2971

2972
                return 0; /* existing item is updated */
15✔
2973
        }
2974

2975
        p = strdup(path);
4,404✔
2976
        if (!p)
4,404✔
2977
                return -ENOMEM;
2978

2979
        if (symlink) {
4,404✔
2980
                s = strv_new(symlink);
6✔
2981
                if (!s)
6✔
2982
                        return -ENOMEM;
2983
        }
2984

2985
        if (!GREEDY_REALLOC(d->items, d->n_items + 1))
4,404✔
2986
                return -ENOMEM;
2987

2988
        d->items[d->n_items++] = (ExecDirectoryItem) {
4,404✔
2989
                .path = TAKE_PTR(p),
4,404✔
2990
                .symlinks = TAKE_PTR(s),
4,404✔
2991
                .flags = flags,
2992
        };
2993

2994
        return 1; /* new item is added */
4,404✔
2995
}
2996

2997
static int exec_directory_item_compare_func(const ExecDirectoryItem *a, const ExecDirectoryItem *b) {
862✔
2998
        assert(a);
862✔
2999
        assert(b);
862✔
3000

3001
        return path_compare(a->path, b->path);
862✔
3002
}
3003

3004
void exec_directory_sort(ExecDirectory *d) {
133,396✔
3005
        assert(d);
133,396✔
3006

3007
        /* Sort the exec directories to make always parent directories processed at first in
3008
         * setup_exec_directory(), e.g., even if StateDirectory=foo/bar foo, we need to create foo at first,
3009
         * then foo/bar. Also, set the ONLY_CREATE flag if one of the parent directories is contained in the
3010
         * list. See also comments in setup_exec_directory() and issue #24783. */
3011

3012
        if (d->n_items <= 1)
133,396✔
3013
                return;
3014

3015
        typesafe_qsort(d->items, d->n_items, exec_directory_item_compare_func);
156✔
3016

3017
        for (size_t i = 1; i < d->n_items; i++)
675✔
3018
                for (size_t j = 0; j < i; j++)
1,724✔
3019
                        if (path_startswith(d->items[i].path, d->items[j].path)) {
1,220✔
3020
                                d->items[i].flags |= EXEC_DIRECTORY_ONLY_CREATE;
15✔
3021
                                break;
15✔
3022
                        }
3023
}
3024

3025
ExecCleanMask exec_clean_mask_from_string(const char *s) {
×
3026
        ExecDirectoryType t;
×
3027

3028
        assert(s);
×
3029

3030
        if (streq(s, "all"))
×
3031
                return EXEC_CLEAN_ALL;
3032
        if (streq(s, "fdstore"))
×
3033
                return EXEC_CLEAN_FDSTORE;
3034

3035
        t = exec_resource_type_from_string(s);
×
3036
        if (t < 0)
×
3037
                return (ExecCleanMask) t;
3038

3039
        return 1U << t;
×
3040
}
3041

3042
static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
3043
        [EXEC_INPUT_NULL]      = "null",
3044
        [EXEC_INPUT_TTY]       = "tty",
3045
        [EXEC_INPUT_TTY_FORCE] = "tty-force",
3046
        [EXEC_INPUT_TTY_FAIL]  = "tty-fail",
3047
        [EXEC_INPUT_SOCKET]    = "socket",
3048
        [EXEC_INPUT_NAMED_FD]  = "fd",
3049
        [EXEC_INPUT_DATA]      = "data",
3050
        [EXEC_INPUT_FILE]      = "file",
3051
};
3052

3053
DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
14,319✔
3054

3055
static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
3056
        [EXEC_OUTPUT_INHERIT]             = "inherit",
3057
        [EXEC_OUTPUT_NULL]                = "null",
3058
        [EXEC_OUTPUT_TTY]                 = "tty",
3059
        [EXEC_OUTPUT_KMSG]                = "kmsg",
3060
        [EXEC_OUTPUT_KMSG_AND_CONSOLE]    = "kmsg+console",
3061
        [EXEC_OUTPUT_JOURNAL]             = "journal",
3062
        [EXEC_OUTPUT_JOURNAL_AND_CONSOLE] = "journal+console",
3063
        [EXEC_OUTPUT_SOCKET]              = "socket",
3064
        [EXEC_OUTPUT_NAMED_FD]            = "fd",
3065
        [EXEC_OUTPUT_FILE]                = "file",
3066
        [EXEC_OUTPUT_FILE_APPEND]         = "append",
3067
        [EXEC_OUTPUT_FILE_TRUNCATE]       = "truncate",
3068
};
3069

3070
DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
28,853✔
3071

3072
static const char* const exec_utmp_mode_table[_EXEC_UTMP_MODE_MAX] = {
3073
        [EXEC_UTMP_INIT]  = "init",
3074
        [EXEC_UTMP_LOGIN] = "login",
3075
        [EXEC_UTMP_USER]  = "user",
3076
};
3077

3078
DEFINE_STRING_TABLE_LOOKUP(exec_utmp_mode, ExecUtmpMode);
13,612✔
3079

3080
static const char* const exec_preserve_mode_table[_EXEC_PRESERVE_MODE_MAX] = {
3081
        [EXEC_PRESERVE_NO]      = "no",
3082
        [EXEC_PRESERVE_YES]     = "yes",
3083
        [EXEC_PRESERVE_RESTART] = "restart",
3084
};
3085

3086
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode, ExecPreserveMode, EXEC_PRESERVE_YES);
15,808✔
3087

3088
/* This table maps ExecDirectoryType to the symlink setting it is configured with in the unit */
3089
static const char* const exec_directory_type_symlink_table[_EXEC_DIRECTORY_TYPE_MAX] = {
3090
        [EXEC_DIRECTORY_RUNTIME]       = "RuntimeDirectorySymlink",
3091
        [EXEC_DIRECTORY_STATE]         = "StateDirectorySymlink",
3092
        [EXEC_DIRECTORY_CACHE]         = "CacheDirectorySymlink",
3093
        [EXEC_DIRECTORY_LOGS]          = "LogsDirectorySymlink",
3094
        [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectorySymlink",
3095
};
3096

3097
DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_symlink, ExecDirectoryType);
14✔
3098

3099
static const char* const exec_directory_type_mode_table[_EXEC_DIRECTORY_TYPE_MAX] = {
3100
        [EXEC_DIRECTORY_RUNTIME]       = "RuntimeDirectoryMode",
3101
        [EXEC_DIRECTORY_STATE]         = "StateDirectoryMode",
3102
        [EXEC_DIRECTORY_CACHE]         = "CacheDirectoryMode",
3103
        [EXEC_DIRECTORY_LOGS]          = "LogsDirectoryMode",
3104
        [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectoryMode",
3105
};
3106

3107
DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_mode, ExecDirectoryType);
×
3108

3109
/* And this table maps ExecDirectoryType too, but to a generic term identifying the type of resource. This
3110
 * one is supposed to be generic enough to be used for unit types that don't use ExecContext and per-unit
3111
 * directories, specifically .timer units with their timestamp touch file. */
3112
static const char* const exec_resource_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
3113
        [EXEC_DIRECTORY_RUNTIME]       = "runtime",
3114
        [EXEC_DIRECTORY_STATE]         = "state",
3115
        [EXEC_DIRECTORY_CACHE]         = "cache",
3116
        [EXEC_DIRECTORY_LOGS]          = "logs",
3117
        [EXEC_DIRECTORY_CONFIGURATION] = "configuration",
3118
};
3119

3120
DEFINE_STRING_TABLE_LOOKUP(exec_resource_type, ExecDirectoryType);
254✔
3121

3122
static const char* const exec_keyring_mode_table[_EXEC_KEYRING_MODE_MAX] = {
3123
        [EXEC_KEYRING_INHERIT] = "inherit",
3124
        [EXEC_KEYRING_PRIVATE] = "private",
3125
        [EXEC_KEYRING_SHARED]  = "shared",
3126
};
3127

3128
DEFINE_STRING_TABLE_LOOKUP(exec_keyring_mode, ExecKeyringMode);
13,950✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc