]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/execute-serialize.c
udev-spawn: slightly adjust logs about timed out commands
[thirdparty/systemd.git] / src / core / execute-serialize.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "af-list.h"
4 #include "capability-util.h"
5 #include "cgroup-setup.h"
6 #include "escape.h"
7 #include "exec-credential.h"
8 #include "execute-serialize.h"
9 #include "hexdecoct.h"
10 #include "fd-util.h"
11 #include "fileio.h"
12 #include "in-addr-prefix-util.h"
13 #include "parse-helpers.h"
14 #include "parse-util.h"
15 #include "percent-util.h"
16 #include "process-util.h"
17 #include "rlimit-util.h"
18 #include "serialize.h"
19 #include "string-util.h"
20 #include "strv.h"
21
22 static int exec_cgroup_context_serialize(const CGroupContext *c, FILE *f) {
23 _cleanup_free_ char *disable_controllers_str = NULL, *delegate_controllers_str = NULL,
24 *cpuset_cpus = NULL, *cpuset_mems = NULL, *startup_cpuset_cpus = NULL,
25 *startup_cpuset_mems = NULL;
26 char *iface;
27 struct in_addr_prefix *iaai;
28 int r;
29
30 assert(f);
31
32 if (!c)
33 return 0;
34
35 r = serialize_bool_elide(f, "exec-cgroup-context-cpu-accounting", c->cpu_accounting);
36 if (r < 0)
37 return r;
38
39 r = serialize_bool_elide(f, "exec-cgroup-context-io-accounting", c->io_accounting);
40 if (r < 0)
41 return r;
42
43 r = serialize_bool_elide(f, "exec-cgroup-context-block-io-accounting", c->blockio_accounting);
44 if (r < 0)
45 return r;
46
47 r = serialize_bool_elide(f, "exec-cgroup-context-memory-accounting", c->memory_accounting);
48 if (r < 0)
49 return r;
50
51 r = serialize_bool_elide(f, "exec-cgroup-context-tasks-accounting", c->tasks_accounting);
52 if (r < 0)
53 return r;
54
55 r = serialize_bool_elide(f, "exec-cgroup-context-ip-accounting", c->ip_accounting);
56 if (r < 0)
57 return r;
58
59 r = serialize_bool_elide(f, "exec-cgroup-context-memory-oom-group", c->memory_oom_group);
60 if (r < 0)
61 return r;
62
63 if (c->cpu_weight != CGROUP_WEIGHT_INVALID) {
64 r = serialize_item_format(f, "exec-cgroup-context-cpu-weight", "%" PRIu64, c->cpu_weight);
65 if (r < 0)
66 return r;
67 }
68
69 if (c->startup_cpu_weight != CGROUP_WEIGHT_INVALID) {
70 r = serialize_item_format(f, "exec-cgroup-context-startup-cpu-weight", "%" PRIu64, c->startup_cpu_weight);
71 if (r < 0)
72 return r;
73 }
74
75 if (c->cpu_shares != CGROUP_CPU_SHARES_INVALID) {
76 r = serialize_item_format(f, "exec-cgroup-context-cpu-shares", "%" PRIu64, c->cpu_shares);
77 if (r < 0)
78 return r;
79 }
80
81 if (c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID) {
82 r = serialize_item_format(f, "exec-cgroup-context-startup-cpu-shares", "%" PRIu64, c->startup_cpu_shares);
83 if (r < 0)
84 return r;
85 }
86
87 if (c->cpu_quota_per_sec_usec != USEC_INFINITY) {
88 r = serialize_usec(f, "exec-cgroup-context-cpu-quota-per-sec-usec", c->cpu_quota_per_sec_usec);
89 if (r < 0)
90 return r;
91 }
92
93 if (c->cpu_quota_period_usec != USEC_INFINITY) {
94 r = serialize_usec(f, "exec-cgroup-context-cpu-quota-period-usec", c->cpu_quota_period_usec);
95 if (r < 0)
96 return r;
97 }
98
99 cpuset_cpus = cpu_set_to_range_string(&c->cpuset_cpus);
100 if (!cpuset_cpus)
101 return log_oom_debug();
102
103 r = serialize_item(f, "exec-cgroup-context-allowed-cpus", cpuset_cpus);
104 if (r < 0)
105 return r;
106
107 startup_cpuset_cpus = cpu_set_to_range_string(&c->startup_cpuset_cpus);
108 if (!startup_cpuset_cpus)
109 return log_oom_debug();
110
111 r = serialize_item(f, "exec-cgroup-context-startup-allowed-cpus", startup_cpuset_cpus);
112 if (r < 0)
113 return r;
114
115 cpuset_mems = cpu_set_to_range_string(&c->cpuset_mems);
116 if (!cpuset_mems)
117 return log_oom_debug();
118
119 r = serialize_item(f, "exec-cgroup-context-allowed-memory-nodes", cpuset_mems);
120 if (r < 0)
121 return r;
122
123 startup_cpuset_mems = cpu_set_to_range_string(&c->startup_cpuset_mems);
124 if (!startup_cpuset_mems)
125 return log_oom_debug();
126
127 r = serialize_item(f, "exec-cgroup-context-startup-allowed-memory-nodes", startup_cpuset_mems);
128 if (r < 0)
129 return r;
130
131 if (c->io_weight != CGROUP_WEIGHT_INVALID) {
132 r = serialize_item_format(f, "exec-cgroup-context-io-weight", "%" PRIu64, c->io_weight);
133 if (r < 0)
134 return r;
135 }
136
137 if (c->startup_io_weight != CGROUP_WEIGHT_INVALID) {
138 r = serialize_item_format(f, "exec-cgroup-context-startup-io-weight", "%" PRIu64, c->startup_io_weight);
139 if (r < 0)
140 return r;
141 }
142
143 if (c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID) {
144 r = serialize_item_format(f, "exec-cgroup-context-block-io-weight", "%" PRIu64, c->blockio_weight);
145 if (r < 0)
146 return r;
147 }
148
149 if (c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID) {
150 r = serialize_item_format(f, "exec-cgroup-context-startup-block-io-weight", "%" PRIu64, c->startup_blockio_weight);
151 if (r < 0)
152 return r;
153 }
154
155 if (c->default_memory_min > 0) {
156 r = serialize_item_format(f, "exec-cgroup-context-default-memory-min", "%" PRIu64, c->default_memory_min);
157 if (r < 0)
158 return r;
159 }
160
161 if (c->default_memory_low > 0) {
162 r = serialize_item_format(f, "exec-cgroup-context-default-memory-low", "%" PRIu64, c->default_memory_low);
163 if (r < 0)
164 return r;
165 }
166
167 if (c->memory_min > 0) {
168 r = serialize_item_format(f, "exec-cgroup-context-memory-min", "%" PRIu64, c->memory_min);
169 if (r < 0)
170 return r;
171 }
172
173 if (c->memory_low > 0) {
174 r = serialize_item_format(f, "exec-cgroup-context-memory-low", "%" PRIu64, c->memory_low);
175 if (r < 0)
176 return r;
177 }
178
179 if (c->startup_memory_low > 0) {
180 r = serialize_item_format(f, "exec-cgroup-context-startup-memory-low", "%" PRIu64, c->startup_memory_low);
181 if (r < 0)
182 return r;
183 }
184
185 if (c->memory_high != CGROUP_LIMIT_MAX) {
186 r = serialize_item_format(f, "exec-cgroup-context-memory-high", "%" PRIu64, c->memory_high);
187 if (r < 0)
188 return r;
189 }
190
191 if (c->startup_memory_high != CGROUP_LIMIT_MAX) {
192 r = serialize_item_format(f, "exec-cgroup-context-startup-memory-high", "%" PRIu64, c->startup_memory_high);
193 if (r < 0)
194 return r;
195 }
196
197 if (c->memory_max != CGROUP_LIMIT_MAX) {
198 r = serialize_item_format(f, "exec-cgroup-context-memory-max", "%" PRIu64, c->memory_max);
199 if (r < 0)
200 return r;
201 }
202
203 if (c->startup_memory_max != CGROUP_LIMIT_MAX) {
204 r = serialize_item_format(f, "exec-cgroup-context-startup-memory-max", "%" PRIu64, c->startup_memory_max);
205 if (r < 0)
206 return r;
207 }
208
209 if (c->memory_swap_max != CGROUP_LIMIT_MAX) {
210 r = serialize_item_format(f, "exec-cgroup-context-memory-swap-max", "%" PRIu64, c->memory_swap_max);
211 if (r < 0)
212 return r;
213 }
214
215 if (c->startup_memory_swap_max != CGROUP_LIMIT_MAX) {
216 r = serialize_item_format(f, "exec-cgroup-context-startup-memory-swap-max", "%" PRIu64, c->startup_memory_swap_max);
217 if (r < 0)
218 return r;
219 }
220
221 if (c->memory_zswap_max != CGROUP_LIMIT_MAX) {
222 r = serialize_item_format(f, "exec-cgroup-context-memory-zswap-max", "%" PRIu64, c->memory_zswap_max);
223 if (r < 0)
224 return r;
225 }
226
227 if (c->startup_memory_zswap_max != CGROUP_LIMIT_MAX) {
228 r = serialize_item_format(f, "exec-cgroup-context-startup-memory-zswap-max", "%" PRIu64, c->startup_memory_zswap_max);
229 if (r < 0)
230 return r;
231 }
232
233 if (c->memory_limit != CGROUP_LIMIT_MAX) {
234 r = serialize_item_format(f, "exec-cgroup-context-memory-limit", "%" PRIu64, c->memory_limit);
235 if (r < 0)
236 return r;
237 }
238
239 if (c->tasks_max.value != UINT64_MAX) {
240 r = serialize_item_format(f, "exec-cgroup-context-tasks-max-value", "%" PRIu64, c->tasks_max.value);
241 if (r < 0)
242 return r;
243 }
244
245 if (c->tasks_max.scale > 0) {
246 r = serialize_item_format(f, "exec-cgroup-context-tasks-max-scale", "%" PRIu64, c->tasks_max.scale);
247 if (r < 0)
248 return r;
249 }
250
251 r = serialize_bool_elide(f, "exec-cgroup-context-default-memory-min-set", c->default_memory_min_set);
252 if (r < 0)
253 return r;
254
255 r = serialize_bool_elide(f, "exec-cgroup-context-default-memory-low-set", c->default_memory_low_set);
256 if (r < 0)
257 return r;
258
259 r = serialize_bool_elide(f, "exec-cgroup-context-default-startup-memory-low-set", c->default_startup_memory_low_set);
260 if (r < 0)
261 return r;
262
263 r = serialize_bool_elide(f, "exec-cgroup-context-memory-min-set", c->memory_min_set);
264 if (r < 0)
265 return r;
266
267 r = serialize_bool_elide(f, "exec-cgroup-context-memory-low-set", c->memory_low_set);
268 if (r < 0)
269 return r;
270
271 r = serialize_bool_elide(f, "exec-cgroup-context-startup-memory-low-set", c->startup_memory_low_set);
272 if (r < 0)
273 return r;
274
275 r = serialize_bool_elide(f, "exec-cgroup-context-startup-memory-high-set", c->startup_memory_high_set);
276 if (r < 0)
277 return r;
278
279 r = serialize_bool_elide(f, "exec-cgroup-context-startup-memory-max-set", c->startup_memory_max_set);
280 if (r < 0)
281 return r;
282
283 r = serialize_bool_elide(f, "exec-cgroup-context-startup-memory-swap-max-set", c->startup_memory_swap_max_set);
284 if (r < 0)
285 return r;
286
287 r = serialize_bool_elide(f, "exec-cgroup-context-startup-memory-zswap-max-set", c->startup_memory_zswap_max_set);
288 if (r < 0)
289 return r;
290
291 r = serialize_item(f, "exec-cgroup-context-device-policy", cgroup_device_policy_to_string(c->device_policy));
292 if (r < 0)
293 return r;
294
295 r = cg_mask_to_string(c->disable_controllers, &disable_controllers_str);
296 if (r < 0)
297 return r;
298
299 r = serialize_item(f, "exec-cgroup-context-disable-controllers", disable_controllers_str);
300 if (r < 0)
301 return r;
302
303 r = cg_mask_to_string(c->delegate_controllers, &delegate_controllers_str);
304 if (r < 0)
305 return r;
306
307 r = serialize_item(f, "exec-cgroup-context-delegate-controllers", delegate_controllers_str);
308 if (r < 0)
309 return r;
310
311 r = serialize_bool_elide(f, "exec-cgroup-context-delegate", c->delegate);
312 if (r < 0)
313 return r;
314
315 r = serialize_item(f, "exec-cgroup-context-managed-oom-swap", managed_oom_mode_to_string(c->moom_swap));
316 if (r < 0)
317 return r;
318
319 r = serialize_item(f, "exec-cgroup-context-managed-oom-memory-pressure", managed_oom_mode_to_string(c->moom_mem_pressure));
320 if (r < 0)
321 return r;
322
323 r = serialize_item_format(f, "exec-cgroup-context-managed-oom-memory-pressure-limit", "%" PRIu32, c->moom_mem_pressure_limit);
324 if (r < 0)
325 return r;
326
327 r = serialize_item(f, "exec-cgroup-context-managed-oom-preference", managed_oom_preference_to_string(c->moom_preference));
328 if (r < 0)
329 return r;
330
331 r = serialize_item(f, "exec-cgroup-context-memory-pressure-watch", cgroup_pressure_watch_to_string(c->memory_pressure_watch));
332 if (r < 0)
333 return r;
334
335 r = serialize_item(f, "exec-cgroup-context-delegate-subgroup", c->delegate_subgroup);
336 if (r < 0)
337 return r;
338
339 if (c->memory_pressure_threshold_usec != USEC_INFINITY) {
340 r = serialize_usec(f, "exec-cgroup-context-memory-pressure-threshold-usec", c->memory_pressure_threshold_usec);
341 if (r < 0)
342 return r;
343 }
344
345 LIST_FOREACH(device_allow, a, c->device_allow) {
346 r = serialize_item_format(f, "exec-cgroup-context-device-allow", "%s %s",
347 a->path,
348 cgroup_device_permissions_to_string(a->permissions));
349 if (r < 0)
350 return r;
351 }
352
353 LIST_FOREACH(device_weights, iw, c->io_device_weights) {
354 r = serialize_item_format(f, "exec-cgroup-context-io-device-weight", "%s %" PRIu64,
355 iw->path,
356 iw->weight);
357 if (r < 0)
358 return r;
359 }
360
361 LIST_FOREACH(device_latencies, l, c->io_device_latencies) {
362 r = serialize_item_format(f, "exec-cgroup-context-io-device-latency-target-usec", "%s " USEC_FMT,
363 l->path,
364 l->target_usec);
365 if (r < 0)
366 return r;
367 }
368
369 LIST_FOREACH(device_limits, il, c->io_device_limits)
370 for (CGroupIOLimitType type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) {
371 _cleanup_free_ char *key = NULL;
372
373 if (il->limits[type] == cgroup_io_limit_defaults[type])
374 continue;
375
376 key = strjoin("exec-cgroup-context-io-device-limit-", cgroup_io_limit_type_to_string(type));
377 if (!key)
378 return -ENOMEM;
379
380 r = serialize_item_format(f, key, "%s %" PRIu64, il->path, il->limits[type]);
381 if (r < 0)
382 return r;
383 }
384
385 LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
386 r = serialize_item_format(f, "exec-cgroup-context-blockio-device-weight", "%s %" PRIu64,
387 w->path,
388 w->weight);
389 if (r < 0)
390 return r;
391 }
392
393 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
394 if (b->rbps != CGROUP_LIMIT_MAX) {
395 r = serialize_item_format(f, "exec-cgroup-context-blockio-read-bandwidth", "%s %" PRIu64,
396 b->path,
397 b->rbps);
398 if (r < 0)
399 return r;
400 }
401 if (b->wbps != CGROUP_LIMIT_MAX) {
402 r = serialize_item_format(f, "exec-cgroup-context-blockio-write-bandwidth", "%s %" PRIu64,
403 b->path,
404 b->wbps);
405 if (r < 0)
406 return r;
407 }
408 }
409
410 SET_FOREACH(iaai, c->ip_address_allow) {
411 r = serialize_item(f,
412 "exec-cgroup-context-ip-address-allow",
413 IN_ADDR_PREFIX_TO_STRING(iaai->family, &iaai->address, iaai->prefixlen));
414 if (r < 0)
415 return r;
416 }
417 SET_FOREACH(iaai, c->ip_address_deny) {
418 r = serialize_item(f,
419 "exec-cgroup-context-ip-address-deny",
420 IN_ADDR_PREFIX_TO_STRING(iaai->family, &iaai->address, iaai->prefixlen));
421 if (r < 0)
422 return r;
423 }
424
425 r = serialize_bool_elide(f, "exec-cgroup-context-ip-address-allow-reduced", c->ip_address_allow_reduced);
426 if (r < 0)
427 return r;
428
429 r = serialize_bool_elide(f, "exec-cgroup-context-ip-address-deny-reduced", c->ip_address_deny_reduced);
430 if (r < 0)
431 return r;
432
433 r = serialize_strv(f, "exec-cgroup-context-ip-ingress-filter-path=", c->ip_filters_ingress);
434 if (r < 0)
435 return r;
436
437 r = serialize_strv(f, "exec-cgroup-context-ip-egress-filter-path=", c->ip_filters_egress);
438 if (r < 0)
439 return r;
440
441 LIST_FOREACH(programs, p, c->bpf_foreign_programs) {
442 r = serialize_item_format(f, "exec-cgroup-context-bpf-program", "%" PRIu32 " %s",
443 p->attach_type,
444 p->bpffs_path);
445 if (r < 0)
446 return r;
447 }
448
449 LIST_FOREACH(socket_bind_items, bi, c->socket_bind_allow) {
450 fprintf(f, "exec-cgroup-context-socket-bind-allow=");
451 cgroup_context_dump_socket_bind_item(bi, f);
452 fputc('\n', f);
453 }
454
455 LIST_FOREACH(socket_bind_items, bi, c->socket_bind_deny) {
456 fprintf(f, "exec-cgroup-context-socket-bind-deny=");
457 cgroup_context_dump_socket_bind_item(bi, f);
458 fputc('\n', f);
459 }
460
461 SET_FOREACH(iface, c->restrict_network_interfaces) {
462 r = serialize_item(f, "exec-cgroup-context-restrict-network-interfaces", iface);
463 if (r < 0)
464 return r;
465 }
466
467 r = serialize_bool_elide(
468 f,
469 "exec-cgroup-context-restrict-network-interfaces-is-allow-list",
470 c->restrict_network_interfaces_is_allow_list);
471 if (r < 0)
472 return r;
473
474 fputc('\n', f); /* End marker */
475
476 return 0;
477 }
478
479 static int exec_cgroup_context_deserialize(CGroupContext *c, FILE *f) {
480 int r;
481
482 assert(f);
483
484 if (!c)
485 return 0;
486
487 for (;;) {
488 _cleanup_free_ char *l = NULL;
489 const char *val;
490
491 r = deserialize_read_line(f, &l);
492 if (r < 0)
493 return r;
494 if (r == 0) /* eof or end marker */
495 break;
496
497 if ((val = startswith(l, "exec-cgroup-context-cpu-accounting="))) {
498 r = parse_boolean(val);
499 if (r < 0)
500 return r;
501 c->cpu_accounting = r;
502 } else if ((val = startswith(l, "exec-cgroup-context-io-accounting="))) {
503 r = parse_boolean(val);
504 if (r < 0)
505 return r;
506 c->io_accounting = r;
507 } else if ((val = startswith(l, "exec-cgroup-context-block-io-accounting="))) {
508 r = parse_boolean(val);
509 if (r < 0)
510 return r;
511 c->blockio_accounting = r;
512 } else if ((val = startswith(l, "exec-cgroup-context-memory-accounting="))) {
513 r = parse_boolean(val);
514 if (r < 0)
515 return r;
516 c->memory_accounting = r;
517 } else if ((val = startswith(l, "exec-cgroup-context-tasks-accounting="))) {
518 r = parse_boolean(val);
519 if (r < 0)
520 return r;
521 c->tasks_accounting = r;
522 } else if ((val = startswith(l, "exec-cgroup-context-ip-accounting="))) {
523 r = parse_boolean(val);
524 if (r < 0)
525 return r;
526 c->ip_accounting = r;
527 } else if ((val = startswith(l, "exec-cgroup-context-memory-oom-group="))) {
528 r = parse_boolean(val);
529 if (r < 0)
530 return r;
531 c->memory_oom_group = r;
532 } else if ((val = startswith(l, "exec-cgroup-context-cpu-weight="))) {
533 r = safe_atou64(val, &c->cpu_weight);
534 if (r < 0)
535 return r;
536 } else if ((val = startswith(l, "exec-cgroup-context-startup-cpu-weight="))) {
537 r = safe_atou64(val, &c->startup_cpu_weight);
538 if (r < 0)
539 return r;
540 } else if ((val = startswith(l, "exec-cgroup-context-cpu-shares="))) {
541 r = safe_atou64(val, &c->cpu_shares);
542 if (r < 0)
543 return r;
544 } else if ((val = startswith(l, "exec-cgroup-context-startup-cpu-shares="))) {
545 r = safe_atou64(val, &c->startup_cpu_shares);
546 if (r < 0)
547 return r;
548 } else if ((val = startswith(l, "exec-cgroup-context-cpu-quota-per-sec-usec="))) {
549 r = deserialize_usec(val, &c->cpu_quota_per_sec_usec);
550 if (r < 0)
551 return r;
552 } else if ((val = startswith(l, "exec-cgroup-context-cpu-quota-period-usec="))) {
553 r = deserialize_usec(val, &c->cpu_quota_period_usec);
554 if (r < 0)
555 return r;
556 } else if ((val = startswith(l, "exec-cgroup-context-allowed-cpus="))) {
557 if (c->cpuset_cpus.set)
558 return -EINVAL; /* duplicated */
559
560 r = parse_cpu_set_full(
561 val,
562 &c->cpuset_cpus,
563 /* warn= */ false,
564 /* unit= */ NULL,
565 /* filename= */ NULL,
566 /* line= */ 0,
567 /* lvalue= */ NULL);
568 if (r < 0)
569 return r;
570 } else if ((val = startswith(l, "exec-cgroup-context-startup-allowed-cpus="))) {
571 if (c->startup_cpuset_cpus.set)
572 return -EINVAL; /* duplicated */
573
574 r = parse_cpu_set_full(
575 val,
576 &c->startup_cpuset_cpus,
577 /* warn= */ false,
578 /* unit= */ NULL,
579 /* filename= */ NULL,
580 /* line= */ 0,
581 /* lvalue= */ NULL);
582 if (r < 0)
583 return r;
584 } else if ((val = startswith(l, "exec-cgroup-context-allowed-memory-nodes="))) {
585 if (c->cpuset_mems.set)
586 return -EINVAL; /* duplicated */
587
588 r = parse_cpu_set_full(
589 val,
590 &c->cpuset_mems,
591 /* warn= */ false,
592 /* unit= */ NULL,
593 /* filename= */ NULL,
594 /* line= */ 0,
595 /* lvalue= */ NULL);
596 if (r < 0)
597 return r;
598 } else if ((val = startswith(l, "exec-cgroup-context-startup-allowed-memory-nodes="))) {
599 if (c->startup_cpuset_mems.set)
600 return -EINVAL; /* duplicated */
601
602 r = parse_cpu_set_full(
603 val,
604 &c->startup_cpuset_mems,
605 /* warn= */ false,
606 /* unit= */ NULL,
607 /* filename= */ NULL,
608 /* line= */ 0,
609 /* lvalue= */ NULL);
610 if (r < 0)
611 return r;
612 } else if ((val = startswith(l, "exec-cgroup-context-io-weight="))) {
613 r = safe_atou64(val, &c->io_weight);
614 if (r < 0)
615 return r;
616 } else if ((val = startswith(l, "exec-cgroup-context-startup-io-weight="))) {
617 r = safe_atou64(val, &c->startup_io_weight);
618 if (r < 0)
619 return r;
620 } else if ((val = startswith(l, "exec-cgroup-context-block-io-weight="))) {
621 r = safe_atou64(val, &c->blockio_weight);
622 if (r < 0)
623 return r;
624 } else if ((val = startswith(l, "exec-cgroup-context-startup-block-io-weight="))) {
625 r = safe_atou64(val, &c->startup_blockio_weight);
626 if (r < 0)
627 return r;
628 } else if ((val = startswith(l, "exec-cgroup-context-default-memory-min="))) {
629 r = safe_atou64(val, &c->default_memory_min);
630 if (r < 0)
631 return r;
632 } else if ((val = startswith(l, "exec-cgroup-context-default-memory-low="))) {
633 r = safe_atou64(val, &c->default_memory_low);
634 if (r < 0)
635 return r;
636 } else if ((val = startswith(l, "exec-cgroup-context-memory-min="))) {
637 r = safe_atou64(val, &c->memory_min);
638 if (r < 0)
639 return r;
640 } else if ((val = startswith(l, "exec-cgroup-context-memory-low="))) {
641 r = safe_atou64(val, &c->memory_low);
642 if (r < 0)
643 return r;
644 } else if ((val = startswith(l, "exec-cgroup-context-startup-memory-low="))) {
645 r = safe_atou64(val, &c->startup_memory_low);
646 if (r < 0)
647 return r;
648 } else if ((val = startswith(l, "exec-cgroup-context-memory-high="))) {
649 r = safe_atou64(val, &c->memory_high);
650 if (r < 0)
651 return r;
652 } else if ((val = startswith(l, "exec-cgroup-context-startup-memory-high="))) {
653 r = safe_atou64(val, &c->startup_memory_high);
654 if (r < 0)
655 return r;
656 } else if ((val = startswith(l, "exec-cgroup-context-memory-max="))) {
657 r = safe_atou64(val, &c->memory_max);
658 if (r < 0)
659 return r;
660 } else if ((val = startswith(l, "exec-cgroup-context-startup-memory-max="))) {
661 r = safe_atou64(val, &c->startup_memory_max);
662 if (r < 0)
663 return r;
664 } else if ((val = startswith(l, "exec-cgroup-context-memory-swap-max="))) {
665 r = safe_atou64(val, &c->memory_swap_max);
666 if (r < 0)
667 return r;
668 } else if ((val = startswith(l, "exec-cgroup-context-startup-memory-swap-max="))) {
669 r = safe_atou64(val, &c->startup_memory_swap_max);
670 if (r < 0)
671 return r;
672 } else if ((val = startswith(l, "exec-cgroup-context-memory-zswap-max="))) {
673 r = safe_atou64(val, &c->memory_zswap_max);
674 if (r < 0)
675 return r;
676 } else if ((val = startswith(l, "exec-cgroup-context-startup-memory-zswap-max="))) {
677 r = safe_atou64(val, &c->startup_memory_zswap_max);
678 if (r < 0)
679 return r;
680 } else if ((val = startswith(l, "exec-cgroup-context-memory-limit="))) {
681 r = safe_atou64(val, &c->memory_limit);
682 if (r < 0)
683 return r;
684 } else if ((val = startswith(l, "exec-cgroup-context-tasks-max-value="))) {
685 r = safe_atou64(val, &c->tasks_max.value);
686 if (r < 0)
687 return r;
688 } else if ((val = startswith(l, "exec-cgroup-context-tasks-max-scale="))) {
689 r = safe_atou64(val, &c->tasks_max.scale);
690 if (r < 0)
691 return r;
692 } else if ((val = startswith(l, "exec-cgroup-context-default-memory-min-set="))) {
693 r = parse_boolean(val);
694 if (r < 0)
695 return r;
696 c->default_memory_min_set = r;
697 } else if ((val = startswith(l, "exec-cgroup-context-default-memory-low-set="))) {
698 r = parse_boolean(val);
699 if (r < 0)
700 return r;
701 c->default_memory_low_set = r;
702 } else if ((val = startswith(l, "exec-cgroup-context-default-startup-memory-low-set="))) {
703 r = parse_boolean(val);
704 if (r < 0)
705 return r;
706 c->default_startup_memory_low_set = r;
707 } else if ((val = startswith(l, "exec-cgroup-context-memory-min-set="))) {
708 r = parse_boolean(val);
709 if (r < 0)
710 return r;
711 c->memory_min_set = r;
712 } else if ((val = startswith(l, "exec-cgroup-context-memory-low-set="))) {
713 r = parse_boolean(val);
714 if (r < 0)
715 return r;
716 c->memory_low_set = r;
717 } else if ((val = startswith(l, "exec-cgroup-context-startup-memory-low-set="))) {
718 r = parse_boolean(val);
719 if (r < 0)
720 return r;
721 c->startup_memory_low_set = r;
722 } else if ((val = startswith(l, "exec-cgroup-context-startup-memory-high-set="))) {
723 r = parse_boolean(val);
724 if (r < 0)
725 return r;
726 c->startup_memory_high_set = r;
727 } else if ((val = startswith(l, "exec-cgroup-context-startup-memory-max-set="))) {
728 r = parse_boolean(val);
729 if (r < 0)
730 return r;
731 c->startup_memory_max_set = r;
732 } else if ((val = startswith(l, "exec-cgroup-context-startup-memory-swap-max-set="))) {
733 r = parse_boolean(val);
734 if (r < 0)
735 return r;
736 c->startup_memory_swap_max_set = r;
737 } else if ((val = startswith(l, "exec-cgroup-context-startup-memory-zswap-max-set="))) {
738 r = parse_boolean(val);
739 if (r < 0)
740 return r;
741 c->startup_memory_zswap_max_set = r;
742 } else if ((val = startswith(l, "exec-cgroup-context-device-policy="))) {
743 c->device_policy = cgroup_device_policy_from_string(val);
744 if (c->device_policy < 0)
745 return -EINVAL;
746 } else if ((val = startswith(l, "exec-cgroup-context-disable-controllers="))) {
747 r = cg_mask_from_string(val, &c->disable_controllers);
748 if (r < 0)
749 return r;
750 } else if ((val = startswith(l, "exec-cgroup-context-delegate-controllers="))) {
751 r = cg_mask_from_string(val, &c->delegate_controllers);
752 if (r < 0)
753 return r;
754 } else if ((val = startswith(l, "exec-cgroup-context-delegate="))) {
755 r = parse_boolean(val);
756 if (r < 0)
757 return r;
758 c->delegate = r;
759 } else if ((val = startswith(l, "exec-cgroup-context-managed-oom-swap="))) {
760 c->moom_swap = managed_oom_mode_from_string(val);
761 if (c->moom_swap < 0)
762 return -EINVAL;
763 } else if ((val = startswith(l, "exec-cgroup-context-managed-oom-memory-pressure="))) {
764 c->moom_mem_pressure = managed_oom_mode_from_string(val);
765 if (c->moom_mem_pressure < 0)
766 return -EINVAL;
767 } else if ((val = startswith(l, "exec-cgroup-context-managed-oom-memory-pressure-limit="))) {
768 r = safe_atou32(val, &c->moom_mem_pressure_limit);
769 if (r < 0)
770 return r;
771 } else if ((val = startswith(l, "exec-cgroup-context-managed-oom-preference="))) {
772 c->moom_preference = managed_oom_preference_from_string(val);
773 if (c->moom_preference < 0)
774 return -EINVAL;
775 } else if ((val = startswith(l, "exec-cgroup-context-memory-pressure-watch="))) {
776 c->memory_pressure_watch = cgroup_pressure_watch_from_string(val);
777 if (c->memory_pressure_watch < 0)
778 return -EINVAL;
779 } else if ((val = startswith(l, "exec-cgroup-context-delegate-subgroup="))) {
780 r = free_and_strdup(&c->delegate_subgroup, val);
781 if (r < 0)
782 return r;
783 } else if ((val = startswith(l, "exec-cgroup-context-memory-pressure-threshold-usec="))) {
784 r = deserialize_usec(val, &c->memory_pressure_threshold_usec);
785 if (r < 0)
786 return r;
787 } else if ((val = startswith(l, "exec-cgroup-context-device-allow="))) {
788 _cleanup_free_ char *path = NULL, *rwm = NULL;
789 CGroupDevicePermissions p;
790
791 r = extract_many_words(&val, " ", 0, &path, &rwm, NULL);
792 if (r < 0)
793 return r;
794 if (r == 0)
795 return -EINVAL;
796
797 p = isempty(rwm) ? 0 : cgroup_device_permissions_from_string(rwm);
798 if (p < 0)
799 return p;
800
801 r = cgroup_context_add_or_update_device_allow(c, path, p);
802 if (r < 0)
803 return r;
804 } else if ((val = startswith(l, "exec-cgroup-context-io-device-weight="))) {
805 _cleanup_free_ char *path = NULL, *weight = NULL;
806 CGroupIODeviceWeight *a = NULL;
807
808 r = extract_many_words(&val, " ", 0, &path, &weight, NULL);
809 if (r < 0)
810 return r;
811 if (r != 2)
812 return -EINVAL;
813
814 LIST_FOREACH(device_weights, b, c->io_device_weights)
815 if (path_equal(b->path, path)) {
816 a = b;
817 break;
818 }
819
820 if (!a) {
821 a = new0(CGroupIODeviceWeight, 1);
822 if (!a)
823 return log_oom_debug();
824
825 a->path = TAKE_PTR(path);
826
827 LIST_PREPEND(device_weights, c->io_device_weights, a);
828 }
829
830 r = safe_atou64(weight, &a->weight);
831 if (r < 0)
832 return r;
833 } else if ((val = startswith(l, "exec-cgroup-context-io-device-latency-target-usec="))) {
834 _cleanup_free_ char *path = NULL, *target = NULL;
835 CGroupIODeviceLatency *a = NULL;
836
837 r = extract_many_words(&val, " ", 0, &path, &target, NULL);
838 if (r < 0)
839 return r;
840 if (r != 2)
841 return -EINVAL;
842
843 LIST_FOREACH(device_latencies, b, c->io_device_latencies)
844 if (path_equal(b->path, path)) {
845 a = b;
846 break;
847 }
848
849 if (!a) {
850 a = new0(CGroupIODeviceLatency, 1);
851 if (!a)
852 return log_oom_debug();
853
854 a->path = TAKE_PTR(path);
855
856 LIST_PREPEND(device_latencies, c->io_device_latencies, a);
857 }
858
859 r = deserialize_usec(target, &a->target_usec);
860 if (r < 0)
861 return r;
862 } else if ((val = startswith(l, "exec-cgroup-context-io-device-limit-"))) {
863 _cleanup_free_ char *type = NULL, *path = NULL, *limits = NULL;
864 CGroupIODeviceLimit *limit = NULL;
865 CGroupIOLimitType t;
866
867 r = extract_many_words(&val, "= ", 0, &type, &path, &limits, NULL);
868 if (r < 0)
869 return r;
870 if (r != 3)
871 return -EINVAL;
872
873 t = cgroup_io_limit_type_from_string(type);
874 if (t < 0)
875 return t;
876
877 LIST_FOREACH(device_limits, i, c->io_device_limits)
878 if (path_equal(path, i->path)) {
879 limit = i;
880 break;
881 }
882
883 if (!limit) {
884 limit = new0(CGroupIODeviceLimit, 1);
885 if (!limit)
886 return log_oom_debug();
887
888 limit->path = TAKE_PTR(path);
889 for (CGroupIOLimitType i = 0; i < _CGROUP_IO_LIMIT_TYPE_MAX; i++)
890 limit->limits[i] = cgroup_io_limit_defaults[i];
891
892 LIST_PREPEND(device_limits, c->io_device_limits, limit);
893 }
894
895 r = safe_atou64(limits, &limit->limits[t]);
896 if (r < 0)
897 return r;
898 } else if ((val = startswith(l, "exec-cgroup-context-block-io-device-weight="))) {
899 _cleanup_free_ char *path = NULL, *weight = NULL;
900 CGroupBlockIODeviceWeight *a = NULL;
901
902 r = extract_many_words(&val, " ", 0, &path, &weight, NULL);
903 if (r < 0)
904 return r;
905 if (r != 2)
906 return -EINVAL;
907
908 a = new0(CGroupBlockIODeviceWeight, 1);
909 if (!a)
910 return log_oom_debug();
911
912 a->path = TAKE_PTR(path);
913
914 LIST_PREPEND(device_weights, c->blockio_device_weights, a);
915
916 r = safe_atou64(weight, &a->weight);
917 if (r < 0)
918 return r;
919 } else if ((val = startswith(l, "exec-cgroup-context-block-io-read-bandwidth="))) {
920 _cleanup_free_ char *path = NULL, *bw = NULL;
921 CGroupBlockIODeviceBandwidth *a = NULL;
922
923 r = extract_many_words(&val, " ", 0, &path, &bw, NULL);
924 if (r < 0)
925 return r;
926 if (r != 2)
927 return -EINVAL;
928
929 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths)
930 if (path_equal(b->path, path)) {
931 a = b;
932 break;
933 }
934
935 if (!a) {
936 a = new0(CGroupBlockIODeviceBandwidth, 1);
937 if (!a)
938 return log_oom_debug();
939
940 a->path = TAKE_PTR(path);
941 a->wbps = CGROUP_LIMIT_MAX;
942
943 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
944 }
945
946 r = safe_atou64(bw, &a->rbps);
947 if (r < 0)
948 return r;
949 } else if ((val = startswith(l, "exec-cgroup-context-block-io-write-bandwidth="))) {
950 _cleanup_free_ char *path = NULL, *bw = NULL;
951 CGroupBlockIODeviceBandwidth *a = NULL;
952
953 r = extract_many_words(&val, " ", 0, &path, &bw, NULL);
954 if (r < 0)
955 return r;
956 if (r != 2)
957 return -EINVAL;
958
959 LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths)
960 if (path_equal(b->path, path)) {
961 a = b;
962 break;
963 }
964
965 if (!a) {
966 a = new0(CGroupBlockIODeviceBandwidth, 1);
967 if (!a)
968 return log_oom_debug();
969
970 a->path = TAKE_PTR(path);
971 a->rbps = CGROUP_LIMIT_MAX;
972
973 LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
974 }
975
976 r = safe_atou64(bw, &a->wbps);
977 if (r < 0)
978 return r;
979 } else if ((val = startswith(l, "exec-cgroup-context-ip-address-allow="))) {
980 struct in_addr_prefix a;
981
982 r = in_addr_prefix_from_string_auto(val, &a.family, &a.address, &a.prefixlen);
983 if (r < 0)
984 return r;
985
986 r = in_addr_prefix_add(&c->ip_address_allow, &a);
987 if (r < 0)
988 return r;
989 } else if ((val = startswith(l, "exec-cgroup-context-ip-address-deny="))) {
990 struct in_addr_prefix a;
991
992 r = in_addr_prefix_from_string_auto(val, &a.family, &a.address, &a.prefixlen);
993 if (r < 0)
994 return r;
995
996 r = in_addr_prefix_add(&c->ip_address_deny, &a);
997 if (r < 0)
998 return r;
999 } else if ((val = startswith(l, "exec-cgroup-context-ip-address-allow-reduced="))) {
1000 r = parse_boolean(val);
1001 if (r < 0)
1002 return r;
1003 c->ip_address_allow_reduced = r;
1004 } else if ((val = startswith(l, "exec-cgroup-context-ip-address-deny-reduced="))) {
1005 r = parse_boolean(val);
1006 if (r < 0)
1007 return r;
1008 c->ip_address_deny_reduced = r;
1009 } else if ((val = startswith(l, "exec-cgroup-context-ip-ingress-filter-path="))) {
1010 r = deserialize_strv(val, &c->ip_filters_ingress);
1011 if (r < 0)
1012 return r;
1013 } else if ((val = startswith(l, "exec-cgroup-context-ip-egress-filter-path="))) {
1014 r = deserialize_strv(val, &c->ip_filters_egress);
1015 if (r < 0)
1016 return r;
1017 } else if ((val = startswith(l, "exec-cgroup-context-bpf-program="))) {
1018 _cleanup_free_ char *type = NULL, *path = NULL;
1019 uint32_t t;
1020
1021 r = extract_many_words(&val, " ", 0, &type, &path, NULL);
1022 if (r < 0)
1023 return r;
1024 if (r != 2)
1025 return -EINVAL;
1026
1027 r = safe_atou32(type, &t);
1028 if (r < 0)
1029 return r;
1030
1031 r = cgroup_context_add_bpf_foreign_program(c, t, path);
1032 if (r < 0)
1033 return r;
1034 } else if ((val = startswith(l, "exec-cgroup-context-socket-bind-allow="))) {
1035 CGroupSocketBindItem *item;
1036 uint16_t nr_ports, port_min;
1037 int af, ip_protocol;
1038
1039 r = parse_socket_bind_item(val, &af, &ip_protocol, &nr_ports, &port_min);
1040 if (r < 0)
1041 return r;
1042
1043 item = new(CGroupSocketBindItem, 1);
1044 if (!item)
1045 return log_oom_debug();
1046 *item = (CGroupSocketBindItem) {
1047 .address_family = af,
1048 .ip_protocol = ip_protocol,
1049 .nr_ports = nr_ports,
1050 .port_min = port_min,
1051 };
1052
1053 LIST_PREPEND(socket_bind_items, c->socket_bind_allow, item);
1054 } else if ((val = startswith(l, "exec-cgroup-context-socket-bind-deny="))) {
1055 CGroupSocketBindItem *item;
1056 uint16_t nr_ports, port_min;
1057 int af, ip_protocol;
1058
1059 r = parse_socket_bind_item(val, &af, &ip_protocol, &nr_ports, &port_min);
1060 if (r < 0)
1061 return r;
1062
1063 item = new(CGroupSocketBindItem, 1);
1064 if (!item)
1065 return log_oom_debug();
1066 *item = (CGroupSocketBindItem) {
1067 .address_family = af,
1068 .ip_protocol = ip_protocol,
1069 .nr_ports = nr_ports,
1070 .port_min = port_min,
1071 };
1072
1073 LIST_PREPEND(socket_bind_items, c->socket_bind_deny, item);
1074 } else if ((val = startswith(l, "exec-cgroup-context-restrict-network-interfaces="))) {
1075 r = set_ensure_allocated(&c->restrict_network_interfaces, &string_hash_ops);
1076 if (r < 0)
1077 return r;
1078
1079 r = set_put_strdup(&c->restrict_network_interfaces, val);
1080 if (r < 0)
1081 return r;
1082 } else if ((val = startswith(l, "exec-cgroup-context-restrict-network-interfaces-is-allow-list="))) {
1083 r = parse_boolean(val);
1084 if (r < 0)
1085 return r;
1086 c->restrict_network_interfaces_is_allow_list = r;
1087 } else
1088 log_warning("Failed to parse serialized line, ignoring: %s", l);
1089 }
1090
1091 return 0;
1092 }
1093
1094 static int exec_runtime_serialize(const ExecRuntime *rt, FILE *f, FDSet *fds) {
1095 int r;
1096
1097 assert(f);
1098 assert(fds);
1099
1100 if (!rt) {
1101 fputc('\n', f); /* End marker */
1102 return 0;
1103 }
1104
1105 if (rt->shared) {
1106 r = serialize_item(f, "exec-runtime-id", rt->shared->id);
1107 if (r < 0)
1108 return r;
1109
1110 r = serialize_item(f, "exec-runtime-tmp-dir", rt->shared->tmp_dir);
1111 if (r < 0)
1112 return r;
1113
1114 r = serialize_item(f, "exec-runtime-var-tmp-dir", rt->shared->var_tmp_dir);
1115 if (r < 0)
1116 return r;
1117
1118 if (rt->shared->netns_storage_socket[0] >= 0 && rt->shared->netns_storage_socket[1] >= 0) {
1119 r = serialize_fd_many(f, fds, "exec-runtime-netns-storage-socket", rt->shared->netns_storage_socket, 2);
1120 if (r < 0)
1121 return r;
1122 }
1123
1124 if (rt->shared->ipcns_storage_socket[0] >= 0 && rt->shared->ipcns_storage_socket[1] >= 0) {
1125 r = serialize_fd_many(f, fds, "exec-runtime-ipcns-storage-socket", rt->shared->ipcns_storage_socket, 2);
1126 if (r < 0)
1127 return r;
1128 }
1129 }
1130
1131 if (rt->dynamic_creds) {
1132 r = dynamic_user_serialize_one(rt->dynamic_creds->user, "exec-runtime-dynamic-creds-user", f, fds);
1133 if (r < 0)
1134 return r;
1135 }
1136
1137 if (rt->dynamic_creds && rt->dynamic_creds->group && rt->dynamic_creds->group == rt->dynamic_creds->user) {
1138 r = serialize_bool(f, "exec-runtime-dynamic-creds-group-copy", true);
1139 if (r < 0)
1140 return r;
1141 } else if (rt->dynamic_creds) {
1142 r = dynamic_user_serialize_one(rt->dynamic_creds->group, "exec-runtime-dynamic-creds-group", f, fds);
1143 if (r < 0)
1144 return r;
1145 }
1146
1147 r = serialize_item(f, "exec-runtime-ephemeral-copy", rt->ephemeral_copy);
1148 if (r < 0)
1149 return r;
1150
1151 if (rt->ephemeral_storage_socket[0] >= 0 && rt->ephemeral_storage_socket[1] >= 0) {
1152 r = serialize_fd_many(f, fds, "exec-runtime-ephemeral-storage-socket", rt->ephemeral_storage_socket, 2);
1153 if (r < 0)
1154 return r;
1155 }
1156
1157 fputc('\n', f); /* End marker */
1158
1159 return 0;
1160 }
1161
1162 static int exec_runtime_deserialize(ExecRuntime *rt, FILE *f, FDSet *fds) {
1163 int r;
1164
1165 assert(rt);
1166 assert(rt->shared);
1167 assert(rt->dynamic_creds);
1168 assert(f);
1169 assert(fds);
1170
1171 for (;;) {
1172 _cleanup_free_ char *l = NULL;
1173 const char *val;
1174
1175 r = deserialize_read_line(f, &l);
1176 if (r < 0)
1177 return r;
1178 if (r == 0) /* eof or end marker */
1179 break;
1180
1181 if ((val = startswith(l, "exec-runtime-id="))) {
1182 r = free_and_strdup(&rt->shared->id, val);
1183 if (r < 0)
1184 return r;
1185 } else if ((val = startswith(l, "exec-runtime-tmp-dir="))) {
1186 r = free_and_strdup(&rt->shared->tmp_dir, val);
1187 if (r < 0)
1188 return r;
1189 } else if ((val = startswith(l, "exec-runtime-var-tmp-dir="))) {
1190 r = free_and_strdup(&rt->shared->var_tmp_dir, val);
1191 if (r < 0)
1192 return r;
1193 } else if ((val = startswith(l, "exec-runtime-netns-storage-socket="))) {
1194
1195 r = deserialize_fd_many(fds, val, 2, rt->shared->netns_storage_socket);
1196 if (r < 0)
1197 continue;
1198
1199 } else if ((val = startswith(l, "exec-runtime-ipcns-storage-socket="))) {
1200
1201 r = deserialize_fd_many(fds, val, 2, rt->shared->ipcns_storage_socket);
1202 if (r < 0)
1203 continue;
1204
1205 } else if ((val = startswith(l, "exec-runtime-dynamic-creds-user=")))
1206 dynamic_user_deserialize_one(/* m= */ NULL, val, fds, &rt->dynamic_creds->user);
1207 else if ((val = startswith(l, "exec-runtime-dynamic-creds-group=")))
1208 dynamic_user_deserialize_one(/* m= */ NULL, val, fds, &rt->dynamic_creds->group);
1209 else if ((val = startswith(l, "exec-runtime-dynamic-creds-group-copy="))) {
1210 r = parse_boolean(val);
1211 if (r < 0)
1212 return r;
1213 if (!r)
1214 continue; /* Nothing to do */
1215
1216 if (!rt->dynamic_creds->user)
1217 return -EINVAL;
1218
1219 rt->dynamic_creds->group = dynamic_user_ref(rt->dynamic_creds->user);
1220 } else if ((val = startswith(l, "exec-runtime-ephemeral-copy="))) {
1221 r = free_and_strdup(&rt->ephemeral_copy, val);
1222 if (r < 0)
1223 return r;
1224 } else if ((val = startswith(l, "exec-runtime-ephemeral-storage-socket="))) {
1225
1226 r = deserialize_fd_many(fds, val, 2, rt->ephemeral_storage_socket);
1227 if (r < 0)
1228 continue;
1229 } else
1230 log_warning("Failed to parse serialized line, ignoring: %s", l);
1231 }
1232
1233 return 0;
1234 }
1235
1236 static bool exec_parameters_is_idle_pipe_set(const ExecParameters *p) {
1237 assert(p);
1238
1239 return p->idle_pipe &&
1240 p->idle_pipe[0] >= 0 &&
1241 p->idle_pipe[1] >= 0 &&
1242 p->idle_pipe[2] >= 0 &&
1243 p->idle_pipe[3] >= 0;
1244 }
1245
1246 static int exec_parameters_serialize(const ExecParameters *p, const ExecContext *c, FILE *f, FDSet *fds) {
1247 int r;
1248
1249 assert(f);
1250 assert(fds);
1251
1252 if (!p)
1253 return 0;
1254
1255 r = serialize_item(f, "exec-parameters-runtime-scope", runtime_scope_to_string(p->runtime_scope));
1256 if (r < 0)
1257 return r;
1258
1259 r = serialize_strv(f, "exec-parameters-environment", p->environment);
1260 if (r < 0)
1261 return r;
1262
1263 if (p->fds) {
1264 if (p->n_socket_fds > 0) {
1265 r = serialize_item_format(f, "exec-parameters-n-socket-fds", "%zu", p->n_socket_fds);
1266 if (r < 0)
1267 return r;
1268 }
1269
1270 if (p->n_storage_fds > 0) {
1271 r = serialize_item_format(f, "exec-parameters-n-storage-fds", "%zu", p->n_storage_fds);
1272 if (r < 0)
1273 return r;
1274 }
1275
1276 r = serialize_fd_many(f, fds, "exec-parameters-fds", p->fds, p->n_socket_fds + p->n_storage_fds);
1277 if (r < 0)
1278 return r;
1279 }
1280
1281 r = serialize_strv(f, "exec-parameters-fd-names", p->fd_names);
1282 if (r < 0)
1283 return r;
1284
1285 if (p->flags != 0) {
1286 r = serialize_item_format(f, "exec-parameters-flags", "%u", (unsigned) p->flags);
1287 if (r < 0)
1288 return r;
1289 }
1290
1291 r = serialize_bool_elide(f, "exec-parameters-selinux-context-net", p->selinux_context_net);
1292 if (r < 0)
1293 return r;
1294
1295 if (p->cgroup_supported != 0) {
1296 r = serialize_item_format(f, "exec-parameters-cgroup-supported", "%u", (unsigned) p->cgroup_supported);
1297 if (r < 0)
1298 return r;
1299 }
1300
1301 r = serialize_item(f, "exec-parameters-cgroup-path", p->cgroup_path);
1302 if (r < 0)
1303 return r;
1304
1305 r = serialize_item_format(f, "exec-parameters-cgroup-id", "%" PRIu64, p->cgroup_id);
1306 if (r < 0)
1307 return r;
1308
1309 for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
1310 _cleanup_free_ char *key = NULL;
1311
1312 key = strjoin("exec-parameters-prefix-directories-", exec_directory_type_to_string(dt));
1313 if (!key)
1314 return log_oom_debug();
1315
1316 /* Always serialize, even an empty prefix, as this is a fixed array and we always expect
1317 * to have all elements (unless fuzzing is happening, hence the NULL check). */
1318 r = serialize_item(f, key, strempty(p->prefix ? p->prefix[dt] : NULL));
1319 if (r < 0)
1320 return r;
1321 }
1322
1323 r = serialize_item(f, "exec-parameters-received-credentials-directory", p->received_credentials_directory);
1324 if (r < 0)
1325 return r;
1326
1327 r = serialize_item(f, "exec-parameters-received-encrypted-credentials-directory", p->received_encrypted_credentials_directory);
1328 if (r < 0)
1329 return r;
1330
1331 r = serialize_item(f, "exec-parameters-confirm-spawn", p->confirm_spawn);
1332 if (r < 0)
1333 return r;
1334
1335 r = serialize_bool_elide(f, "exec-parameters-shall-confirm-spawn", p->shall_confirm_spawn);
1336 if (r < 0)
1337 return r;
1338
1339 if (p->watchdog_usec > 0) {
1340 r = serialize_usec(f, "exec-parameters-watchdog-usec", p->watchdog_usec);
1341 if (r < 0)
1342 return r;
1343 }
1344
1345 if (exec_parameters_is_idle_pipe_set(p)) {
1346 r = serialize_fd_many(f, fds, "exec-parameters-idle-pipe", p->idle_pipe, 4);
1347 if (r < 0)
1348 return r;
1349 }
1350
1351 r = serialize_fd(f, fds, "exec-parameters-stdin-fd", p->stdin_fd);
1352 if (r < 0)
1353 return r;
1354
1355 r = serialize_fd(f, fds, "exec-parameters-stdout-fd", p->stdout_fd);
1356 if (r < 0)
1357 return r;
1358
1359 r = serialize_fd(f, fds, "exec-parameters-stderr-fd", p->stderr_fd);
1360 if (r < 0)
1361 return r;
1362
1363 r = serialize_fd(f, fds, "exec-parameters-exec-fd", p->exec_fd);
1364 if (r < 0)
1365 return r;
1366
1367 if (c && exec_context_restrict_filesystems_set(c)) {
1368 r = serialize_fd(f, fds, "exec-parameters-bpf-outer-map-fd", p->bpf_outer_map_fd);
1369 if (r < 0)
1370 return r;
1371 }
1372
1373 r = serialize_item(f, "exec-parameters-notify-socket", p->notify_socket);
1374 if (r < 0)
1375 return r;
1376
1377 LIST_FOREACH(open_files, file, p->open_files) {
1378 _cleanup_free_ char *ofs = NULL;
1379
1380 r = open_file_to_string(file, &ofs);
1381 if (r < 0)
1382 return r;
1383
1384 r = serialize_item(f, "exec-parameters-open-file", ofs);
1385 if (r < 0)
1386 return r;
1387 }
1388
1389 r = serialize_item(f, "exec-parameters-fallback-smack-process-label", p->fallback_smack_process_label);
1390 if (r < 0)
1391 return r;
1392
1393 r = serialize_fd(f, fds, "exec-parameters-user-lookup-fd", p->user_lookup_fd);
1394 if (r < 0)
1395 return r;
1396
1397 r = serialize_strv(f, "exec-parameters-files-env", p->files_env);
1398 if (r < 0)
1399 return r;
1400
1401 r = serialize_item(f, "exec-parameters-unit-id", p->unit_id);
1402 if (r < 0)
1403 return r;
1404
1405 r = serialize_item(f, "exec-parameters-invocation-id-string", p->invocation_id_string);
1406 if (r < 0)
1407 return r;
1408
1409 fputc('\n', f); /* End marker */
1410
1411 return 0;
1412 }
1413
1414 static int exec_parameters_deserialize(ExecParameters *p, FILE *f, FDSet *fds) {
1415 int r, nr_open;
1416
1417 assert(p);
1418 assert(f);
1419 assert(fds);
1420
1421 nr_open = read_nr_open();
1422 if (nr_open < 3)
1423 nr_open = HIGH_RLIMIT_NOFILE;
1424 assert(nr_open > 0); /* For compilers/static analyzers */
1425
1426 for (;;) {
1427 _cleanup_free_ char *l = NULL;
1428 const char *val;
1429
1430 r = deserialize_read_line(f, &l);
1431 if (r < 0)
1432 return r;
1433 if (r == 0) /* eof or end marker */
1434 break;
1435
1436 if ((val = startswith(l, "exec-parameters-runtime-scope="))) {
1437 p->runtime_scope = runtime_scope_from_string(val);
1438 if (p->runtime_scope < 0)
1439 return p->runtime_scope;
1440 } else if ((val = startswith(l, "exec-parameters-environment="))) {
1441 r = deserialize_strv(val, &p->environment);
1442 if (r < 0)
1443 return r;
1444 } else if ((val = startswith(l, "exec-parameters-n-socket-fds="))) {
1445 if (p->fds)
1446 return -EINVAL; /* Already received */
1447
1448 r = safe_atozu(val, &p->n_socket_fds);
1449 if (r < 0)
1450 return r;
1451
1452 if (p->n_socket_fds > (size_t) nr_open)
1453 return -EINVAL; /* too many, someone is playing games with us */
1454 } else if ((val = startswith(l, "exec-parameters-n-storage-fds="))) {
1455 if (p->fds)
1456 return -EINVAL; /* Already received */
1457
1458 r = safe_atozu(val, &p->n_storage_fds);
1459 if (r < 0)
1460 return r;
1461
1462 if (p->n_storage_fds > (size_t) nr_open)
1463 return -EINVAL; /* too many, someone is playing games with us */
1464 } else if ((val = startswith(l, "exec-parameters-fds="))) {
1465 if (p->n_socket_fds + p->n_storage_fds == 0)
1466 return log_warning_errno(
1467 SYNTHETIC_ERRNO(EINVAL),
1468 "Got exec-parameters-fds= without "
1469 "prior exec-parameters-n-socket-fds= or exec-parameters-n-storage-fds=");
1470 if (p->n_socket_fds + p->n_storage_fds > (size_t) nr_open)
1471 return -EINVAL; /* too many, someone is playing games with us */
1472
1473 if (p->fds)
1474 return -EINVAL; /* duplicated */
1475
1476 p->fds = new(int, p->n_socket_fds + p->n_storage_fds);
1477 if (!p->fds)
1478 return log_oom_debug();
1479
1480 /* Ensure we don't leave any FD uninitialized on error, it makes the fuzzer sad */
1481 FOREACH_ARRAY(i, p->fds, p->n_socket_fds + p->n_storage_fds)
1482 *i = -EBADF;
1483
1484 r = deserialize_fd_many(fds, val, p->n_socket_fds + p->n_storage_fds, p->fds);
1485 if (r < 0)
1486 continue;
1487
1488 } else if ((val = startswith(l, "exec-parameters-fd-names="))) {
1489 r = deserialize_strv(val, &p->fd_names);
1490 if (r < 0)
1491 return r;
1492 } else if ((val = startswith(l, "exec-parameters-flags="))) {
1493 unsigned flags;
1494
1495 r = safe_atou(val, &flags);
1496 if (r < 0)
1497 return r;
1498 p->flags = flags;
1499 } else if ((val = startswith(l, "exec-parameters-selinux-context-net="))) {
1500 r = parse_boolean(val);
1501 if (r < 0)
1502 return r;
1503
1504 p->selinux_context_net = r;
1505 } else if ((val = startswith(l, "exec-parameters-cgroup-supported="))) {
1506 unsigned cgroup_supported;
1507
1508 r = safe_atou(val, &cgroup_supported);
1509 if (r < 0)
1510 return r;
1511 p->cgroup_supported = cgroup_supported;
1512 } else if ((val = startswith(l, "exec-parameters-cgroup-path="))) {
1513 r = free_and_strdup(&p->cgroup_path, val);
1514 if (r < 0)
1515 return r;
1516 } else if ((val = startswith(l, "exec-parameters-cgroup-id="))) {
1517 r = safe_atou64(val, &p->cgroup_id);
1518 if (r < 0)
1519 return r;
1520 } else if ((val = startswith(l, "exec-parameters-prefix-directories-"))) {
1521 _cleanup_free_ char *type = NULL, *prefix = NULL;
1522 ExecDirectoryType dt;
1523
1524 r = extract_many_words(&val, "= ", 0, &type, &prefix, NULL);
1525 if (r < 0)
1526 return r;
1527 if (r == 0)
1528 return -EINVAL;
1529
1530 dt = exec_directory_type_from_string(type);
1531 if (dt < 0)
1532 return -EINVAL;
1533
1534 if (!p->prefix) {
1535 p->prefix = new0(char*, _EXEC_DIRECTORY_TYPE_MAX+1);
1536 if (!p->prefix)
1537 return log_oom_debug();
1538 }
1539
1540 if (isempty(prefix))
1541 p->prefix[dt] = mfree(p->prefix[dt]);
1542 else
1543 free_and_replace(p->prefix[dt], prefix);
1544 } else if ((val = startswith(l, "exec-parameters-received-credentials-directory="))) {
1545 r = free_and_strdup(&p->received_credentials_directory, val);
1546 if (r < 0)
1547 return r;
1548 } else if ((val = startswith(l, "exec-parameters-received-encrypted-credentials-directory="))) {
1549 r = free_and_strdup(&p->received_encrypted_credentials_directory, val);
1550 if (r < 0)
1551 return r;
1552 } else if ((val = startswith(l, "exec-parameters-confirm-spawn="))) {
1553 r = free_and_strdup(&p->confirm_spawn, val);
1554 if (r < 0)
1555 return r;
1556 } else if ((val = startswith(l, "exec-parameters-shall-confirm-spawn="))) {
1557 r = parse_boolean(val);
1558 if (r < 0)
1559 return r;
1560
1561 p->shall_confirm_spawn = r;
1562 } else if ((val = startswith(l, "exec-parameters-watchdog-usec="))) {
1563 r = deserialize_usec(val, &p->watchdog_usec);
1564 if (r < 0)
1565 return r;
1566 } else if ((val = startswith(l, "exec-parameters-idle-pipe="))) {
1567 if (p->idle_pipe)
1568 return -EINVAL; /* duplicated */
1569
1570 p->idle_pipe = new(int, 4);
1571 if (!p->idle_pipe)
1572 return log_oom_debug();
1573
1574 p->idle_pipe[0] = p->idle_pipe[1] = p->idle_pipe[2] = p->idle_pipe[3] = -EBADF;
1575
1576 r = deserialize_fd_many(fds, val, 4, p->idle_pipe);
1577 if (r < 0)
1578 continue;
1579
1580 } else if ((val = startswith(l, "exec-parameters-stdin-fd="))) {
1581 int fd;
1582
1583 fd = deserialize_fd(fds, val);
1584 if (fd < 0)
1585 continue;
1586
1587 p->stdin_fd = fd;
1588
1589 } else if ((val = startswith(l, "exec-parameters-stdout-fd="))) {
1590 int fd;
1591
1592 fd = deserialize_fd(fds, val);
1593 if (fd < 0)
1594 continue;
1595
1596 p->stdout_fd = fd;
1597
1598 } else if ((val = startswith(l, "exec-parameters-stderr-fd="))) {
1599 int fd;
1600
1601 fd = deserialize_fd(fds, val);
1602 if (fd < 0)
1603 continue;
1604
1605 p->stderr_fd = fd;
1606 } else if ((val = startswith(l, "exec-parameters-exec-fd="))) {
1607 int fd;
1608
1609 fd = deserialize_fd(fds, val);
1610 if (fd < 0)
1611 continue;
1612
1613 p->exec_fd = fd;
1614 } else if ((val = startswith(l, "exec-parameters-bpf-outer-map-fd="))) {
1615 int fd;
1616
1617 fd = deserialize_fd(fds, val);
1618 if (fd < 0)
1619 continue;
1620
1621 p->bpf_outer_map_fd = fd;
1622 } else if ((val = startswith(l, "exec-parameters-notify-socket="))) {
1623 r = free_and_strdup(&p->notify_socket, val);
1624 if (r < 0)
1625 return r;
1626 } else if ((val = startswith(l, "exec-parameters-open-file="))) {
1627 OpenFile *of = NULL;
1628
1629 r = open_file_parse(val, &of);
1630 if (r < 0)
1631 return r;
1632
1633 LIST_APPEND(open_files, p->open_files, of);
1634 } else if ((val = startswith(l, "exec-parameters-fallback-smack-process-label="))) {
1635 r = free_and_strdup(&p->fallback_smack_process_label, val);
1636 if (r < 0)
1637 return r;
1638 } else if ((val = startswith(l, "exec-parameters-user-lookup-fd="))) {
1639 int fd;
1640
1641 fd = deserialize_fd(fds, val);
1642 if (fd < 0)
1643 continue;
1644
1645 p->user_lookup_fd = fd;
1646 } else if ((val = startswith(l, "exec-parameters-files-env="))) {
1647 r = deserialize_strv(val, &p->files_env);
1648 if (r < 0)
1649 return r;
1650 } else if ((val = startswith(l, "exec-parameters-unit-id="))) {
1651 r = free_and_strdup(&p->unit_id, val);
1652 if (r < 0)
1653 return r;
1654 } else if ((val = startswith(l, "exec-parameters-invocation-id-string="))) {
1655 if (strlen(val) > SD_ID128_STRING_MAX - 1)
1656 return -EINVAL;
1657
1658 r = sd_id128_from_string(val, &p->invocation_id);
1659 if (r < 0)
1660 return r;
1661
1662 sd_id128_to_string(p->invocation_id, p->invocation_id_string);
1663 } else
1664 log_warning("Failed to parse serialized line, ignoring: %s", l);
1665 }
1666
1667 /* Bail out if we got exec-parameters-n-{socket/storage}-fds= but no corresponding
1668 * exec-parameters-fds= */
1669 if (p->n_socket_fds + p->n_storage_fds > 0 && !p->fds)
1670 return -EINVAL;
1671
1672 return 0;
1673 }
1674
1675 static int serialize_std_out_err(const ExecContext *c, FILE *f, int fileno) {
1676 char *key, *value;
1677 const char *type;
1678
1679 assert(c);
1680 assert(f);
1681 assert(IN_SET(fileno, STDOUT_FILENO, STDERR_FILENO));
1682
1683 type = fileno == STDOUT_FILENO ? "output" : "error";
1684
1685 switch (fileno == STDOUT_FILENO ? c->std_output : c->std_error) {
1686 case EXEC_OUTPUT_NAMED_FD:
1687 key = strjoina("exec-context-std-", type, "-fd-name");
1688 value = c->stdio_fdname[fileno];
1689
1690 break;
1691
1692 case EXEC_OUTPUT_FILE:
1693 key = strjoina("exec-context-std-", type, "-file");
1694 value = c->stdio_file[fileno];
1695
1696 break;
1697
1698 case EXEC_OUTPUT_FILE_APPEND:
1699 key = strjoina("exec-context-std-", type, "-file-append");
1700 value = c->stdio_file[fileno];
1701
1702 break;
1703
1704 case EXEC_OUTPUT_FILE_TRUNCATE:
1705 key = strjoina("exec-context-std-", type, "-file-truncate");
1706 value = c->stdio_file[fileno];
1707
1708 break;
1709
1710 default:
1711 return 0;
1712 }
1713
1714 return serialize_item(f, key, value);
1715 }
1716
1717 static int exec_context_serialize(const ExecContext *c, FILE *f) {
1718 int r;
1719
1720 assert(f);
1721
1722 if (!c)
1723 return 0;
1724
1725 r = serialize_strv(f, "exec-context-environment", c->environment);
1726 if (r < 0)
1727 return r;
1728
1729 r = serialize_strv(f, "exec-context-environment-files", c->environment_files);
1730 if (r < 0)
1731 return r;
1732
1733 r = serialize_strv(f, "exec-context-pass-environment", c->pass_environment);
1734 if (r < 0)
1735 return r;
1736
1737 r = serialize_strv(f, "exec-context-unset-environment", c->unset_environment);
1738 if (r < 0)
1739 return r;
1740
1741 r = serialize_item(f, "exec-context-working-directory", c->working_directory);
1742 if (r < 0)
1743 return r;
1744
1745 r = serialize_item(f, "exec-context-root-directory", c->root_directory);
1746 if (r < 0)
1747 return r;
1748
1749 r = serialize_item(f, "exec-context-root-image", c->root_image);
1750 if (r < 0)
1751 return r;
1752
1753 if (c->root_image_options) {
1754 _cleanup_free_ char *options = NULL;
1755
1756 LIST_FOREACH(mount_options, o, c->root_image_options) {
1757 if (isempty(o->options))
1758 continue;
1759
1760 _cleanup_free_ char *escaped = NULL;
1761 escaped = shell_escape(o->options, ":");
1762 if (!escaped)
1763 return log_oom_debug();
1764
1765 if (!strextend(&options,
1766 " ",
1767 partition_designator_to_string(o->partition_designator),
1768 ":",
1769 escaped))
1770 return log_oom_debug();
1771 }
1772
1773 r = serialize_item(f, "exec-context-root-image-options", options);
1774 if (r < 0)
1775 return r;
1776 }
1777
1778 r = serialize_item(f, "exec-context-root-verity", c->root_verity);
1779 if (r < 0)
1780 return r;
1781
1782 r = serialize_item(f, "exec-context-root-hash-path", c->root_hash_path);
1783 if (r < 0)
1784 return r;
1785
1786 r = serialize_item(f, "exec-context-root-hash-sig-path", c->root_hash_sig_path);
1787 if (r < 0)
1788 return r;
1789
1790 r = serialize_item_hexmem(f, "exec-context-root-hash", c->root_hash, c->root_hash_size);
1791 if (r < 0)
1792 return r;
1793
1794 r = serialize_item_base64mem(f, "exec-context-root-hash-sig", c->root_hash_sig, c->root_hash_sig_size);
1795 if (r < 0)
1796 return r;
1797
1798 r = serialize_bool_elide(f, "exec-context-root-ephemeral", c->root_ephemeral);
1799 if (r < 0)
1800 return r;
1801
1802 r = serialize_item_format(f, "exec-context-umask", "%04o", c->umask);
1803 if (r < 0)
1804 return r;
1805
1806 r = serialize_bool_elide(f, "exec-context-non-blocking", c->non_blocking);
1807 if (r < 0)
1808 return r;
1809
1810 r = serialize_item_tristate(f, "exec-context-private-mounts", c->private_mounts);
1811 if (r < 0)
1812 return r;
1813
1814 r = serialize_item_tristate(f, "exec-context-memory-ksm", c->memory_ksm);
1815 if (r < 0)
1816 return r;
1817
1818 r = serialize_bool_elide(f, "exec-context-private-tmp", c->private_tmp);
1819 if (r < 0)
1820 return r;
1821
1822 r = serialize_bool_elide(f, "exec-context-private-devices", c->private_devices);
1823 if (r < 0)
1824 return r;
1825
1826 r = serialize_bool_elide(f, "exec-context-protect-kernel-tunables", c->protect_kernel_tunables);
1827 if (r < 0)
1828 return r;
1829
1830 r = serialize_bool_elide(f, "exec-context-protect-kernel-modules", c->protect_kernel_modules);
1831 if (r < 0)
1832 return r;
1833
1834 r = serialize_bool_elide(f, "exec-context-protect-kernel-logs", c->protect_kernel_logs);
1835 if (r < 0)
1836 return r;
1837
1838 r = serialize_bool_elide(f, "exec-context-protect-clock", c->protect_clock);
1839 if (r < 0)
1840 return r;
1841
1842 r = serialize_bool_elide(f, "exec-context-protect-control-groups", c->protect_control_groups);
1843 if (r < 0)
1844 return r;
1845
1846 r = serialize_bool_elide(f, "exec-context-private-network", c->private_network);
1847 if (r < 0)
1848 return r;
1849
1850 r = serialize_bool_elide(f, "exec-context-private-users", c->private_users);
1851 if (r < 0)
1852 return r;
1853
1854 r = serialize_bool_elide(f, "exec-context-private-ipc", c->private_ipc);
1855 if (r < 0)
1856 return r;
1857
1858 r = serialize_bool_elide(f, "exec-context-remove-ipc", c->remove_ipc);
1859 if (r < 0)
1860 return r;
1861
1862 r = serialize_item(f, "exec-context-protect-home", protect_home_to_string(c->protect_home));
1863 if (r < 0)
1864 return r;
1865
1866 r = serialize_item(f, "exec-context-protect-system", protect_system_to_string(c->protect_system));
1867 if (r < 0)
1868 return r;
1869
1870 if (c->mount_apivfs_set) {
1871 r = serialize_bool(f, "exec-context-mount-api-vfs", c->mount_apivfs);
1872 if (r < 0)
1873 return r;
1874 }
1875
1876 r = serialize_bool_elide(f, "exec-context-same-pgrp", c->same_pgrp);
1877 if (r < 0)
1878 return r;
1879
1880 r = serialize_bool_elide(f, "exec-context-cpu-sched-reset-on-fork", c->cpu_sched_reset_on_fork);
1881 if (r < 0)
1882 return r;
1883
1884 r = serialize_bool(f, "exec-context-ignore-sigpipe", c->ignore_sigpipe);
1885 if (r < 0)
1886 return r;
1887
1888 r = serialize_bool_elide(f, "exec-context-memory-deny-write-execute", c->memory_deny_write_execute);
1889 if (r < 0)
1890 return r;
1891
1892 r = serialize_bool_elide(f, "exec-context-restrict-realtime", c->restrict_realtime);
1893 if (r < 0)
1894 return r;
1895
1896 r = serialize_bool_elide(f, "exec-context-restrict-suid-sgid", c->restrict_suid_sgid);
1897 if (r < 0)
1898 return r;
1899
1900 r = serialize_item(f, "exec-context-keyring-mode", exec_keyring_mode_to_string(c->keyring_mode));
1901 if (r < 0)
1902 return r;
1903
1904 r = serialize_bool_elide(f, "exec-context-protect-hostname", c->protect_hostname);
1905 if (r < 0)
1906 return r;
1907
1908 r = serialize_item(f, "exec-context-protect-proc", protect_proc_to_string(c->protect_proc));
1909 if (r < 0)
1910 return r;
1911
1912 r = serialize_item(f, "exec-context-proc-subset", proc_subset_to_string(c->proc_subset));
1913 if (r < 0)
1914 return r;
1915
1916 r = serialize_item(f, "exec-context-runtime-directory-preserve-mode", exec_preserve_mode_to_string(c->runtime_directory_preserve_mode));
1917 if (r < 0)
1918 return r;
1919
1920 for (ExecDirectoryType dt = 0; dt < _EXEC_DIRECTORY_TYPE_MAX; dt++) {
1921 _cleanup_free_ char *key = NULL, *value = NULL;
1922
1923 key = strjoin("exec-context-directories-", exec_directory_type_to_string(dt));
1924 if (!key)
1925 return log_oom_debug();
1926
1927 if (asprintf(&value, "%04o", c->directories[dt].mode) < 0)
1928 return log_oom_debug();
1929
1930 FOREACH_ARRAY(i, c->directories[dt].items, c->directories[dt].n_items) {
1931 _cleanup_free_ char *path_escaped = NULL;
1932
1933 path_escaped = shell_escape(i->path, ":");
1934 if (!path_escaped)
1935 return log_oom_debug();
1936
1937 if (!strextend(&value, " ", path_escaped))
1938 return log_oom_debug();
1939
1940 if (!strextend(&value, ":", yes_no(i->only_create)))
1941 return log_oom_debug();
1942
1943 STRV_FOREACH(d, i->symlinks) {
1944 _cleanup_free_ char *link_escaped = NULL;
1945
1946 link_escaped = shell_escape(*d, ":");
1947 if (!link_escaped)
1948 return log_oom_debug();
1949
1950 if (!strextend(&value, ":", link_escaped))
1951 return log_oom_debug();
1952 }
1953 }
1954
1955 r = serialize_item(f, key, value);
1956 if (r < 0)
1957 return r;
1958 }
1959
1960 r = serialize_usec(f, "exec-context-timeout-clean-usec", c->timeout_clean_usec);
1961 if (r < 0)
1962 return r;
1963
1964 if (c->nice_set) {
1965 r = serialize_item_format(f, "exec-context-nice", "%i", c->nice);
1966 if (r < 0)
1967 return r;
1968 }
1969
1970 r = serialize_bool_elide(f, "exec-context-working-directory-missing-ok", c->working_directory_missing_ok);
1971 if (r < 0)
1972 return r;
1973
1974 r = serialize_bool_elide(f, "exec-context-working-directory-home", c->working_directory_home);
1975 if (r < 0)
1976 return r;
1977
1978 if (c->oom_score_adjust_set) {
1979 r = serialize_item_format(f, "exec-context-oom-score-adjust", "%i", c->oom_score_adjust);
1980 if (r < 0)
1981 return r;
1982 }
1983
1984 if (c->coredump_filter_set) {
1985 r = serialize_item_format(f, "exec-context-coredump-filter", "%"PRIx64, c->coredump_filter);
1986 if (r < 0)
1987 return r;
1988 }
1989
1990 for (unsigned i = 0; i < RLIM_NLIMITS; i++) {
1991 _cleanup_free_ char *key = NULL, *limit = NULL;
1992
1993 if (!c->rlimit[i])
1994 continue;
1995
1996 key = strjoin("exec-context-limit-", rlimit_to_string(i));
1997 if (!key)
1998 return log_oom_debug();
1999
2000 r = rlimit_format(c->rlimit[i], &limit);
2001 if (r < 0)
2002 return r;
2003
2004 r = serialize_item(f, key, limit);
2005 if (r < 0)
2006 return r;
2007 }
2008
2009 if (c->ioprio_set) {
2010 r = serialize_item_format(f, "exec-context-ioprio", "%d", c->ioprio);
2011 if (r < 0)
2012 return r;
2013 }
2014
2015 if (c->cpu_sched_set) {
2016 _cleanup_free_ char *policy_str = NULL;
2017
2018 r = sched_policy_to_string_alloc(c->cpu_sched_policy, &policy_str);
2019 if (r < 0)
2020 return r;
2021
2022 r = serialize_item(f, "exec-context-cpu-scheduling-policy", policy_str);
2023 if (r < 0)
2024 return r;
2025
2026 r = serialize_item_format(f, "exec-context-cpu-scheduling-priority", "%i", c->cpu_sched_priority);
2027 if (r < 0)
2028 return r;
2029
2030 r = serialize_bool_elide(f, "exec-context-cpu-scheduling-reset-on-fork", c->cpu_sched_reset_on_fork);
2031 if (r < 0)
2032 return r;
2033 }
2034
2035 if (c->cpu_set.set) {
2036 _cleanup_free_ char *affinity = NULL;
2037
2038 affinity = cpu_set_to_range_string(&c->cpu_set);
2039 if (!affinity)
2040 return log_oom_debug();
2041
2042 r = serialize_item(f, "exec-context-cpu-affinity", affinity);
2043 if (r < 0)
2044 return r;
2045 }
2046
2047 if (mpol_is_valid(numa_policy_get_type(&c->numa_policy))) {
2048 _cleanup_free_ char *nodes = NULL;
2049
2050 nodes = cpu_set_to_range_string(&c->numa_policy.nodes);
2051 if (!nodes)
2052 return log_oom_debug();
2053
2054 if (nodes) {
2055 r = serialize_item(f, "exec-context-numa-mask", nodes);
2056 if (r < 0)
2057 return r;
2058 }
2059
2060 r = serialize_item_format(f, "exec-context-numa-policy", "%d", c->numa_policy.type);
2061 if (r < 0)
2062 return r;
2063 }
2064
2065 r = serialize_bool_elide(f, "exec-context-cpu-affinity-from-numa", c->cpu_affinity_from_numa);
2066 if (r < 0)
2067 return r;
2068
2069 if (c->timer_slack_nsec != NSEC_INFINITY) {
2070 r = serialize_item_format(f, "exec-context-timer-slack-nsec", NSEC_FMT, c->timer_slack_nsec);
2071 if (r < 0)
2072 return r;
2073 }
2074
2075 r = serialize_item(f, "exec-context-std-input", exec_input_to_string(c->std_input));
2076 if (r < 0)
2077 return r;
2078
2079 r = serialize_item(f, "exec-context-std-output", exec_output_to_string(c->std_output));
2080 if (r < 0)
2081 return r;
2082
2083 r = serialize_item(f, "exec-context-std-error", exec_output_to_string(c->std_error));
2084 if (r < 0)
2085 return r;
2086
2087 r = serialize_bool_elide(f, "exec-context-stdio-as-fds", c->stdio_as_fds);
2088 if (r < 0)
2089 return r;
2090
2091 switch (c->std_input) {
2092 case EXEC_INPUT_NAMED_FD:
2093 r = serialize_item(f, "exec-context-std-input-fd-name", c->stdio_fdname[STDIN_FILENO]);
2094 if (r < 0)
2095 return r;
2096 break;
2097
2098 case EXEC_INPUT_FILE:
2099 r = serialize_item(f, "exec-context-std-input-file", c->stdio_file[STDIN_FILENO]);
2100 if (r < 0)
2101 return r;
2102 break;
2103
2104 default:
2105 break;
2106 }
2107
2108 r = serialize_std_out_err(c, f, STDOUT_FILENO);
2109 if (r < 0)
2110 return r;
2111
2112 r = serialize_std_out_err(c, f, STDERR_FILENO);
2113 if (r < 0)
2114 return r;
2115
2116 r = serialize_item_base64mem(f, "exec-context-stdin-data", c->stdin_data, c->stdin_data_size);
2117 if (r < 0)
2118 return r;
2119
2120 r = serialize_item(f, "exec-context-tty-path", c->tty_path);
2121 if (r < 0)
2122 return r;
2123
2124 r = serialize_bool_elide(f, "exec-context-tty-reset", c->tty_reset);
2125 if (r < 0)
2126 return r;
2127
2128 r = serialize_bool_elide(f, "exec-context-tty-vhangup", c->tty_vhangup);
2129 if (r < 0)
2130 return r;
2131
2132 r = serialize_bool_elide(f, "exec-context-tty-vt-disallocate", c->tty_vt_disallocate);
2133 if (r < 0)
2134 return r;
2135
2136 r = serialize_item_format(f, "exec-context-tty-rows", "%u", c->tty_rows);
2137 if (r < 0)
2138 return r;
2139
2140 r = serialize_item_format(f, "exec-context-tty-columns", "%u", c->tty_cols);
2141 if (r < 0)
2142 return r;
2143
2144 r = serialize_item_format(f, "exec-context-syslog-priority", "%i", c->syslog_priority);
2145 if (r < 0)
2146 return r;
2147
2148 r = serialize_bool(f, "exec-context-syslog-level-prefix", c->syslog_level_prefix);
2149 if (r < 0)
2150 return r;
2151
2152 r = serialize_item(f, "exec-context-syslog-identifier", c->syslog_identifier);
2153 if (r < 0)
2154 return r;
2155
2156 r = serialize_item_format(f, "exec-context-log-level-max", "%d", c->log_level_max);
2157 if (r < 0)
2158 return r;
2159
2160 if (c->log_ratelimit_interval_usec > 0) {
2161 r = serialize_usec(f, "exec-context-log-ratelimit-interval-usec", c->log_ratelimit_interval_usec);
2162 if (r < 0)
2163 return r;
2164 }
2165
2166 if (c->log_ratelimit_burst > 0) {
2167 r = serialize_item_format(f, "exec-context-log-ratelimit-burst", "%u", c->log_ratelimit_burst);
2168 if (r < 0)
2169 return r;
2170 }
2171
2172 r = serialize_string_set(f, "exec-context-log-filter-allowed-patterns", c->log_filter_allowed_patterns);
2173 if (r < 0)
2174 return r;
2175
2176 r = serialize_string_set(f, "exec-context-log-filter-denied-patterns", c->log_filter_denied_patterns);
2177 if (r < 0)
2178 return r;
2179
2180 FOREACH_ARRAY(field, c->log_extra_fields, c->n_log_extra_fields) {
2181 r = serialize_item(f, "exec-context-log-extra-fields", field->iov_base);
2182 if (r < 0)
2183 return r;
2184 }
2185
2186 r = serialize_item(f, "exec-context-log-namespace", c->log_namespace);
2187 if (r < 0)
2188 return r;
2189
2190 if (c->secure_bits != 0) {
2191 r = serialize_item_format(f, "exec-context-secure-bits", "%d", c->secure_bits);
2192 if (r < 0)
2193 return r;
2194 }
2195
2196 if (c->capability_bounding_set != CAP_MASK_UNSET) {
2197 r = serialize_item_format(f, "exec-context-capability-bounding-set", "%" PRIu64, c->capability_bounding_set);
2198 if (r < 0)
2199 return r;
2200 }
2201
2202 if (c->capability_ambient_set != 0) {
2203 r = serialize_item_format(f, "exec-context-capability-ambient-set", "%" PRIu64, c->capability_ambient_set);
2204 if (r < 0)
2205 return r;
2206 }
2207
2208 if (c->user) {
2209 r = serialize_item(f, "exec-context-user", c->user);
2210 if (r < 0)
2211 return r;
2212 }
2213
2214 r = serialize_item(f, "exec-context-group", c->group);
2215 if (r < 0)
2216 return r;
2217
2218 r = serialize_bool_elide(f, "exec-context-dynamic-user", c->dynamic_user);
2219 if (r < 0)
2220 return r;
2221
2222 r = serialize_strv(f, "exec-context-supplementary-groups", c->supplementary_groups);
2223 if (r < 0)
2224 return r;
2225
2226 r = serialize_item_tristate(f, "exec-context-set-login-environment", c->set_login_environment);
2227 if (r < 0)
2228 return r;
2229
2230 r = serialize_item(f, "exec-context-pam-name", c->pam_name);
2231 if (r < 0)
2232 return r;
2233
2234 r = serialize_strv(f, "exec-context-read-write-paths", c->read_write_paths);
2235 if (r < 0)
2236 return r;
2237
2238 r = serialize_strv(f, "exec-context-read-only-paths", c->read_only_paths);
2239 if (r < 0)
2240 return r;
2241
2242 r = serialize_strv(f, "exec-context-inaccessible-paths", c->inaccessible_paths);
2243 if (r < 0)
2244 return r;
2245
2246 r = serialize_strv(f, "exec-context-exec-paths", c->exec_paths);
2247 if (r < 0)
2248 return r;
2249
2250 r = serialize_strv(f, "exec-context-no-exec-paths", c->no_exec_paths);
2251 if (r < 0)
2252 return r;
2253
2254 r = serialize_strv(f, "exec-context-exec-search-path", c->exec_search_path);
2255 if (r < 0)
2256 return r;
2257
2258 r = serialize_item_format(f, "exec-context-mount-propagation-flag", "%lu", c->mount_propagation_flag);
2259 if (r < 0)
2260 return r;
2261
2262 FOREACH_ARRAY(mount, c->bind_mounts, c->n_bind_mounts) {
2263 _cleanup_free_ char *src_escaped = NULL, *dst_escaped = NULL;
2264
2265 src_escaped = shell_escape(mount->source, ":");
2266 if (!src_escaped)
2267 return log_oom_debug();
2268
2269 dst_escaped = shell_escape(mount->destination, ":");
2270 if (!dst_escaped)
2271 return log_oom_debug();
2272
2273 r = serialize_item_format(f,
2274 mount->read_only ? "exec-context-bind-read-only-path" : "exec-context-bind-path",
2275 "%s%s:%s:%s",
2276 mount->ignore_enoent ? "-" : "",
2277 src_escaped,
2278 dst_escaped,
2279 mount->recursive ? "rbind" : "norbind");
2280 if (r < 0)
2281 return r;
2282 }
2283
2284 FOREACH_ARRAY(tmpfs, c->temporary_filesystems, c->n_temporary_filesystems) {
2285 _cleanup_free_ char *escaped = NULL;
2286
2287 if (!isempty(tmpfs->options)) {
2288 escaped = shell_escape(tmpfs->options, ":");
2289 if (!escaped)
2290 return log_oom_debug();
2291 }
2292
2293 r = serialize_item_format(f, "exec-context-temporary-filesystems", "%s%s%s",
2294 tmpfs->path,
2295 isempty(escaped) ? "" : ":",
2296 strempty(escaped));
2297 if (r < 0)
2298 return r;
2299 }
2300
2301 r = serialize_item(f, "exec-context-utmp-id", c->utmp_id);
2302 if (r < 0)
2303 return r;
2304
2305 r = serialize_item(f, "exec-context-utmp-mode", exec_utmp_mode_to_string(c->utmp_mode));
2306 if (r < 0)
2307 return r;
2308
2309 r = serialize_bool_elide(f, "exec-context-no-new-privileges", c->no_new_privileges);
2310 if (r < 0)
2311 return r;
2312
2313 r = serialize_bool_elide(f, "exec-context-selinux-context-ignore", c->selinux_context_ignore);
2314 if (r < 0)
2315 return r;
2316
2317 r = serialize_bool_elide(f, "exec-context-apparmor-profile-ignore", c->apparmor_profile_ignore);
2318 if (r < 0)
2319 return r;
2320
2321 r = serialize_bool_elide(f, "exec-context-smack-process-label-ignore", c->smack_process_label_ignore);
2322 if (r < 0)
2323 return r;
2324
2325 if (c->selinux_context) {
2326 r = serialize_item_format(f, "exec-context-selinux-context",
2327 "%s%s",
2328 c->selinux_context_ignore ? "-" : "",
2329 c->selinux_context);
2330 if (r < 0)
2331 return r;
2332 }
2333
2334 if (c->apparmor_profile) {
2335 r = serialize_item_format(f, "exec-context-apparmor-profile",
2336 "%s%s",
2337 c->apparmor_profile_ignore ? "-" : "",
2338 c->apparmor_profile);
2339 if (r < 0)
2340 return r;
2341 }
2342
2343 if (c->smack_process_label) {
2344 r = serialize_item_format(f, "exec-context-smack-process-label",
2345 "%s%s",
2346 c->smack_process_label_ignore ? "-" : "",
2347 c->smack_process_label);
2348 if (r < 0)
2349 return r;
2350 }
2351
2352 if (c->personality != PERSONALITY_INVALID) {
2353 r = serialize_item(f, "exec-context-personality", personality_to_string(c->personality));
2354 if (r < 0)
2355 return r;
2356 }
2357
2358 r = serialize_bool_elide(f, "exec-context-lock-personality", c->lock_personality);
2359 if (r < 0)
2360 return r;
2361
2362 #if HAVE_SECCOMP
2363 if (!hashmap_isempty(c->syscall_filter)) {
2364 void *errno_num, *id;
2365 HASHMAP_FOREACH_KEY(errno_num, id, c->syscall_filter) {
2366 r = serialize_item_format(f, "exec-context-syscall-filter", "%d %d", PTR_TO_INT(id) - 1, PTR_TO_INT(errno_num));
2367 if (r < 0)
2368 return r;
2369 }
2370 }
2371
2372 if (!set_isempty(c->syscall_archs)) {
2373 void *id;
2374 SET_FOREACH(id, c->syscall_archs) {
2375 r = serialize_item_format(f, "exec-context-syscall-archs", "%u", PTR_TO_UINT(id) - 1);
2376 if (r < 0)
2377 return r;
2378 }
2379 }
2380
2381 if (c->syscall_errno > 0) {
2382 r = serialize_item_format(f, "exec-context-syscall-errno", "%d", c->syscall_errno);
2383 if (r < 0)
2384 return r;
2385 }
2386
2387 r = serialize_bool_elide(f, "exec-context-syscall-allow-list", c->syscall_allow_list);
2388 if (r < 0)
2389 return r;
2390
2391 if (!hashmap_isempty(c->syscall_log)) {
2392 void *errno_num, *id;
2393 HASHMAP_FOREACH_KEY(errno_num, id, c->syscall_log) {
2394 r = serialize_item_format(f, "exec-context-syscall-log", "%d %d", PTR_TO_INT(id) - 1, PTR_TO_INT(errno_num));
2395 if (r < 0)
2396 return r;
2397 }
2398 }
2399
2400 r = serialize_bool_elide(f, "exec-context-syscall-log-allow-list", c->syscall_log_allow_list);
2401 if (r < 0)
2402 return r;
2403 #endif
2404
2405 if (c->restrict_namespaces != NAMESPACE_FLAGS_INITIAL) {
2406 r = serialize_item_format(f, "exec-context-restrict-namespaces", "%lu", c->restrict_namespaces);
2407 if (r < 0)
2408 return r;
2409 }
2410
2411 #if HAVE_LIBBPF
2412 if (exec_context_restrict_filesystems_set(c)) {
2413 char *fs;
2414 SET_FOREACH(fs, c->restrict_filesystems) {
2415 r = serialize_item(f, "exec-context-restrict-filesystems", fs);
2416 if (r < 0)
2417 return r;
2418 }
2419 }
2420
2421 r = serialize_bool_elide(f, "exec-context-restrict-filesystems-allow-list", c->restrict_filesystems_allow_list);
2422 if (r < 0)
2423 return r;
2424 #endif
2425
2426 if (!set_isempty(c->address_families)) {
2427 void *afp;
2428
2429 SET_FOREACH(afp, c->address_families) {
2430 int af = PTR_TO_INT(afp);
2431
2432 if (af <= 0 || af >= af_max())
2433 continue;
2434
2435 r = serialize_item_format(f, "exec-context-address-families", "%d", af);
2436 if (r < 0)
2437 return r;
2438 }
2439 }
2440
2441 r = serialize_bool_elide(f, "exec-context-address-families-allow-list", c->address_families_allow_list);
2442 if (r < 0)
2443 return r;
2444
2445 r = serialize_item(f, "exec-context-network-namespace-path", c->network_namespace_path);
2446 if (r < 0)
2447 return r;
2448
2449 r = serialize_item(f, "exec-context-ipc-namespace-path", c->ipc_namespace_path);
2450 if (r < 0)
2451 return r;
2452
2453 FOREACH_ARRAY(mount, c->mount_images, c->n_mount_images) {
2454 _cleanup_free_ char *s = NULL, *source_escaped = NULL, *dest_escaped = NULL;
2455
2456 source_escaped = shell_escape(mount->source, " ");
2457 if (!source_escaped)
2458 return log_oom_debug();
2459
2460 dest_escaped = shell_escape(mount->destination, " ");
2461 if (!dest_escaped)
2462 return log_oom_debug();
2463
2464 s = strjoin(mount->ignore_enoent ? "-" : "",
2465 source_escaped,
2466 " ",
2467 dest_escaped);
2468 if (!s)
2469 return log_oom_debug();
2470
2471 LIST_FOREACH(mount_options, o, mount->mount_options) {
2472 _cleanup_free_ char *escaped = NULL;
2473
2474 if (isempty(o->options))
2475 continue;
2476
2477 escaped = shell_escape(o->options, ":");
2478 if (!escaped)
2479 return log_oom_debug();
2480
2481 if (!strextend(&s,
2482 " ",
2483 partition_designator_to_string(o->partition_designator),
2484 ":",
2485 escaped))
2486 return log_oom_debug();
2487 }
2488
2489 r = serialize_item(f, "exec-context-mount-image", s);
2490 if (r < 0)
2491 return r;
2492 }
2493
2494 FOREACH_ARRAY(mount, c->extension_images, c->n_extension_images) {
2495 _cleanup_free_ char *s = NULL, *source_escaped = NULL;
2496
2497 source_escaped = shell_escape(mount->source, ":");
2498 if (!source_escaped)
2499 return log_oom_debug();
2500
2501 s = strjoin(mount->ignore_enoent ? "-" : "",
2502 source_escaped);
2503 if (!s)
2504 return log_oom_debug();
2505
2506 LIST_FOREACH(mount_options, o, mount->mount_options) {
2507 _cleanup_free_ char *escaped = NULL;
2508
2509 if (isempty(o->options))
2510 continue;
2511
2512 escaped = shell_escape(o->options, ":");
2513 if (!escaped)
2514 return log_oom_debug();
2515
2516 if (!strextend(&s,
2517 " ",
2518 partition_designator_to_string(o->partition_designator),
2519 ":",
2520 escaped))
2521 return log_oom_debug();
2522 }
2523
2524 r = serialize_item(f, "exec-context-extension-image", s);
2525 if (r < 0)
2526 return r;
2527 }
2528
2529 r = serialize_strv(f, "exec-context-extension-directories", c->extension_directories);
2530 if (r < 0)
2531 return r;
2532
2533 ExecSetCredential *sc;
2534 HASHMAP_FOREACH(sc, c->set_credentials) {
2535 _cleanup_free_ char *data = NULL;
2536
2537 if (base64mem(sc->data, sc->size, &data) < 0)
2538 return log_oom_debug();
2539
2540 r = serialize_item_format(f, "exec-context-set-credentials", "%s %s %s", sc->id, yes_no(sc->encrypted), data);
2541 if (r < 0)
2542 return r;
2543 }
2544
2545 ExecLoadCredential *lc;
2546 HASHMAP_FOREACH(lc, c->load_credentials) {
2547 r = serialize_item_format(f, "exec-context-load-credentials", "%s %s %s", lc->id, yes_no(lc->encrypted), lc->path);
2548 if (r < 0)
2549 return r;
2550 }
2551
2552 if (!set_isempty(c->import_credentials)) {
2553 char *ic;
2554 SET_FOREACH(ic, c->import_credentials) {
2555 r = serialize_item(f, "exec-context-import-credentials", ic);
2556 if (r < 0)
2557 return r;
2558 }
2559 }
2560
2561 r = serialize_image_policy(f, "exec-context-root-image-policy", c->root_image_policy);
2562 if (r < 0)
2563 return r;
2564
2565 r = serialize_image_policy(f, "exec-context-mount-image-policy", c->mount_image_policy);
2566 if (r < 0)
2567 return r;
2568
2569 r = serialize_image_policy(f, "exec-context-extension-image-policy", c->extension_image_policy);
2570 if (r < 0)
2571 return r;
2572
2573 fputc('\n', f); /* End marker */
2574
2575 return 0;
2576 }
2577
2578 static int exec_context_deserialize(ExecContext *c, FILE *f) {
2579 int r;
2580
2581 assert(f);
2582
2583 if (!c)
2584 return 0;
2585
2586 for (;;) {
2587 _cleanup_free_ char *l = NULL;
2588 const char *val;
2589
2590 r = deserialize_read_line(f, &l);
2591 if (r < 0)
2592 return r;
2593 if (r == 0) /* eof or end marker */
2594 break;
2595
2596 if ((val = startswith(l, "exec-context-environment="))) {
2597 r = deserialize_strv(val, &c->environment);
2598 if (r < 0)
2599 return r;
2600 } else if ((val = startswith(l, "exec-context-environment-files="))) {
2601 r = deserialize_strv(val, &c->environment_files);
2602 if (r < 0)
2603 return r;
2604 } else if ((val = startswith(l, "exec-context-pass-environment="))) {
2605 r = deserialize_strv(val, &c->pass_environment);
2606 if (r < 0)
2607 return r;
2608 } else if ((val = startswith(l, "exec-context-unset-environment="))) {
2609 r = deserialize_strv(val, &c->unset_environment);
2610 if (r < 0)
2611 return r;
2612 } else if ((val = startswith(l, "exec-context-working-directory="))) {
2613 r = free_and_strdup(&c->working_directory, val);
2614 if (r < 0)
2615 return r;
2616 } else if ((val = startswith(l, "exec-context-root-directory="))) {
2617 r = free_and_strdup(&c->root_directory, val);
2618 if (r < 0)
2619 return r;
2620 } else if ((val = startswith(l, "exec-context-root-image="))) {
2621 r = free_and_strdup(&c->root_image, val);
2622 if (r < 0)
2623 return r;
2624 } else if ((val = startswith(l, "exec-context-root-image-options="))) {
2625 for (;;) {
2626 _cleanup_free_ char *word = NULL, *mount_options = NULL, *partition = NULL;
2627 PartitionDesignator partition_designator;
2628 MountOptions *o = NULL;
2629 const char *p;
2630
2631 r = extract_first_word(&val, &word, NULL, 0);
2632 if (r < 0)
2633 return r;
2634 if (r == 0)
2635 break;
2636
2637 p = word;
2638 r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
2639 if (r < 0)
2640 return r;
2641 if (r == 0)
2642 continue;
2643
2644 partition_designator = partition_designator_from_string(partition);
2645 if (partition_designator < 0)
2646 return -EINVAL;
2647
2648 o = new(MountOptions, 1);
2649 if (!o)
2650 return log_oom_debug();
2651 *o = (MountOptions) {
2652 .partition_designator = partition_designator,
2653 .options = TAKE_PTR(mount_options),
2654 };
2655 LIST_APPEND(mount_options, c->root_image_options, o);
2656 }
2657 } else if ((val = startswith(l, "exec-context-root-verity="))) {
2658 r = free_and_strdup(&c->root_verity, val);
2659 if (r < 0)
2660 return r;
2661 } else if ((val = startswith(l, "exec-context-root-hash-path="))) {
2662 r = free_and_strdup(&c->root_hash_path, val);
2663 if (r < 0)
2664 return r;
2665 } else if ((val = startswith(l, "exec-context-root-hash-sig-path="))) {
2666 r = free_and_strdup(&c->root_hash_sig_path, val);
2667 if (r < 0)
2668 return r;
2669 } else if ((val = startswith(l, "exec-context-root-hash="))) {
2670 c->root_hash = mfree(c->root_hash);
2671 r = unhexmem(val, strlen(val), &c->root_hash, &c->root_hash_size);
2672 if (r < 0)
2673 return r;
2674 } else if ((val = startswith(l, "exec-context-root-hash-sig="))) {
2675 c->root_hash_sig = mfree(c->root_hash_sig);
2676 r= unbase64mem(val, strlen(val), &c->root_hash_sig, &c->root_hash_sig_size);
2677 if (r < 0)
2678 return r;
2679 } else if ((val = startswith(l, "exec-context-root-ephemeral="))) {
2680 r = parse_boolean(val);
2681 if (r < 0)
2682 return r;
2683 c->root_ephemeral = r;
2684 } else if ((val = startswith(l, "exec-context-umask="))) {
2685 r = parse_mode(val, &c->umask);
2686 if (r < 0)
2687 return r;
2688 } else if ((val = startswith(l, "exec-context-private-non-blocking="))) {
2689 r = parse_boolean(val);
2690 if (r < 0)
2691 return r;
2692 c->non_blocking = r;
2693 } else if ((val = startswith(l, "exec-context-private-mounts="))) {
2694 r = safe_atoi(val, &c->private_mounts);
2695 if (r < 0)
2696 return r;
2697 } else if ((val = startswith(l, "exec-context-memory-ksm="))) {
2698 r = safe_atoi(val, &c->memory_ksm);
2699 if (r < 0)
2700 return r;
2701 } else if ((val = startswith(l, "exec-context-private-tmp="))) {
2702 r = parse_boolean(val);
2703 if (r < 0)
2704 return r;
2705 c->private_tmp = r;
2706 } else if ((val = startswith(l, "exec-context-private-devices="))) {
2707 r = parse_boolean(val);
2708 if (r < 0)
2709 return r;
2710 c->private_devices = r;
2711 } else if ((val = startswith(l, "exec-context-protect-kernel-tunables="))) {
2712 r = parse_boolean(val);
2713 if (r < 0)
2714 return r;
2715 c->protect_kernel_tunables = r;
2716 } else if ((val = startswith(l, "exec-context-protect-kernel-modules="))) {
2717 r = parse_boolean(val);
2718 if (r < 0)
2719 return r;
2720 c->protect_kernel_modules = r;
2721 } else if ((val = startswith(l, "exec-context-protect-kernel-logs="))) {
2722 r = parse_boolean(val);
2723 if (r < 0)
2724 return r;
2725 c->protect_kernel_logs = r;
2726 } else if ((val = startswith(l, "exec-context-protect-clock="))) {
2727 r = parse_boolean(val);
2728 if (r < 0)
2729 return r;
2730 c->protect_clock = r;
2731 } else if ((val = startswith(l, "exec-context-protect-control-groups="))) {
2732 r = parse_boolean(val);
2733 if (r < 0)
2734 return r;
2735 c->protect_control_groups = r;
2736 } else if ((val = startswith(l, "exec-context-private-network="))) {
2737 r = parse_boolean(val);
2738 if (r < 0)
2739 return r;
2740 c->private_network = r;
2741 } else if ((val = startswith(l, "exec-context-private-users="))) {
2742 r = parse_boolean(val);
2743 if (r < 0)
2744 return r;
2745 c->private_users = r;
2746 } else if ((val = startswith(l, "exec-context-private-ipc="))) {
2747 r = parse_boolean(val);
2748 if (r < 0)
2749 return r;
2750 c->private_ipc = r;
2751 } else if ((val = startswith(l, "exec-context-remove-ipc="))) {
2752 r = parse_boolean(val);
2753 if (r < 0)
2754 return r;
2755 c->remove_ipc = r;
2756 } else if ((val = startswith(l, "exec-context-protect-home="))) {
2757 c->protect_home = protect_home_from_string(val);
2758 if (c->protect_home < 0)
2759 return -EINVAL;
2760 } else if ((val = startswith(l, "exec-context-protect-system="))) {
2761 c->protect_system = protect_system_from_string(val);
2762 if (c->protect_system < 0)
2763 return -EINVAL;
2764 } else if ((val = startswith(l, "exec-context-mount-api-vfs="))) {
2765 r = parse_boolean(val);
2766 if (r < 0)
2767 return r;
2768 c->mount_apivfs = r;
2769 c->mount_apivfs_set = true;
2770 } else if ((val = startswith(l, "exec-context-same-pgrp="))) {
2771 r = parse_boolean(val);
2772 if (r < 0)
2773 return r;
2774 c->same_pgrp = r;
2775 } else if ((val = startswith(l, "exec-context-cpu-sched-reset-on-fork="))) {
2776 r = parse_boolean(val);
2777 if (r < 0)
2778 return r;
2779 c->cpu_sched_reset_on_fork = r;
2780 } else if ((val = startswith(l, "exec-context-non-blocking="))) {
2781 r = parse_boolean(val);
2782 if (r < 0)
2783 return r;
2784 c->non_blocking = r;
2785 } else if ((val = startswith(l, "exec-context-ignore-sigpipe="))) {
2786 r = parse_boolean(val);
2787 if (r < 0)
2788 return r;
2789 c->ignore_sigpipe = r;
2790 } else if ((val = startswith(l, "exec-context-memory-deny-write-execute="))) {
2791 r = parse_boolean(val);
2792 if (r < 0)
2793 return r;
2794 c->memory_deny_write_execute = r;
2795 } else if ((val = startswith(l, "exec-context-restrict-realtime="))) {
2796 r = parse_boolean(val);
2797 if (r < 0)
2798 return r;
2799 c->restrict_realtime = r;
2800 } else if ((val = startswith(l, "exec-context-restrict-suid-sgid="))) {
2801 r = parse_boolean(val);
2802 if (r < 0)
2803 return r;
2804 c->restrict_suid_sgid = r;
2805 } else if ((val = startswith(l, "exec-context-keyring-mode="))) {
2806 c->keyring_mode = exec_keyring_mode_from_string(val);
2807 if (c->keyring_mode < 0)
2808 return -EINVAL;
2809 } else if ((val = startswith(l, "exec-context-protect-hostname="))) {
2810 r = parse_boolean(val);
2811 if (r < 0)
2812 return r;
2813 c->protect_hostname = r;
2814 } else if ((val = startswith(l, "exec-context-protect-proc="))) {
2815 c->protect_proc = protect_proc_from_string(val);
2816 if (c->protect_proc < 0)
2817 return -EINVAL;
2818 } else if ((val = startswith(l, "exec-context-proc-subset="))) {
2819 c->proc_subset = proc_subset_from_string(val);
2820 if (c->proc_subset < 0)
2821 return -EINVAL;
2822 } else if ((val = startswith(l, "exec-context-runtime-directory-preserve-mode="))) {
2823 c->runtime_directory_preserve_mode = exec_preserve_mode_from_string(val);
2824 if (c->runtime_directory_preserve_mode < 0)
2825 return -EINVAL;
2826 } else if ((val = startswith(l, "exec-context-directories-"))) {
2827 _cleanup_free_ char *type = NULL, *mode = NULL;
2828 ExecDirectoryType dt;
2829
2830 r = extract_many_words(&val, "= ", 0, &type, &mode, NULL);
2831 if (r < 0)
2832 return r;
2833 if (r == 0 || !mode)
2834 return -EINVAL;
2835
2836 dt = exec_directory_type_from_string(type);
2837 if (dt < 0)
2838 return -EINVAL;
2839
2840 r = parse_mode(mode, &c->directories[dt].mode);
2841 if (r < 0)
2842 return r;
2843
2844 for (;;) {
2845 _cleanup_free_ char *tuple = NULL, *path = NULL, *only_create = NULL;
2846 const char *p;
2847
2848 r = extract_first_word(&val, &tuple, WHITESPACE, EXTRACT_RETAIN_ESCAPE);
2849 if (r < 0)
2850 return r;
2851 if (r == 0)
2852 break;
2853
2854 p = tuple;
2855 r = extract_many_words(&p, ":", EXTRACT_UNESCAPE_SEPARATORS, &path, &only_create, NULL);
2856 if (r < 0)
2857 return r;
2858 if (r < 2)
2859 continue;
2860
2861 r = exec_directory_add(&c->directories[dt], path, NULL);
2862 if (r < 0)
2863 return r;
2864
2865 r = parse_boolean(only_create);
2866 if (r < 0)
2867 return r;
2868 c->directories[dt].items[c->directories[dt].n_items - 1].only_create = r;
2869
2870 if (isempty(p))
2871 continue;
2872
2873 for (;;) {
2874 _cleanup_free_ char *link = NULL;
2875
2876 r = extract_first_word(&p, &link, ":", EXTRACT_UNESCAPE_SEPARATORS);
2877 if (r < 0)
2878 return r;
2879 if (r == 0)
2880 break;
2881
2882 r = strv_consume(&c->directories[dt].items[c->directories[dt].n_items - 1].symlinks, TAKE_PTR(link));
2883 if (r < 0)
2884 return r;
2885 }
2886 }
2887 } else if ((val = startswith(l, "exec-context-timeout-clean-usec="))) {
2888 r = deserialize_usec(val, &c->timeout_clean_usec);
2889 if (r < 0)
2890 return r;
2891 } else if ((val = startswith(l, "exec-context-nice="))) {
2892 r = safe_atoi(val, &c->nice);
2893 if (r < 0)
2894 return r;
2895 c->nice_set = true;
2896 } else if ((val = startswith(l, "exec-context-working-directory-missing-ok="))) {
2897 r = parse_boolean(val);
2898 if (r < 0)
2899 return r;
2900 c->working_directory_missing_ok = r;
2901 } else if ((val = startswith(l, "exec-context-working-directory-home="))) {
2902 r = parse_boolean(val);
2903 if (r < 0)
2904 return r;
2905 c->working_directory_home = r;
2906 } else if ((val = startswith(l, "exec-context-oom-score-adjust="))) {
2907 r = safe_atoi(val, &c->oom_score_adjust);
2908 if (r < 0)
2909 return r;
2910 c->oom_score_adjust_set = true;
2911 } else if ((val = startswith(l, "exec-context-coredump-filter="))) {
2912 r = safe_atoux64(val, &c->coredump_filter);
2913 if (r < 0)
2914 return r;
2915 c->coredump_filter_set = true;
2916 } else if ((val = startswith(l, "exec-context-limit-"))) {
2917 _cleanup_free_ struct rlimit *rlimit = NULL;
2918 _cleanup_free_ char *limit = NULL;
2919 int type;
2920
2921 r = extract_first_word(&val, &limit, "=", 0);
2922 if (r < 0)
2923 return r;
2924 if (r == 0 || !val)
2925 return -EINVAL;
2926
2927 type = rlimit_from_string(limit);
2928 if (type < 0)
2929 return -EINVAL;
2930
2931 if (!c->rlimit[type]) {
2932 rlimit = new0(struct rlimit, 1);
2933 if (!rlimit)
2934 return log_oom_debug();
2935
2936 r = rlimit_parse(type, val, rlimit);
2937 if (r < 0)
2938 return r;
2939
2940 c->rlimit[type] = TAKE_PTR(rlimit);
2941 } else {
2942 r = rlimit_parse(type, val, c->rlimit[type]);
2943 if (r < 0)
2944 return r;
2945 }
2946 } else if ((val = startswith(l, "exec-context-ioprio="))) {
2947 r = safe_atoi(val, &c->ioprio);
2948 if (r < 0)
2949 return r;
2950 c->ioprio_set = true;
2951 } else if ((val = startswith(l, "exec-context-cpu-scheduling-policy="))) {
2952 c->cpu_sched_policy = sched_policy_from_string(val);
2953 if (c->cpu_sched_policy < 0)
2954 return -EINVAL;
2955 c->cpu_sched_set = true;
2956 } else if ((val = startswith(l, "exec-context-cpu-scheduling-priority="))) {
2957 r = safe_atoi(val, &c->cpu_sched_priority);
2958 if (r < 0)
2959 return r;
2960 c->cpu_sched_set = true;
2961 } else if ((val = startswith(l, "exec-context-cpu-scheduling-reset-on-fork="))) {
2962 r = parse_boolean(val);
2963 if (r < 0)
2964 return r;
2965 c->cpu_sched_reset_on_fork = r;
2966 c->cpu_sched_set = true;
2967 } else if ((val = startswith(l, "exec-context-cpu-affinity="))) {
2968 if (c->cpu_set.set)
2969 return -EINVAL; /* duplicated */
2970
2971 r = parse_cpu_set(val, &c->cpu_set);
2972 if (r < 0)
2973 return r;
2974 } else if ((val = startswith(l, "exec-context-numa-mask="))) {
2975 if (c->numa_policy.nodes.set)
2976 return -EINVAL; /* duplicated */
2977
2978 r = parse_cpu_set(val, &c->numa_policy.nodes);
2979 if (r < 0)
2980 return r;
2981 } else if ((val = startswith(l, "exec-context-numa-policy="))) {
2982 r = safe_atoi(val, &c->numa_policy.type);
2983 if (r < 0)
2984 return r;
2985 } else if ((val = startswith(l, "exec-context-cpu-affinity-from-numa="))) {
2986 r = parse_boolean(val);
2987 if (r < 0)
2988 return r;
2989 c->cpu_affinity_from_numa = r;
2990 } else if ((val = startswith(l, "exec-context-timer-slack-nsec="))) {
2991 r = deserialize_usec(val, (usec_t *)&c->timer_slack_nsec);
2992 if (r < 0)
2993 return r;
2994 } else if ((val = startswith(l, "exec-context-std-input="))) {
2995 c->std_input = exec_input_from_string(val);
2996 if (c->std_input < 0)
2997 return c->std_input;
2998 } else if ((val = startswith(l, "exec-context-std-output="))) {
2999 c->std_output = exec_output_from_string(val);
3000 if (c->std_output < 0)
3001 return c->std_output;
3002 } else if ((val = startswith(l, "exec-context-std-error="))) {
3003 c->std_error = exec_output_from_string(val);
3004 if (c->std_error < 0)
3005 return c->std_error;
3006 } else if ((val = startswith(l, "exec-context-stdio-as-fds="))) {
3007 r = parse_boolean(val);
3008 if (r < 0)
3009 return r;
3010 c->stdio_as_fds = r;
3011 } else if ((val = startswith(l, "exec-context-std-input-fd-name="))) {
3012 r = free_and_strdup(&c->stdio_fdname[STDIN_FILENO], val);
3013 if (r < 0)
3014 return r;
3015 } else if ((val = startswith(l, "exec-context-std-output-fd-name="))) {
3016 r = free_and_strdup(&c->stdio_fdname[STDOUT_FILENO], val);
3017 if (r < 0)
3018 return r;
3019 } else if ((val = startswith(l, "exec-context-std-error-fd-name="))) {
3020 r = free_and_strdup(&c->stdio_fdname[STDERR_FILENO], val);
3021 if (r < 0)
3022 return r;
3023 } else if ((val = startswith(l, "exec-context-std-input-file="))) {
3024 r = free_and_strdup(&c->stdio_file[STDIN_FILENO], val);
3025 if (r < 0)
3026 return r;
3027 } else if ((val = startswith(l, "exec-context-std-output-file="))) {
3028 r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], val);
3029 if (r < 0)
3030 return r;
3031 } else if ((val = startswith(l, "exec-context-std-output-file-append="))) {
3032 r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], val);
3033 if (r < 0)
3034 return r;
3035 } else if ((val = startswith(l, "exec-context-std-output-file-truncate="))) {
3036 r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], val);
3037 if (r < 0)
3038 return r;
3039 } else if ((val = startswith(l, "exec-context-std-error-file="))) {
3040 r = free_and_strdup(&c->stdio_file[STDERR_FILENO], val);
3041 if (r < 0)
3042 return r;
3043 } else if ((val = startswith(l, "exec-context-std-error-file-append="))) {
3044 r = free_and_strdup(&c->stdio_file[STDERR_FILENO], val);
3045 if (r < 0)
3046 return r;
3047 } else if ((val = startswith(l, "exec-context-std-error-file-truncate="))) {
3048 r = free_and_strdup(&c->stdio_file[STDERR_FILENO], val);
3049 if (r < 0)
3050 return r;
3051 } else if ((val = startswith(l, "exec-context-stdin-data="))) {
3052 if (c->stdin_data)
3053 return -EINVAL; /* duplicated */
3054
3055 r = unbase64mem(val, strlen(val), &c->stdin_data, &c->stdin_data_size);
3056 if (r < 0)
3057 return r;
3058 } else if ((val = startswith(l, "exec-context-tty-path="))) {
3059 r = free_and_strdup(&c->tty_path, val);
3060 if (r < 0)
3061 return r;
3062 } else if ((val = startswith(l, "exec-context-tty-reset="))) {
3063 r = parse_boolean(val);
3064 if (r < 0)
3065 return r;
3066 c->tty_reset = r;
3067 } else if ((val = startswith(l, "exec-context-tty-vhangup="))) {
3068 r = parse_boolean(val);
3069 if (r < 0)
3070 return r;
3071 c->tty_vhangup = r;
3072 } else if ((val = startswith(l, "exec-context-tty-vt-disallocate="))) {
3073 r = parse_boolean(val);
3074 if (r < 0)
3075 return r;
3076 c->tty_vt_disallocate = r;
3077 } else if ((val = startswith(l, "exec-context-tty-rows="))) {
3078 r = safe_atou(val, &c->tty_rows);
3079 if (r < 0)
3080 return r;
3081 } else if ((val = startswith(l, "exec-context-tty-columns="))) {
3082 r = safe_atou(val, &c->tty_cols);
3083 if (r < 0)
3084 return r;
3085 } else if ((val = startswith(l, "exec-context-syslog-priority="))) {
3086 r = safe_atoi(val, &c->syslog_priority);
3087 if (r < 0)
3088 return r;
3089 } else if ((val = startswith(l, "exec-context-syslog-level-prefix="))) {
3090 r = parse_boolean(val);
3091 if (r < 0)
3092 return r;
3093 c->syslog_level_prefix = r;
3094 } else if ((val = startswith(l, "exec-context-syslog-identifier="))) {
3095 r = free_and_strdup(&c->syslog_identifier, val);
3096 if (r < 0)
3097 return r;
3098 } else if ((val = startswith(l, "exec-context-log-level-max="))) {
3099 r = safe_atoi(val, &c->log_level_max);
3100 if (r < 0)
3101 return r;
3102 } else if ((val = startswith(l, "exec-context-log-ratelimit-interval-usec="))) {
3103 r = deserialize_usec(val, &c->log_ratelimit_interval_usec);
3104 if (r < 0)
3105 return r;
3106 } else if ((val = startswith(l, "exec-context-log-ratelimit-burst="))) {
3107 r = safe_atou(val, &c->log_ratelimit_burst);
3108 if (r < 0)
3109 return r;
3110 } else if ((val = startswith(l, "exec-context-log-filter-allowed-patterns="))) {
3111 r = set_put_strdup(&c->log_filter_allowed_patterns, val);
3112 if (r < 0)
3113 return r;
3114 } else if ((val = startswith(l, "exec-context-log-filter-denied-patterns="))) {
3115 r = set_put_strdup(&c->log_filter_denied_patterns, val);
3116 if (r < 0)
3117 return r;
3118 } else if ((val = startswith(l, "exec-context-log-extra-fields="))) {
3119 if (!GREEDY_REALLOC(c->log_extra_fields, c->n_log_extra_fields + 1))
3120 return log_oom_debug();
3121
3122 c->log_extra_fields[c->n_log_extra_fields++].iov_base = strdup(val);
3123 if (!c->log_extra_fields[c->n_log_extra_fields-1].iov_base)
3124 return log_oom_debug();
3125 } else if ((val = startswith(l, "exec-context-log-namespace="))) {
3126 r = free_and_strdup(&c->log_namespace, val);
3127 if (r < 0)
3128 return r;
3129 } else if ((val = startswith(l, "exec-context-secure-bits="))) {
3130 r = safe_atoi(val, &c->secure_bits);
3131 if (r < 0)
3132 return r;
3133 } else if ((val = startswith(l, "exec-context-capability-bounding-set="))) {
3134 r = safe_atou64(val, &c->capability_bounding_set);
3135 if (r < 0)
3136 return r;
3137 } else if ((val = startswith(l, "exec-context-capability-ambient-set="))) {
3138 r = safe_atou64(val, &c->capability_ambient_set);
3139 if (r < 0)
3140 return r;
3141 } else if ((val = startswith(l, "exec-context-user="))) {
3142 r = free_and_strdup(&c->user, val);
3143 if (r < 0)
3144 return r;
3145 } else if ((val = startswith(l, "exec-context-group="))) {
3146 r = free_and_strdup(&c->group, val);
3147 if (r < 0)
3148 return r;
3149 } else if ((val = startswith(l, "exec-context-dynamic-user="))) {
3150 r = parse_boolean(val);
3151 if (r < 0)
3152 return r;
3153 c->dynamic_user = r;
3154 } else if ((val = startswith(l, "exec-context-supplementary-groups="))) {
3155 r = deserialize_strv(val, &c->supplementary_groups);
3156 if (r < 0)
3157 return r;
3158 } else if ((val = startswith(l, "exec-context-set-login-environment="))) {
3159 r = safe_atoi(val, &c->set_login_environment);
3160 if (r < 0)
3161 return r;
3162 } else if ((val = startswith(l, "exec-context-pam-name="))) {
3163 r = free_and_strdup(&c->pam_name, val);
3164 if (r < 0)
3165 return r;
3166 } else if ((val = startswith(l, "exec-context-read-write-paths="))) {
3167 r = deserialize_strv(val, &c->read_write_paths);
3168 if (r < 0)
3169 return r;
3170 } else if ((val = startswith(l, "exec-context-read-only-paths="))) {
3171 r = deserialize_strv(val, &c->read_only_paths);
3172 if (r < 0)
3173 return r;
3174 } else if ((val = startswith(l, "exec-context-inaccessible-paths="))) {
3175 r = deserialize_strv(val, &c->inaccessible_paths);
3176 if (r < 0)
3177 return r;
3178 } else if ((val = startswith(l, "exec-context-exec-paths="))) {
3179 r = deserialize_strv(val, &c->exec_paths);
3180 if (r < 0)
3181 return r;
3182 } else if ((val = startswith(l, "exec-context-no-exec-paths="))) {
3183 r = deserialize_strv(val, &c->no_exec_paths);
3184 if (r < 0)
3185 return r;
3186 } else if ((val = startswith(l, "exec-context-exec-search-path="))) {
3187 r = deserialize_strv(val, &c->exec_search_path);
3188 if (r < 0)
3189 return r;
3190 } else if ((val = startswith(l, "exec-context-mount-propagation-flag="))) {
3191 r = safe_atolu(val, &c->mount_propagation_flag);
3192 if (r < 0)
3193 return r;
3194 } else if ((val = startswith(l, "exec-context-bind-read-only-path="))) {
3195 _cleanup_free_ char *source = NULL, *destination = NULL;
3196 bool rbind = true, ignore_enoent = false;
3197 char *s = NULL, *d = NULL;
3198
3199 r = extract_first_word(&val,
3200 &source,
3201 ":" WHITESPACE,
3202 EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNESCAPE_SEPARATORS);
3203 if (r < 0)
3204 return r;
3205 if (r == 0)
3206 return -EINVAL;
3207
3208 s = source;
3209 if (s[0] == '-') {
3210 ignore_enoent = true;
3211 s++;
3212 }
3213
3214 if (val && val[-1] == ':') {
3215 r = extract_first_word(&val,
3216 &destination,
3217 ":" WHITESPACE,
3218 EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNESCAPE_SEPARATORS);
3219 if (r < 0)
3220 return r;
3221 if (r == 0)
3222 continue;
3223
3224 d = destination;
3225
3226 if (val && val[-1] == ':') {
3227 _cleanup_free_ char *options = NULL;
3228
3229 r = extract_first_word(&val, &options, NULL, EXTRACT_UNQUOTE);
3230 if (r < 0)
3231 return -r;
3232
3233 if (isempty(options) || streq(options, "rbind"))
3234 rbind = true;
3235 else if (streq(options, "norbind"))
3236 rbind = false;
3237 else
3238 continue;
3239 }
3240 } else
3241 d = s;
3242
3243 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
3244 &(BindMount) {
3245 .source = s,
3246 .destination = d,
3247 .read_only = true,
3248 .recursive = rbind,
3249 .ignore_enoent = ignore_enoent,
3250 });
3251 if (r < 0)
3252 return log_oom_debug();
3253 } else if ((val = startswith(l, "exec-context-bind-path="))) {
3254 _cleanup_free_ char *source = NULL, *destination = NULL;
3255 bool rbind = true, ignore_enoent = false;
3256 char *s = NULL, *d = NULL;
3257
3258 r = extract_first_word(&val,
3259 &source,
3260 ":" WHITESPACE,
3261 EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNESCAPE_SEPARATORS);
3262 if (r < 0)
3263 return r;
3264 if (r == 0)
3265 return -EINVAL;
3266
3267 s = source;
3268 if (s[0] == '-') {
3269 ignore_enoent = true;
3270 s++;
3271 }
3272
3273 if (val && val[-1] == ':') {
3274 r = extract_first_word(&val,
3275 &destination,
3276 ":" WHITESPACE,
3277 EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNESCAPE_SEPARATORS);
3278 if (r < 0)
3279 return r;
3280 if (r == 0)
3281 continue;
3282
3283 d = destination;
3284
3285 if (val && val[-1] == ':') {
3286 _cleanup_free_ char *options = NULL;
3287
3288 r = extract_first_word(&val, &options, NULL, EXTRACT_UNQUOTE);
3289 if (r < 0)
3290 return -r;
3291
3292 if (isempty(options) || streq(options, "rbind"))
3293 rbind = true;
3294 else if (streq(options, "norbind"))
3295 rbind = false;
3296 else
3297 continue;
3298 }
3299 } else
3300 d = s;
3301
3302 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
3303 &(BindMount) {
3304 .source = s,
3305 .destination = d,
3306 .read_only = false,
3307 .recursive = rbind,
3308 .ignore_enoent = ignore_enoent,
3309 });
3310 if (r < 0)
3311 return log_oom_debug();
3312 } else if ((val = startswith(l, "exec-context-temporary-filesystems="))) {
3313 _cleanup_free_ char *path = NULL, *options = NULL;
3314
3315 r = extract_many_words(&val, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &path, &options, NULL);
3316 if (r < 0)
3317 return r;
3318 if (r < 1)
3319 continue;
3320
3321 r = temporary_filesystem_add(&c->temporary_filesystems, &c->n_temporary_filesystems, path, options);
3322 if (r < 0)
3323 return log_oom_debug();
3324 } else if ((val = startswith(l, "exec-context-utmp-id="))) {
3325 r = free_and_strdup(&c->utmp_id, val);
3326 if (r < 0)
3327 return r;
3328 } else if ((val = startswith(l, "exec-context-utmp-mode="))) {
3329 c->utmp_mode = exec_utmp_mode_from_string(val);
3330 if (c->utmp_mode < 0)
3331 return c->utmp_mode;
3332 } else if ((val = startswith(l, "exec-context-no-new-privileges="))) {
3333 r = parse_boolean(val);
3334 if (r < 0)
3335 return r;
3336 c->no_new_privileges = r;
3337 } else if ((val = startswith(l, "exec-context-selinux-context-ignore="))) {
3338 r = parse_boolean(val);
3339 if (r < 0)
3340 return r;
3341 c->selinux_context_ignore = r;
3342 } else if ((val = startswith(l, "exec-context-apparmor-profile-ignore="))) {
3343 r = parse_boolean(val);
3344 if (r < 0)
3345 return r;
3346 c->apparmor_profile_ignore = r;
3347 } else if ((val = startswith(l, "exec-context-smack-process-label-ignore="))) {
3348 r = parse_boolean(val);
3349 if (r < 0)
3350 return r;
3351 c->smack_process_label_ignore = r;
3352 } else if ((val = startswith(l, "exec-context-selinux-context="))) {
3353 if (val[0] == '-') {
3354 c->selinux_context_ignore = true;
3355 val++;
3356 }
3357
3358 r = free_and_strdup(&c->selinux_context, val);
3359 if (r < 0)
3360 return r;
3361 } else if ((val = startswith(l, "exec-context-apparmor-profile="))) {
3362 if (val[0] == '-') {
3363 c->apparmor_profile_ignore = true;
3364 val++;
3365 }
3366
3367 r = free_and_strdup(&c->apparmor_profile, val);
3368 if (r < 0)
3369 return r;
3370 } else if ((val = startswith(l, "exec-context-smack-process-label="))) {
3371 if (val[0] == '-') {
3372 c->smack_process_label_ignore = true;
3373 val++;
3374 }
3375
3376 r = free_and_strdup(&c->smack_process_label, val);
3377 if (r < 0)
3378 return r;
3379 } else if ((val = startswith(l, "exec-context-personality="))) {
3380 c->personality = personality_from_string(val);
3381 if (c->personality == PERSONALITY_INVALID)
3382 return -EINVAL;
3383 } else if ((val = startswith(l, "exec-context-lock-personality="))) {
3384 r = parse_boolean(val);
3385 if (r < 0)
3386 return r;
3387 c->lock_personality = r;
3388 #if HAVE_SECCOMP
3389 } else if ((val = startswith(l, "exec-context-syscall-filter="))) {
3390 _cleanup_free_ char *s_id = NULL, *s_errno_num = NULL;
3391 int id, errno_num;
3392
3393 r = extract_many_words(&val, NULL, 0, &s_id, &s_errno_num, NULL);
3394 if (r < 0)
3395 return r;
3396 if (r != 2)
3397 continue;
3398
3399 r = safe_atoi(s_id, &id);
3400 if (r < 0)
3401 return r;
3402
3403 r = safe_atoi(s_errno_num, &errno_num);
3404 if (r < 0)
3405 return r;
3406
3407 r = hashmap_ensure_put(&c->syscall_filter, NULL, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num));
3408 if (r < 0)
3409 return r;
3410 } else if ((val = startswith(l, "exec-context-syscall-archs="))) {
3411 unsigned int id;
3412
3413 r = safe_atou(val, &id);
3414 if (r < 0)
3415 return r;
3416
3417 r = set_ensure_put(&c->syscall_archs, NULL, UINT_TO_PTR(id + 1));
3418 if (r < 0)
3419 return r;
3420 } else if ((val = startswith(l, "exec-context-syscall-errno="))) {
3421 r = safe_atoi(val, &c->syscall_errno);
3422 if (r < 0)
3423 return r;
3424 } else if ((val = startswith(l, "exec-context-syscall-allow-list="))) {
3425 r = parse_boolean(val);
3426 if (r < 0)
3427 return r;
3428 c->syscall_allow_list = r;
3429 } else if ((val = startswith(l, "exec-context-syscall-log="))) {
3430 _cleanup_free_ char *s_id = NULL, *s_errno_num = NULL;
3431 int id, errno_num;
3432
3433 r = extract_many_words(&val, " ", 0, &s_id, &s_errno_num, NULL);
3434 if (r < 0)
3435 return r;
3436 if (r != 2)
3437 continue;
3438
3439 r = safe_atoi(s_id, &id);
3440 if (r < 0)
3441 return r;
3442
3443 r = safe_atoi(s_errno_num, &errno_num);
3444 if (r < 0)
3445 return r;
3446
3447 r = hashmap_ensure_put(&c->syscall_log, NULL, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num));
3448 if (r < 0)
3449 return r;
3450 } else if ((val = startswith(l, "exec-context-syscall-log-allow-list="))) {
3451 r = parse_boolean(val);
3452 if (r < 0)
3453 return r;
3454 c->syscall_log_allow_list = r;
3455 #endif
3456 } else if ((val = startswith(l, "exec-context-restrict-namespaces="))) {
3457 r = safe_atolu(val, &c->restrict_namespaces);
3458 if (r < 0)
3459 return r;
3460 } else if ((val = startswith(l, "exec-context-restrict-filesystems="))) {
3461 r = set_ensure_allocated(&c->restrict_filesystems, &string_hash_ops);
3462 if (r < 0)
3463 return r;
3464
3465 r = set_put_strdup(&c->restrict_filesystems, val);
3466 if (r < 0)
3467 return r;
3468 } else if ((val = startswith(l, "exec-context-restrict-filesystems-allow-list="))) {
3469 r = parse_boolean(val);
3470 if (r < 0)
3471 return r;
3472 c->restrict_filesystems_allow_list = r;
3473 } else if ((val = startswith(l, "exec-context-address-families="))) {
3474 int af;
3475
3476 r = safe_atoi(val, &af);
3477 if (r < 0)
3478 return r;
3479
3480 r = set_ensure_put(&c->address_families, NULL, INT_TO_PTR(af));
3481 if (r < 0)
3482 return r;
3483 } else if ((val = startswith(l, "exec-context-address-families-allow-list="))) {
3484 r = parse_boolean(val);
3485 if (r < 0)
3486 return r;
3487 c->address_families_allow_list = r;
3488 } else if ((val = startswith(l, "exec-context-network-namespace-path="))) {
3489 r = free_and_strdup(&c->network_namespace_path, val);
3490 if (r < 0)
3491 return r;
3492 } else if ((val = startswith(l, "exec-context-ipc-namespace-path="))) {
3493 r = free_and_strdup(&c->ipc_namespace_path, val);
3494 if (r < 0)
3495 return r;
3496 } else if ((val = startswith(l, "exec-context-mount-image="))) {
3497 _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
3498 _cleanup_free_ char *source = NULL, *destination = NULL;
3499 bool permissive = false;
3500 char *s;
3501
3502 r = extract_many_words(&val,
3503 NULL,
3504 EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
3505 &source,
3506 &destination,
3507 NULL);
3508 if (r < 0)
3509 return r;
3510 if (r == 0)
3511 return -EINVAL;
3512
3513 s = source;
3514 if (s[0] == '-') {
3515 permissive = true;
3516 s++;
3517 }
3518
3519 if (isempty(destination))
3520 continue;
3521
3522 for (;;) {
3523 _cleanup_free_ char *tuple = NULL, *partition = NULL, *opts = NULL;
3524 PartitionDesignator partition_designator;
3525 MountOptions *o = NULL;
3526 const char *p;
3527
3528 r = extract_first_word(&val, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
3529 if (r < 0)
3530 return r;
3531 if (r == 0)
3532 break;
3533
3534 p = tuple;
3535 r = extract_many_words(&p,
3536 ":",
3537 EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
3538 &partition,
3539 &opts,
3540 NULL);
3541 if (r < 0)
3542 return r;
3543 if (r == 0)
3544 continue;
3545 if (r == 1) {
3546 o = new(MountOptions, 1);
3547 if (!o)
3548 return log_oom_debug();
3549 *o = (MountOptions) {
3550 .partition_designator = PARTITION_ROOT,
3551 .options = TAKE_PTR(partition),
3552 };
3553 LIST_APPEND(mount_options, options, o);
3554
3555 continue;
3556 }
3557
3558 partition_designator = partition_designator_from_string(partition);
3559 if (partition_designator < 0)
3560 continue;
3561
3562 o = new(MountOptions, 1);
3563 if (!o)
3564 return log_oom_debug();
3565 *o = (MountOptions) {
3566 .partition_designator = partition_designator,
3567 .options = TAKE_PTR(opts),
3568 };
3569 LIST_APPEND(mount_options, options, o);
3570 }
3571
3572 r = mount_image_add(&c->mount_images, &c->n_mount_images,
3573 &(MountImage) {
3574 .source = s,
3575 .destination = destination,
3576 .mount_options = options,
3577 .ignore_enoent = permissive,
3578 .type = MOUNT_IMAGE_DISCRETE,
3579 });
3580 if (r < 0)
3581 return log_oom_debug();
3582 } else if ((val = startswith(l, "exec-context-extension-image="))) {
3583 _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
3584 _cleanup_free_ char *source = NULL;
3585 bool permissive = false;
3586 char *s;
3587
3588 r = extract_first_word(&val,
3589 &source,
3590 NULL,
3591 EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
3592 if (r < 0)
3593 return r;
3594 if (r == 0)
3595 return -EINVAL;
3596
3597 s = source;
3598 if (s[0] == '-') {
3599 permissive = true;
3600 s++;
3601 }
3602
3603 for (;;) {
3604 _cleanup_free_ char *tuple = NULL, *partition = NULL, *opts = NULL;
3605 PartitionDesignator partition_designator;
3606 MountOptions *o = NULL;
3607 const char *p;
3608
3609 r = extract_first_word(&val, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
3610 if (r < 0)
3611 return r;
3612 if (r == 0)
3613 break;
3614
3615 p = tuple;
3616 r = extract_many_words(&p,
3617 ":",
3618 EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
3619 &partition,
3620 &opts,
3621 NULL);
3622 if (r < 0)
3623 return r;
3624 if (r == 0)
3625 continue;
3626 if (r == 1) {
3627 o = new(MountOptions, 1);
3628 if (!o)
3629 return log_oom_debug();
3630 *o = (MountOptions) {
3631 .partition_designator = PARTITION_ROOT,
3632 .options = TAKE_PTR(partition),
3633 };
3634 LIST_APPEND(mount_options, options, o);
3635
3636 continue;
3637 }
3638
3639 partition_designator = partition_designator_from_string(partition);
3640 if (partition_designator < 0)
3641 continue;
3642
3643 o = new(MountOptions, 1);
3644 if (!o)
3645 return log_oom_debug();
3646 *o = (MountOptions) {
3647 .partition_designator = partition_designator,
3648 .options = TAKE_PTR(opts),
3649 };
3650 LIST_APPEND(mount_options, options, o);
3651 }
3652
3653 r = mount_image_add(&c->extension_images, &c->n_extension_images,
3654 &(MountImage) {
3655 .source = s,
3656 .mount_options = options,
3657 .ignore_enoent = permissive,
3658 .type = MOUNT_IMAGE_EXTENSION,
3659 });
3660 if (r < 0)
3661 return log_oom_debug();
3662 } else if ((val = startswith(l, "exec-context-extension-directories="))) {
3663 r = deserialize_strv(val, &c->extension_directories);
3664 if (r < 0)
3665 return r;
3666 } else if ((val = startswith(l, "exec-context-set-credentials="))) {
3667 _cleanup_(exec_set_credential_freep) ExecSetCredential *sc = NULL;
3668 _cleanup_free_ char *id = NULL, *encrypted = NULL, *data = NULL;
3669
3670 r = extract_many_words(&val, " ", 0, &id, &encrypted, &data, NULL);
3671 if (r < 0)
3672 return r;
3673 if (r != 3)
3674 return -EINVAL;
3675
3676 r = parse_boolean(encrypted);
3677 if (r < 0)
3678 return r;
3679
3680 sc = new(ExecSetCredential, 1);
3681 if (!sc)
3682 return -ENOMEM;
3683
3684 *sc = (ExecSetCredential) {
3685 .id = TAKE_PTR(id),
3686 .encrypted = r,
3687 };
3688
3689 r = unbase64mem(data, strlen(data), &sc->data, &sc->size);
3690 if (r < 0)
3691 return r;
3692
3693 r = hashmap_ensure_put(&c->set_credentials, &exec_set_credential_hash_ops, sc->id, sc);
3694 if (r < 0)
3695 return r;
3696
3697 TAKE_PTR(sc);
3698 } else if ((val = startswith(l, "exec-context-load-credentials="))) {
3699 _cleanup_(exec_load_credential_freep) ExecLoadCredential *lc = NULL;
3700 _cleanup_free_ char *id = NULL, *encrypted = NULL, *path = NULL;
3701
3702 r = extract_many_words(&val, " ", 0, &id, &encrypted, &path, NULL);
3703 if (r < 0)
3704 return r;
3705 if (r != 3)
3706 return -EINVAL;
3707
3708 r = parse_boolean(encrypted);
3709 if (r < 0)
3710 return r;
3711
3712 lc = new(ExecLoadCredential, 1);
3713 if (!lc)
3714 return -ENOMEM;
3715
3716 *lc = (ExecLoadCredential) {
3717 .id = TAKE_PTR(id),
3718 .path = TAKE_PTR(path),
3719 .encrypted = r,
3720 };
3721
3722 r = hashmap_ensure_put(&c->load_credentials, &exec_load_credential_hash_ops, lc->id, lc);
3723 if (r < 0)
3724 return r;
3725
3726 TAKE_PTR(lc);
3727 } else if ((val = startswith(l, "exec-context-import-credentials="))) {
3728 r = set_ensure_allocated(&c->import_credentials, &string_hash_ops);
3729 if (r < 0)
3730 return r;
3731
3732 r = set_put_strdup(&c->import_credentials, val);
3733 if (r < 0)
3734 return r;
3735 } else if ((val = startswith(l, "exec-context-root-image-policy="))) {
3736 if (c->root_image_policy)
3737 return -EINVAL; /* duplicated */
3738
3739 r = image_policy_from_string(val, &c->root_image_policy);
3740 if (r < 0)
3741 return r;
3742 } else if ((val = startswith(l, "exec-context-mount-image-policy="))) {
3743 if (c->mount_image_policy)
3744 return -EINVAL; /* duplicated */
3745
3746 r = image_policy_from_string(val, &c->mount_image_policy);
3747 if (r < 0)
3748 return r;
3749 } else if ((val = startswith(l, "exec-context-extension-image-policy="))) {
3750 if (c->extension_image_policy)
3751 return -EINVAL; /* duplicated */
3752
3753 r = image_policy_from_string(val, &c->extension_image_policy);
3754 if (r < 0)
3755 return r;
3756 } else
3757 log_warning("Failed to parse serialized line, ignoring: %s", l);
3758 }
3759
3760 return 0;
3761 }
3762
3763 static int exec_command_serialize(const ExecCommand *c, FILE *f) {
3764 int r;
3765
3766 assert(c);
3767 assert(f);
3768
3769 r = serialize_item(f, "exec-command-path", c->path);
3770 if (r < 0)
3771 return r;
3772
3773 r = serialize_strv(f, "exec-command-argv", c->argv);
3774 if (r < 0)
3775 return r;
3776
3777 r = serialize_item_format(f, "exec-command-flags", "%d", (int) c->flags);
3778 if (r < 0)
3779 return r;
3780
3781 fputc('\n', f); /* End marker */
3782
3783 return 0;
3784 }
3785
3786 static int exec_command_deserialize(ExecCommand *c, FILE *f) {
3787 int r;
3788
3789 assert(c);
3790 assert(f);
3791
3792 for (;;) {
3793 _cleanup_free_ char *l = NULL;
3794 const char *val;
3795
3796 r = deserialize_read_line(f, &l);
3797 if (r < 0)
3798 return r;
3799 if (r == 0) /* eof or end marker */
3800 break;
3801
3802 if ((val = startswith(l, "exec-command-path="))) {
3803 r = free_and_strdup(&c->path, val);
3804 if (r < 0)
3805 return r;
3806 } else if ((val = startswith(l, "exec-command-argv="))) {
3807 r = deserialize_strv(val, &c->argv);
3808 if (r < 0)
3809 return r;
3810 } else if ((val = startswith(l, "exec-command-flags="))) {
3811 r = safe_atoi(val, &c->flags);
3812 if (r < 0)
3813 return r;
3814 } else
3815 log_warning("Failed to parse serialized line, ignoring: %s", l);
3816
3817 }
3818
3819 return 0;
3820 }
3821
3822 int exec_serialize_invocation(
3823 FILE *f,
3824 FDSet *fds,
3825 const ExecContext *ctx,
3826 const ExecCommand *cmd,
3827 const ExecParameters *p,
3828 const ExecRuntime *rt,
3829 const CGroupContext *cg) {
3830
3831 int r;
3832
3833 assert(f);
3834 assert(fds);
3835
3836 r = exec_context_serialize(ctx, f);
3837 if (r < 0)
3838 return log_debug_errno(r, "Failed to serialize context: %m");
3839
3840 r = exec_command_serialize(cmd, f);
3841 if (r < 0)
3842 return log_debug_errno(r, "Failed to serialize command: %m");
3843
3844 r = exec_parameters_serialize(p, ctx, f, fds);
3845 if (r < 0)
3846 return log_debug_errno(r, "Failed to serialize parameters: %m");
3847
3848 r = exec_runtime_serialize(rt, f, fds);
3849 if (r < 0)
3850 return log_debug_errno(r, "Failed to serialize runtime: %m");
3851
3852 r = exec_cgroup_context_serialize(cg, f);
3853 if (r < 0)
3854 return log_debug_errno(r, "Failed to serialize cgroup context: %m");
3855
3856 return 0;
3857 }
3858
3859 int exec_deserialize_invocation(
3860 FILE *f,
3861 FDSet *fds,
3862 ExecContext *ctx,
3863 ExecCommand *cmd,
3864 ExecParameters *p,
3865 ExecRuntime *rt,
3866 CGroupContext *cg) {
3867
3868 int r;
3869
3870 assert(f);
3871 assert(fds);
3872
3873 r = exec_context_deserialize(ctx, f);
3874 if (r < 0)
3875 return log_debug_errno(r, "Failed to deserialize context: %m");
3876
3877 r = exec_command_deserialize(cmd, f);
3878 if (r < 0)
3879 return log_debug_errno(r, "Failed to deserialize command: %m");
3880
3881 r = exec_parameters_deserialize(p, f, fds);
3882 if (r < 0)
3883 return log_debug_errno(r, "Failed to deserialize parameters: %m");
3884
3885 r = exec_runtime_deserialize(rt, f, fds);
3886 if (r < 0)
3887 return log_debug_errno(r, "Failed to deserialize runtime: %m");
3888
3889 r = exec_cgroup_context_deserialize(cg, f);
3890 if (r < 0)
3891 return log_debug_errno(r, "Failed to deserialize cgroup context: %m");
3892
3893 return 0;
3894 }