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

systemd / systemd / 15288324789

27 May 2025 07:40PM UTC coverage: 71.981% (-0.07%) from 72.046%
15288324789

push

github

yuwata
timedate: print better errors when systemd-timesyncd.service unavailable

If the error is a common bus error indicating the service is not
available, print a more user-friendly message indicating so.

0 of 7 new or added lines in 1 file covered. (0.0%)

3467 existing lines in 62 files now uncovered.

299170 of 415625 relevant lines covered (71.98%)

704053.27 hits per line

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

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

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

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

68
static bool is_terminal_input(ExecInput i) {
34,524✔
69
        return IN_SET(i,
34,524✔
70
                      EXEC_INPUT_TTY,
71
                      EXEC_INPUT_TTY_FORCE,
72
                      EXEC_INPUT_TTY_FAIL);
73
}
74

75
static bool is_terminal_output(ExecOutput o) {
67,990✔
76
        return IN_SET(o,
67,990✔
77
                      EXEC_OUTPUT_TTY,
78
                      EXEC_OUTPUT_KMSG_AND_CONSOLE,
79
                      EXEC_OUTPUT_JOURNAL_AND_CONSOLE);
80
}
81

82
const char* exec_context_tty_path(const ExecContext *context) {
14,755✔
83
        assert(context);
14,755✔
84

85
        if (context->stdio_as_fds)
14,755✔
86
                return NULL;
87

88
        if (context->tty_path)
14,077✔
89
                return context->tty_path;
708✔
90

91
        return "/dev/console";
92
}
93

94
int exec_context_apply_tty_size(
1,842✔
95
                const ExecContext *context,
96
                int input_fd,
97
                int output_fd,
98
                const char *tty_path) {
99

100
        unsigned rows, cols;
1,842✔
101
        int r;
1,842✔
102

103
        assert(context);
1,842✔
104
        assert(input_fd >= 0);
1,842✔
105
        assert(output_fd >= 0);
1,842✔
106

107
        if (!isatty_safe(output_fd))
1,842✔
108
                return 0;
1,842✔
109

110
        if (!tty_path)
1,084✔
111
                tty_path = exec_context_tty_path(context);
419✔
112

113
        /* Preferably use explicitly configured data */
114
        rows = context->tty_rows;
1,084✔
115
        cols = context->tty_cols;
1,084✔
116

117
        /* Fill in data from kernel command line if anything is unspecified */
118
        if (tty_path && (rows == UINT_MAX || cols == UINT_MAX))
1,084✔
119
                (void) proc_cmdline_tty_size(
1,052✔
120
                                tty_path,
121
                                rows == UINT_MAX ? &rows : NULL,
122
                                cols == UINT_MAX ? &cols : NULL);
123

124
        /* If we got nothing so far and we are talking to a physical device, then let's query dimensions from
125
         * the ANSI terminal driver. Note that we will not bother with this in case terminal reset via ansi
126
         * sequences is not enabled, as the DSR logic relies on ANSI sequences after all, and if we shall not
127
         * use those during initialization we need to skip it. */
128
        if (rows == UINT_MAX && cols == UINT_MAX &&
1,301✔
129
            exec_context_shall_ansi_seq_reset(context) &&
406✔
130
            isatty_safe(input_fd)) {
189✔
131
                r = terminal_get_size_by_dsr(input_fd, output_fd, &rows, &cols);
189✔
132
                if (r < 0)
189✔
133
                        log_debug_errno(r, "Failed to get terminal size by DSR, ignoring: %m");
189✔
134
        }
135

136
        return terminal_set_size_fd(output_fd, tty_path, rows, cols);
1,084✔
137
}
138

139
void exec_context_tty_reset(const ExecContext *context, const ExecParameters *parameters, sd_id128_t invocation_id) {
13,081✔
140
        _cleanup_close_ int _fd = -EBADF, lock_fd = -EBADF;
26,162✔
141
        int fd, r;
13,081✔
142

143
        assert(context);
13,081✔
144

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

150
        const char *path = exec_context_tty_path(context);
13,081✔
151

152
        if (parameters && parameters->stdout_fd >= 0 && isatty_safe(parameters->stdout_fd))
13,081✔
153
                fd = parameters->stdout_fd;
16✔
154
        else if (path && (context->tty_path || is_terminal_input(context->std_input) ||
13,065✔
155
                        is_terminal_output(context->std_output) || is_terminal_output(context->std_error))) {
12,074✔
156
                fd = _fd = open_terminal(path, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
665✔
157
                if (fd < 0)
665✔
UNCOV
158
                        return (void) log_debug_errno(fd, "Failed to open terminal '%s', ignoring: %m", path);
×
159
        } else
160
                return;   /* nothing to do */
161

162
        /* Take a synchronization lock for the duration of the setup that we do here.
163
         * systemd-vconsole-setup.service also takes the lock to avoid being interrupted. We open a new fd
164
         * that will be closed automatically, and operate on it for convenience. */
165
        lock_fd = lock_dev_console();
681✔
166
        if (ERRNO_IS_NEG_PRIVILEGE(lock_fd))
681✔
167
                log_debug_errno(lock_fd, "No privileges to lock /dev/console, proceeding without lock: %m");
×
168
        else if (ERRNO_IS_NEG_DEVICE_ABSENT(lock_fd))
681✔
169
                log_debug_errno(lock_fd, "Device /dev/console does not exist, proceeding without lock: %m");
×
170
        else if (lock_fd < 0)
681✔
171
                log_warning_errno(lock_fd, "Failed to lock /dev/console, proceeding without lock: %m");
×
172

173
        if (context->tty_reset)
681✔
174
                (void) terminal_reset_defensive(
178✔
175
                                fd,
176
                                TERMINAL_RESET_SWITCH_TO_TEXT |
177
                                (exec_context_shall_ansi_seq_reset(context) ? TERMINAL_RESET_FORCE_ANSI_SEQ : TERMINAL_RESET_AVOID_ANSI_SEQ));
175✔
178

179
        r = exec_context_apply_tty_size(context, fd, fd, path);
681✔
180
        if (r < 0)
681✔
181
                log_debug_errno(r, "Failed to configure TTY dimensions, ignoring: %m");
×
182

183
        if (!sd_id128_is_null(invocation_id)) {
1,313✔
184
                sd_id128_t context_id;
49✔
185

186
                r = osc_context_id_from_invocation_id(invocation_id, &context_id);
49✔
187
                if (r < 0)
49✔
188
                        log_debug_errno(r, "Failed to derive context ID from invocation ID, ignoring: %m");
49✔
189
                else {
190
                        _cleanup_free_ char *seq = NULL;
49✔
191

192
                        r = osc_context_close(context_id, &seq);
49✔
193
                        if (r < 0)
49✔
194
                                log_debug_errno(r, "Failed to acquire OSC close sequence, ignoring: %m");
×
195
                        else
196
                                (void) loop_write(fd, seq, SIZE_MAX);
49✔
197
                }
198
        }
199

200
        if (context->tty_vhangup)
681✔
201
                (void) terminal_vhangup_fd(fd);
170✔
202

203
        /* We don't need the fd anymore now, and it potentially points to a hungup TTY anyway, let's close it
204
         * hence. */
205
        _fd = safe_close(_fd);
681✔
206

207
        if (context->tty_vt_disallocate && path)
681✔
208
                (void) vt_disallocate(path);
94✔
209
}
210

211
bool exec_needs_network_namespace(const ExecContext *context) {
56,659✔
212
        assert(context);
56,659✔
213

214
        return context->private_network || context->network_namespace_path;
56,659✔
215
}
216

217
static bool exec_needs_ephemeral(const ExecContext *context) {
6,315✔
218
        return (context->root_image || context->root_directory) && context->root_ephemeral;
6,315✔
219
}
220

221
bool exec_needs_ipc_namespace(const ExecContext *context) {
52,517✔
222
        assert(context);
52,517✔
223

224
        return context->private_ipc || context->ipc_namespace_path;
52,517✔
225
}
226

227
static bool needs_cgroup_namespace(ProtectControlGroups i) {
91,371✔
228
        return IN_SET(i, PROTECT_CONTROL_GROUPS_PRIVATE, PROTECT_CONTROL_GROUPS_STRICT);
91,371✔
229
}
230

231
ProtectControlGroups exec_get_protect_control_groups(const ExecContext *context) {
61,031✔
232
        assert(context);
61,031✔
233

234
        /* If cgroup namespace is configured via ProtectControlGroups=private or strict but we can't actually
235
         * use cgroup namespace, we ignore the setting and do not unshare the namespace.
236
         * ProtectControlGroups=private and strict get downgraded to no and yes respectively. This ensures
237
         * that strict always gets a read-only mount of /sys/fs/cgroup/. */
238
        if (needs_cgroup_namespace(context->protect_control_groups) && !namespace_type_supported(NAMESPACE_CGROUP)) {
61,031✔
239
                if (context->protect_control_groups == PROTECT_CONTROL_GROUPS_PRIVATE)
×
240
                        return PROTECT_CONTROL_GROUPS_NO;
241
                if (context->protect_control_groups == PROTECT_CONTROL_GROUPS_STRICT)
×
242
                        return PROTECT_CONTROL_GROUPS_YES;
243
        }
244
        return context->protect_control_groups;
61,031✔
245
}
246

247
bool exec_needs_cgroup_namespace(const ExecContext *context) {
30,340✔
248
        assert(context);
30,340✔
249

250
        return needs_cgroup_namespace(exec_get_protect_control_groups(context));
30,340✔
251
}
252

253
bool exec_needs_cgroup_mount(const ExecContext *context) {
26,683✔
254
        assert(context);
26,683✔
255

256
        return exec_get_protect_control_groups(context) != PROTECT_CONTROL_GROUPS_NO;
26,683✔
257
}
258

259
bool exec_is_cgroup_mount_read_only(const ExecContext *context) {
2,004✔
260
        assert(context);
2,004✔
261

262
        return IN_SET(exec_get_protect_control_groups(context), PROTECT_CONTROL_GROUPS_YES, PROTECT_CONTROL_GROUPS_STRICT);
2,004✔
263
}
264

265
bool exec_needs_pid_namespace(const ExecContext *context) {
73,663✔
266
        assert(context);
73,663✔
267

268
        return context->private_pids != PRIVATE_PIDS_NO && namespace_type_supported(NAMESPACE_PID);
73,663✔
269
}
270

271
bool exec_needs_mount_namespace(
31,879✔
272
                const ExecContext *context,
273
                const ExecParameters *params,
274
                const ExecRuntime *runtime) {
275

276
        assert(context);
31,879✔
277

278
        if (context->root_image)
31,879✔
279
                return true;
280

281
        if (!strv_isempty(context->read_write_paths) ||
31,855✔
282
            !strv_isempty(context->read_only_paths) ||
29,796✔
283
            !strv_isempty(context->inaccessible_paths) ||
29,783✔
284
            !strv_isempty(context->exec_paths) ||
29,764✔
285
            !strv_isempty(context->no_exec_paths))
29,764✔
286
                return true;
287

288
        if (context->n_bind_mounts > 0)
29,764✔
289
                return true;
290

291
        if (context->n_temporary_filesystems > 0)
29,708✔
292
                return true;
293

294
        if (context->n_mount_images > 0)
29,549✔
295
                return true;
296

297
        if (context->n_extension_images > 0)
29,526✔
298
                return true;
299

300
        if (!strv_isempty(context->extension_directories))
29,515✔
301
                return true;
302

303
        if (!IN_SET(context->mount_propagation_flag, 0, MS_SHARED))
29,510✔
304
                return true;
305

306
        if (context->private_tmp == PRIVATE_TMP_DISCONNECTED)
29,510✔
307
                return true;
308

309
        if (context->private_tmp == PRIVATE_TMP_CONNECTED && runtime && runtime->shared && (runtime->shared->tmp_dir || runtime->shared->var_tmp_dir))
28,483✔
310
                return true;
311

312
        if (context->private_devices ||
27,997✔
313
            context->private_mounts > 0 ||
27,257✔
314
            (context->private_mounts < 0 && exec_needs_network_namespace(context)) ||
26,833✔
315
            context->protect_system != PROTECT_SYSTEM_NO ||
26,816✔
316
            context->protect_home != PROTECT_HOME_NO ||
26,816✔
317
            context->protect_kernel_tunables ||
26,816✔
318
            context->protect_kernel_modules ||
26,816✔
319
            context->protect_kernel_logs ||
50,271✔
320
            exec_needs_cgroup_mount(context) ||
25,134✔
321
            context->protect_proc != PROTECT_PROC_DEFAULT ||
25,116✔
322
            context->proc_subset != PROC_SUBSET_ALL ||
50,115✔
323
            exec_needs_ipc_namespace(context) ||
50,106✔
324
            exec_needs_pid_namespace(context))
25,053✔
325
                return true;
2,985✔
326

327
        if (context->root_directory) {
25,012✔
328
                if (exec_context_get_effective_mount_apivfs(context))
5✔
329
                        return true;
330

331
                for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
×
332
                        if (params && !params->prefix[t])
×
333
                                continue;
×
334

335
                        if (context->directories[t].n_items > 0)
×
336
                                return true;
337
                }
338
        }
339

340
        if (context->dynamic_user &&
25,007✔
341
            (context->directories[EXEC_DIRECTORY_STATE].n_items > 0 ||
×
342
             context->directories[EXEC_DIRECTORY_CACHE].n_items > 0 ||
×
343
             context->directories[EXEC_DIRECTORY_LOGS].n_items > 0))
×
344
                return true;
345

346
        if (exec_context_get_effective_bind_log_sockets(context))
25,007✔
347
                return true;
348

349
        for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++)
149,698✔
350
                FOREACH_ARRAY(i, context->directories[t].items, context->directories[t].n_items)
129,819✔
351
                        if (FLAGS_SET(i->flags, EXEC_DIRECTORY_READ_ONLY))
5,122✔
352
                                return true;
353

354
        return false;
355
}
356

357
const char* exec_get_private_notify_socket_path(const ExecContext *context, const ExecParameters *params, bool needs_sandboxing) {
3,899✔
358
        assert(context);
3,899✔
359
        assert(params);
3,899✔
360

361
        if (!params->notify_socket)
3,899✔
362
                return NULL;
363

364
        if (!needs_sandboxing)
3,257✔
365
                return NULL;
366

367
        if (!context->root_directory && !context->root_image)
3,257✔
368
                return NULL;
369

370
        if (!exec_context_get_effective_mount_apivfs(context))
×
371
                return NULL;
372

373
        if (!FLAGS_SET(params->flags, EXEC_APPLY_CHROOT))
×
374
                return NULL;
×
375

376
        return "/run/host/notify";
377
}
378

379
int exec_log_level_max(const ExecContext *context, const ExecParameters *params) {
23,120✔
380
        assert(context);
23,120✔
381
        assert(params);
23,120✔
382

383
        if (params->debug_invocation)
23,120✔
384
                return LOG_DEBUG;
385

386
        return context->log_level_max < 0 ? log_get_max_level() : context->log_level_max;
23,116✔
387
}
388

389
bool exec_directory_is_private(const ExecContext *context, ExecDirectoryType type) {
11,871✔
390
        assert(context);
11,871✔
391

392
        if (!context->dynamic_user)
11,871✔
393
                return false;
394

395
        if (!EXEC_DIRECTORY_TYPE_SHALL_CHOWN(type))
104✔
396
                return false;
397

398
        if (type == EXEC_DIRECTORY_RUNTIME && context->runtime_directory_preserve_mode == EXEC_PRESERVE_NO)
98✔
399
                return false;
14✔
400

401
        return true;
402
}
403

404
int exec_params_get_cgroup_path(
14,447✔
405
                const ExecParameters *params,
406
                const CGroupContext *c,
407
                char **ret) {
408

409
        const char *subgroup = NULL;
14,447✔
410
        char *p;
14,447✔
411

412
        assert(params);
14,447✔
413
        assert(ret);
14,447✔
414

415
        if (!params->cgroup_path)
14,447✔
416
                return -EINVAL;
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
        if (FLAGS_SET(params->flags, EXEC_CGROUP_DELEGATE) && (FLAGS_SET(params->flags, EXEC_CONTROL_CGROUP) || c->delegate_subgroup)) {
14,447✔
428
                if (FLAGS_SET(params->flags, EXEC_IS_CONTROL))
708✔
429
                        subgroup = ".control";
430
                else
431
                        subgroup = c->delegate_subgroup;
674✔
432
        }
433

434
        if (subgroup)
674✔
435
                p = path_join(params->cgroup_path, subgroup);
708✔
436
        else
437
                p = strdup(params->cgroup_path);
13,739✔
438
        if (!p)
14,447✔
439
                return -ENOMEM;
440

441
        *ret = p;
14,447✔
442
        return !!subgroup;
14,447✔
443
}
444

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

448
        return c->cpu_affinity_from_numa;
1,340✔
449
}
450

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

456
        if (!DEBUG_LOGGING)
2,220✔
457
                return;
2,220✔
458

459
        _cleanup_free_ char *cmdline = quote_command_line(argv, SHELL_ESCAPE_EMPTY);
4,440✔
460

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

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

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

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

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

495
        LOG_CONTEXT_PUSH_UNIT(unit);
4,440✔
496

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

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

505
        if (params->cgroup_path) {
2,220✔
506
                r = exec_params_get_cgroup_path(params, cgroup_context, &subcgroup_path);
2,220✔
507
                if (r < 0)
2,220✔
508
                        return log_unit_error_errno(unit, r, "Failed to acquire subcgroup path: %m");
×
509
                if (r > 0) {
2,220✔
510
                        /* If there's a subcgroup, then let's create it here now (the main cgroup was already
511
                         * realized by the unit logic) */
512

513
                        r = cg_create(subcgroup_path);
50✔
514
                        if (r < 0)
50✔
515
                                return log_unit_error_errno(unit, r, "Failed to create subcgroup '%s': %m", subcgroup_path);
×
516
                }
517
        }
518

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

526
        r = open_serialization_file("sd-executor-state", &f);
2,220✔
527
        if (r < 0)
2,220✔
528
                return log_unit_error_errno(unit, r, "Failed to open serialization stream: %m");
×
529

530
        fdset = fdset_new();
2,220✔
531
        if (!fdset)
2,220✔
532
                return log_oom();
×
533

534
        r = exec_serialize_invocation(f, fdset, context, command, params, runtime, cgroup_context);
2,220✔
535
        if (r < 0)
2,220✔
536
                return log_unit_error_errno(unit, r, "Failed to serialize parameters: %m");
×
537

538
        r = finish_serialization_file(f);
2,220✔
539
        if (r < 0)
2,220✔
540
                return log_unit_error_errno(unit, r, "Failed to finish serialization stream: %m");
×
541

542
        r = fd_cloexec(fileno(f), false);
2,220✔
543
        if (r < 0)
2,220✔
544
                return log_unit_error_errno(unit, r, "Failed to set O_CLOEXEC on serialization fd: %m");
×
545

546
        r = fdset_cloexec(fdset, false);
2,220✔
547
        if (r < 0)
2,220✔
548
                return log_unit_error_errno(unit, r, "Failed to set O_CLOEXEC on serialized fds: %m");
×
549

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

557
        char serialization_fd_number[DECIMAL_STR_MAX(int)];
2,220✔
558
        xsprintf(serialization_fd_number, "%i", fileno(f));
2,220✔
559

560
        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
2,220✔
561
        dual_timestamp start_timestamp;
2,220✔
562

563
        /* Restore the original ambient capability set the manager was started with to pass it to
564
         * sd-executor. */
565
        r = capability_ambient_set_apply(unit->manager->saved_ambient_set, /* also_inherit= */ false);
2,220✔
566
        if (r < 0)
2,220✔
567
                return log_unit_error_errno(unit, r, "Failed to apply the starting ambient set: %m");
×
568

569
        /* Record the start timestamp before we fork so that it is guaranteed to be earlier than the
570
         * handoff timestamp. */
571
        dual_timestamp_now(&start_timestamp);
2,220✔
572

573
        /* The executor binary is pinned, to avoid compatibility problems during upgrades. */
574
        r = posix_spawn_wrapper(
2,220✔
575
                        FORMAT_PROC_FD_PATH(unit->manager->executor_fd),
2,220✔
576
                        STRV_MAKE(unit->manager->executor_path,
2,220✔
577
                                  "--deserialize", serialization_fd_number,
578
                                  "--log-level", max_log_levels,
579
                                  "--log-target", log_target_to_string(manager_get_executor_log_target(unit->manager))),
580
                        environ,
581
                        subcgroup_path,
582
                        &pidref);
583

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

587
        if (r == -EUCLEAN && subcgroup_path)
2,220✔
588
                return log_unit_error_errno(unit, r,
×
589
                                            "Failed to spawn process into cgroup '%s', because the cgroup "
590
                                            "or one of its parents or siblings is in the threaded mode.",
591
                                            subcgroup_path);
592
        if (r < 0)
2,220✔
593
                return log_unit_error_errno(unit, r, "Failed to spawn executor: %m");
×
594
        /* We add the new process to the cgroup both in the child (so that we can be sure that no user code is ever
595
         * executed outside of the cgroup) and in the parent (so that we can be sure that when we kill the cgroup the
596
         * process will be killed too). */
597
        if (r == 0 && subcgroup_path)
2,220✔
598
                (void) cg_attach(subcgroup_path, pidref.pid);
×
599
        /* r > 0: Already in the right cgroup thanks to CLONE_INTO_CGROUP */
600

601
        log_unit_debug(unit, "Forked %s as " PID_FMT " (%s CLONE_INTO_CGROUP)",
2,220✔
602
                       command->path, pidref.pid, r > 0 ? "via" : "without");
603

604
        exec_status_start(&command->exec_status, pidref.pid, &start_timestamp);
2,220✔
605

606
        *ret = TAKE_PIDREF(pidref);
2,220✔
607
        return 0;
2,220✔
608
}
609

610
void exec_context_init(ExecContext *c) {
58,463✔
611
        assert(c);
58,463✔
612

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

616
        *c = (ExecContext) {
58,463✔
617
                .umask = 0022,
618
                .ioprio = IOPRIO_DEFAULT_CLASS_AND_PRIO,
58,463✔
619
                .cpu_sched_policy = SCHED_OTHER,
620
                .syslog_priority = LOG_DAEMON|LOG_INFO,
621
                .syslog_level_prefix = true,
622
                .ignore_sigpipe = true,
623
                .timer_slack_nsec = NSEC_INFINITY,
624
                .personality = PERSONALITY_INVALID,
625
                .timeout_clean_usec = USEC_INFINITY,
626
                .capability_bounding_set = CAP_MASK_UNSET,
627
                .restrict_namespaces = NAMESPACE_FLAGS_INITIAL,
628
                .delegate_namespaces = NAMESPACE_FLAGS_INITIAL,
629
                .log_level_max = -1,
630
#if HAVE_SECCOMP
631
                .syscall_errno = SECCOMP_ERROR_NUMBER_KILL,
632
#endif
633
                .tty_rows = UINT_MAX,
634
                .tty_cols = UINT_MAX,
635
                .private_mounts = -1,
636
                .mount_apivfs = -1,
637
                .bind_log_sockets = -1,
638
                .memory_ksm = -1,
639
                .private_var_tmp = _PRIVATE_TMP_INVALID,
640
                .set_login_environment = -1,
641
        };
642

643
        FOREACH_ARRAY(d, c->directories, _EXEC_DIRECTORY_TYPE_MAX)
350,778✔
644
                d->mode = 0755;
292,315✔
645

646
        numa_policy_reset(&c->numa_policy);
58,463✔
647

648
        assert_cc(NAMESPACE_FLAGS_INITIAL != NAMESPACE_FLAGS_ALL);
58,463✔
649
}
58,463✔
650

651
void exec_context_done(ExecContext *c) {
46,932✔
652
        assert(c);
46,932✔
653

654
        c->environment = strv_free(c->environment);
46,932✔
655
        c->environment_files = strv_free(c->environment_files);
46,932✔
656
        c->pass_environment = strv_free(c->pass_environment);
46,932✔
657
        c->unset_environment = strv_free(c->unset_environment);
46,932✔
658

659
        rlimit_free_all(c->rlimit);
46,932✔
660

661
        for (size_t l = 0; l < 3; l++) {
187,728✔
662
                c->stdio_fdname[l] = mfree(c->stdio_fdname[l]);
140,796✔
663
                c->stdio_file[l] = mfree(c->stdio_file[l]);
140,796✔
664
        }
665

666
        c->working_directory = mfree(c->working_directory);
46,932✔
667
        c->root_directory = mfree(c->root_directory);
46,932✔
668
        c->root_image = mfree(c->root_image);
46,932✔
669
        c->root_image_options = mount_options_free_all(c->root_image_options);
46,932✔
670
        c->root_hash = mfree(c->root_hash);
46,932✔
671
        c->root_hash_size = 0;
46,932✔
672
        c->root_hash_path = mfree(c->root_hash_path);
46,932✔
673
        c->root_hash_sig = mfree(c->root_hash_sig);
46,932✔
674
        c->root_hash_sig_size = 0;
46,932✔
675
        c->root_hash_sig_path = mfree(c->root_hash_sig_path);
46,932✔
676
        c->root_verity = mfree(c->root_verity);
46,932✔
677
        c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
46,932✔
678
        c->extension_directories = strv_free(c->extension_directories);
46,932✔
679
        c->tty_path = mfree(c->tty_path);
46,932✔
680
        c->syslog_identifier = mfree(c->syslog_identifier);
46,932✔
681
        c->user = mfree(c->user);
46,932✔
682
        c->group = mfree(c->group);
46,932✔
683

684
        c->supplementary_groups = strv_free(c->supplementary_groups);
46,932✔
685

686
        c->pam_name = mfree(c->pam_name);
46,932✔
687

688
        c->read_only_paths = strv_free(c->read_only_paths);
46,932✔
689
        c->read_write_paths = strv_free(c->read_write_paths);
46,932✔
690
        c->inaccessible_paths = strv_free(c->inaccessible_paths);
46,932✔
691
        c->exec_paths = strv_free(c->exec_paths);
46,932✔
692
        c->no_exec_paths = strv_free(c->no_exec_paths);
46,932✔
693
        c->exec_search_path = strv_free(c->exec_search_path);
46,932✔
694

695
        bind_mount_free_many(c->bind_mounts, c->n_bind_mounts);
46,932✔
696
        c->bind_mounts = NULL;
46,932✔
697
        c->n_bind_mounts = 0;
46,932✔
698
        temporary_filesystem_free_many(c->temporary_filesystems, c->n_temporary_filesystems);
46,932✔
699
        c->temporary_filesystems = NULL;
46,932✔
700
        c->n_temporary_filesystems = 0;
46,932✔
701
        c->mount_images = mount_image_free_many(c->mount_images, &c->n_mount_images);
46,932✔
702

703
        cpu_set_reset(&c->cpu_set);
46,932✔
704
        numa_policy_reset(&c->numa_policy);
46,932✔
705

706
        c->utmp_id = mfree(c->utmp_id);
46,932✔
707
        c->selinux_context = mfree(c->selinux_context);
46,932✔
708
        c->apparmor_profile = mfree(c->apparmor_profile);
46,932✔
709
        c->smack_process_label = mfree(c->smack_process_label);
46,932✔
710

711
        c->restrict_filesystems = set_free(c->restrict_filesystems);
46,932✔
712

713
        c->syscall_filter = hashmap_free(c->syscall_filter);
46,932✔
714
        c->syscall_archs = set_free(c->syscall_archs);
46,932✔
715
        c->syscall_log = hashmap_free(c->syscall_log);
46,932✔
716
        c->address_families = set_free(c->address_families);
46,932✔
717

718
        FOREACH_ARRAY(d, c->directories, _EXEC_DIRECTORY_TYPE_MAX)
281,592✔
719
                exec_directory_done(d);
234,660✔
720

721
        c->log_level_max = -1;
46,932✔
722

723
        exec_context_free_log_extra_fields(c);
46,932✔
724
        c->log_filter_allowed_patterns = set_free(c->log_filter_allowed_patterns);
46,932✔
725
        c->log_filter_denied_patterns = set_free(c->log_filter_denied_patterns);
46,932✔
726

727
        c->log_ratelimit = (RateLimit) {};
46,932✔
728

729
        c->stdin_data = mfree(c->stdin_data);
46,932✔
730
        c->stdin_data_size = 0;
46,932✔
731

732
        c->network_namespace_path = mfree(c->network_namespace_path);
46,932✔
733
        c->ipc_namespace_path = mfree(c->ipc_namespace_path);
46,932✔
734

735
        c->log_namespace = mfree(c->log_namespace);
46,932✔
736

737
        c->load_credentials = hashmap_free(c->load_credentials);
46,932✔
738
        c->set_credentials = hashmap_free(c->set_credentials);
46,932✔
739
        c->import_credentials = ordered_set_free(c->import_credentials);
46,932✔
740

741
        c->root_image_policy = image_policy_free(c->root_image_policy);
46,932✔
742
        c->mount_image_policy = image_policy_free(c->mount_image_policy);
46,932✔
743
        c->extension_image_policy = image_policy_free(c->extension_image_policy);
46,932✔
744

745
        c->private_hostname = mfree(c->private_hostname);
46,932✔
746
}
46,932✔
747

748
int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) {
4,977✔
749
        assert(c);
4,977✔
750

751
        if (!runtime_prefix)
4,977✔
752
                return 0;
753

754
        FOREACH_ARRAY(i, c->directories[EXEC_DIRECTORY_RUNTIME].items, c->directories[EXEC_DIRECTORY_RUNTIME].n_items) {
4,990✔
755
                _cleanup_free_ char *p = NULL;
13✔
756

757
                if (exec_directory_is_private(c, EXEC_DIRECTORY_RUNTIME))
13✔
758
                        p = path_join(runtime_prefix, "private", i->path);
×
759
                else
760
                        p = path_join(runtime_prefix, i->path);
13✔
761
                if (!p)
13✔
762
                        return -ENOMEM;
763

764
                /* We execute this synchronously, since we need to be sure this is gone when we start the
765
                 * service next. */
766
                (void) rm_rf(p, REMOVE_ROOT);
13✔
767

768
                STRV_FOREACH(symlink, i->symlinks) {
13✔
769
                        _cleanup_free_ char *symlink_abs = NULL;
×
770

771
                        if (exec_directory_is_private(c, EXEC_DIRECTORY_RUNTIME))
×
772
                                symlink_abs = path_join(runtime_prefix, "private", *symlink);
×
773
                        else
774
                                symlink_abs = path_join(runtime_prefix, *symlink);
×
775
                        if (!symlink_abs)
×
776
                                return -ENOMEM;
×
777

778
                        (void) unlink(symlink_abs);
×
779
                }
780
        }
781

782
        return 0;
783
}
784

785
int exec_context_destroy_mount_ns_dir(Unit *u) {
10,984✔
786
        _cleanup_free_ char *p = NULL;
10,984✔
787

788
        if (!u || !MANAGER_IS_SYSTEM(u->manager))
10,984✔
789
                return 0;
790

791
        p = path_join("/run/systemd/propagate/", u->id);
2,060✔
792
        if (!p)
2,060✔
793
                return -ENOMEM;
794

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

799
        return 0;
800
}
801

802
void exec_command_done(ExecCommand *c) {
99,967✔
803
        assert(c);
99,967✔
804

805
        c->path = mfree(c->path);
99,967✔
806
        c->argv = strv_free(c->argv);
99,967✔
807
}
99,967✔
808

809
void exec_command_done_array(ExecCommand *c, size_t n) {
27,743✔
810
        FOREACH_ARRAY(i, c, n)
110,970✔
811
                exec_command_done(i);
83,227✔
812
}
27,743✔
813

814
ExecCommand* exec_command_free(ExecCommand *c) {
16,712✔
815
        if (!c)
16,712✔
816
                return NULL;
817

818
        exec_command_done(c);
16,712✔
819
        return mfree(c);
16,712✔
820
}
821

822
ExecCommand* exec_command_free_list(ExecCommand *c) {
123,392✔
823
        ExecCommand *i;
123,392✔
824

825
        while ((i = LIST_POP(command, c)))
140,104✔
826
                exec_command_free(i);
16,712✔
827

828
        return NULL;
123,392✔
829
}
830

831
void exec_command_free_array(ExecCommand **c, size_t n) {
19,161✔
832
        FOREACH_ARRAY(i, c, n)
142,538✔
833
                *i = exec_command_free_list(*i);
123,377✔
834
}
19,161✔
835

836
void exec_command_reset_status_array(ExecCommand *c, size_t n) {
6,925✔
837
        FOREACH_ARRAY(i, c, n)
27,699✔
838
                exec_status_reset(&i->exec_status);
20,774✔
839
}
6,925✔
840

841
void exec_command_reset_status_list_array(ExecCommand **c, size_t n) {
4,263✔
842
        FOREACH_ARRAY(i, c, n)
29,444✔
843
                LIST_FOREACH(command, z, *i)
27,379✔
844
                        exec_status_reset(&z->exec_status);
2,198✔
845
}
4,263✔
846

847
typedef struct InvalidEnvInfo {
848
        const Unit *unit;
849
        const char *path;
850
} InvalidEnvInfo;
851

852
static void invalid_env(const char *p, void *userdata) {
×
853
        InvalidEnvInfo *info = userdata;
×
854

855
        log_unit_error(info->unit, "Ignoring invalid environment assignment '%s': %s", p, info->path);
×
856
}
×
857

858
const char* exec_context_fdname(const ExecContext *c, int fd_index) {
38,700✔
859
        assert(c);
38,700✔
860

861
        switch (fd_index) {
38,700✔
862

863
        case STDIN_FILENO:
12,900✔
864
                if (c->std_input != EXEC_INPUT_NAMED_FD)
12,900✔
865
                        return NULL;
866

867
                return c->stdio_fdname[STDIN_FILENO] ?: "stdin";
×
868

869
        case STDOUT_FILENO:
12,900✔
870
                if (c->std_output != EXEC_OUTPUT_NAMED_FD)
12,900✔
871
                        return NULL;
872

873
                return c->stdio_fdname[STDOUT_FILENO] ?: "stdout";
×
874

875
        case STDERR_FILENO:
12,900✔
876
                if (c->std_error != EXEC_OUTPUT_NAMED_FD)
12,900✔
877
                        return NULL;
878

879
                return c->stdio_fdname[STDERR_FILENO] ?: "stderr";
×
880

881
        default:
882
                return NULL;
883
        }
884
}
885

886
static int exec_context_load_environment(const Unit *unit, const ExecContext *c, char ***ret) {
2,220✔
887
        _cleanup_strv_free_ char **v = NULL;
2,220✔
888
        int r;
2,220✔
889

890
        assert(c);
2,220✔
891
        assert(ret);
2,220✔
892

893
        STRV_FOREACH(i, c->environment_files) {
2,222✔
894
                _cleanup_globfree_ glob_t pglob = {};
2✔
895
                bool ignore = false;
2✔
896
                char *fn = *i;
2✔
897

898
                if (fn[0] == '-') {
2✔
899
                        ignore = true;
1✔
900
                        fn++;
1✔
901
                }
902

903
                if (!path_is_absolute(fn)) {
2✔
904
                        if (ignore)
×
905
                                continue;
×
906
                        return -EINVAL;
907
                }
908

909
                /* Filename supports globbing, take all matching files */
910
                r = safe_glob(fn, 0, &pglob);
2✔
911
                if (r < 0) {
2✔
912
                        if (ignore)
1✔
913
                                continue;
1✔
914
                        return r;
915
                }
916

917
                /* When we don't match anything, -ENOENT should be returned */
918
                assert(pglob.gl_pathc > 0);
1✔
919

920
                FOREACH_ARRAY(path, pglob.gl_pathv, pglob.gl_pathc) {
2✔
921
                        _cleanup_strv_free_ char **p = NULL;
1✔
922

923
                        r = load_env_file(NULL, *path, &p);
1✔
924
                        if (r < 0) {
1✔
925
                                if (ignore)
×
926
                                        continue;
×
927
                                return r;
928
                        }
929

930
                        /* Log invalid environment variables with filename */
931
                        if (p) {
1✔
932
                                InvalidEnvInfo info = {
1✔
933
                                        .unit = unit,
934
                                        .path = *path,
1✔
935
                                };
936

937
                                p = strv_env_clean_with_callback(p, invalid_env, &info);
1✔
938
                        }
939

940
                        if (!v)
1✔
941
                                v = TAKE_PTR(p);
1✔
942
                        else {
943
                                char **m = strv_env_merge(v, p);
×
944
                                if (!m)
×
945
                                        return -ENOMEM;
×
946

947
                                strv_free_and_replace(v, m);
×
948
                        }
949
                }
950
        }
951

952
        *ret = TAKE_PTR(v);
2,220✔
953

954
        return 0;
2,220✔
955
}
956

957
static bool tty_may_match_dev_console(const char *tty) {
367✔
958
        _cleanup_free_ char *resolved = NULL;
367✔
959

960
        if (!tty)
367✔
961
                return true;
962

963
        tty = skip_dev_prefix(tty);
367✔
964

965
        /* trivial identity? */
966
        if (streq(tty, "console"))
367✔
967
                return true;
968

969
        if (resolve_dev_console(&resolved) < 0)
39✔
970
                return true; /* if we could not resolve, assume it may */
971

972
        /* "tty0" means the active VC, so it may be the same sometimes */
973
        return path_equal(skip_dev_prefix(resolved), tty) || (streq(skip_dev_prefix(resolved), "tty0") && tty_is_vc(tty));
39✔
974
}
975

976
static bool exec_context_may_touch_tty(const ExecContext *ec) {
22,394✔
977
        assert(ec);
22,394✔
978

979
        return ec->tty_reset ||
44,637✔
980
                ec->tty_vhangup ||
22,243✔
981
                ec->tty_vt_disallocate ||
22,243✔
982
                is_terminal_input(ec->std_input) ||
22,243✔
983
                is_terminal_output(ec->std_output) ||
44,545✔
984
                is_terminal_output(ec->std_error);
21,978✔
985
}
986

987
bool exec_context_may_touch_console(const ExecContext *ec) {
20,872✔
988

989
        return exec_context_may_touch_tty(ec) &&
21,239✔
990
               tty_may_match_dev_console(exec_context_tty_path(ec));
367✔
991
}
992

993
bool exec_context_shall_ansi_seq_reset(const ExecContext *c) {
1,553✔
994
        assert(c);
1,553✔
995

996
        /* Determines whether ANSI sequences shall be used during any terminal initialisation:
997
         *
998
         * 1. If the reset logic is enabled at all, this is an immediate no.
999
         *
1000
         * 2. If $TERM is set to anything other than "dumb", it's a yes.
1001
         */
1002

1003
        if (!c->tty_reset)
1,553✔
1004
                return false;
1005

1006
        return !streq_ptr(strv_env_get(c->environment, "TERM"), "dumb");
531✔
1007
}
1008

1009
static void strv_fprintf(FILE *f, char **l) {
×
1010
        assert(f);
×
1011

1012
        STRV_FOREACH(g, l)
×
1013
                fprintf(f, " %s", *g);
×
1014
}
×
1015

1016
static void strv_dump(FILE* f, const char *prefix, const char *name, char **strv) {
1,792✔
1017
        assert(f);
1,792✔
1018
        assert(prefix);
1,792✔
1019
        assert(name);
1,792✔
1020

1021
        if (!strv_isempty(strv)) {
1,792✔
1022
                fprintf(f, "%s%s:", prefix, name);
×
1023
                strv_fprintf(f, strv);
×
1024
                fputs("\n", f);
×
1025
        }
1026
}
1,792✔
1027

1028
void exec_params_dump(const ExecParameters *p, FILE* f, const char *prefix) {
×
1029
        assert(p);
×
1030
        assert(f);
×
1031

1032
        prefix = strempty(prefix);
×
1033

1034
        fprintf(f,
×
1035
                "%sRuntimeScope: %s\n"
1036
                "%sExecFlags: %u\n"
1037
                "%sSELinuxContextNetwork: %s\n"
1038
                "%sCgroupSupportedMask: %u\n"
1039
                "%sCgroupPath: %s\n"
1040
                "%sCrededentialsDirectory: %s\n"
1041
                "%sEncryptedCredentialsDirectory: %s\n"
1042
                "%sConfirmSpawn: %s\n"
1043
                "%sShallConfirmSpawn: %s\n"
1044
                "%sWatchdogUSec: " USEC_FMT "\n"
1045
                "%sNotifySocket: %s\n"
1046
                "%sDebugInvocation: %s\n"
1047
                "%sFallbackSmackProcessLabel: %s\n",
1048
                prefix, runtime_scope_to_string(p->runtime_scope),
×
1049
                prefix, p->flags,
×
1050
                prefix, yes_no(p->selinux_context_net),
×
1051
                prefix, p->cgroup_supported,
×
1052
                prefix, p->cgroup_path,
×
1053
                prefix, strempty(p->received_credentials_directory),
×
1054
                prefix, strempty(p->received_encrypted_credentials_directory),
×
1055
                prefix, strempty(p->confirm_spawn),
×
1056
                prefix, yes_no(p->shall_confirm_spawn),
×
1057
                prefix, p->watchdog_usec,
×
1058
                prefix, strempty(p->notify_socket),
×
1059
                prefix, yes_no(p->debug_invocation),
×
1060
                prefix, strempty(p->fallback_smack_process_label));
×
1061

1062
        strv_dump(f, prefix, "FdNames", p->fd_names);
×
1063
        strv_dump(f, prefix, "Environment", p->environment);
×
1064
        strv_dump(f, prefix, "Prefix", p->prefix);
×
1065

1066
        LIST_FOREACH(open_files, file, p->open_files)
×
1067
                fprintf(f, "%sOpenFile: %s %s", prefix, file->path, open_file_flags_to_string(file->flags));
×
1068

1069
        strv_dump(f, prefix, "FilesEnv", p->files_env);
×
1070
}
×
1071

1072
void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
224✔
1073
        int r;
224✔
1074

1075
        assert(c);
224✔
1076
        assert(f);
224✔
1077

1078
        prefix = strempty(prefix);
224✔
1079

1080
        fprintf(f,
224✔
1081
                "%sUMask: %04o\n"
1082
                "%sWorkingDirectory: %s\n"
1083
                "%sRootDirectory: %s\n"
1084
                "%sRootEphemeral: %s\n"
1085
                "%sNonBlocking: %s\n"
1086
                "%sPrivateTmp: %s\n"
1087
                "%sPrivateDevices: %s\n"
1088
                "%sProtectKernelTunables: %s\n"
1089
                "%sProtectKernelModules: %s\n"
1090
                "%sProtectKernelLogs: %s\n"
1091
                "%sProtectClock: %s\n"
1092
                "%sProtectControlGroups: %s\n"
1093
                "%sPrivateNetwork: %s\n"
1094
                "%sPrivateUsers: %s\n"
1095
                "%sPrivatePIDs: %s\n"
1096
                "%sProtectHome: %s\n"
1097
                "%sProtectSystem: %s\n"
1098
                "%sMountAPIVFS: %s\n"
1099
                "%sBindLogSockets: %s\n"
1100
                "%sIgnoreSIGPIPE: %s\n"
1101
                "%sMemoryDenyWriteExecute: %s\n"
1102
                "%sRestrictRealtime: %s\n"
1103
                "%sRestrictSUIDSGID: %s\n"
1104
                "%sKeyringMode: %s\n"
1105
                "%sProtectHostname: %s%s%s\n"
1106
                "%sProtectProc: %s\n"
1107
                "%sProcSubset: %s\n",
1108
                prefix, c->umask,
224✔
1109
                prefix, empty_to_root(c->working_directory),
224✔
1110
                prefix, empty_to_root(c->root_directory),
224✔
1111
                prefix, yes_no(c->root_ephemeral),
224✔
1112
                prefix, yes_no(c->non_blocking),
224✔
1113
                prefix, private_tmp_to_string(c->private_tmp),
224✔
1114
                prefix, yes_no(c->private_devices),
224✔
1115
                prefix, yes_no(c->protect_kernel_tunables),
224✔
1116
                prefix, yes_no(c->protect_kernel_modules),
224✔
1117
                prefix, yes_no(c->protect_kernel_logs),
224✔
1118
                prefix, yes_no(c->protect_clock),
224✔
1119
                prefix, protect_control_groups_to_string(c->protect_control_groups),
224✔
1120
                prefix, yes_no(c->private_network),
224✔
1121
                prefix, private_users_to_string(c->private_users),
224✔
1122
                prefix, private_pids_to_string(c->private_pids),
224✔
1123
                prefix, protect_home_to_string(c->protect_home),
224✔
1124
                prefix, protect_system_to_string(c->protect_system),
224✔
1125
                prefix, yes_no(exec_context_get_effective_mount_apivfs(c)),
224✔
1126
                prefix, yes_no(exec_context_get_effective_bind_log_sockets(c)),
224✔
1127
                prefix, yes_no(c->ignore_sigpipe),
224✔
1128
                prefix, yes_no(c->memory_deny_write_execute),
224✔
1129
                prefix, yes_no(c->restrict_realtime),
224✔
1130
                prefix, yes_no(c->restrict_suid_sgid),
224✔
1131
                prefix, exec_keyring_mode_to_string(c->keyring_mode),
224✔
1132
                prefix, protect_hostname_to_string(c->protect_hostname), c->private_hostname ? ":" : "", strempty(c->private_hostname),
448✔
1133
                prefix, protect_proc_to_string(c->protect_proc),
224✔
1134
                prefix, proc_subset_to_string(c->proc_subset));
224✔
1135

1136
        if (c->set_login_environment >= 0)
224✔
1137
                fprintf(f, "%sSetLoginEnvironment: %s\n", prefix, yes_no(c->set_login_environment > 0));
2✔
1138

1139
        if (c->root_image)
224✔
1140
                fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
×
1141

1142
        if (c->root_image_options) {
224✔
1143
                fprintf(f, "%sRootImageOptions:", prefix);
×
1144
                LIST_FOREACH(mount_options, o, c->root_image_options)
×
1145
                        if (!isempty(o->options))
×
1146
                                fprintf(f, " %s:%s",
×
1147
                                        partition_designator_to_string(o->partition_designator),
1148
                                        o->options);
1149
                fprintf(f, "\n");
×
1150
        }
1151

1152
        if (c->root_hash) {
224✔
1153
                _cleanup_free_ char *encoded = NULL;
×
1154
                encoded = hexmem(c->root_hash, c->root_hash_size);
×
1155
                if (encoded)
×
1156
                        fprintf(f, "%sRootHash: %s\n", prefix, encoded);
×
1157
        }
1158

1159
        if (c->root_hash_path)
224✔
1160
                fprintf(f, "%sRootHash: %s\n", prefix, c->root_hash_path);
×
1161

1162
        if (c->root_hash_sig) {
224✔
1163
                _cleanup_free_ char *encoded = NULL;
×
1164
                ssize_t len;
×
1165
                len = base64mem(c->root_hash_sig, c->root_hash_sig_size, &encoded);
×
1166
                if (len)
×
1167
                        fprintf(f, "%sRootHashSignature: base64:%s\n", prefix, encoded);
×
1168
        }
1169

1170
        if (c->root_hash_sig_path)
224✔
1171
                fprintf(f, "%sRootHashSignature: %s\n", prefix, c->root_hash_sig_path);
×
1172

1173
        if (c->root_verity)
224✔
1174
                fprintf(f, "%sRootVerity: %s\n", prefix, c->root_verity);
×
1175

1176
        STRV_FOREACH(e, c->environment)
224✔
1177
                fprintf(f, "%sEnvironment: %s\n", prefix, *e);
×
1178

1179
        STRV_FOREACH(e, c->environment_files)
224✔
1180
                fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
×
1181

1182
        STRV_FOREACH(e, c->pass_environment)
234✔
1183
                fprintf(f, "%sPassEnvironment: %s\n", prefix, *e);
10✔
1184

1185
        STRV_FOREACH(e, c->unset_environment)
224✔
1186
                fprintf(f, "%sUnsetEnvironment: %s\n", prefix, *e);
×
1187

1188
        fprintf(f, "%sRuntimeDirectoryPreserve: %s\n", prefix, exec_preserve_mode_to_string(c->runtime_directory_preserve_mode));
224✔
1189

1190
        for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
1,344✔
1191
                fprintf(f, "%s%sMode: %04o\n", prefix, exec_directory_type_to_string(dt), c->directories[dt].mode);
1,120✔
1192

1193
                for (size_t i = 0; i < c->directories[dt].n_items; i++) {
1,130✔
1194
                        fprintf(f,
10✔
1195
                                "%s%s: %s%s\n",
1196
                                prefix,
1197
                                exec_directory_type_to_string(dt),
1198
                                c->directories[dt].items[i].path,
1199
                                FLAGS_SET(c->directories[dt].items[i].flags, EXEC_DIRECTORY_READ_ONLY) ? " (ro)" : "");
10✔
1200

1201
                        STRV_FOREACH(d, c->directories[dt].items[i].symlinks)
10✔
1202
                                fprintf(f, "%s%s: %s:%s\n", prefix, exec_directory_type_symlink_to_string(dt), c->directories[dt].items[i].path, *d);
×
1203
                }
1204
        }
1205

1206
        fprintf(f, "%sTimeoutCleanSec: %s\n", prefix, FORMAT_TIMESPAN(c->timeout_clean_usec, USEC_PER_SEC));
224✔
1207

1208
        if (c->memory_ksm >= 0)
224✔
1209
                fprintf(f, "%sMemoryKSM: %s\n", prefix, yes_no(c->memory_ksm > 0));
2✔
1210

1211
        if (c->nice_set)
224✔
1212
                fprintf(f, "%sNice: %i\n", prefix, c->nice);
×
1213

1214
        if (c->oom_score_adjust_set)
224✔
1215
                fprintf(f, "%sOOMScoreAdjust: %i\n", prefix, c->oom_score_adjust);
10✔
1216

1217
        if (c->coredump_filter_set)
224✔
1218
                fprintf(f, "%sCoredumpFilter: 0x%"PRIx64"\n", prefix, c->coredump_filter);
×
1219

1220
        for (unsigned i = 0; i < RLIM_NLIMITS; i++)
3,808✔
1221
                if (c->rlimit[i]) {
3,584✔
1222
                        fprintf(f, "%sLimit%s: " RLIM_FMT "\n",
20✔
1223
                                prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
1224
                        fprintf(f, "%sLimit%sSoft: " RLIM_FMT "\n",
20✔
1225
                                prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur);
20✔
1226
                }
1227

1228
        if (c->ioprio_set) {
224✔
1229
                _cleanup_free_ char *class_str = NULL;
×
1230

1231
                r = ioprio_class_to_string_alloc(ioprio_prio_class(c->ioprio), &class_str);
×
1232
                if (r >= 0)
×
1233
                        fprintf(f, "%sIOSchedulingClass: %s\n", prefix, class_str);
×
1234

1235
                fprintf(f, "%sIOPriority: %d\n", prefix, ioprio_prio_data(c->ioprio));
×
1236
        }
1237

1238
        if (c->cpu_sched_set) {
224✔
1239
                _cleanup_free_ char *policy_str = NULL;
×
1240

1241
                r = sched_policy_to_string_alloc(c->cpu_sched_policy, &policy_str);
×
1242
                if (r >= 0)
×
1243
                        fprintf(f, "%sCPUSchedulingPolicy: %s\n", prefix, policy_str);
×
1244

1245
                fprintf(f,
×
1246
                        "%sCPUSchedulingPriority: %i\n"
1247
                        "%sCPUSchedulingResetOnFork: %s\n",
1248
                        prefix, c->cpu_sched_priority,
×
1249
                        prefix, yes_no(c->cpu_sched_reset_on_fork));
×
1250
        }
1251

1252
        if (c->cpu_set.set) {
224✔
1253
                _cleanup_free_ char *affinity = NULL;
×
1254

1255
                affinity = cpu_set_to_range_string(&c->cpu_set);
×
1256
                fprintf(f, "%sCPUAffinity: %s\n", prefix, affinity);
×
1257
        }
1258

1259
        if (mpol_is_valid(numa_policy_get_type(&c->numa_policy))) {
224✔
1260
                _cleanup_free_ char *nodes = NULL;
1✔
1261

1262
                nodes = cpu_set_to_range_string(&c->numa_policy.nodes);
1✔
1263
                fprintf(f, "%sNUMAPolicy: %s\n", prefix, mpol_to_string(numa_policy_get_type(&c->numa_policy)));
1✔
1264
                fprintf(f, "%sNUMAMask: %s\n", prefix, strnull(nodes));
1✔
1265
        }
1266

1267
        if (c->timer_slack_nsec != NSEC_INFINITY)
224✔
1268
                fprintf(f, "%sTimerSlackNSec: "NSEC_FMT "\n", prefix, c->timer_slack_nsec);
1✔
1269

1270
        fprintf(f,
224✔
1271
                "%sStandardInput: %s\n"
1272
                "%sStandardOutput: %s\n"
1273
                "%sStandardError: %s\n",
1274
                prefix, exec_input_to_string(c->std_input),
224✔
1275
                prefix, exec_output_to_string(c->std_output),
224✔
1276
                prefix, exec_output_to_string(c->std_error));
224✔
1277

1278
        if (c->std_input == EXEC_INPUT_NAMED_FD)
224✔
1279
                fprintf(f, "%sStandardInputFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDIN_FILENO]);
×
1280
        if (c->std_output == EXEC_OUTPUT_NAMED_FD)
224✔
1281
                fprintf(f, "%sStandardOutputFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDOUT_FILENO]);
×
1282
        if (c->std_error == EXEC_OUTPUT_NAMED_FD)
224✔
1283
                fprintf(f, "%sStandardErrorFileDescriptorName: %s\n", prefix, c->stdio_fdname[STDERR_FILENO]);
×
1284

1285
        if (c->std_input == EXEC_INPUT_FILE)
224✔
1286
                fprintf(f, "%sStandardInputFile: %s\n", prefix, c->stdio_file[STDIN_FILENO]);
×
1287
        if (c->std_output == EXEC_OUTPUT_FILE)
224✔
1288
                fprintf(f, "%sStandardOutputFile: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
×
1289
        if (c->std_output == EXEC_OUTPUT_FILE_APPEND)
224✔
1290
                fprintf(f, "%sStandardOutputFileToAppend: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
×
1291
        if (c->std_output == EXEC_OUTPUT_FILE_TRUNCATE)
224✔
1292
                fprintf(f, "%sStandardOutputFileToTruncate: %s\n", prefix, c->stdio_file[STDOUT_FILENO]);
×
1293
        if (c->std_error == EXEC_OUTPUT_FILE)
224✔
1294
                fprintf(f, "%sStandardErrorFile: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
×
1295
        if (c->std_error == EXEC_OUTPUT_FILE_APPEND)
224✔
1296
                fprintf(f, "%sStandardErrorFileToAppend: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
×
1297
        if (c->std_error == EXEC_OUTPUT_FILE_TRUNCATE)
224✔
1298
                fprintf(f, "%sStandardErrorFileToTruncate: %s\n", prefix, c->stdio_file[STDERR_FILENO]);
×
1299

1300
        if (c->tty_path)
224✔
1301
                fprintf(f,
×
1302
                        "%sTTYPath: %s\n"
1303
                        "%sTTYReset: %s\n"
1304
                        "%sTTYVHangup: %s\n"
1305
                        "%sTTYVTDisallocate: %s\n"
1306
                        "%sTTYRows: %u\n"
1307
                        "%sTTYColumns: %u\n",
1308
                        prefix, c->tty_path,
1309
                        prefix, yes_no(c->tty_reset),
×
1310
                        prefix, yes_no(c->tty_vhangup),
×
1311
                        prefix, yes_no(c->tty_vt_disallocate),
×
1312
                        prefix, c->tty_rows,
×
1313
                        prefix, c->tty_cols);
×
1314

1315
        if (IN_SET(c->std_output,
224✔
1316
                   EXEC_OUTPUT_KMSG,
1317
                   EXEC_OUTPUT_JOURNAL,
1318
                   EXEC_OUTPUT_KMSG_AND_CONSOLE,
1319
                   EXEC_OUTPUT_JOURNAL_AND_CONSOLE) ||
1320
            IN_SET(c->std_error,
17✔
1321
                   EXEC_OUTPUT_KMSG,
1322
                   EXEC_OUTPUT_JOURNAL,
1323
                   EXEC_OUTPUT_KMSG_AND_CONSOLE,
1324
                   EXEC_OUTPUT_JOURNAL_AND_CONSOLE)) {
1325

1326
                _cleanup_free_ char *fac_str = NULL, *lvl_str = NULL;
207✔
1327

1328
                r = log_facility_unshifted_to_string_alloc(c->syslog_priority >> 3, &fac_str);
207✔
1329
                if (r >= 0)
207✔
1330
                        fprintf(f, "%sSyslogFacility: %s\n", prefix, fac_str);
207✔
1331

1332
                r = log_level_to_string_alloc(LOG_PRI(c->syslog_priority), &lvl_str);
207✔
1333
                if (r >= 0)
207✔
1334
                        fprintf(f, "%sSyslogLevel: %s\n", prefix, lvl_str);
207✔
1335
        }
1336

1337
        if (c->log_level_max >= 0) {
224✔
1338
                _cleanup_free_ char *t = NULL;
1✔
1339

1340
                (void) log_level_to_string_alloc(c->log_level_max, &t);
1✔
1341

1342
                fprintf(f, "%sLogLevelMax: %s\n", prefix, strna(t));
1✔
1343
        }
1344

1345
        if (c->log_ratelimit.interval > 0)
224✔
1346
                fprintf(f,
×
1347
                        "%sLogRateLimitIntervalSec: %s\n",
1348
                        prefix, FORMAT_TIMESPAN(c->log_ratelimit.interval, USEC_PER_SEC));
×
1349

1350
        if (c->log_ratelimit.burst > 0)
224✔
1351
                fprintf(f, "%sLogRateLimitBurst: %u\n", prefix, c->log_ratelimit.burst);
×
1352

1353
        if (!set_isempty(c->log_filter_allowed_patterns) || !set_isempty(c->log_filter_denied_patterns)) {
224✔
1354
                fprintf(f, "%sLogFilterPatterns:", prefix);
×
1355

1356
                char *pattern;
×
1357
                SET_FOREACH(pattern, c->log_filter_allowed_patterns)
×
1358
                        fprintf(f, " %s", pattern);
×
1359
                SET_FOREACH(pattern, c->log_filter_denied_patterns)
×
1360
                        fprintf(f, " ~%s", pattern);
×
1361
                fputc('\n', f);
×
1362
        }
1363

1364
        FOREACH_ARRAY(field, c->log_extra_fields, c->n_log_extra_fields) {
228✔
1365
                fprintf(f, "%sLogExtraFields: ", prefix);
4✔
1366
                fwrite(field->iov_base, 1, field->iov_len, f);
4✔
1367
                fputc('\n', f);
4✔
1368
        }
1369

1370
        if (c->log_namespace)
224✔
1371
                fprintf(f, "%sLogNamespace: %s\n", prefix, c->log_namespace);
×
1372

1373
        if (c->secure_bits) {
224✔
1374
                _cleanup_free_ char *str = NULL;
×
1375

1376
                r = secure_bits_to_string_alloc(c->secure_bits, &str);
×
1377
                if (r >= 0)
×
1378
                        fprintf(f, "%sSecure Bits: %s\n", prefix, str);
×
1379
        }
1380

1381
        if (c->capability_bounding_set != CAP_MASK_UNSET) {
224✔
1382
                _cleanup_free_ char *str = NULL;
16✔
1383

1384
                r = capability_set_to_string(c->capability_bounding_set, &str);
16✔
1385
                if (r >= 0)
16✔
1386
                        fprintf(f, "%sCapabilityBoundingSet: %s\n", prefix, str);
16✔
1387
        }
1388

1389
        if (c->capability_ambient_set != 0) {
224✔
1390
                _cleanup_free_ char *str = NULL;
×
1391

1392
                r = capability_set_to_string(c->capability_ambient_set, &str);
×
1393
                if (r >= 0)
×
1394
                        fprintf(f, "%sAmbientCapabilities: %s\n", prefix, str);
×
1395
        }
1396

1397
        if (c->user)
224✔
1398
                fprintf(f, "%sUser: %s\n", prefix, c->user);
1✔
1399
        if (c->group)
224✔
1400
                fprintf(f, "%sGroup: %s\n", prefix, c->group);
1✔
1401

1402
        fprintf(f, "%sDynamicUser: %s\n", prefix, yes_no(c->dynamic_user));
447✔
1403

1404
        strv_dump(f, prefix, "SupplementaryGroups", c->supplementary_groups);
224✔
1405

1406
        if (c->pam_name)
224✔
1407
                fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
×
1408

1409
        strv_dump(f, prefix, "ReadWritePaths", c->read_write_paths);
224✔
1410
        strv_dump(f, prefix, "ReadOnlyPaths", c->read_only_paths);
224✔
1411
        strv_dump(f, prefix, "InaccessiblePaths", c->inaccessible_paths);
224✔
1412
        strv_dump(f, prefix, "ExecPaths", c->exec_paths);
224✔
1413
        strv_dump(f, prefix, "NoExecPaths", c->no_exec_paths);
224✔
1414
        strv_dump(f, prefix, "ExecSearchPath", c->exec_search_path);
224✔
1415

1416
        FOREACH_ARRAY(mount, c->bind_mounts, c->n_bind_mounts)
228✔
1417
                fprintf(f, "%s%s: %s%s:%s:%s\n", prefix,
4✔
1418
                        mount->read_only ? "BindReadOnlyPaths" : "BindPaths",
4✔
1419
                        mount->ignore_enoent ? "-": "",
4✔
1420
                        mount->source,
1421
                        mount->destination,
1422
                        mount->recursive ? "rbind" : "norbind");
4✔
1423

1424
        FOREACH_ARRAY(tmpfs, c->temporary_filesystems, c->n_temporary_filesystems)
224✔
1425
                fprintf(f, "%sTemporaryFileSystem: %s%s%s\n", prefix,
×
1426
                        tmpfs->path,
1427
                        isempty(tmpfs->options) ? "" : ":",
×
1428
                        strempty(tmpfs->options));
×
1429

1430
        if (c->utmp_id)
224✔
1431
                fprintf(f,
×
1432
                        "%sUtmpIdentifier: %s\n",
1433
                        prefix, c->utmp_id);
1434

1435
        if (c->selinux_context)
224✔
1436
                fprintf(f,
×
1437
                        "%sSELinuxContext: %s%s\n",
1438
                        prefix, c->selinux_context_ignore ? "-" : "", c->selinux_context);
×
1439

1440
        if (c->apparmor_profile)
224✔
1441
                fprintf(f,
×
1442
                        "%sAppArmorProfile: %s%s\n",
1443
                        prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile);
×
1444

1445
        if (c->smack_process_label)
224✔
1446
                fprintf(f,
×
1447
                        "%sSmackProcessLabel: %s%s\n",
1448
                        prefix, c->smack_process_label_ignore ? "-" : "", c->smack_process_label);
×
1449

1450
        if (c->personality != PERSONALITY_INVALID)
224✔
1451
                fprintf(f,
1✔
1452
                        "%sPersonality: %s\n",
1453
                        prefix, strna(personality_to_string(c->personality)));
1454

1455
        fprintf(f,
224✔
1456
                "%sLockPersonality: %s\n",
1457
                prefix, yes_no(c->lock_personality));
224✔
1458

1459
        if (c->syscall_filter) {
224✔
1460
                fprintf(f,
11✔
1461
                        "%sSystemCallFilter: ",
1462
                        prefix);
1463

1464
                if (!c->syscall_allow_list)
11✔
1465
                        fputc('~', f);
×
1466

1467
#if HAVE_SECCOMP
1468
                void *id, *val;
11✔
1469
                bool first = true;
11✔
1470
                HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
4,268✔
1471
                        _cleanup_free_ char *name = NULL;
4,257✔
1472
                        const char *errno_name = NULL;
4,257✔
1473
                        int num = PTR_TO_INT(val);
4,257✔
1474

1475
                        if (first)
4,257✔
1476
                                first = false;
1477
                        else
1478
                                fputc(' ', f);
4,246✔
1479

1480
                        name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
4,257✔
1481
                        fputs(strna(name), f);
4,257✔
1482

1483
                        if (num >= 0) {
4,257✔
1484
                                errno_name = seccomp_errno_or_action_to_string(num);
×
1485
                                if (errno_name)
×
1486
                                        fprintf(f, ":%s", errno_name);
×
1487
                                else
1488
                                        fprintf(f, ":%d", num);
×
1489
                        }
1490
                }
1491
#endif
1492

1493
                fputc('\n', f);
11✔
1494
        }
1495

1496
        if (c->syscall_archs) {
224✔
1497
                fprintf(f,
11✔
1498
                        "%sSystemCallArchitectures:",
1499
                        prefix);
1500

1501
#if HAVE_SECCOMP
1502
                void *id;
11✔
1503
                SET_FOREACH(id, c->syscall_archs)
22✔
1504
                        fprintf(f, " %s", strna(seccomp_arch_to_string(PTR_TO_UINT32(id) - 1)));
11✔
1505
#endif
1506
                fputc('\n', f);
11✔
1507
        }
1508

1509
        if (exec_context_restrict_namespaces_set(c)) {
224✔
1510
                _cleanup_free_ char *s = NULL;
12✔
1511

1512
                r = namespace_flags_to_string(c->restrict_namespaces, &s);
12✔
1513
                if (r >= 0)
12✔
1514
                        fprintf(f, "%sRestrictNamespaces: %s\n",
24✔
1515
                                prefix, strna(s));
1516
        }
1517

1518
#if HAVE_LIBBPF
1519
        if (exec_context_restrict_filesystems_set(c)) {
224✔
1520
                char *fs;
×
1521
                SET_FOREACH(fs, c->restrict_filesystems)
×
1522
                        fprintf(f, "%sRestrictFileSystems: %s\n", prefix, fs);
×
1523
        }
1524
#endif
1525

1526
        if (c->network_namespace_path)
224✔
1527
                fprintf(f,
×
1528
                        "%sNetworkNamespacePath: %s\n",
1529
                        prefix, c->network_namespace_path);
1530

1531
        if (c->syscall_errno > 0) {
224✔
1532
                fprintf(f, "%sSystemCallErrorNumber: ", prefix);
223✔
1533

1534
#if HAVE_SECCOMP
1535
                const char *errno_name = seccomp_errno_or_action_to_string(c->syscall_errno);
223✔
1536
                if (errno_name)
223✔
1537
                        fputs(errno_name, f);
223✔
1538
                else
1539
                        fprintf(f, "%d", c->syscall_errno);
×
1540
#endif
1541
                fputc('\n', f);
223✔
1542
        }
1543

1544
        FOREACH_ARRAY(mount, c->mount_images, c->n_mount_images) {
224✔
1545
                fprintf(f, "%sMountImages: %s%s:%s", prefix,
×
1546
                        mount->ignore_enoent ? "-": "",
×
1547
                        mount->source,
1548
                        mount->destination);
1549
                LIST_FOREACH(mount_options, o, mount->mount_options)
×
1550
                        fprintf(f, ":%s:%s",
×
1551
                                partition_designator_to_string(o->partition_designator),
1552
                                strempty(o->options));
×
1553
                fprintf(f, "\n");
×
1554
        }
1555

1556
        FOREACH_ARRAY(mount, c->extension_images, c->n_extension_images) {
224✔
1557
                fprintf(f, "%sExtensionImages: %s%s", prefix,
×
1558
                        mount->ignore_enoent ? "-": "",
×
1559
                        mount->source);
1560
                LIST_FOREACH(mount_options, o, mount->mount_options)
×
1561
                        fprintf(f, ":%s:%s",
×
1562
                                partition_designator_to_string(o->partition_designator),
1563
                                strempty(o->options));
×
1564
                fprintf(f, "\n");
×
1565
        }
1566

1567
        strv_dump(f, prefix, "ExtensionDirectories", c->extension_directories);
224✔
1568
}
224✔
1569

1570
bool exec_context_maintains_privileges(const ExecContext *c) {
×
1571
        assert(c);
×
1572

1573
        /* Returns true if the process forked off would run under
1574
         * an unchanged UID or as root. */
1575

1576
        if (!c->user)
×
1577
                return true;
1578

1579
        if (STR_IN_SET(c->user, "root", "0"))
×
1580
                return true;
×
1581

1582
        return false;
×
1583
}
1584

1585
int exec_context_get_effective_ioprio(const ExecContext *c) {
2,680✔
1586
        int p;
2,680✔
1587

1588
        assert(c);
2,680✔
1589

1590
        if (c->ioprio_set)
2,680✔
1591
                return c->ioprio;
18✔
1592

1593
        p = ioprio_get(IOPRIO_WHO_PROCESS, 0);
2,662✔
1594
        if (p < 0)
2,662✔
1595
                return IOPRIO_DEFAULT_CLASS_AND_PRIO;
1596

1597
        return ioprio_normalize(p);
2,662✔
1598
}
1599

1600
bool exec_context_get_effective_mount_apivfs(const ExecContext *c) {
34,142✔
1601
        assert(c);
34,142✔
1602

1603
        /* Explicit setting wins */
1604
        if (c->mount_apivfs >= 0)
34,142✔
1605
                return c->mount_apivfs > 0;
110✔
1606

1607
        /* Default to "yes" if root directory or image are specified */
1608
        if (exec_context_with_rootfs(c))
34,032✔
1609
                return true;
62✔
1610

1611
        return false;
1612
}
1613

1614
bool exec_context_get_effective_bind_log_sockets(const ExecContext *c) {
28,575✔
1615
        assert(c);
28,575✔
1616

1617
        /* If log namespace is specified, "/run/systemd/journal.namespace/" would be bind mounted to
1618
         * "/run/systemd/journal/", which effectively means BindLogSockets=yes */
1619
        if (c->log_namespace)
28,575✔
1620
                return true;
1621

1622
        if (c->bind_log_sockets >= 0)
28,567✔
1623
                return c->bind_log_sockets > 0;
2✔
1624

1625
        if (exec_context_get_effective_mount_apivfs(c))
28,565✔
1626
                return true;
1627

1628
        /* When PrivateDevices=yes, /dev/log gets symlinked to /run/systemd/journal/dev-log */
1629
        if (exec_context_with_rootfs(c) && c->private_devices)
28,500✔
1630
                return true;
×
1631

1632
        return false;
1633
}
1634

1635
void exec_context_free_log_extra_fields(ExecContext *c) {
46,934✔
1636
        assert(c);
46,934✔
1637

1638
        FOREACH_ARRAY(field, c->log_extra_fields, c->n_log_extra_fields)
46,939✔
1639
                free(field->iov_base);
5✔
1640

1641
        c->log_extra_fields = mfree(c->log_extra_fields);
46,934✔
1642
        c->n_log_extra_fields = 0;
46,934✔
1643
}
46,934✔
1644

1645
void exec_context_revert_tty(ExecContext *c, sd_id128_t invocation_id) {
1,522✔
1646
        _cleanup_close_ int fd = -EBADF;
1,522✔
1647
        const char *path;
1,522✔
1648
        struct stat st;
1,522✔
1649
        int r;
1,522✔
1650

1651
        assert(c);
1,522✔
1652

1653
        /* First, reset the TTY (possibly kicking everybody else from the TTY) */
1654
        exec_context_tty_reset(c, /* parameters= */ NULL, invocation_id);
1,522✔
1655

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

1662
        path = exec_context_tty_path(c);
49✔
1663
        if (!path)
49✔
1664
                return;
1665

1666
        fd = open(path, O_PATH|O_CLOEXEC); /* Pin the inode */
49✔
1667
        if (fd < 0)
49✔
1668
                return (void) log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
×
1669
                                             "Failed to open TTY inode of '%s' to adjust ownership/access mode, ignoring: %m",
1670
                                             path);
1671

1672
        if (fstat(fd, &st) < 0)
49✔
1673
                return (void) log_warning_errno(errno, "Failed to stat TTY '%s', ignoring: %m", path);
×
1674

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

1683
        r = fchmod_and_chown(fd, TTY_MODE, 0, TTY_GID);
49✔
1684
        if (r < 0)
49✔
1685
                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);
49✔
1686
}
1687

1688
int exec_context_get_clean_directories(
×
1689
                ExecContext *c,
1690
                char **prefix,
1691
                ExecCleanMask mask,
1692
                char ***ret) {
1693

1694
        _cleanup_strv_free_ char **l = NULL;
×
1695
        int r;
×
1696

1697
        assert(c);
×
1698
        assert(prefix);
×
1699
        assert(ret);
×
1700

1701
        for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) {
×
1702
                if (!BIT_SET(mask, t))
×
1703
                        continue;
×
1704

1705
                if (!prefix[t])
×
1706
                        continue;
×
1707

1708
                FOREACH_ARRAY(i, c->directories[t].items, c->directories[t].n_items) {
×
1709
                        char *j;
×
1710

1711
                        j = path_join(prefix[t], i->path);
×
1712
                        if (!j)
×
1713
                                return -ENOMEM;
1714

1715
                        r = strv_consume(&l, j);
×
1716
                        if (r < 0)
×
1717
                                return r;
1718

1719
                        /* Also remove private directories unconditionally. */
1720
                        if (EXEC_DIRECTORY_TYPE_SHALL_CHOWN(t)) {
×
1721
                                j = path_join(prefix[t], "private", i->path);
×
1722
                                if (!j)
×
1723
                                        return -ENOMEM;
1724

1725
                                r = strv_consume(&l, j);
×
1726
                                if (r < 0)
×
1727
                                        return r;
1728
                        }
1729

1730
                        STRV_FOREACH(symlink, i->symlinks) {
×
1731
                                j = path_join(prefix[t], *symlink);
×
1732
                                if (!j)
×
1733
                                        return -ENOMEM;
1734

1735
                                r = strv_consume(&l, j);
×
1736
                                if (r < 0)
×
1737
                                        return r;
1738
                        }
1739
                }
1740
        }
1741

1742
        *ret = TAKE_PTR(l);
×
1743
        return 0;
×
1744
}
1745

1746
int exec_context_get_clean_mask(ExecContext *c, ExecCleanMask *ret) {
1,360✔
1747
        ExecCleanMask mask = 0;
1,360✔
1748

1749
        assert(c);
1,360✔
1750
        assert(ret);
1,360✔
1751

1752
        for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++)
8,160✔
1753
                if (c->directories[t].n_items > 0)
6,800✔
1754
                        mask |= 1U << t;
347✔
1755

1756
        *ret = mask;
1,360✔
1757
        return 0;
1,360✔
1758
}
1759

1760
int exec_context_get_oom_score_adjust(const ExecContext *c) {
1,340✔
1761
        int n = 0, r;
1,340✔
1762

1763
        assert(c);
1,340✔
1764

1765
        if (c->oom_score_adjust_set)
1,340✔
1766
                return c->oom_score_adjust;
376✔
1767

1768
        r = get_oom_score_adjust(&n);
964✔
1769
        if (r < 0)
964✔
1770
                log_debug_errno(r, "Failed to read /proc/self/oom_score_adj, ignoring: %m");
×
1771

1772
        return n;
964✔
1773
}
1774

1775
uint64_t exec_context_get_coredump_filter(const ExecContext *c) {
1,340✔
1776
        _cleanup_free_ char *t = NULL;
1,340✔
1777
        uint64_t n = COREDUMP_FILTER_MASK_DEFAULT;
1,340✔
1778
        int r;
1,340✔
1779

1780
        assert(c);
1,340✔
1781

1782
        if (c->coredump_filter_set)
1,340✔
1783
                return c->coredump_filter;
×
1784

1785
        r = read_one_line_file("/proc/self/coredump_filter", &t);
1,340✔
1786
        if (r < 0)
1,340✔
1787
                log_debug_errno(r, "Failed to read /proc/self/coredump_filter, ignoring: %m");
×
1788
        else {
1789
                r = safe_atoux64(t, &n);
1,340✔
1790
                if (r < 0)
1,340✔
1791
                        log_debug_errno(r, "Failed to parse \"%s\" from /proc/self/coredump_filter, ignoring: %m", t);
×
1792
        }
1793

1794
        return n;
1,340✔
1795
}
1796

1797
int exec_context_get_nice(const ExecContext *c) {
1,340✔
1798
        int n;
1,340✔
1799

1800
        assert(c);
1,340✔
1801

1802
        if (c->nice_set)
1,340✔
1803
                return c->nice;
6✔
1804

1805
        errno = 0;
1,334✔
1806
        n = getpriority(PRIO_PROCESS, 0);
1,334✔
1807
        if (errno > 0) {
1,334✔
1808
                log_debug_errno(errno, "Failed to get process nice value, ignoring: %m");
×
1809
                n = 0;
1810
        }
1811

1812
        return n;
1813
}
1814

1815
int exec_context_get_cpu_sched_policy(const ExecContext *c) {
1,340✔
1816
        int n;
1,340✔
1817

1818
        assert(c);
1,340✔
1819

1820
        if (c->cpu_sched_set)
1,340✔
1821
                return c->cpu_sched_policy;
×
1822

1823
        n = sched_getscheduler(0);
1,340✔
1824
        if (n < 0)
1,340✔
1825
                log_debug_errno(errno, "Failed to get scheduler policy, ignoring: %m");
×
1826

1827
        return n < 0 ? SCHED_OTHER : n;
1,340✔
1828
}
1829

1830
int exec_context_get_cpu_sched_priority(const ExecContext *c) {
1,340✔
1831
        struct sched_param p = {};
1,340✔
1832
        int r;
1,340✔
1833

1834
        assert(c);
1,340✔
1835

1836
        if (c->cpu_sched_set)
1,340✔
1837
                return c->cpu_sched_priority;
×
1838

1839
        r = sched_getparam(0, &p);
1,340✔
1840
        if (r < 0)
1,340✔
1841
                log_debug_errno(errno, "Failed to get scheduler priority, ignoring: %m");
×
1842

1843
        return r >= 0 ? p.sched_priority : 0;
1,340✔
1844
}
1845

1846
uint64_t exec_context_get_timer_slack_nsec(const ExecContext *c) {
1,340✔
1847
        int r;
1,340✔
1848

1849
        assert(c);
1,340✔
1850

1851
        if (c->timer_slack_nsec != NSEC_INFINITY)
1,340✔
1852
                return c->timer_slack_nsec;
1853

1854
        r = prctl(PR_GET_TIMERSLACK);
1,340✔
1855
        if (r < 0)
1,340✔
1856
                log_debug_errno(r, "Failed to get timer slack, ignoring: %m");
×
1857

1858
        return (uint64_t) MAX(r, 0);
1,340✔
1859
}
1860

1861
bool exec_context_get_set_login_environment(const ExecContext *c) {
10,943✔
1862
        assert(c);
10,943✔
1863

1864
        if (c->set_login_environment >= 0)
10,943✔
1865
                return c->set_login_environment;
×
1866

1867
        return c->user || c->dynamic_user || c->pam_name;
19,702✔
1868
}
1869

1870
char** exec_context_get_syscall_filter(const ExecContext *c) {
1,340✔
1871
        _cleanup_strv_free_ char **l = NULL;
1,340✔
1872

1873
        assert(c);
1,340✔
1874

1875
#if HAVE_SECCOMP
1876
        void *id, *val;
1,340✔
1877
        HASHMAP_FOREACH_KEY(val, id, c->syscall_filter) {
18,878✔
1878
                _cleanup_free_ char *name = NULL;
17,538✔
1879
                const char *e = NULL;
17,538✔
1880
                char *s;
17,538✔
1881
                int num = PTR_TO_INT(val);
17,538✔
1882

1883
                if (c->syscall_allow_list && num >= 0)
17,538✔
1884
                        /* syscall with num >= 0 in allow-list is denied. */
1885
                        continue;
×
1886

1887
                name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
17,538✔
1888
                if (!name)
17,538✔
1889
                        continue;
×
1890

1891
                if (num >= 0) {
17,538✔
1892
                        e = seccomp_errno_or_action_to_string(num);
×
1893
                        if (e) {
×
1894
                                s = strjoin(name, ":", e);
×
1895
                                if (!s)
×
1896
                                        return NULL;
1897
                        } else {
1898
                                if (asprintf(&s, "%s:%d", name, num) < 0)
×
1899
                                        return NULL;
1900
                        }
1901
                } else
1902
                        s = TAKE_PTR(name);
17,538✔
1903

1904
                if (strv_consume(&l, s) < 0)
17,538✔
1905
                        return NULL;
1906
        }
1907

1908
        strv_sort(l);
1,340✔
1909
#endif
1910

1911
        return l ? TAKE_PTR(l) : strv_new(NULL);
1,340✔
1912
}
1913

1914
char** exec_context_get_syscall_archs(const ExecContext *c) {
1,340✔
1915
        _cleanup_strv_free_ char **l = NULL;
1,340✔
1916

1917
        assert(c);
1,340✔
1918

1919
#if HAVE_SECCOMP
1920
        void *id;
1,340✔
1921
        SET_FOREACH(id, c->syscall_archs) {
1,391✔
1922
                const char *name;
51✔
1923

1924
                name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
51✔
1925
                if (!name)
51✔
1926
                        continue;
×
1927

1928
                if (strv_extend(&l, name) < 0)
51✔
1929
                        return NULL;
×
1930
        }
1931

1932
        strv_sort(l);
1,340✔
1933
#endif
1934

1935
        return l ? TAKE_PTR(l) : strv_new(NULL);
1,340✔
1936
}
1937

1938
char** exec_context_get_syscall_log(const ExecContext *c) {
1,340✔
1939
        _cleanup_strv_free_ char **l = NULL;
1,340✔
1940

1941
        assert(c);
1,340✔
1942

1943
#if HAVE_SECCOMP
1944
        void *id, *val;
1,340✔
1945
        HASHMAP_FOREACH_KEY(val, id, c->syscall_log) {
1,340✔
1946
                char *name = NULL;
×
1947

1948
                name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
×
1949
                if (!name)
×
1950
                        continue;
×
1951

1952
                if (strv_consume(&l, name) < 0)
×
1953
                        return NULL;
×
1954
        }
1955

1956
        strv_sort(l);
1,340✔
1957
#endif
1958

1959
        return l ? TAKE_PTR(l) : strv_new(NULL);
1,340✔
1960
}
1961

1962
char** exec_context_get_address_families(const ExecContext *c) {
1,340✔
1963
        _cleanup_strv_free_ char **l = NULL;
1,340✔
1964
        void *af;
1,340✔
1965

1966
        assert(c);
1,340✔
1967

1968
        SET_FOREACH(af, c->address_families) {
1,490✔
1969
                const char *name;
150✔
1970

1971
                name = af_to_name(PTR_TO_INT(af));
150✔
1972
                if (!name)
150✔
1973
                        continue;
×
1974

1975
                if (strv_extend(&l, name) < 0)
150✔
1976
                        return NULL;
×
1977
        }
1978

1979
        strv_sort(l);
1,340✔
1980

1981
        return l ? TAKE_PTR(l) : strv_new(NULL);
1,340✔
1982
}
1983

1984
char** exec_context_get_restrict_filesystems(const ExecContext *c) {
1,340✔
1985
        assert(c);
1,340✔
1986

1987
#if HAVE_LIBBPF
1988
        char **l = set_get_strv(c->restrict_filesystems);
1,340✔
1989
        if (!l)
1,340✔
1990
                return NULL;
1991

1992
        return strv_sort(l);
1,340✔
1993
#else
1994
        return strv_new(NULL);
1995
#endif
1996
}
1997

1998
bool exec_context_restrict_namespaces_set(const ExecContext *c) {
12,737✔
1999
        assert(c);
12,737✔
2000

2001
        return (c->restrict_namespaces & NAMESPACE_FLAGS_ALL) != NAMESPACE_FLAGS_ALL;
12,737✔
2002
}
2003

2004
bool exec_context_restrict_filesystems_set(const ExecContext *c) {
14,241✔
2005
        assert(c);
14,241✔
2006

2007
        return c->restrict_filesystems_allow_list ||
14,241✔
2008
          !set_isempty(c->restrict_filesystems);
14,241✔
2009
}
2010

2011
bool exec_context_with_rootfs(const ExecContext *c) {
62,910✔
2012
        assert(c);
62,910✔
2013

2014
        /* Checks if RootDirectory= or RootImage= are used */
2015

2016
        return !empty_or_root(c->root_directory) || c->root_image;
62,910✔
2017
}
2018

2019
int exec_context_has_vpicked_extensions(const ExecContext *context) {
3✔
2020
        int r;
3✔
2021

2022
        assert(context);
3✔
2023

2024
        FOREACH_ARRAY(mi, context->extension_images, context->n_extension_images) {
3✔
2025
                r = path_uses_vpick(mi->source);
×
2026
                if (r != 0)
×
2027
                        return r;
2028
        }
2029
        STRV_FOREACH(ed, context->extension_directories) {
3✔
2030
                r = path_uses_vpick(*ed);
×
2031
                if (r != 0)
×
2032
                        return r;
2033
        }
2034

2035
        return 0;
2036
}
2037

2038
void exec_status_start(ExecStatus *s, pid_t pid, const dual_timestamp *ts) {
4,605✔
2039
        assert(s);
4,605✔
2040

2041
        *s = (ExecStatus) {
4,605✔
2042
                .pid = pid,
2043
        };
2044

2045
        if (ts)
4,605✔
2046
                s->start_timestamp = *ts;
4,605✔
2047
        else
2048
                dual_timestamp_now(&s->start_timestamp);
×
2049
}
4,605✔
2050

2051
void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int code, int status) {
2,052✔
2052
        assert(s);
2,052✔
2053

2054
        if (s->pid != pid)
2,052✔
2055
                *s = (ExecStatus) {
3✔
2056
                        .pid = pid,
2057
                };
2058

2059
        dual_timestamp_now(&s->exit_timestamp);
2,052✔
2060

2061
        s->code = code;
2,052✔
2062
        s->status = status;
2,052✔
2063

2064
        if (context && context->utmp_id)
2,052✔
2065
                (void) utmp_put_dead_process(context->utmp_id, pid, code, status);
14✔
2066
}
2,052✔
2067

2068
void exec_status_handoff(ExecStatus *s, const struct ucred *ucred, const dual_timestamp *ts) {
7,822✔
2069
        assert(s);
7,822✔
2070
        assert(ucred);
7,822✔
2071
        assert(ts);
7,822✔
2072

2073
        if (ucred->pid != s->pid)
7,822✔
2074
                *s = (ExecStatus) {
10✔
2075
                        .pid = ucred->pid,
2076
                };
2077

2078
        s->handoff_timestamp = *ts;
7,822✔
2079
}
7,822✔
2080

2081
void exec_status_reset(ExecStatus *s) {
24,905✔
2082
        assert(s);
24,905✔
2083

2084
        *s = (ExecStatus) {};
24,905✔
2085
}
24,905✔
2086

2087
void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix) {
94✔
2088
        assert(s);
94✔
2089
        assert(f);
94✔
2090

2091
        if (s->pid <= 0)
94✔
2092
                return;
2093

2094
        prefix = strempty(prefix);
10✔
2095

2096
        fprintf(f,
10✔
2097
                "%sPID: "PID_FMT"\n",
2098
                prefix, s->pid);
2099

2100
        if (dual_timestamp_is_set(&s->start_timestamp))
10✔
2101
                fprintf(f,
10✔
2102
                        "%sStart Timestamp: %s\n",
2103
                        prefix, FORMAT_TIMESTAMP_STYLE(s->start_timestamp.realtime, TIMESTAMP_US));
10✔
2104

2105
        if (dual_timestamp_is_set(&s->handoff_timestamp) && dual_timestamp_is_set(&s->start_timestamp) &&
10✔
2106
            s->handoff_timestamp.monotonic > s->start_timestamp.monotonic)
10✔
2107
                fprintf(f,
10✔
2108
                        "%sHandoff Timestamp: %s since start\n",
2109
                        prefix,
2110
                        FORMAT_TIMESPAN(usec_sub_unsigned(s->handoff_timestamp.monotonic, s->start_timestamp.monotonic), 1));
20✔
2111
        else
2112
                fprintf(f,
×
2113
                        "%sHandoff Timestamp: %s\n",
2114
                        prefix, FORMAT_TIMESTAMP_STYLE(s->handoff_timestamp.realtime, TIMESTAMP_US));
×
2115

2116
        if (dual_timestamp_is_set(&s->exit_timestamp)) {
10✔
2117

2118
                if (dual_timestamp_is_set(&s->handoff_timestamp) && s->exit_timestamp.monotonic > s->handoff_timestamp.monotonic)
×
2119
                        fprintf(f,
×
2120
                                "%sExit Timestamp: %s since handoff\n",
2121
                                prefix,
2122
                                FORMAT_TIMESPAN(usec_sub_unsigned(s->exit_timestamp.monotonic, s->handoff_timestamp.monotonic), 1));
×
2123
                else if (dual_timestamp_is_set(&s->start_timestamp) && s->exit_timestamp.monotonic > s->start_timestamp.monotonic)
×
2124
                        fprintf(f,
×
2125
                                "%sExit Timestamp: %s since start\n",
2126
                                prefix,
2127
                                FORMAT_TIMESPAN(usec_sub_unsigned(s->exit_timestamp.monotonic, s->start_timestamp.monotonic), 1));
×
2128
                else
2129
                        fprintf(f,
×
2130
                                "%sExit Timestamp: %s\n",
2131
                                prefix, FORMAT_TIMESTAMP_STYLE(s->exit_timestamp.realtime, TIMESTAMP_US));
×
2132

2133
                fprintf(f,
×
2134
                        "%sExit Code: %s\n"
2135
                        "%sExit Status: %i\n",
2136
                        prefix, sigchld_code_to_string(s->code),
×
2137
                        prefix, s->status);
×
2138
        }
2139
}
2140

2141
void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
94✔
2142
        _cleanup_free_ char *cmd = NULL;
188✔
2143
        const char *prefix2;
94✔
2144

2145
        assert(c);
94✔
2146
        assert(f);
94✔
2147

2148
        prefix = strempty(prefix);
94✔
2149
        prefix2 = strjoina(prefix, "\t");
470✔
2150

2151
        cmd = quote_command_line(c->argv, SHELL_ESCAPE_EMPTY);
94✔
2152

2153
        fprintf(f,
94✔
2154
                "%sCommand Line: %s\n",
2155
                prefix, strnull(cmd));
2156

2157
        exec_status_dump(&c->exec_status, f, prefix2);
94✔
2158
}
94✔
2159

2160
void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
91✔
2161
        assert(f);
91✔
2162

2163
        prefix = strempty(prefix);
91✔
2164

2165
        LIST_FOREACH(command, i, c)
185✔
2166
                exec_command_dump(i, f, prefix);
94✔
2167
}
91✔
2168

2169
void exec_command_append_list(ExecCommand **l, ExecCommand *e) {
16,712✔
2170
        ExecCommand *end;
16,712✔
2171

2172
        assert(l);
16,712✔
2173
        assert(e);
16,712✔
2174

2175
        if (*l) {
16,712✔
2176
                /* It's kind of important, that we keep the order here */
2177
                end = LIST_FIND_TAIL(command, *l);
479✔
2178
                LIST_INSERT_AFTER(command, *l, end, e);
242✔
2179
        } else
2180
                *l = e;
16,470✔
2181
}
16,712✔
2182

2183
int exec_command_set(ExecCommand *c, const char *path, ...) {
172✔
2184
        va_list ap;
172✔
2185
        char **l, *p;
172✔
2186

2187
        assert(c);
172✔
2188
        assert(path);
172✔
2189

2190
        va_start(ap, path);
172✔
2191
        l = strv_new_ap(path, ap);
172✔
2192
        va_end(ap);
172✔
2193

2194
        if (!l)
172✔
2195
                return -ENOMEM;
172✔
2196

2197
        p = strdup(path);
172✔
2198
        if (!p) {
172✔
2199
                strv_free(l);
×
2200
                return -ENOMEM;
×
2201
        }
2202

2203
        free_and_replace(c->path, p);
172✔
2204

2205
        return strv_free_and_replace(c->argv, l);
172✔
2206
}
2207

2208
int exec_command_append(ExecCommand *c, const char *path, ...) {
247✔
2209
        char **l;
247✔
2210
        va_list ap;
247✔
2211
        int r;
247✔
2212

2213
        assert(c);
247✔
2214
        assert(path);
247✔
2215

2216
        va_start(ap, path);
247✔
2217
        l = strv_new_ap(path, ap);
247✔
2218
        va_end(ap);
247✔
2219

2220
        if (!l)
247✔
2221
                return -ENOMEM;
247✔
2222

2223
        r = strv_extend_strv_consume(&c->argv, l, /* filter_duplicates = */ false);
247✔
2224
        if (r < 0)
247✔
2225
                return r;
×
2226

2227
        return 0;
2228
}
2229

2230
static char *destroy_tree(char *path) {
269✔
2231
        if (!path)
269✔
2232
                return NULL;
2233

2234
        if (!path_equal(path, RUN_SYSTEMD_EMPTY)) {
84✔
2235
                log_debug("Spawning process to nuke '%s'", path);
84✔
2236

2237
                (void) asynchronous_rm_rf(path, REMOVE_ROOT|REMOVE_SUBVOLUME|REMOVE_PHYSICAL);
84✔
2238
        }
2239

2240
        return mfree(path);
84✔
2241
}
2242

2243
void exec_shared_runtime_done(ExecSharedRuntime *rt) {
130,305✔
2244
        assert(rt);
130,305✔
2245

2246
        if (rt->manager)
130,305✔
2247
                (void) hashmap_remove(rt->manager->exec_shared_runtime_by_id, rt->id);
172✔
2248

2249
        rt->id = mfree(rt->id);
130,305✔
2250
        rt->tmp_dir = mfree(rt->tmp_dir);
130,305✔
2251
        rt->var_tmp_dir = mfree(rt->var_tmp_dir);
130,305✔
2252
        safe_close_pair(rt->netns_storage_socket);
130,305✔
2253
        safe_close_pair(rt->ipcns_storage_socket);
130,305✔
2254
}
130,305✔
2255

2256
static ExecSharedRuntime* exec_shared_runtime_free(ExecSharedRuntime *rt) {
130,277✔
2257
        if (!rt)
130,277✔
2258
                return NULL;
2259

2260
        exec_shared_runtime_done(rt);
130,277✔
2261
        return mfree(rt);
130,277✔
2262
}
2263

2264
DEFINE_TRIVIAL_UNREF_FUNC(ExecSharedRuntime, exec_shared_runtime, exec_shared_runtime_free);
173✔
2265
DEFINE_TRIVIAL_CLEANUP_FUNC(ExecSharedRuntime*, exec_shared_runtime_free);
133,407✔
2266

2267
ExecSharedRuntime* exec_shared_runtime_destroy(ExecSharedRuntime *rt) {
49✔
2268
        if (!rt)
49✔
2269
                return NULL;
2270

2271
        assert(rt->n_ref > 0);
48✔
2272
        rt->n_ref--;
48✔
2273

2274
        if (rt->n_ref > 0)
48✔
2275
                return NULL;
2276

2277
        rt->tmp_dir = destroy_tree(rt->tmp_dir);
48✔
2278
        rt->var_tmp_dir = destroy_tree(rt->var_tmp_dir);
48✔
2279

2280
        return exec_shared_runtime_free(rt);
48✔
2281
}
2282

2283
static int exec_shared_runtime_allocate(ExecSharedRuntime **ret, const char *id) {
130,277✔
2284
        _cleanup_free_ char *id_copy = NULL;
260,554✔
2285
        ExecSharedRuntime *n;
130,277✔
2286

2287
        assert(ret);
130,277✔
2288

2289
        id_copy = strdup(id);
130,277✔
2290
        if (!id_copy)
130,277✔
2291
                return -ENOMEM;
2292

2293
        n = new(ExecSharedRuntime, 1);
130,277✔
2294
        if (!n)
130,277✔
2295
                return -ENOMEM;
2296

2297
        *n = (ExecSharedRuntime) {
130,277✔
2298
                .id = TAKE_PTR(id_copy),
130,277✔
2299
                .netns_storage_socket = EBADF_PAIR,
2300
                .ipcns_storage_socket = EBADF_PAIR,
2301
        };
2302

2303
        *ret = n;
130,277✔
2304
        return 0;
130,277✔
2305
}
2306

2307
static int exec_shared_runtime_add(
172✔
2308
                Manager *m,
2309
                const char *id,
2310
                char **tmp_dir,
2311
                char **var_tmp_dir,
2312
                int netns_storage_socket[2],
2313
                int ipcns_storage_socket[2],
2314
                ExecSharedRuntime **ret) {
2315

2316
        _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt = NULL;
172✔
2317
        int r;
172✔
2318

2319
        assert(m);
172✔
2320
        assert(id);
172✔
2321

2322
        /* tmp_dir, var_tmp_dir, {net,ipc}ns_storage_socket fds are donated on success */
2323

2324
        r = exec_shared_runtime_allocate(&rt, id);
172✔
2325
        if (r < 0)
172✔
2326
                return r;
2327

2328
        r = hashmap_ensure_put(&m->exec_shared_runtime_by_id, &string_hash_ops, rt->id, rt);
172✔
2329
        if (r < 0)
172✔
2330
                return r;
2331

2332
        assert(!!rt->tmp_dir == !!rt->var_tmp_dir); /* We require both to be set together */
172✔
2333
        rt->tmp_dir = TAKE_PTR(*tmp_dir);
172✔
2334
        rt->var_tmp_dir = TAKE_PTR(*var_tmp_dir);
172✔
2335

2336
        if (netns_storage_socket) {
172✔
2337
                rt->netns_storage_socket[0] = TAKE_FD(netns_storage_socket[0]);
172✔
2338
                rt->netns_storage_socket[1] = TAKE_FD(netns_storage_socket[1]);
172✔
2339
        }
2340

2341
        if (ipcns_storage_socket) {
172✔
2342
                rt->ipcns_storage_socket[0] = TAKE_FD(ipcns_storage_socket[0]);
172✔
2343
                rt->ipcns_storage_socket[1] = TAKE_FD(ipcns_storage_socket[1]);
172✔
2344
        }
2345

2346
        rt->manager = m;
172✔
2347

2348
        if (ret)
172✔
2349
                *ret = rt;
69✔
2350
        /* do not remove created ExecSharedRuntime object when the operation succeeds. */
2351
        TAKE_PTR(rt);
172✔
2352
        return 0;
172✔
2353
}
2354

2355
static int exec_shared_runtime_make(
6,212✔
2356
                Manager *m,
2357
                const ExecContext *c,
2358
                const char *id,
2359
                ExecSharedRuntime **ret) {
2360

2361
        _cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
6,212✔
2362
        _cleanup_close_pair_ int netns_storage_socket[2] = EBADF_PAIR, ipcns_storage_socket[2] = EBADF_PAIR;
12,424✔
2363
        int r;
6,212✔
2364

2365
        assert(m);
6,212✔
2366
        assert(c);
6,212✔
2367
        assert(id);
6,212✔
2368

2369
        /* It is not necessary to create ExecSharedRuntime object. */
2370
        if (!exec_needs_network_namespace(c) && !exec_needs_ipc_namespace(c) && c->private_tmp != PRIVATE_TMP_CONNECTED) {
6,212✔
2371
                *ret = NULL;
6,143✔
2372
                return 0;
6,143✔
2373
        }
2374

2375
        if (c->private_tmp == PRIVATE_TMP_CONNECTED &&
132✔
2376
            !(prefixed_path_strv_contains(c->inaccessible_paths, "/tmp") &&
63✔
2377
              (prefixed_path_strv_contains(c->inaccessible_paths, "/var/tmp") ||
×
2378
               prefixed_path_strv_contains(c->inaccessible_paths, "/var")))) {
×
2379
                r = setup_tmp_dirs(id, &tmp_dir, &var_tmp_dir);
63✔
2380
                if (r < 0)
63✔
2381
                        return r;
2382
        }
2383

2384
        if (exec_needs_network_namespace(c))
69✔
2385
                if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, netns_storage_socket) < 0)
7✔
2386
                        return -errno;
×
2387

2388
        if (exec_needs_ipc_namespace(c))
69✔
2389
                if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ipcns_storage_socket) < 0)
2✔
2390
                        return -errno;
×
2391

2392
        r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ipcns_storage_socket, ret);
69✔
2393
        if (r < 0)
69✔
2394
                return r;
×
2395

2396
        return 1;
2397
}
2398

2399
int exec_shared_runtime_acquire(Manager *m, const ExecContext *c, const char *id, bool create, ExecSharedRuntime **ret) {
6,315✔
2400
        ExecSharedRuntime *rt;
6,315✔
2401
        int r;
6,315✔
2402

2403
        assert(m);
6,315✔
2404
        assert(id);
6,315✔
2405
        assert(ret);
6,315✔
2406

2407
        rt = hashmap_get(m->exec_shared_runtime_by_id, id);
6,315✔
2408
        if (rt)
6,315✔
2409
                /* We already have an ExecSharedRuntime object, let's increase the ref count and reuse it */
2410
                goto ref;
103✔
2411

2412
        if (!create) {
6,212✔
2413
                *ret = NULL;
×
2414
                return 0;
×
2415
        }
2416

2417
        /* If not found, then create a new object. */
2418
        r = exec_shared_runtime_make(m, c, id, &rt);
6,212✔
2419
        if (r < 0)
6,212✔
2420
                return r;
2421
        if (r == 0) {
6,212✔
2422
                /* When r == 0, it is not necessary to create ExecSharedRuntime object. */
2423
                *ret = NULL;
6,143✔
2424
                return 0;
6,143✔
2425
        }
2426

2427
ref:
69✔
2428
        /* increment reference counter. */
2429
        rt->n_ref++;
172✔
2430
        *ret = rt;
172✔
2431
        return 1;
172✔
2432
}
2433

2434
int exec_shared_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
73✔
2435
        ExecSharedRuntime *rt;
73✔
2436

2437
        assert(m);
73✔
2438
        assert(f);
73✔
2439
        assert(fds);
73✔
2440

2441
        HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
197✔
2442
                fprintf(f, "exec-runtime=%s", rt->id);
124✔
2443

2444
                if (rt->tmp_dir)
124✔
2445
                        fprintf(f, " tmp-dir=%s", rt->tmp_dir);
124✔
2446

2447
                if (rt->var_tmp_dir)
124✔
2448
                        fprintf(f, " var-tmp-dir=%s", rt->var_tmp_dir);
124✔
2449

2450
                if (rt->netns_storage_socket[0] >= 0) {
124✔
2451
                        int copy;
2✔
2452

2453
                        copy = fdset_put_dup(fds, rt->netns_storage_socket[0]);
2✔
2454
                        if (copy < 0)
2✔
2455
                                return copy;
×
2456

2457
                        fprintf(f, " netns-socket-0=%i", copy);
2✔
2458
                }
2459

2460
                if (rt->netns_storage_socket[1] >= 0) {
124✔
2461
                        int copy;
2✔
2462

2463
                        copy = fdset_put_dup(fds, rt->netns_storage_socket[1]);
2✔
2464
                        if (copy < 0)
2✔
2465
                                return copy;
2466

2467
                        fprintf(f, " netns-socket-1=%i", copy);
2✔
2468
                }
2469

2470
                if (rt->ipcns_storage_socket[0] >= 0) {
124✔
2471
                        int copy;
×
2472

2473
                        copy = fdset_put_dup(fds, rt->ipcns_storage_socket[0]);
×
2474
                        if (copy < 0)
×
2475
                                return copy;
2476

2477
                        fprintf(f, " ipcns-socket-0=%i", copy);
×
2478
                }
2479

2480
                if (rt->ipcns_storage_socket[1] >= 0) {
124✔
2481
                        int copy;
×
2482

2483
                        copy = fdset_put_dup(fds, rt->ipcns_storage_socket[1]);
×
2484
                        if (copy < 0)
×
2485
                                return copy;
2486

2487
                        fprintf(f, " ipcns-socket-1=%i", copy);
×
2488
                }
2489

2490
                fputc('\n', f);
124✔
2491
        }
2492

2493
        return 0;
73✔
2494
}
2495

2496
int exec_shared_runtime_deserialize_compat(Unit *u, const char *key, const char *value, FDSet *fds) {
133,235✔
2497
        _cleanup_(exec_shared_runtime_freep) ExecSharedRuntime *rt_create = NULL;
133,235✔
2498
        ExecSharedRuntime *rt = NULL;
133,235✔
2499
        int r;
133,235✔
2500

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

2506
        assert(u);
133,235✔
2507
        assert(key);
133,235✔
2508
        assert(value);
133,235✔
2509

2510
        /* Manager manages ExecSharedRuntime objects by the unit id.
2511
         * So, we omit the serialized text when the unit does not have id (yet?)... */
2512
        if (isempty(u->id)) {
133,235✔
2513
                log_unit_debug(u, "Invocation ID not found. Dropping runtime parameter.");
×
2514
                return 0;
×
2515
        }
2516

2517
        if (u->manager) {
133,235✔
2518
                if (hashmap_ensure_allocated(&u->manager->exec_shared_runtime_by_id, &string_hash_ops) < 0)
133,235✔
2519
                        return log_oom();
×
2520

2521
                rt = hashmap_get(u->manager->exec_shared_runtime_by_id, u->id);
133,235✔
2522
        }
2523
        if (!rt) {
133,235✔
2524
                if (exec_shared_runtime_allocate(&rt_create, u->id) < 0)
130,105✔
2525
                        return log_oom();
×
2526

2527
                rt = rt_create;
130,105✔
2528
        }
2529

2530
        if (streq(key, "tmp-dir")) {
133,235✔
2531
                if (free_and_strdup_warn(&rt->tmp_dir, value) < 0)
×
2532
                        return -ENOMEM;
2533

2534
        } else if (streq(key, "var-tmp-dir")) {
133,235✔
2535
                if (free_and_strdup_warn(&rt->var_tmp_dir, value) < 0)
×
2536
                        return -ENOMEM;
2537

2538
        } else if (streq(key, "netns-socket-0")) {
133,235✔
2539

2540
                safe_close(rt->netns_storage_socket[0]);
×
2541
                rt->netns_storage_socket[0] = deserialize_fd(fds, value);
×
2542
                if (rt->netns_storage_socket[0] < 0)
×
2543
                        return 0;
2544

2545
        } else if (streq(key, "netns-socket-1")) {
133,235✔
2546

2547
                safe_close(rt->netns_storage_socket[1]);
×
2548
                rt->netns_storage_socket[1] = deserialize_fd(fds, value);
×
2549
                if (rt->netns_storage_socket[1] < 0)
×
2550
                        return 0;
2551
        } else
2552
                return 0;
2553

2554
        /* If the object is newly created, then put it to the hashmap which manages ExecSharedRuntime objects. */
2555
        if (rt_create && u->manager) {
×
2556
                r = hashmap_put(u->manager->exec_shared_runtime_by_id, rt_create->id, rt_create);
×
2557
                if (r < 0) {
×
2558
                        log_unit_debug_errno(u, r, "Failed to put runtime parameter to manager's storage: %m");
×
2559
                        return 0;
×
2560
                }
2561

2562
                rt_create->manager = u->manager;
×
2563

2564
                /* Avoid cleanup */
2565
                TAKE_PTR(rt_create);
×
2566
        }
2567

2568
        return 1;
2569
}
2570

2571
int exec_shared_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
103✔
2572
        _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
103✔
2573
        char *id = NULL;
103✔
2574
        int r, netns_fdpair[] = {-1, -1}, ipcns_fdpair[] = {-1, -1};
103✔
2575
        const char *p, *v = ASSERT_PTR(value);
103✔
2576
        size_t n;
103✔
2577

2578
        assert(m);
103✔
2579
        assert(fds);
103✔
2580

2581
        n = strcspn(v, " ");
103✔
2582
        id = strndupa_safe(v, n);
103✔
2583
        if (v[n] != ' ')
103✔
2584
                goto finalize;
×
2585
        p = v + n + 1;
103✔
2586

2587
        v = startswith(p, "tmp-dir=");
103✔
2588
        if (v) {
103✔
2589
                n = strcspn(v, " ");
103✔
2590
                tmp_dir = strndup(v, n);
103✔
2591
                if (!tmp_dir)
103✔
2592
                        return log_oom();
×
2593
                if (v[n] != ' ')
103✔
2594
                        goto finalize;
×
2595
                p = v + n + 1;
103✔
2596
        }
2597

2598
        v = startswith(p, "var-tmp-dir=");
103✔
2599
        if (v) {
103✔
2600
                n = strcspn(v, " ");
103✔
2601
                var_tmp_dir = strndup(v, n);
103✔
2602
                if (!var_tmp_dir)
103✔
2603
                        return log_oom();
×
2604
                if (v[n] != ' ')
103✔
2605
                        goto finalize;
102✔
2606
                p = v + n + 1;
1✔
2607
        }
2608

2609
        v = startswith(p, "netns-socket-0=");
1✔
2610
        if (v) {
1✔
2611
                char *buf;
1✔
2612

2613
                n = strcspn(v, " ");
1✔
2614
                buf = strndupa_safe(v, n);
1✔
2615

2616
                netns_fdpair[0] = deserialize_fd(fds, buf);
1✔
2617
                if (netns_fdpair[0] < 0)
1✔
2618
                        return netns_fdpair[0];
2619
                if (v[n] != ' ')
1✔
2620
                        goto finalize;
×
2621
                p = v + n + 1;
1✔
2622
        }
2623

2624
        v = startswith(p, "netns-socket-1=");
1✔
2625
        if (v) {
1✔
2626
                char *buf;
1✔
2627

2628
                n = strcspn(v, " ");
1✔
2629
                buf = strndupa_safe(v, n);
1✔
2630

2631
                netns_fdpair[1] = deserialize_fd(fds, buf);
1✔
2632
                if (netns_fdpair[1] < 0)
1✔
2633
                        return netns_fdpair[1];
2634
                if (v[n] != ' ')
1✔
2635
                        goto finalize;
1✔
2636
                p = v + n + 1;
×
2637
        }
2638

2639
        v = startswith(p, "ipcns-socket-0=");
×
2640
        if (v) {
×
2641
                char *buf;
×
2642

2643
                n = strcspn(v, " ");
×
2644
                buf = strndupa_safe(v, n);
×
2645

2646
                ipcns_fdpair[0] = deserialize_fd(fds, buf);
×
2647
                if (ipcns_fdpair[0] < 0)
×
2648
                        return ipcns_fdpair[0];
2649
                if (v[n] != ' ')
×
2650
                        goto finalize;
×
2651
                p = v + n + 1;
×
2652
        }
2653

2654
        v = startswith(p, "ipcns-socket-1=");
×
2655
        if (v) {
×
2656
                char *buf;
×
2657

2658
                n = strcspn(v, " ");
×
2659
                buf = strndupa_safe(v, n);
×
2660

2661
                ipcns_fdpair[1] = deserialize_fd(fds, buf);
×
2662
                if (ipcns_fdpair[1] < 0)
×
2663
                        return ipcns_fdpair[1];
2664
        }
2665

2666
finalize:
×
2667
        r = exec_shared_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_fdpair, ipcns_fdpair, NULL);
103✔
2668
        if (r < 0)
103✔
2669
                return log_debug_errno(r, "Failed to add exec-runtime: %m");
×
2670
        return 0;
2671
}
2672

2673
void exec_shared_runtime_vacuum(Manager *m) {
1,456✔
2674
        ExecSharedRuntime *rt;
1,456✔
2675

2676
        assert(m);
1,456✔
2677

2678
        /* Free unreferenced ExecSharedRuntime objects. This is used after manager deserialization process. */
2679

2680
        HASHMAP_FOREACH(rt, m->exec_shared_runtime_by_id) {
1,559✔
2681
                if (rt->n_ref > 0)
103✔
2682
                        continue;
103✔
2683

2684
                (void) exec_shared_runtime_free(rt);
×
2685
        }
2686
}
1,456✔
2687

2688
int exec_runtime_make(
6,315✔
2689
                const Unit *unit,
2690
                const ExecContext *context,
2691
                ExecSharedRuntime *shared,
2692
                DynamicCreds *creds,
2693
                ExecRuntime **ret) {
2694
        _cleanup_close_pair_ int ephemeral_storage_socket[2] = EBADF_PAIR;
6,315✔
2695
        _cleanup_free_ char *ephemeral = NULL;
6,315✔
2696
        _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
6,315✔
2697
        int r;
6,315✔
2698

2699
        assert(unit);
6,315✔
2700
        assert(context);
6,315✔
2701
        assert(ret);
6,315✔
2702

2703
        if (!shared && !creds && !exec_needs_ephemeral(context)) {
6,315✔
2704
                *ret = NULL;
6,142✔
2705
                return 0;
6,142✔
2706
        }
2707

2708
        if (exec_needs_ephemeral(context)) {
173✔
2709
                r = mkdir_p("/var/lib/systemd/ephemeral-trees", 0755);
×
2710
                if (r < 0)
×
2711
                        return r;
2712

2713
                r = tempfn_random_child("/var/lib/systemd/ephemeral-trees", unit->id, &ephemeral);
×
2714
                if (r < 0)
×
2715
                        return r;
2716

2717
                if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ephemeral_storage_socket) < 0)
×
2718
                        return -errno;
×
2719
        }
2720

2721
        rt = new(ExecRuntime, 1);
173✔
2722
        if (!rt)
173✔
2723
                return -ENOMEM;
2724

2725
        *rt = (ExecRuntime) {
173✔
2726
                .shared = shared,
2727
                .dynamic_creds = creds,
2728
                .ephemeral_copy = TAKE_PTR(ephemeral),
173✔
2729
                .ephemeral_storage_socket[0] = TAKE_FD(ephemeral_storage_socket[0]),
173✔
2730
                .ephemeral_storage_socket[1] = TAKE_FD(ephemeral_storage_socket[1]),
173✔
2731
        };
2732

2733
        *ret = TAKE_PTR(rt);
173✔
2734
        return 1;
173✔
2735
}
2736

2737
ExecRuntime* exec_runtime_free(ExecRuntime *rt) {
46,953✔
2738
        if (!rt)
46,953✔
2739
                return NULL;
2740

2741
        exec_shared_runtime_unref(rt->shared);
173✔
2742
        dynamic_creds_unref(rt->dynamic_creds);
173✔
2743

2744
        rt->ephemeral_copy = destroy_tree(rt->ephemeral_copy);
173✔
2745

2746
        safe_close_pair(rt->ephemeral_storage_socket);
173✔
2747
        return mfree(rt);
173✔
2748
}
2749

2750
ExecRuntime* exec_runtime_destroy(ExecRuntime *rt) {
5,037✔
2751
        if (!rt)
5,037✔
2752
                return NULL;
2753

2754
        rt->shared = exec_shared_runtime_destroy(rt->shared);
49✔
2755
        rt->dynamic_creds = dynamic_creds_destroy(rt->dynamic_creds);
49✔
2756
        return exec_runtime_free(rt);
49✔
2757
}
2758

2759
void exec_runtime_clear(ExecRuntime *rt) {
28✔
2760
        if (!rt)
28✔
2761
                return;
2762

2763
        safe_close_pair(rt->ephemeral_storage_socket);
28✔
2764
        rt->ephemeral_copy = mfree(rt->ephemeral_copy);
28✔
2765
}
2766

2767
void exec_params_shallow_clear(ExecParameters *p) {
2,248✔
2768
        if (!p)
2,248✔
2769
                return;
2770

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

2774
        p->environment = strv_free(p->environment);
2,248✔
2775
        p->fd_names = strv_free(p->fd_names);
2,248✔
2776
        p->files_env = strv_free(p->files_env);
2,248✔
2777
        p->fds = mfree(p->fds);
2,248✔
2778
        p->exec_fd = safe_close(p->exec_fd);
2,248✔
2779
        p->user_lookup_fd = -EBADF;
2,248✔
2780
        p->bpf_restrict_fs_map_fd = -EBADF;
2,248✔
2781
        p->unit_id = mfree(p->unit_id);
2,248✔
2782
        p->invocation_id = SD_ID128_NULL;
2,248✔
2783
        p->invocation_id_string[0] = '\0';
2,248✔
2784
        p->confirm_spawn = mfree(p->confirm_spawn);
2,248✔
2785
}
2786

2787
void exec_params_deep_clear(ExecParameters *p) {
28✔
2788
        if (!p)
28✔
2789
                return;
2790

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

2795
        close_many_unset(p->fds, p->n_socket_fds + p->n_storage_fds + p->n_extra_fds);
28✔
2796

2797
        p->cgroup_path = mfree(p->cgroup_path);
28✔
2798

2799
        if (p->prefix) {
28✔
2800
                free_many_charp(p->prefix, _EXEC_DIRECTORY_TYPE_MAX);
28✔
2801
                p->prefix = mfree(p->prefix);
28✔
2802
        }
2803

2804
        p->received_credentials_directory = mfree(p->received_credentials_directory);
28✔
2805
        p->received_encrypted_credentials_directory = mfree(p->received_encrypted_credentials_directory);
28✔
2806

2807
        if (p->idle_pipe) {
28✔
UNCOV
2808
                close_many_and_free(p->idle_pipe, 4);
×
UNCOV
2809
                p->idle_pipe = NULL;
×
2810
        }
2811

2812
        p->stdin_fd = safe_close(p->stdin_fd);
28✔
2813
        p->stdout_fd = safe_close(p->stdout_fd);
28✔
2814
        p->stderr_fd = safe_close(p->stderr_fd);
28✔
2815

2816
        p->notify_socket = mfree(p->notify_socket);
28✔
2817

2818
        open_file_free_many(&p->open_files);
28✔
2819

2820
        p->fallback_smack_process_label = mfree(p->fallback_smack_process_label);
28✔
2821

2822
        exec_params_shallow_clear(p);
28✔
2823
}
2824

2825
void exec_directory_done(ExecDirectory *d) {
234,660✔
2826
        if (!d)
234,660✔
2827
                return;
2828

2829
        FOREACH_ARRAY(i, d->items, d->n_items) {
236,454✔
2830
                free(i->path);
1,794✔
2831
                strv_free(i->symlinks);
1,794✔
2832
        }
2833

2834
        d->items = mfree(d->items);
234,660✔
2835
        d->n_items = 0;
234,660✔
2836
        d->mode = 0755;
234,660✔
2837
}
2838

2839
static ExecDirectoryItem *exec_directory_find(ExecDirectory *d, const char *path) {
5,518✔
2840
        assert(d);
5,518✔
2841
        assert(path);
5,518✔
2842

2843
        FOREACH_ARRAY(i, d->items, d->n_items)
7,862✔
2844
                if (path_equal(i->path, path))
2,359✔
2845
                        return i;
2846

2847
        return NULL;
2848
}
2849

2850
int exec_directory_add(ExecDirectory *d, const char *path, const char *symlink, ExecDirectoryFlags flags) {
5,518✔
2851
        _cleanup_strv_free_ char **s = NULL;
×
2852
        _cleanup_free_ char *p = NULL;
5,518✔
2853
        ExecDirectoryItem *existing;
5,518✔
2854
        int r;
5,518✔
2855

2856
        assert(d);
5,518✔
2857
        assert(path);
5,518✔
2858

2859
        existing = exec_directory_find(d, path);
5,518✔
2860
        if (existing) {
5,518✔
2861
                r = strv_extend(&existing->symlinks, symlink);
15✔
2862
                if (r < 0)
15✔
2863
                        return r;
2864

2865
                existing->flags |= flags;
15✔
2866

2867
                return 0; /* existing item is updated */
15✔
2868
        }
2869

2870
        p = strdup(path);
5,503✔
2871
        if (!p)
5,503✔
2872
                return -ENOMEM;
2873

2874
        if (symlink) {
5,503✔
2875
                s = strv_new(symlink);
6✔
2876
                if (!s)
6✔
2877
                        return -ENOMEM;
2878
        }
2879

2880
        if (!GREEDY_REALLOC(d->items, d->n_items + 1))
5,503✔
2881
                return -ENOMEM;
2882

2883
        d->items[d->n_items++] = (ExecDirectoryItem) {
5,503✔
2884
                .path = TAKE_PTR(p),
5,503✔
2885
                .symlinks = TAKE_PTR(s),
5,503✔
2886
                .flags = flags,
2887
        };
2888

2889
        return 1; /* new item is added */
5,503✔
2890
}
2891

2892
static int exec_directory_item_compare_func(const ExecDirectoryItem *a, const ExecDirectoryItem *b) {
890✔
2893
        assert(a);
890✔
2894
        assert(b);
890✔
2895

2896
        return path_compare(a->path, b->path);
890✔
2897
}
2898

2899
void exec_directory_sort(ExecDirectory *d) {
128,726✔
2900
        assert(d);
128,726✔
2901

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

2907
        if (d->n_items <= 1)
128,726✔
2908
                return;
2909

2910
        typesafe_qsort(d->items, d->n_items, exec_directory_item_compare_func);
160✔
2911

2912
        for (size_t i = 1; i < d->n_items; i++)
695✔
2913
                for (size_t j = 0; j < i; j++)
1,780✔
2914
                        if (path_startswith(d->items[i].path, d->items[j].path)) {
1,260✔
2915
                                d->items[i].flags |= EXEC_DIRECTORY_ONLY_CREATE;
15✔
2916
                                break;
15✔
2917
                        }
2918
}
2919

2920
ExecCleanMask exec_clean_mask_from_string(const char *s) {
×
2921
        ExecDirectoryType t;
×
2922

2923
        assert(s);
×
2924

2925
        if (streq(s, "all"))
×
2926
                return EXEC_CLEAN_ALL;
2927
        if (streq(s, "fdstore"))
×
2928
                return EXEC_CLEAN_FDSTORE;
2929

2930
        t = exec_resource_type_from_string(s);
×
2931
        if (t < 0)
×
2932
                return (ExecCleanMask) t;
2933

2934
        return 1U << t;
×
2935
}
2936

2937
static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
2938
        [EXEC_INPUT_NULL]      = "null",
2939
        [EXEC_INPUT_TTY]       = "tty",
2940
        [EXEC_INPUT_TTY_FORCE] = "tty-force",
2941
        [EXEC_INPUT_TTY_FAIL]  = "tty-fail",
2942
        [EXEC_INPUT_SOCKET]    = "socket",
2943
        [EXEC_INPUT_NAMED_FD]  = "fd",
2944
        [EXEC_INPUT_DATA]      = "data",
2945
        [EXEC_INPUT_FILE]      = "file",
2946
};
2947

2948
DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
15,928✔
2949

2950
static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
2951
        [EXEC_OUTPUT_INHERIT]             = "inherit",
2952
        [EXEC_OUTPUT_NULL]                = "null",
2953
        [EXEC_OUTPUT_TTY]                 = "tty",
2954
        [EXEC_OUTPUT_KMSG]                = "kmsg",
2955
        [EXEC_OUTPUT_KMSG_AND_CONSOLE]    = "kmsg+console",
2956
        [EXEC_OUTPUT_JOURNAL]             = "journal",
2957
        [EXEC_OUTPUT_JOURNAL_AND_CONSOLE] = "journal+console",
2958
        [EXEC_OUTPUT_SOCKET]              = "socket",
2959
        [EXEC_OUTPUT_NAMED_FD]            = "fd",
2960
        [EXEC_OUTPUT_FILE]                = "file",
2961
        [EXEC_OUTPUT_FILE_APPEND]         = "append",
2962
        [EXEC_OUTPUT_FILE_TRUNCATE]       = "truncate",
2963
};
2964

2965
DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
32,051✔
2966

2967
static const char* const exec_utmp_mode_table[_EXEC_UTMP_MODE_MAX] = {
2968
        [EXEC_UTMP_INIT]  = "init",
2969
        [EXEC_UTMP_LOGIN] = "login",
2970
        [EXEC_UTMP_USER]  = "user",
2971
};
2972

2973
DEFINE_STRING_TABLE_LOOKUP(exec_utmp_mode, ExecUtmpMode);
15,172✔
2974

2975
static const char* const exec_preserve_mode_table[_EXEC_PRESERVE_MODE_MAX] = {
2976
        [EXEC_PRESERVE_NO]      = "no",
2977
        [EXEC_PRESERVE_YES]     = "yes",
2978
        [EXEC_PRESERVE_RESTART] = "restart",
2979
};
2980

2981
DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(exec_preserve_mode, ExecPreserveMode, EXEC_PRESERVE_YES);
17,245✔
2982

2983
/* This table maps ExecDirectoryType to the setting it is configured with in the unit */
2984
static const char* const exec_directory_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2985
        [EXEC_DIRECTORY_RUNTIME]       = "RuntimeDirectory",
2986
        [EXEC_DIRECTORY_STATE]         = "StateDirectory",
2987
        [EXEC_DIRECTORY_CACHE]         = "CacheDirectory",
2988
        [EXEC_DIRECTORY_LOGS]          = "LogsDirectory",
2989
        [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectory",
2990
};
2991

2992
DEFINE_STRING_TABLE_LOOKUP(exec_directory_type, ExecDirectoryType);
139,048✔
2993

2994
/* This table maps ExecDirectoryType to the symlink setting it is configured with in the unit */
2995
static const char* const exec_directory_type_symlink_table[_EXEC_DIRECTORY_TYPE_MAX] = {
2996
        [EXEC_DIRECTORY_RUNTIME]       = "RuntimeDirectorySymlink",
2997
        [EXEC_DIRECTORY_STATE]         = "StateDirectorySymlink",
2998
        [EXEC_DIRECTORY_CACHE]         = "CacheDirectorySymlink",
2999
        [EXEC_DIRECTORY_LOGS]          = "LogsDirectorySymlink",
3000
        [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectorySymlink",
3001
};
3002

3003
DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_symlink, ExecDirectoryType);
14✔
3004

3005
static const char* const exec_directory_type_mode_table[_EXEC_DIRECTORY_TYPE_MAX] = {
3006
        [EXEC_DIRECTORY_RUNTIME]       = "RuntimeDirectoryMode",
3007
        [EXEC_DIRECTORY_STATE]         = "StateDirectoryMode",
3008
        [EXEC_DIRECTORY_CACHE]         = "CacheDirectoryMode",
3009
        [EXEC_DIRECTORY_LOGS]          = "LogsDirectoryMode",
3010
        [EXEC_DIRECTORY_CONFIGURATION] = "ConfigurationDirectoryMode",
3011
};
3012

3013
DEFINE_STRING_TABLE_LOOKUP(exec_directory_type_mode, ExecDirectoryType);
×
3014

3015
/* And this table maps ExecDirectoryType too, but to a generic term identifying the type of resource. This
3016
 * one is supposed to be generic enough to be used for unit types that don't use ExecContext and per-unit
3017
 * directories, specifically .timer units with their timestamp touch file. */
3018
static const char* const exec_resource_type_table[_EXEC_DIRECTORY_TYPE_MAX] = {
3019
        [EXEC_DIRECTORY_RUNTIME]       = "runtime",
3020
        [EXEC_DIRECTORY_STATE]         = "state",
3021
        [EXEC_DIRECTORY_CACHE]         = "cache",
3022
        [EXEC_DIRECTORY_LOGS]          = "logs",
3023
        [EXEC_DIRECTORY_CONFIGURATION] = "configuration",
3024
};
3025

3026
DEFINE_STRING_TABLE_LOOKUP(exec_resource_type, ExecDirectoryType);
353✔
3027

3028
static const char* const exec_keyring_mode_table[_EXEC_KEYRING_MODE_MAX] = {
3029
        [EXEC_KEYRING_INHERIT] = "inherit",
3030
        [EXEC_KEYRING_PRIVATE] = "private",
3031
        [EXEC_KEYRING_SHARED]  = "shared",
3032
};
3033

3034
DEFINE_STRING_TABLE_LOOKUP(exec_keyring_mode, ExecKeyringMode);
15,537✔
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