]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/execute-serialize.c
ccfc00c6e950f6dd49af6174bc3607d3f839acc6
[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, ":" WHITESPACE);
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, ":" WHITESPACE);
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 /* This is also passed to executor as an argument. So, the information should be redundant in general.
2157 * But, let's keep this as is for consistency with other elements of ExecContext. See exec_spawn(). */
2158 r = serialize_item_format(f, "exec-context-log-level-max", "%d", c->log_level_max);
2159 if (r < 0)
2160 return r;
2161
2162 if (c->log_ratelimit_interval_usec > 0) {
2163 r = serialize_usec(f, "exec-context-log-ratelimit-interval-usec", c->log_ratelimit_interval_usec);
2164 if (r < 0)
2165 return r;
2166 }
2167
2168 if (c->log_ratelimit_burst > 0) {
2169 r = serialize_item_format(f, "exec-context-log-ratelimit-burst", "%u", c->log_ratelimit_burst);
2170 if (r < 0)
2171 return r;
2172 }
2173
2174 r = serialize_string_set(f, "exec-context-log-filter-allowed-patterns", c->log_filter_allowed_patterns);
2175 if (r < 0)
2176 return r;
2177
2178 r = serialize_string_set(f, "exec-context-log-filter-denied-patterns", c->log_filter_denied_patterns);
2179 if (r < 0)
2180 return r;
2181
2182 FOREACH_ARRAY(field, c->log_extra_fields, c->n_log_extra_fields) {
2183 r = serialize_item(f, "exec-context-log-extra-fields", field->iov_base);
2184 if (r < 0)
2185 return r;
2186 }
2187
2188 r = serialize_item(f, "exec-context-log-namespace", c->log_namespace);
2189 if (r < 0)
2190 return r;
2191
2192 if (c->secure_bits != 0) {
2193 r = serialize_item_format(f, "exec-context-secure-bits", "%d", c->secure_bits);
2194 if (r < 0)
2195 return r;
2196 }
2197
2198 if (c->capability_bounding_set != CAP_MASK_UNSET) {
2199 r = serialize_item_format(f, "exec-context-capability-bounding-set", "%" PRIu64, c->capability_bounding_set);
2200 if (r < 0)
2201 return r;
2202 }
2203
2204 if (c->capability_ambient_set != 0) {
2205 r = serialize_item_format(f, "exec-context-capability-ambient-set", "%" PRIu64, c->capability_ambient_set);
2206 if (r < 0)
2207 return r;
2208 }
2209
2210 if (c->user) {
2211 r = serialize_item(f, "exec-context-user", c->user);
2212 if (r < 0)
2213 return r;
2214 }
2215
2216 r = serialize_item(f, "exec-context-group", c->group);
2217 if (r < 0)
2218 return r;
2219
2220 r = serialize_bool_elide(f, "exec-context-dynamic-user", c->dynamic_user);
2221 if (r < 0)
2222 return r;
2223
2224 r = serialize_strv(f, "exec-context-supplementary-groups", c->supplementary_groups);
2225 if (r < 0)
2226 return r;
2227
2228 r = serialize_item_tristate(f, "exec-context-set-login-environment", c->set_login_environment);
2229 if (r < 0)
2230 return r;
2231
2232 r = serialize_item(f, "exec-context-pam-name", c->pam_name);
2233 if (r < 0)
2234 return r;
2235
2236 r = serialize_strv(f, "exec-context-read-write-paths", c->read_write_paths);
2237 if (r < 0)
2238 return r;
2239
2240 r = serialize_strv(f, "exec-context-read-only-paths", c->read_only_paths);
2241 if (r < 0)
2242 return r;
2243
2244 r = serialize_strv(f, "exec-context-inaccessible-paths", c->inaccessible_paths);
2245 if (r < 0)
2246 return r;
2247
2248 r = serialize_strv(f, "exec-context-exec-paths", c->exec_paths);
2249 if (r < 0)
2250 return r;
2251
2252 r = serialize_strv(f, "exec-context-no-exec-paths", c->no_exec_paths);
2253 if (r < 0)
2254 return r;
2255
2256 r = serialize_strv(f, "exec-context-exec-search-path", c->exec_search_path);
2257 if (r < 0)
2258 return r;
2259
2260 r = serialize_item_format(f, "exec-context-mount-propagation-flag", "%lu", c->mount_propagation_flag);
2261 if (r < 0)
2262 return r;
2263
2264 FOREACH_ARRAY(mount, c->bind_mounts, c->n_bind_mounts) {
2265 _cleanup_free_ char *src_escaped = NULL, *dst_escaped = NULL;
2266
2267 src_escaped = shell_escape(mount->source, ":" WHITESPACE);
2268 if (!src_escaped)
2269 return log_oom_debug();
2270
2271 dst_escaped = shell_escape(mount->destination, ":" WHITESPACE);
2272 if (!dst_escaped)
2273 return log_oom_debug();
2274
2275 r = serialize_item_format(f,
2276 mount->read_only ? "exec-context-bind-read-only-path" : "exec-context-bind-path",
2277 "%s%s:%s:%s",
2278 mount->ignore_enoent ? "-" : "",
2279 src_escaped,
2280 dst_escaped,
2281 mount->recursive ? "rbind" : "norbind");
2282 if (r < 0)
2283 return r;
2284 }
2285
2286 FOREACH_ARRAY(tmpfs, c->temporary_filesystems, c->n_temporary_filesystems) {
2287 _cleanup_free_ char *escaped = NULL;
2288
2289 if (!isempty(tmpfs->options)) {
2290 escaped = shell_escape(tmpfs->options, ":");
2291 if (!escaped)
2292 return log_oom_debug();
2293 }
2294
2295 r = serialize_item_format(f, "exec-context-temporary-filesystems", "%s%s%s",
2296 tmpfs->path,
2297 isempty(escaped) ? "" : ":",
2298 strempty(escaped));
2299 if (r < 0)
2300 return r;
2301 }
2302
2303 r = serialize_item(f, "exec-context-utmp-id", c->utmp_id);
2304 if (r < 0)
2305 return r;
2306
2307 r = serialize_item(f, "exec-context-utmp-mode", exec_utmp_mode_to_string(c->utmp_mode));
2308 if (r < 0)
2309 return r;
2310
2311 r = serialize_bool_elide(f, "exec-context-no-new-privileges", c->no_new_privileges);
2312 if (r < 0)
2313 return r;
2314
2315 r = serialize_bool_elide(f, "exec-context-selinux-context-ignore", c->selinux_context_ignore);
2316 if (r < 0)
2317 return r;
2318
2319 r = serialize_bool_elide(f, "exec-context-apparmor-profile-ignore", c->apparmor_profile_ignore);
2320 if (r < 0)
2321 return r;
2322
2323 r = serialize_bool_elide(f, "exec-context-smack-process-label-ignore", c->smack_process_label_ignore);
2324 if (r < 0)
2325 return r;
2326
2327 if (c->selinux_context) {
2328 r = serialize_item_format(f, "exec-context-selinux-context",
2329 "%s%s",
2330 c->selinux_context_ignore ? "-" : "",
2331 c->selinux_context);
2332 if (r < 0)
2333 return r;
2334 }
2335
2336 if (c->apparmor_profile) {
2337 r = serialize_item_format(f, "exec-context-apparmor-profile",
2338 "%s%s",
2339 c->apparmor_profile_ignore ? "-" : "",
2340 c->apparmor_profile);
2341 if (r < 0)
2342 return r;
2343 }
2344
2345 if (c->smack_process_label) {
2346 r = serialize_item_format(f, "exec-context-smack-process-label",
2347 "%s%s",
2348 c->smack_process_label_ignore ? "-" : "",
2349 c->smack_process_label);
2350 if (r < 0)
2351 return r;
2352 }
2353
2354 if (c->personality != PERSONALITY_INVALID) {
2355 r = serialize_item(f, "exec-context-personality", personality_to_string(c->personality));
2356 if (r < 0)
2357 return r;
2358 }
2359
2360 r = serialize_bool_elide(f, "exec-context-lock-personality", c->lock_personality);
2361 if (r < 0)
2362 return r;
2363
2364 #if HAVE_SECCOMP
2365 if (!hashmap_isempty(c->syscall_filter)) {
2366 void *errno_num, *id;
2367 HASHMAP_FOREACH_KEY(errno_num, id, c->syscall_filter) {
2368 r = serialize_item_format(f, "exec-context-syscall-filter", "%d %d", PTR_TO_INT(id) - 1, PTR_TO_INT(errno_num));
2369 if (r < 0)
2370 return r;
2371 }
2372 }
2373
2374 if (!set_isempty(c->syscall_archs)) {
2375 void *id;
2376 SET_FOREACH(id, c->syscall_archs) {
2377 r = serialize_item_format(f, "exec-context-syscall-archs", "%u", PTR_TO_UINT(id) - 1);
2378 if (r < 0)
2379 return r;
2380 }
2381 }
2382
2383 if (c->syscall_errno > 0) {
2384 r = serialize_item_format(f, "exec-context-syscall-errno", "%d", c->syscall_errno);
2385 if (r < 0)
2386 return r;
2387 }
2388
2389 r = serialize_bool_elide(f, "exec-context-syscall-allow-list", c->syscall_allow_list);
2390 if (r < 0)
2391 return r;
2392
2393 if (!hashmap_isempty(c->syscall_log)) {
2394 void *errno_num, *id;
2395 HASHMAP_FOREACH_KEY(errno_num, id, c->syscall_log) {
2396 r = serialize_item_format(f, "exec-context-syscall-log", "%d %d", PTR_TO_INT(id) - 1, PTR_TO_INT(errno_num));
2397 if (r < 0)
2398 return r;
2399 }
2400 }
2401
2402 r = serialize_bool_elide(f, "exec-context-syscall-log-allow-list", c->syscall_log_allow_list);
2403 if (r < 0)
2404 return r;
2405 #endif
2406
2407 if (c->restrict_namespaces != NAMESPACE_FLAGS_INITIAL) {
2408 r = serialize_item_format(f, "exec-context-restrict-namespaces", "%lu", c->restrict_namespaces);
2409 if (r < 0)
2410 return r;
2411 }
2412
2413 #if HAVE_LIBBPF
2414 if (exec_context_restrict_filesystems_set(c)) {
2415 char *fs;
2416 SET_FOREACH(fs, c->restrict_filesystems) {
2417 r = serialize_item(f, "exec-context-restrict-filesystems", fs);
2418 if (r < 0)
2419 return r;
2420 }
2421 }
2422
2423 r = serialize_bool_elide(f, "exec-context-restrict-filesystems-allow-list", c->restrict_filesystems_allow_list);
2424 if (r < 0)
2425 return r;
2426 #endif
2427
2428 if (!set_isempty(c->address_families)) {
2429 void *afp;
2430
2431 SET_FOREACH(afp, c->address_families) {
2432 int af = PTR_TO_INT(afp);
2433
2434 if (af <= 0 || af >= af_max())
2435 continue;
2436
2437 r = serialize_item_format(f, "exec-context-address-families", "%d", af);
2438 if (r < 0)
2439 return r;
2440 }
2441 }
2442
2443 r = serialize_bool_elide(f, "exec-context-address-families-allow-list", c->address_families_allow_list);
2444 if (r < 0)
2445 return r;
2446
2447 r = serialize_item(f, "exec-context-network-namespace-path", c->network_namespace_path);
2448 if (r < 0)
2449 return r;
2450
2451 r = serialize_item(f, "exec-context-ipc-namespace-path", c->ipc_namespace_path);
2452 if (r < 0)
2453 return r;
2454
2455 FOREACH_ARRAY(mount, c->mount_images, c->n_mount_images) {
2456 _cleanup_free_ char *s = NULL, *source_escaped = NULL, *dest_escaped = NULL;
2457
2458 source_escaped = shell_escape(mount->source, WHITESPACE);
2459 if (!source_escaped)
2460 return log_oom_debug();
2461
2462 dest_escaped = shell_escape(mount->destination, WHITESPACE);
2463 if (!dest_escaped)
2464 return log_oom_debug();
2465
2466 s = strjoin(mount->ignore_enoent ? "-" : "",
2467 source_escaped,
2468 " ",
2469 dest_escaped);
2470 if (!s)
2471 return log_oom_debug();
2472
2473 LIST_FOREACH(mount_options, o, mount->mount_options) {
2474 _cleanup_free_ char *escaped = NULL;
2475
2476 if (isempty(o->options))
2477 continue;
2478
2479 escaped = shell_escape(o->options, ":");
2480 if (!escaped)
2481 return log_oom_debug();
2482
2483 if (!strextend(&s,
2484 " ",
2485 partition_designator_to_string(o->partition_designator),
2486 ":",
2487 escaped))
2488 return log_oom_debug();
2489 }
2490
2491 r = serialize_item(f, "exec-context-mount-image", s);
2492 if (r < 0)
2493 return r;
2494 }
2495
2496 FOREACH_ARRAY(mount, c->extension_images, c->n_extension_images) {
2497 _cleanup_free_ char *s = NULL, *source_escaped = NULL;
2498
2499 source_escaped = shell_escape(mount->source, ":" WHITESPACE);
2500 if (!source_escaped)
2501 return log_oom_debug();
2502
2503 s = strjoin(mount->ignore_enoent ? "-" : "",
2504 source_escaped);
2505 if (!s)
2506 return log_oom_debug();
2507
2508 LIST_FOREACH(mount_options, o, mount->mount_options) {
2509 _cleanup_free_ char *escaped = NULL;
2510
2511 if (isempty(o->options))
2512 continue;
2513
2514 escaped = shell_escape(o->options, ":");
2515 if (!escaped)
2516 return log_oom_debug();
2517
2518 if (!strextend(&s,
2519 " ",
2520 partition_designator_to_string(o->partition_designator),
2521 ":",
2522 escaped))
2523 return log_oom_debug();
2524 }
2525
2526 r = serialize_item(f, "exec-context-extension-image", s);
2527 if (r < 0)
2528 return r;
2529 }
2530
2531 r = serialize_strv(f, "exec-context-extension-directories", c->extension_directories);
2532 if (r < 0)
2533 return r;
2534
2535 ExecSetCredential *sc;
2536 HASHMAP_FOREACH(sc, c->set_credentials) {
2537 _cleanup_free_ char *data = NULL;
2538
2539 if (base64mem(sc->data, sc->size, &data) < 0)
2540 return log_oom_debug();
2541
2542 r = serialize_item_format(f, "exec-context-set-credentials", "%s %s %s", sc->id, yes_no(sc->encrypted), data);
2543 if (r < 0)
2544 return r;
2545 }
2546
2547 ExecLoadCredential *lc;
2548 HASHMAP_FOREACH(lc, c->load_credentials) {
2549 r = serialize_item_format(f, "exec-context-load-credentials", "%s %s %s", lc->id, yes_no(lc->encrypted), lc->path);
2550 if (r < 0)
2551 return r;
2552 }
2553
2554 if (!set_isempty(c->import_credentials)) {
2555 char *ic;
2556 SET_FOREACH(ic, c->import_credentials) {
2557 r = serialize_item(f, "exec-context-import-credentials", ic);
2558 if (r < 0)
2559 return r;
2560 }
2561 }
2562
2563 r = serialize_image_policy(f, "exec-context-root-image-policy", c->root_image_policy);
2564 if (r < 0)
2565 return r;
2566
2567 r = serialize_image_policy(f, "exec-context-mount-image-policy", c->mount_image_policy);
2568 if (r < 0)
2569 return r;
2570
2571 r = serialize_image_policy(f, "exec-context-extension-image-policy", c->extension_image_policy);
2572 if (r < 0)
2573 return r;
2574
2575 fputc('\n', f); /* End marker */
2576
2577 return 0;
2578 }
2579
2580 static int exec_context_deserialize(ExecContext *c, FILE *f) {
2581 int r;
2582
2583 assert(f);
2584
2585 if (!c)
2586 return 0;
2587
2588 for (;;) {
2589 _cleanup_free_ char *l = NULL;
2590 const char *val;
2591
2592 r = deserialize_read_line(f, &l);
2593 if (r < 0)
2594 return r;
2595 if (r == 0) /* eof or end marker */
2596 break;
2597
2598 if ((val = startswith(l, "exec-context-environment="))) {
2599 r = deserialize_strv(val, &c->environment);
2600 if (r < 0)
2601 return r;
2602 } else if ((val = startswith(l, "exec-context-environment-files="))) {
2603 r = deserialize_strv(val, &c->environment_files);
2604 if (r < 0)
2605 return r;
2606 } else if ((val = startswith(l, "exec-context-pass-environment="))) {
2607 r = deserialize_strv(val, &c->pass_environment);
2608 if (r < 0)
2609 return r;
2610 } else if ((val = startswith(l, "exec-context-unset-environment="))) {
2611 r = deserialize_strv(val, &c->unset_environment);
2612 if (r < 0)
2613 return r;
2614 } else if ((val = startswith(l, "exec-context-working-directory="))) {
2615 r = free_and_strdup(&c->working_directory, val);
2616 if (r < 0)
2617 return r;
2618 } else if ((val = startswith(l, "exec-context-root-directory="))) {
2619 r = free_and_strdup(&c->root_directory, val);
2620 if (r < 0)
2621 return r;
2622 } else if ((val = startswith(l, "exec-context-root-image="))) {
2623 r = free_and_strdup(&c->root_image, val);
2624 if (r < 0)
2625 return r;
2626 } else if ((val = startswith(l, "exec-context-root-image-options="))) {
2627 for (;;) {
2628 _cleanup_free_ char *word = NULL, *mount_options = NULL, *partition = NULL;
2629 PartitionDesignator partition_designator;
2630 MountOptions *o = NULL;
2631 const char *p;
2632
2633 r = extract_first_word(&val, &word, NULL, 0);
2634 if (r < 0)
2635 return r;
2636 if (r == 0)
2637 break;
2638
2639 p = word;
2640 r = extract_many_words(&p, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
2641 if (r < 0)
2642 return r;
2643 if (r == 0)
2644 continue;
2645
2646 partition_designator = partition_designator_from_string(partition);
2647 if (partition_designator < 0)
2648 return -EINVAL;
2649
2650 o = new(MountOptions, 1);
2651 if (!o)
2652 return log_oom_debug();
2653 *o = (MountOptions) {
2654 .partition_designator = partition_designator,
2655 .options = TAKE_PTR(mount_options),
2656 };
2657 LIST_APPEND(mount_options, c->root_image_options, o);
2658 }
2659 } else if ((val = startswith(l, "exec-context-root-verity="))) {
2660 r = free_and_strdup(&c->root_verity, val);
2661 if (r < 0)
2662 return r;
2663 } else if ((val = startswith(l, "exec-context-root-hash-path="))) {
2664 r = free_and_strdup(&c->root_hash_path, val);
2665 if (r < 0)
2666 return r;
2667 } else if ((val = startswith(l, "exec-context-root-hash-sig-path="))) {
2668 r = free_and_strdup(&c->root_hash_sig_path, val);
2669 if (r < 0)
2670 return r;
2671 } else if ((val = startswith(l, "exec-context-root-hash="))) {
2672 c->root_hash = mfree(c->root_hash);
2673 r = unhexmem(val, &c->root_hash, &c->root_hash_size);
2674 if (r < 0)
2675 return r;
2676 } else if ((val = startswith(l, "exec-context-root-hash-sig="))) {
2677 c->root_hash_sig = mfree(c->root_hash_sig);
2678 r= unbase64mem(val, &c->root_hash_sig, &c->root_hash_sig_size);
2679 if (r < 0)
2680 return r;
2681 } else if ((val = startswith(l, "exec-context-root-ephemeral="))) {
2682 r = parse_boolean(val);
2683 if (r < 0)
2684 return r;
2685 c->root_ephemeral = r;
2686 } else if ((val = startswith(l, "exec-context-umask="))) {
2687 r = parse_mode(val, &c->umask);
2688 if (r < 0)
2689 return r;
2690 } else if ((val = startswith(l, "exec-context-private-non-blocking="))) {
2691 r = parse_boolean(val);
2692 if (r < 0)
2693 return r;
2694 c->non_blocking = r;
2695 } else if ((val = startswith(l, "exec-context-private-mounts="))) {
2696 r = safe_atoi(val, &c->private_mounts);
2697 if (r < 0)
2698 return r;
2699 } else if ((val = startswith(l, "exec-context-memory-ksm="))) {
2700 r = safe_atoi(val, &c->memory_ksm);
2701 if (r < 0)
2702 return r;
2703 } else if ((val = startswith(l, "exec-context-private-tmp="))) {
2704 r = parse_boolean(val);
2705 if (r < 0)
2706 return r;
2707 c->private_tmp = r;
2708 } else if ((val = startswith(l, "exec-context-private-devices="))) {
2709 r = parse_boolean(val);
2710 if (r < 0)
2711 return r;
2712 c->private_devices = r;
2713 } else if ((val = startswith(l, "exec-context-protect-kernel-tunables="))) {
2714 r = parse_boolean(val);
2715 if (r < 0)
2716 return r;
2717 c->protect_kernel_tunables = r;
2718 } else if ((val = startswith(l, "exec-context-protect-kernel-modules="))) {
2719 r = parse_boolean(val);
2720 if (r < 0)
2721 return r;
2722 c->protect_kernel_modules = r;
2723 } else if ((val = startswith(l, "exec-context-protect-kernel-logs="))) {
2724 r = parse_boolean(val);
2725 if (r < 0)
2726 return r;
2727 c->protect_kernel_logs = r;
2728 } else if ((val = startswith(l, "exec-context-protect-clock="))) {
2729 r = parse_boolean(val);
2730 if (r < 0)
2731 return r;
2732 c->protect_clock = r;
2733 } else if ((val = startswith(l, "exec-context-protect-control-groups="))) {
2734 r = parse_boolean(val);
2735 if (r < 0)
2736 return r;
2737 c->protect_control_groups = r;
2738 } else if ((val = startswith(l, "exec-context-private-network="))) {
2739 r = parse_boolean(val);
2740 if (r < 0)
2741 return r;
2742 c->private_network = r;
2743 } else if ((val = startswith(l, "exec-context-private-users="))) {
2744 r = parse_boolean(val);
2745 if (r < 0)
2746 return r;
2747 c->private_users = r;
2748 } else if ((val = startswith(l, "exec-context-private-ipc="))) {
2749 r = parse_boolean(val);
2750 if (r < 0)
2751 return r;
2752 c->private_ipc = r;
2753 } else if ((val = startswith(l, "exec-context-remove-ipc="))) {
2754 r = parse_boolean(val);
2755 if (r < 0)
2756 return r;
2757 c->remove_ipc = r;
2758 } else if ((val = startswith(l, "exec-context-protect-home="))) {
2759 c->protect_home = protect_home_from_string(val);
2760 if (c->protect_home < 0)
2761 return -EINVAL;
2762 } else if ((val = startswith(l, "exec-context-protect-system="))) {
2763 c->protect_system = protect_system_from_string(val);
2764 if (c->protect_system < 0)
2765 return -EINVAL;
2766 } else if ((val = startswith(l, "exec-context-mount-api-vfs="))) {
2767 r = parse_boolean(val);
2768 if (r < 0)
2769 return r;
2770 c->mount_apivfs = r;
2771 c->mount_apivfs_set = true;
2772 } else if ((val = startswith(l, "exec-context-same-pgrp="))) {
2773 r = parse_boolean(val);
2774 if (r < 0)
2775 return r;
2776 c->same_pgrp = r;
2777 } else if ((val = startswith(l, "exec-context-cpu-sched-reset-on-fork="))) {
2778 r = parse_boolean(val);
2779 if (r < 0)
2780 return r;
2781 c->cpu_sched_reset_on_fork = r;
2782 } else if ((val = startswith(l, "exec-context-non-blocking="))) {
2783 r = parse_boolean(val);
2784 if (r < 0)
2785 return r;
2786 c->non_blocking = r;
2787 } else if ((val = startswith(l, "exec-context-ignore-sigpipe="))) {
2788 r = parse_boolean(val);
2789 if (r < 0)
2790 return r;
2791 c->ignore_sigpipe = r;
2792 } else if ((val = startswith(l, "exec-context-memory-deny-write-execute="))) {
2793 r = parse_boolean(val);
2794 if (r < 0)
2795 return r;
2796 c->memory_deny_write_execute = r;
2797 } else if ((val = startswith(l, "exec-context-restrict-realtime="))) {
2798 r = parse_boolean(val);
2799 if (r < 0)
2800 return r;
2801 c->restrict_realtime = r;
2802 } else if ((val = startswith(l, "exec-context-restrict-suid-sgid="))) {
2803 r = parse_boolean(val);
2804 if (r < 0)
2805 return r;
2806 c->restrict_suid_sgid = r;
2807 } else if ((val = startswith(l, "exec-context-keyring-mode="))) {
2808 c->keyring_mode = exec_keyring_mode_from_string(val);
2809 if (c->keyring_mode < 0)
2810 return -EINVAL;
2811 } else if ((val = startswith(l, "exec-context-protect-hostname="))) {
2812 r = parse_boolean(val);
2813 if (r < 0)
2814 return r;
2815 c->protect_hostname = r;
2816 } else if ((val = startswith(l, "exec-context-protect-proc="))) {
2817 c->protect_proc = protect_proc_from_string(val);
2818 if (c->protect_proc < 0)
2819 return -EINVAL;
2820 } else if ((val = startswith(l, "exec-context-proc-subset="))) {
2821 c->proc_subset = proc_subset_from_string(val);
2822 if (c->proc_subset < 0)
2823 return -EINVAL;
2824 } else if ((val = startswith(l, "exec-context-runtime-directory-preserve-mode="))) {
2825 c->runtime_directory_preserve_mode = exec_preserve_mode_from_string(val);
2826 if (c->runtime_directory_preserve_mode < 0)
2827 return -EINVAL;
2828 } else if ((val = startswith(l, "exec-context-directories-"))) {
2829 _cleanup_free_ char *type = NULL, *mode = NULL;
2830 ExecDirectoryType dt;
2831
2832 r = extract_many_words(&val, "= ", 0, &type, &mode, NULL);
2833 if (r < 0)
2834 return r;
2835 if (r == 0 || !mode)
2836 return -EINVAL;
2837
2838 dt = exec_directory_type_from_string(type);
2839 if (dt < 0)
2840 return -EINVAL;
2841
2842 r = parse_mode(mode, &c->directories[dt].mode);
2843 if (r < 0)
2844 return r;
2845
2846 for (;;) {
2847 _cleanup_free_ char *tuple = NULL, *path = NULL, *only_create = NULL;
2848 const char *p;
2849
2850 /* Use EXTRACT_UNESCAPE_RELAX here, as we unescape the colons in subsequent calls */
2851 r = extract_first_word(&val, &tuple, WHITESPACE, EXTRACT_UNESCAPE_SEPARATORS|EXTRACT_UNESCAPE_RELAX);
2852 if (r < 0)
2853 return r;
2854 if (r == 0)
2855 break;
2856
2857 p = tuple;
2858 r = extract_many_words(&p, ":", EXTRACT_UNESCAPE_SEPARATORS, &path, &only_create, NULL);
2859 if (r < 0)
2860 return r;
2861 if (r < 2)
2862 continue;
2863
2864 r = exec_directory_add(&c->directories[dt], path, NULL);
2865 if (r < 0)
2866 return r;
2867
2868 r = parse_boolean(only_create);
2869 if (r < 0)
2870 return r;
2871 c->directories[dt].items[c->directories[dt].n_items - 1].only_create = r;
2872
2873 if (isempty(p))
2874 continue;
2875
2876 for (;;) {
2877 _cleanup_free_ char *link = NULL;
2878
2879 r = extract_first_word(&p, &link, ":", EXTRACT_UNESCAPE_SEPARATORS);
2880 if (r < 0)
2881 return r;
2882 if (r == 0)
2883 break;
2884
2885 r = strv_consume(&c->directories[dt].items[c->directories[dt].n_items - 1].symlinks, TAKE_PTR(link));
2886 if (r < 0)
2887 return r;
2888 }
2889 }
2890 } else if ((val = startswith(l, "exec-context-timeout-clean-usec="))) {
2891 r = deserialize_usec(val, &c->timeout_clean_usec);
2892 if (r < 0)
2893 return r;
2894 } else if ((val = startswith(l, "exec-context-nice="))) {
2895 r = safe_atoi(val, &c->nice);
2896 if (r < 0)
2897 return r;
2898 c->nice_set = true;
2899 } else if ((val = startswith(l, "exec-context-working-directory-missing-ok="))) {
2900 r = parse_boolean(val);
2901 if (r < 0)
2902 return r;
2903 c->working_directory_missing_ok = r;
2904 } else if ((val = startswith(l, "exec-context-working-directory-home="))) {
2905 r = parse_boolean(val);
2906 if (r < 0)
2907 return r;
2908 c->working_directory_home = r;
2909 } else if ((val = startswith(l, "exec-context-oom-score-adjust="))) {
2910 r = safe_atoi(val, &c->oom_score_adjust);
2911 if (r < 0)
2912 return r;
2913 c->oom_score_adjust_set = true;
2914 } else if ((val = startswith(l, "exec-context-coredump-filter="))) {
2915 r = safe_atoux64(val, &c->coredump_filter);
2916 if (r < 0)
2917 return r;
2918 c->coredump_filter_set = true;
2919 } else if ((val = startswith(l, "exec-context-limit-"))) {
2920 _cleanup_free_ struct rlimit *rlimit = NULL;
2921 _cleanup_free_ char *limit = NULL;
2922 int type;
2923
2924 r = extract_first_word(&val, &limit, "=", 0);
2925 if (r < 0)
2926 return r;
2927 if (r == 0 || !val)
2928 return -EINVAL;
2929
2930 type = rlimit_from_string(limit);
2931 if (type < 0)
2932 return -EINVAL;
2933
2934 if (!c->rlimit[type]) {
2935 rlimit = new0(struct rlimit, 1);
2936 if (!rlimit)
2937 return log_oom_debug();
2938
2939 r = rlimit_parse(type, val, rlimit);
2940 if (r < 0)
2941 return r;
2942
2943 c->rlimit[type] = TAKE_PTR(rlimit);
2944 } else {
2945 r = rlimit_parse(type, val, c->rlimit[type]);
2946 if (r < 0)
2947 return r;
2948 }
2949 } else if ((val = startswith(l, "exec-context-ioprio="))) {
2950 r = safe_atoi(val, &c->ioprio);
2951 if (r < 0)
2952 return r;
2953 c->ioprio_set = true;
2954 } else if ((val = startswith(l, "exec-context-cpu-scheduling-policy="))) {
2955 c->cpu_sched_policy = sched_policy_from_string(val);
2956 if (c->cpu_sched_policy < 0)
2957 return -EINVAL;
2958 c->cpu_sched_set = true;
2959 } else if ((val = startswith(l, "exec-context-cpu-scheduling-priority="))) {
2960 r = safe_atoi(val, &c->cpu_sched_priority);
2961 if (r < 0)
2962 return r;
2963 c->cpu_sched_set = true;
2964 } else if ((val = startswith(l, "exec-context-cpu-scheduling-reset-on-fork="))) {
2965 r = parse_boolean(val);
2966 if (r < 0)
2967 return r;
2968 c->cpu_sched_reset_on_fork = r;
2969 c->cpu_sched_set = true;
2970 } else if ((val = startswith(l, "exec-context-cpu-affinity="))) {
2971 if (c->cpu_set.set)
2972 return -EINVAL; /* duplicated */
2973
2974 r = parse_cpu_set(val, &c->cpu_set);
2975 if (r < 0)
2976 return r;
2977 } else if ((val = startswith(l, "exec-context-numa-mask="))) {
2978 if (c->numa_policy.nodes.set)
2979 return -EINVAL; /* duplicated */
2980
2981 r = parse_cpu_set(val, &c->numa_policy.nodes);
2982 if (r < 0)
2983 return r;
2984 } else if ((val = startswith(l, "exec-context-numa-policy="))) {
2985 r = safe_atoi(val, &c->numa_policy.type);
2986 if (r < 0)
2987 return r;
2988 } else if ((val = startswith(l, "exec-context-cpu-affinity-from-numa="))) {
2989 r = parse_boolean(val);
2990 if (r < 0)
2991 return r;
2992 c->cpu_affinity_from_numa = r;
2993 } else if ((val = startswith(l, "exec-context-timer-slack-nsec="))) {
2994 r = deserialize_usec(val, (usec_t *)&c->timer_slack_nsec);
2995 if (r < 0)
2996 return r;
2997 } else if ((val = startswith(l, "exec-context-std-input="))) {
2998 c->std_input = exec_input_from_string(val);
2999 if (c->std_input < 0)
3000 return c->std_input;
3001 } else if ((val = startswith(l, "exec-context-std-output="))) {
3002 c->std_output = exec_output_from_string(val);
3003 if (c->std_output < 0)
3004 return c->std_output;
3005 } else if ((val = startswith(l, "exec-context-std-error="))) {
3006 c->std_error = exec_output_from_string(val);
3007 if (c->std_error < 0)
3008 return c->std_error;
3009 } else if ((val = startswith(l, "exec-context-stdio-as-fds="))) {
3010 r = parse_boolean(val);
3011 if (r < 0)
3012 return r;
3013 c->stdio_as_fds = r;
3014 } else if ((val = startswith(l, "exec-context-std-input-fd-name="))) {
3015 r = free_and_strdup(&c->stdio_fdname[STDIN_FILENO], val);
3016 if (r < 0)
3017 return r;
3018 } else if ((val = startswith(l, "exec-context-std-output-fd-name="))) {
3019 r = free_and_strdup(&c->stdio_fdname[STDOUT_FILENO], val);
3020 if (r < 0)
3021 return r;
3022 } else if ((val = startswith(l, "exec-context-std-error-fd-name="))) {
3023 r = free_and_strdup(&c->stdio_fdname[STDERR_FILENO], val);
3024 if (r < 0)
3025 return r;
3026 } else if ((val = startswith(l, "exec-context-std-input-file="))) {
3027 r = free_and_strdup(&c->stdio_file[STDIN_FILENO], val);
3028 if (r < 0)
3029 return r;
3030 } else if ((val = startswith(l, "exec-context-std-output-file="))) {
3031 r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], val);
3032 if (r < 0)
3033 return r;
3034 } else if ((val = startswith(l, "exec-context-std-output-file-append="))) {
3035 r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], val);
3036 if (r < 0)
3037 return r;
3038 } else if ((val = startswith(l, "exec-context-std-output-file-truncate="))) {
3039 r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], val);
3040 if (r < 0)
3041 return r;
3042 } else if ((val = startswith(l, "exec-context-std-error-file="))) {
3043 r = free_and_strdup(&c->stdio_file[STDERR_FILENO], val);
3044 if (r < 0)
3045 return r;
3046 } else if ((val = startswith(l, "exec-context-std-error-file-append="))) {
3047 r = free_and_strdup(&c->stdio_file[STDERR_FILENO], val);
3048 if (r < 0)
3049 return r;
3050 } else if ((val = startswith(l, "exec-context-std-error-file-truncate="))) {
3051 r = free_and_strdup(&c->stdio_file[STDERR_FILENO], val);
3052 if (r < 0)
3053 return r;
3054 } else if ((val = startswith(l, "exec-context-stdin-data="))) {
3055 if (c->stdin_data)
3056 return -EINVAL; /* duplicated */
3057
3058 r = unbase64mem(val, &c->stdin_data, &c->stdin_data_size);
3059 if (r < 0)
3060 return r;
3061 } else if ((val = startswith(l, "exec-context-tty-path="))) {
3062 r = free_and_strdup(&c->tty_path, val);
3063 if (r < 0)
3064 return r;
3065 } else if ((val = startswith(l, "exec-context-tty-reset="))) {
3066 r = parse_boolean(val);
3067 if (r < 0)
3068 return r;
3069 c->tty_reset = r;
3070 } else if ((val = startswith(l, "exec-context-tty-vhangup="))) {
3071 r = parse_boolean(val);
3072 if (r < 0)
3073 return r;
3074 c->tty_vhangup = r;
3075 } else if ((val = startswith(l, "exec-context-tty-vt-disallocate="))) {
3076 r = parse_boolean(val);
3077 if (r < 0)
3078 return r;
3079 c->tty_vt_disallocate = r;
3080 } else if ((val = startswith(l, "exec-context-tty-rows="))) {
3081 r = safe_atou(val, &c->tty_rows);
3082 if (r < 0)
3083 return r;
3084 } else if ((val = startswith(l, "exec-context-tty-columns="))) {
3085 r = safe_atou(val, &c->tty_cols);
3086 if (r < 0)
3087 return r;
3088 } else if ((val = startswith(l, "exec-context-syslog-priority="))) {
3089 r = safe_atoi(val, &c->syslog_priority);
3090 if (r < 0)
3091 return r;
3092 } else if ((val = startswith(l, "exec-context-syslog-level-prefix="))) {
3093 r = parse_boolean(val);
3094 if (r < 0)
3095 return r;
3096 c->syslog_level_prefix = r;
3097 } else if ((val = startswith(l, "exec-context-syslog-identifier="))) {
3098 r = free_and_strdup(&c->syslog_identifier, val);
3099 if (r < 0)
3100 return r;
3101 } else if ((val = startswith(l, "exec-context-log-level-max="))) {
3102 /* See comment in serialization. */
3103 r = safe_atoi(val, &c->log_level_max);
3104 if (r < 0)
3105 return r;
3106 } else if ((val = startswith(l, "exec-context-log-ratelimit-interval-usec="))) {
3107 r = deserialize_usec(val, &c->log_ratelimit_interval_usec);
3108 if (r < 0)
3109 return r;
3110 } else if ((val = startswith(l, "exec-context-log-ratelimit-burst="))) {
3111 r = safe_atou(val, &c->log_ratelimit_burst);
3112 if (r < 0)
3113 return r;
3114 } else if ((val = startswith(l, "exec-context-log-filter-allowed-patterns="))) {
3115 r = set_put_strdup(&c->log_filter_allowed_patterns, val);
3116 if (r < 0)
3117 return r;
3118 } else if ((val = startswith(l, "exec-context-log-filter-denied-patterns="))) {
3119 r = set_put_strdup(&c->log_filter_denied_patterns, val);
3120 if (r < 0)
3121 return r;
3122 } else if ((val = startswith(l, "exec-context-log-extra-fields="))) {
3123 if (!GREEDY_REALLOC(c->log_extra_fields, c->n_log_extra_fields + 1))
3124 return log_oom_debug();
3125
3126 c->log_extra_fields[c->n_log_extra_fields++].iov_base = strdup(val);
3127 if (!c->log_extra_fields[c->n_log_extra_fields-1].iov_base)
3128 return log_oom_debug();
3129 } else if ((val = startswith(l, "exec-context-log-namespace="))) {
3130 r = free_and_strdup(&c->log_namespace, val);
3131 if (r < 0)
3132 return r;
3133 } else if ((val = startswith(l, "exec-context-secure-bits="))) {
3134 r = safe_atoi(val, &c->secure_bits);
3135 if (r < 0)
3136 return r;
3137 } else if ((val = startswith(l, "exec-context-capability-bounding-set="))) {
3138 r = safe_atou64(val, &c->capability_bounding_set);
3139 if (r < 0)
3140 return r;
3141 } else if ((val = startswith(l, "exec-context-capability-ambient-set="))) {
3142 r = safe_atou64(val, &c->capability_ambient_set);
3143 if (r < 0)
3144 return r;
3145 } else if ((val = startswith(l, "exec-context-user="))) {
3146 r = free_and_strdup(&c->user, val);
3147 if (r < 0)
3148 return r;
3149 } else if ((val = startswith(l, "exec-context-group="))) {
3150 r = free_and_strdup(&c->group, val);
3151 if (r < 0)
3152 return r;
3153 } else if ((val = startswith(l, "exec-context-dynamic-user="))) {
3154 r = parse_boolean(val);
3155 if (r < 0)
3156 return r;
3157 c->dynamic_user = r;
3158 } else if ((val = startswith(l, "exec-context-supplementary-groups="))) {
3159 r = deserialize_strv(val, &c->supplementary_groups);
3160 if (r < 0)
3161 return r;
3162 } else if ((val = startswith(l, "exec-context-set-login-environment="))) {
3163 r = safe_atoi(val, &c->set_login_environment);
3164 if (r < 0)
3165 return r;
3166 } else if ((val = startswith(l, "exec-context-pam-name="))) {
3167 r = free_and_strdup(&c->pam_name, val);
3168 if (r < 0)
3169 return r;
3170 } else if ((val = startswith(l, "exec-context-read-write-paths="))) {
3171 r = deserialize_strv(val, &c->read_write_paths);
3172 if (r < 0)
3173 return r;
3174 } else if ((val = startswith(l, "exec-context-read-only-paths="))) {
3175 r = deserialize_strv(val, &c->read_only_paths);
3176 if (r < 0)
3177 return r;
3178 } else if ((val = startswith(l, "exec-context-inaccessible-paths="))) {
3179 r = deserialize_strv(val, &c->inaccessible_paths);
3180 if (r < 0)
3181 return r;
3182 } else if ((val = startswith(l, "exec-context-exec-paths="))) {
3183 r = deserialize_strv(val, &c->exec_paths);
3184 if (r < 0)
3185 return r;
3186 } else if ((val = startswith(l, "exec-context-no-exec-paths="))) {
3187 r = deserialize_strv(val, &c->no_exec_paths);
3188 if (r < 0)
3189 return r;
3190 } else if ((val = startswith(l, "exec-context-exec-search-path="))) {
3191 r = deserialize_strv(val, &c->exec_search_path);
3192 if (r < 0)
3193 return r;
3194 } else if ((val = startswith(l, "exec-context-mount-propagation-flag="))) {
3195 r = safe_atolu(val, &c->mount_propagation_flag);
3196 if (r < 0)
3197 return r;
3198 } else if ((val = startswith(l, "exec-context-bind-read-only-path="))) {
3199 _cleanup_free_ char *source = NULL, *destination = NULL;
3200 bool rbind = true, ignore_enoent = false;
3201 char *s = NULL, *d = NULL;
3202
3203 r = extract_first_word(&val,
3204 &source,
3205 ":" WHITESPACE,
3206 EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNESCAPE_SEPARATORS);
3207 if (r < 0)
3208 return r;
3209 if (r == 0)
3210 return -EINVAL;
3211
3212 s = source;
3213 if (s[0] == '-') {
3214 ignore_enoent = true;
3215 s++;
3216 }
3217
3218 if (val && val[-1] == ':') {
3219 r = extract_first_word(&val,
3220 &destination,
3221 ":" WHITESPACE,
3222 EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNESCAPE_SEPARATORS);
3223 if (r < 0)
3224 return r;
3225 if (r == 0)
3226 continue;
3227
3228 d = destination;
3229
3230 if (val && val[-1] == ':') {
3231 _cleanup_free_ char *options = NULL;
3232
3233 r = extract_first_word(&val, &options, NULL, EXTRACT_UNQUOTE);
3234 if (r < 0)
3235 return -r;
3236
3237 if (isempty(options) || streq(options, "rbind"))
3238 rbind = true;
3239 else if (streq(options, "norbind"))
3240 rbind = false;
3241 else
3242 continue;
3243 }
3244 } else
3245 d = s;
3246
3247 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
3248 &(BindMount) {
3249 .source = s,
3250 .destination = d,
3251 .read_only = true,
3252 .recursive = rbind,
3253 .ignore_enoent = ignore_enoent,
3254 });
3255 if (r < 0)
3256 return log_oom_debug();
3257 } else if ((val = startswith(l, "exec-context-bind-path="))) {
3258 _cleanup_free_ char *source = NULL, *destination = NULL;
3259 bool rbind = true, ignore_enoent = false;
3260 char *s = NULL, *d = NULL;
3261
3262 r = extract_first_word(&val,
3263 &source,
3264 ":" WHITESPACE,
3265 EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNESCAPE_SEPARATORS);
3266 if (r < 0)
3267 return r;
3268 if (r == 0)
3269 return -EINVAL;
3270
3271 s = source;
3272 if (s[0] == '-') {
3273 ignore_enoent = true;
3274 s++;
3275 }
3276
3277 if (val && val[-1] == ':') {
3278 r = extract_first_word(&val,
3279 &destination,
3280 ":" WHITESPACE,
3281 EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNESCAPE_SEPARATORS);
3282 if (r < 0)
3283 return r;
3284 if (r == 0)
3285 continue;
3286
3287 d = destination;
3288
3289 if (val && val[-1] == ':') {
3290 _cleanup_free_ char *options = NULL;
3291
3292 r = extract_first_word(&val, &options, NULL, EXTRACT_UNQUOTE);
3293 if (r < 0)
3294 return -r;
3295
3296 if (isempty(options) || streq(options, "rbind"))
3297 rbind = true;
3298 else if (streq(options, "norbind"))
3299 rbind = false;
3300 else
3301 continue;
3302 }
3303 } else
3304 d = s;
3305
3306 r = bind_mount_add(&c->bind_mounts, &c->n_bind_mounts,
3307 &(BindMount) {
3308 .source = s,
3309 .destination = d,
3310 .read_only = false,
3311 .recursive = rbind,
3312 .ignore_enoent = ignore_enoent,
3313 });
3314 if (r < 0)
3315 return log_oom_debug();
3316 } else if ((val = startswith(l, "exec-context-temporary-filesystems="))) {
3317 _cleanup_free_ char *path = NULL, *options = NULL;
3318
3319 r = extract_many_words(&val, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &path, &options, NULL);
3320 if (r < 0)
3321 return r;
3322 if (r < 1)
3323 continue;
3324
3325 r = temporary_filesystem_add(&c->temporary_filesystems, &c->n_temporary_filesystems, path, options);
3326 if (r < 0)
3327 return log_oom_debug();
3328 } else if ((val = startswith(l, "exec-context-utmp-id="))) {
3329 r = free_and_strdup(&c->utmp_id, val);
3330 if (r < 0)
3331 return r;
3332 } else if ((val = startswith(l, "exec-context-utmp-mode="))) {
3333 c->utmp_mode = exec_utmp_mode_from_string(val);
3334 if (c->utmp_mode < 0)
3335 return c->utmp_mode;
3336 } else if ((val = startswith(l, "exec-context-no-new-privileges="))) {
3337 r = parse_boolean(val);
3338 if (r < 0)
3339 return r;
3340 c->no_new_privileges = r;
3341 } else if ((val = startswith(l, "exec-context-selinux-context-ignore="))) {
3342 r = parse_boolean(val);
3343 if (r < 0)
3344 return r;
3345 c->selinux_context_ignore = r;
3346 } else if ((val = startswith(l, "exec-context-apparmor-profile-ignore="))) {
3347 r = parse_boolean(val);
3348 if (r < 0)
3349 return r;
3350 c->apparmor_profile_ignore = r;
3351 } else if ((val = startswith(l, "exec-context-smack-process-label-ignore="))) {
3352 r = parse_boolean(val);
3353 if (r < 0)
3354 return r;
3355 c->smack_process_label_ignore = r;
3356 } else if ((val = startswith(l, "exec-context-selinux-context="))) {
3357 if (val[0] == '-') {
3358 c->selinux_context_ignore = true;
3359 val++;
3360 }
3361
3362 r = free_and_strdup(&c->selinux_context, val);
3363 if (r < 0)
3364 return r;
3365 } else if ((val = startswith(l, "exec-context-apparmor-profile="))) {
3366 if (val[0] == '-') {
3367 c->apparmor_profile_ignore = true;
3368 val++;
3369 }
3370
3371 r = free_and_strdup(&c->apparmor_profile, val);
3372 if (r < 0)
3373 return r;
3374 } else if ((val = startswith(l, "exec-context-smack-process-label="))) {
3375 if (val[0] == '-') {
3376 c->smack_process_label_ignore = true;
3377 val++;
3378 }
3379
3380 r = free_and_strdup(&c->smack_process_label, val);
3381 if (r < 0)
3382 return r;
3383 } else if ((val = startswith(l, "exec-context-personality="))) {
3384 c->personality = personality_from_string(val);
3385 if (c->personality == PERSONALITY_INVALID)
3386 return -EINVAL;
3387 } else if ((val = startswith(l, "exec-context-lock-personality="))) {
3388 r = parse_boolean(val);
3389 if (r < 0)
3390 return r;
3391 c->lock_personality = r;
3392 #if HAVE_SECCOMP
3393 } else if ((val = startswith(l, "exec-context-syscall-filter="))) {
3394 _cleanup_free_ char *s_id = NULL, *s_errno_num = NULL;
3395 int id, errno_num;
3396
3397 r = extract_many_words(&val, NULL, 0, &s_id, &s_errno_num, NULL);
3398 if (r < 0)
3399 return r;
3400 if (r != 2)
3401 continue;
3402
3403 r = safe_atoi(s_id, &id);
3404 if (r < 0)
3405 return r;
3406
3407 r = safe_atoi(s_errno_num, &errno_num);
3408 if (r < 0)
3409 return r;
3410
3411 r = hashmap_ensure_put(&c->syscall_filter, NULL, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num));
3412 if (r < 0)
3413 return r;
3414 } else if ((val = startswith(l, "exec-context-syscall-archs="))) {
3415 unsigned int id;
3416
3417 r = safe_atou(val, &id);
3418 if (r < 0)
3419 return r;
3420
3421 r = set_ensure_put(&c->syscall_archs, NULL, UINT_TO_PTR(id + 1));
3422 if (r < 0)
3423 return r;
3424 } else if ((val = startswith(l, "exec-context-syscall-errno="))) {
3425 r = safe_atoi(val, &c->syscall_errno);
3426 if (r < 0)
3427 return r;
3428 } else if ((val = startswith(l, "exec-context-syscall-allow-list="))) {
3429 r = parse_boolean(val);
3430 if (r < 0)
3431 return r;
3432 c->syscall_allow_list = r;
3433 } else if ((val = startswith(l, "exec-context-syscall-log="))) {
3434 _cleanup_free_ char *s_id = NULL, *s_errno_num = NULL;
3435 int id, errno_num;
3436
3437 r = extract_many_words(&val, " ", 0, &s_id, &s_errno_num, NULL);
3438 if (r < 0)
3439 return r;
3440 if (r != 2)
3441 continue;
3442
3443 r = safe_atoi(s_id, &id);
3444 if (r < 0)
3445 return r;
3446
3447 r = safe_atoi(s_errno_num, &errno_num);
3448 if (r < 0)
3449 return r;
3450
3451 r = hashmap_ensure_put(&c->syscall_log, NULL, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num));
3452 if (r < 0)
3453 return r;
3454 } else if ((val = startswith(l, "exec-context-syscall-log-allow-list="))) {
3455 r = parse_boolean(val);
3456 if (r < 0)
3457 return r;
3458 c->syscall_log_allow_list = r;
3459 #endif
3460 } else if ((val = startswith(l, "exec-context-restrict-namespaces="))) {
3461 r = safe_atolu(val, &c->restrict_namespaces);
3462 if (r < 0)
3463 return r;
3464 } else if ((val = startswith(l, "exec-context-restrict-filesystems="))) {
3465 r = set_ensure_allocated(&c->restrict_filesystems, &string_hash_ops);
3466 if (r < 0)
3467 return r;
3468
3469 r = set_put_strdup(&c->restrict_filesystems, val);
3470 if (r < 0)
3471 return r;
3472 } else if ((val = startswith(l, "exec-context-restrict-filesystems-allow-list="))) {
3473 r = parse_boolean(val);
3474 if (r < 0)
3475 return r;
3476 c->restrict_filesystems_allow_list = r;
3477 } else if ((val = startswith(l, "exec-context-address-families="))) {
3478 int af;
3479
3480 r = safe_atoi(val, &af);
3481 if (r < 0)
3482 return r;
3483
3484 r = set_ensure_put(&c->address_families, NULL, INT_TO_PTR(af));
3485 if (r < 0)
3486 return r;
3487 } else if ((val = startswith(l, "exec-context-address-families-allow-list="))) {
3488 r = parse_boolean(val);
3489 if (r < 0)
3490 return r;
3491 c->address_families_allow_list = r;
3492 } else if ((val = startswith(l, "exec-context-network-namespace-path="))) {
3493 r = free_and_strdup(&c->network_namespace_path, val);
3494 if (r < 0)
3495 return r;
3496 } else if ((val = startswith(l, "exec-context-ipc-namespace-path="))) {
3497 r = free_and_strdup(&c->ipc_namespace_path, val);
3498 if (r < 0)
3499 return r;
3500 } else if ((val = startswith(l, "exec-context-mount-image="))) {
3501 _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
3502 _cleanup_free_ char *source = NULL, *destination = NULL;
3503 bool permissive = false;
3504 char *s;
3505
3506 r = extract_many_words(&val,
3507 NULL,
3508 EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
3509 &source,
3510 &destination,
3511 NULL);
3512 if (r < 0)
3513 return r;
3514 if (r == 0)
3515 return -EINVAL;
3516
3517 s = source;
3518 if (s[0] == '-') {
3519 permissive = true;
3520 s++;
3521 }
3522
3523 if (isempty(destination))
3524 continue;
3525
3526 for (;;) {
3527 _cleanup_free_ char *tuple = NULL, *partition = NULL, *opts = NULL;
3528 PartitionDesignator partition_designator;
3529 MountOptions *o = NULL;
3530 const char *p;
3531
3532 r = extract_first_word(&val, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
3533 if (r < 0)
3534 return r;
3535 if (r == 0)
3536 break;
3537
3538 p = tuple;
3539 r = extract_many_words(&p,
3540 ":",
3541 EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
3542 &partition,
3543 &opts,
3544 NULL);
3545 if (r < 0)
3546 return r;
3547 if (r == 0)
3548 continue;
3549 if (r == 1) {
3550 o = new(MountOptions, 1);
3551 if (!o)
3552 return log_oom_debug();
3553 *o = (MountOptions) {
3554 .partition_designator = PARTITION_ROOT,
3555 .options = TAKE_PTR(partition),
3556 };
3557 LIST_APPEND(mount_options, options, o);
3558
3559 continue;
3560 }
3561
3562 partition_designator = partition_designator_from_string(partition);
3563 if (partition_designator < 0)
3564 continue;
3565
3566 o = new(MountOptions, 1);
3567 if (!o)
3568 return log_oom_debug();
3569 *o = (MountOptions) {
3570 .partition_designator = partition_designator,
3571 .options = TAKE_PTR(opts),
3572 };
3573 LIST_APPEND(mount_options, options, o);
3574 }
3575
3576 r = mount_image_add(&c->mount_images, &c->n_mount_images,
3577 &(MountImage) {
3578 .source = s,
3579 .destination = destination,
3580 .mount_options = options,
3581 .ignore_enoent = permissive,
3582 .type = MOUNT_IMAGE_DISCRETE,
3583 });
3584 if (r < 0)
3585 return log_oom_debug();
3586 } else if ((val = startswith(l, "exec-context-extension-image="))) {
3587 _cleanup_(mount_options_free_allp) MountOptions *options = NULL;
3588 _cleanup_free_ char *source = NULL;
3589 bool permissive = false;
3590 char *s;
3591
3592 r = extract_first_word(&val,
3593 &source,
3594 NULL,
3595 EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
3596 if (r < 0)
3597 return r;
3598 if (r == 0)
3599 return -EINVAL;
3600
3601 s = source;
3602 if (s[0] == '-') {
3603 permissive = true;
3604 s++;
3605 }
3606
3607 for (;;) {
3608 _cleanup_free_ char *tuple = NULL, *partition = NULL, *opts = NULL;
3609 PartitionDesignator partition_designator;
3610 MountOptions *o = NULL;
3611 const char *p;
3612
3613 r = extract_first_word(&val, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
3614 if (r < 0)
3615 return r;
3616 if (r == 0)
3617 break;
3618
3619 p = tuple;
3620 r = extract_many_words(&p,
3621 ":",
3622 EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS,
3623 &partition,
3624 &opts,
3625 NULL);
3626 if (r < 0)
3627 return r;
3628 if (r == 0)
3629 continue;
3630 if (r == 1) {
3631 o = new(MountOptions, 1);
3632 if (!o)
3633 return log_oom_debug();
3634 *o = (MountOptions) {
3635 .partition_designator = PARTITION_ROOT,
3636 .options = TAKE_PTR(partition),
3637 };
3638 LIST_APPEND(mount_options, options, o);
3639
3640 continue;
3641 }
3642
3643 partition_designator = partition_designator_from_string(partition);
3644 if (partition_designator < 0)
3645 continue;
3646
3647 o = new(MountOptions, 1);
3648 if (!o)
3649 return log_oom_debug();
3650 *o = (MountOptions) {
3651 .partition_designator = partition_designator,
3652 .options = TAKE_PTR(opts),
3653 };
3654 LIST_APPEND(mount_options, options, o);
3655 }
3656
3657 r = mount_image_add(&c->extension_images, &c->n_extension_images,
3658 &(MountImage) {
3659 .source = s,
3660 .mount_options = options,
3661 .ignore_enoent = permissive,
3662 .type = MOUNT_IMAGE_EXTENSION,
3663 });
3664 if (r < 0)
3665 return log_oom_debug();
3666 } else if ((val = startswith(l, "exec-context-extension-directories="))) {
3667 r = deserialize_strv(val, &c->extension_directories);
3668 if (r < 0)
3669 return r;
3670 } else if ((val = startswith(l, "exec-context-set-credentials="))) {
3671 _cleanup_(exec_set_credential_freep) ExecSetCredential *sc = NULL;
3672 _cleanup_free_ char *id = NULL, *encrypted = NULL, *data = NULL;
3673
3674 r = extract_many_words(&val, " ", 0, &id, &encrypted, &data, NULL);
3675 if (r < 0)
3676 return r;
3677 if (r != 3)
3678 return -EINVAL;
3679
3680 r = parse_boolean(encrypted);
3681 if (r < 0)
3682 return r;
3683
3684 sc = new(ExecSetCredential, 1);
3685 if (!sc)
3686 return -ENOMEM;
3687
3688 *sc = (ExecSetCredential) {
3689 .id = TAKE_PTR(id),
3690 .encrypted = r,
3691 };
3692
3693 r = unbase64mem(data, &sc->data, &sc->size);
3694 if (r < 0)
3695 return r;
3696
3697 r = hashmap_ensure_put(&c->set_credentials, &exec_set_credential_hash_ops, sc->id, sc);
3698 if (r < 0)
3699 return r;
3700
3701 TAKE_PTR(sc);
3702 } else if ((val = startswith(l, "exec-context-load-credentials="))) {
3703 _cleanup_(exec_load_credential_freep) ExecLoadCredential *lc = NULL;
3704 _cleanup_free_ char *id = NULL, *encrypted = NULL, *path = NULL;
3705
3706 r = extract_many_words(&val, " ", 0, &id, &encrypted, &path, NULL);
3707 if (r < 0)
3708 return r;
3709 if (r != 3)
3710 return -EINVAL;
3711
3712 r = parse_boolean(encrypted);
3713 if (r < 0)
3714 return r;
3715
3716 lc = new(ExecLoadCredential, 1);
3717 if (!lc)
3718 return -ENOMEM;
3719
3720 *lc = (ExecLoadCredential) {
3721 .id = TAKE_PTR(id),
3722 .path = TAKE_PTR(path),
3723 .encrypted = r,
3724 };
3725
3726 r = hashmap_ensure_put(&c->load_credentials, &exec_load_credential_hash_ops, lc->id, lc);
3727 if (r < 0)
3728 return r;
3729
3730 TAKE_PTR(lc);
3731 } else if ((val = startswith(l, "exec-context-import-credentials="))) {
3732 r = set_ensure_allocated(&c->import_credentials, &string_hash_ops);
3733 if (r < 0)
3734 return r;
3735
3736 r = set_put_strdup(&c->import_credentials, val);
3737 if (r < 0)
3738 return r;
3739 } else if ((val = startswith(l, "exec-context-root-image-policy="))) {
3740 if (c->root_image_policy)
3741 return -EINVAL; /* duplicated */
3742
3743 r = image_policy_from_string(val, &c->root_image_policy);
3744 if (r < 0)
3745 return r;
3746 } else if ((val = startswith(l, "exec-context-mount-image-policy="))) {
3747 if (c->mount_image_policy)
3748 return -EINVAL; /* duplicated */
3749
3750 r = image_policy_from_string(val, &c->mount_image_policy);
3751 if (r < 0)
3752 return r;
3753 } else if ((val = startswith(l, "exec-context-extension-image-policy="))) {
3754 if (c->extension_image_policy)
3755 return -EINVAL; /* duplicated */
3756
3757 r = image_policy_from_string(val, &c->extension_image_policy);
3758 if (r < 0)
3759 return r;
3760 } else
3761 log_warning("Failed to parse serialized line, ignoring: %s", l);
3762 }
3763
3764 return 0;
3765 }
3766
3767 static int exec_command_serialize(const ExecCommand *c, FILE *f) {
3768 int r;
3769
3770 assert(c);
3771 assert(f);
3772
3773 r = serialize_item(f, "exec-command-path", c->path);
3774 if (r < 0)
3775 return r;
3776
3777 r = serialize_strv(f, "exec-command-argv", c->argv);
3778 if (r < 0)
3779 return r;
3780
3781 r = serialize_item_format(f, "exec-command-flags", "%d", (int) c->flags);
3782 if (r < 0)
3783 return r;
3784
3785 fputc('\n', f); /* End marker */
3786
3787 return 0;
3788 }
3789
3790 static int exec_command_deserialize(ExecCommand *c, FILE *f) {
3791 int r;
3792
3793 assert(c);
3794 assert(f);
3795
3796 for (;;) {
3797 _cleanup_free_ char *l = NULL;
3798 const char *val;
3799
3800 r = deserialize_read_line(f, &l);
3801 if (r < 0)
3802 return r;
3803 if (r == 0) /* eof or end marker */
3804 break;
3805
3806 if ((val = startswith(l, "exec-command-path="))) {
3807 r = free_and_strdup(&c->path, val);
3808 if (r < 0)
3809 return r;
3810 } else if ((val = startswith(l, "exec-command-argv="))) {
3811 r = deserialize_strv(val, &c->argv);
3812 if (r < 0)
3813 return r;
3814 } else if ((val = startswith(l, "exec-command-flags="))) {
3815 r = safe_atoi(val, &c->flags);
3816 if (r < 0)
3817 return r;
3818 } else
3819 log_warning("Failed to parse serialized line, ignoring: %s", l);
3820
3821 }
3822
3823 return 0;
3824 }
3825
3826 int exec_serialize_invocation(
3827 FILE *f,
3828 FDSet *fds,
3829 const ExecContext *ctx,
3830 const ExecCommand *cmd,
3831 const ExecParameters *p,
3832 const ExecRuntime *rt,
3833 const CGroupContext *cg) {
3834
3835 int r;
3836
3837 assert(f);
3838 assert(fds);
3839
3840 r = exec_context_serialize(ctx, f);
3841 if (r < 0)
3842 return log_debug_errno(r, "Failed to serialize context: %m");
3843
3844 r = exec_command_serialize(cmd, f);
3845 if (r < 0)
3846 return log_debug_errno(r, "Failed to serialize command: %m");
3847
3848 r = exec_parameters_serialize(p, ctx, f, fds);
3849 if (r < 0)
3850 return log_debug_errno(r, "Failed to serialize parameters: %m");
3851
3852 r = exec_runtime_serialize(rt, f, fds);
3853 if (r < 0)
3854 return log_debug_errno(r, "Failed to serialize runtime: %m");
3855
3856 r = exec_cgroup_context_serialize(cg, f);
3857 if (r < 0)
3858 return log_debug_errno(r, "Failed to serialize cgroup context: %m");
3859
3860 return 0;
3861 }
3862
3863 int exec_deserialize_invocation(
3864 FILE *f,
3865 FDSet *fds,
3866 ExecContext *ctx,
3867 ExecCommand *cmd,
3868 ExecParameters *p,
3869 ExecRuntime *rt,
3870 CGroupContext *cg) {
3871
3872 int r;
3873
3874 assert(f);
3875 assert(fds);
3876
3877 r = exec_context_deserialize(ctx, f);
3878 if (r < 0)
3879 return log_debug_errno(r, "Failed to deserialize context: %m");
3880
3881 r = exec_command_deserialize(cmd, f);
3882 if (r < 0)
3883 return log_debug_errno(r, "Failed to deserialize command: %m");
3884
3885 r = exec_parameters_deserialize(p, f, fds);
3886 if (r < 0)
3887 return log_debug_errno(r, "Failed to deserialize parameters: %m");
3888
3889 r = exec_runtime_deserialize(rt, f, fds);
3890 if (r < 0)
3891 return log_debug_errno(r, "Failed to deserialize runtime: %m");
3892
3893 r = exec_cgroup_context_deserialize(cg, f);
3894 if (r < 0)
3895 return log_debug_errno(r, "Failed to deserialize cgroup context: %m");
3896
3897 return 0;
3898 }