1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include "capability-util.h"
5 #include "cgroup-setup.h"
7 #include "exec-credential.h"
8 #include "execute-serialize.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"
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
;
27 struct in_addr_prefix
*iaai
;
35 r
= serialize_bool_elide(f
, "exec-cgroup-context-cpu-accounting", c
->cpu_accounting
);
39 r
= serialize_bool_elide(f
, "exec-cgroup-context-io-accounting", c
->io_accounting
);
43 r
= serialize_bool_elide(f
, "exec-cgroup-context-block-io-accounting", c
->blockio_accounting
);
47 r
= serialize_bool_elide(f
, "exec-cgroup-context-memory-accounting", c
->memory_accounting
);
51 r
= serialize_bool_elide(f
, "exec-cgroup-context-tasks-accounting", c
->tasks_accounting
);
55 r
= serialize_bool_elide(f
, "exec-cgroup-context-ip-accounting", c
->ip_accounting
);
59 r
= serialize_bool_elide(f
, "exec-cgroup-context-memory-oom-group", c
->memory_oom_group
);
63 if (c
->cpu_weight
!= CGROUP_WEIGHT_INVALID
) {
64 r
= serialize_item_format(f
, "exec-cgroup-context-cpu-weight", "%" PRIu64
, c
->cpu_weight
);
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
);
75 if (c
->cpu_shares
!= CGROUP_CPU_SHARES_INVALID
) {
76 r
= serialize_item_format(f
, "exec-cgroup-context-cpu-shares", "%" PRIu64
, c
->cpu_shares
);
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
);
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
);
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
);
99 cpuset_cpus
= cpu_set_to_range_string(&c
->cpuset_cpus
);
101 return log_oom_debug();
103 r
= serialize_item(f
, "exec-cgroup-context-allowed-cpus", cpuset_cpus
);
107 startup_cpuset_cpus
= cpu_set_to_range_string(&c
->startup_cpuset_cpus
);
108 if (!startup_cpuset_cpus
)
109 return log_oom_debug();
111 r
= serialize_item(f
, "exec-cgroup-context-startup-allowed-cpus", startup_cpuset_cpus
);
115 cpuset_mems
= cpu_set_to_range_string(&c
->cpuset_mems
);
117 return log_oom_debug();
119 r
= serialize_item(f
, "exec-cgroup-context-allowed-memory-nodes", cpuset_mems
);
123 startup_cpuset_mems
= cpu_set_to_range_string(&c
->startup_cpuset_mems
);
124 if (!startup_cpuset_mems
)
125 return log_oom_debug();
127 r
= serialize_item(f
, "exec-cgroup-context-startup-allowed-memory-nodes", startup_cpuset_mems
);
131 if (c
->io_weight
!= CGROUP_WEIGHT_INVALID
) {
132 r
= serialize_item_format(f
, "exec-cgroup-context-io-weight", "%" PRIu64
, c
->io_weight
);
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
);
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
);
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
);
155 if (c
->default_memory_min
> 0) {
156 r
= serialize_item_format(f
, "exec-cgroup-context-default-memory-min", "%" PRIu64
, c
->default_memory_min
);
161 if (c
->default_memory_low
> 0) {
162 r
= serialize_item_format(f
, "exec-cgroup-context-default-memory-low", "%" PRIu64
, c
->default_memory_low
);
167 if (c
->memory_min
> 0) {
168 r
= serialize_item_format(f
, "exec-cgroup-context-memory-min", "%" PRIu64
, c
->memory_min
);
173 if (c
->memory_low
> 0) {
174 r
= serialize_item_format(f
, "exec-cgroup-context-memory-low", "%" PRIu64
, c
->memory_low
);
179 if (c
->startup_memory_low
> 0) {
180 r
= serialize_item_format(f
, "exec-cgroup-context-startup-memory-low", "%" PRIu64
, c
->startup_memory_low
);
185 if (c
->memory_high
!= CGROUP_LIMIT_MAX
) {
186 r
= serialize_item_format(f
, "exec-cgroup-context-memory-high", "%" PRIu64
, c
->memory_high
);
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
);
197 if (c
->memory_max
!= CGROUP_LIMIT_MAX
) {
198 r
= serialize_item_format(f
, "exec-cgroup-context-memory-max", "%" PRIu64
, c
->memory_max
);
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
);
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
);
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
);
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
);
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
);
233 if (c
->memory_limit
!= CGROUP_LIMIT_MAX
) {
234 r
= serialize_item_format(f
, "exec-cgroup-context-memory-limit", "%" PRIu64
, c
->memory_limit
);
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
);
245 if (c
->tasks_max
.scale
> 0) {
246 r
= serialize_item_format(f
, "exec-cgroup-context-tasks-max-scale", "%" PRIu64
, c
->tasks_max
.scale
);
251 r
= serialize_bool_elide(f
, "exec-cgroup-context-default-memory-min-set", c
->default_memory_min_set
);
255 r
= serialize_bool_elide(f
, "exec-cgroup-context-default-memory-low-set", c
->default_memory_low_set
);
259 r
= serialize_bool_elide(f
, "exec-cgroup-context-default-startup-memory-low-set", c
->default_startup_memory_low_set
);
263 r
= serialize_bool_elide(f
, "exec-cgroup-context-memory-min-set", c
->memory_min_set
);
267 r
= serialize_bool_elide(f
, "exec-cgroup-context-memory-low-set", c
->memory_low_set
);
271 r
= serialize_bool_elide(f
, "exec-cgroup-context-startup-memory-low-set", c
->startup_memory_low_set
);
275 r
= serialize_bool_elide(f
, "exec-cgroup-context-startup-memory-high-set", c
->startup_memory_high_set
);
279 r
= serialize_bool_elide(f
, "exec-cgroup-context-startup-memory-max-set", c
->startup_memory_max_set
);
283 r
= serialize_bool_elide(f
, "exec-cgroup-context-startup-memory-swap-max-set", c
->startup_memory_swap_max_set
);
287 r
= serialize_bool_elide(f
, "exec-cgroup-context-startup-memory-zswap-max-set", c
->startup_memory_zswap_max_set
);
291 r
= serialize_item(f
, "exec-cgroup-context-device-policy", cgroup_device_policy_to_string(c
->device_policy
));
295 r
= cg_mask_to_string(c
->disable_controllers
, &disable_controllers_str
);
299 r
= serialize_item(f
, "exec-cgroup-context-disable-controllers", disable_controllers_str
);
303 r
= cg_mask_to_string(c
->delegate_controllers
, &delegate_controllers_str
);
307 r
= serialize_item(f
, "exec-cgroup-context-delegate-controllers", delegate_controllers_str
);
311 r
= serialize_bool_elide(f
, "exec-cgroup-context-delegate", c
->delegate
);
315 r
= serialize_item(f
, "exec-cgroup-context-managed-oom-swap", managed_oom_mode_to_string(c
->moom_swap
));
319 r
= serialize_item(f
, "exec-cgroup-context-managed-oom-memory-pressure", managed_oom_mode_to_string(c
->moom_mem_pressure
));
323 r
= serialize_item_format(f
, "exec-cgroup-context-managed-oom-memory-pressure-limit", "%" PRIu32
, c
->moom_mem_pressure_limit
);
327 r
= serialize_item(f
, "exec-cgroup-context-managed-oom-preference", managed_oom_preference_to_string(c
->moom_preference
));
331 r
= serialize_item(f
, "exec-cgroup-context-memory-pressure-watch", cgroup_pressure_watch_to_string(c
->memory_pressure_watch
));
335 r
= serialize_item(f
, "exec-cgroup-context-delegate-subgroup", c
->delegate_subgroup
);
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
);
345 LIST_FOREACH(device_allow
, a
, c
->device_allow
) {
346 r
= serialize_item_format(f
, "exec-cgroup-context-device-allow", "%s %s",
348 cgroup_device_permissions_to_string(a
->permissions
));
353 LIST_FOREACH(device_weights
, iw
, c
->io_device_weights
) {
354 r
= serialize_item_format(f
, "exec-cgroup-context-io-device-weight", "%s %" PRIu64
,
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
,
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
;
373 if (il
->limits
[type
] == cgroup_io_limit_defaults
[type
])
376 key
= strjoin("exec-cgroup-context-io-device-limit-", cgroup_io_limit_type_to_string(type
));
380 r
= serialize_item_format(f
, key
, "%s %" PRIu64
, il
->path
, il
->limits
[type
]);
385 LIST_FOREACH(device_weights
, w
, c
->blockio_device_weights
) {
386 r
= serialize_item_format(f
, "exec-cgroup-context-blockio-device-weight", "%s %" PRIu64
,
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
,
401 if (b
->wbps
!= CGROUP_LIMIT_MAX
) {
402 r
= serialize_item_format(f
, "exec-cgroup-context-blockio-write-bandwidth", "%s %" PRIu64
,
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
));
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
));
425 r
= serialize_bool_elide(f
, "exec-cgroup-context-ip-address-allow-reduced", c
->ip_address_allow_reduced
);
429 r
= serialize_bool_elide(f
, "exec-cgroup-context-ip-address-deny-reduced", c
->ip_address_deny_reduced
);
433 r
= serialize_strv(f
, "exec-cgroup-context-ip-ingress-filter-path=", c
->ip_filters_ingress
);
437 r
= serialize_strv(f
, "exec-cgroup-context-ip-egress-filter-path=", c
->ip_filters_egress
);
441 LIST_FOREACH(programs
, p
, c
->bpf_foreign_programs
) {
442 r
= serialize_item_format(f
, "exec-cgroup-context-bpf-program", "%" PRIu32
" %s",
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
);
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
);
461 SET_FOREACH(iface
, c
->restrict_network_interfaces
) {
462 r
= serialize_item(f
, "exec-cgroup-context-restrict-network-interfaces", iface
);
467 r
= serialize_bool_elide(
469 "exec-cgroup-context-restrict-network-interfaces-is-allow-list",
470 c
->restrict_network_interfaces_is_allow_list
);
474 fputc('\n', f
); /* End marker */
479 static int exec_cgroup_context_deserialize(CGroupContext
*c
, FILE *f
) {
488 _cleanup_free_
char *l
= NULL
;
491 r
= deserialize_read_line(f
, &l
);
494 if (r
== 0) /* eof or end marker */
497 if ((val
= startswith(l
, "exec-cgroup-context-cpu-accounting="))) {
498 r
= parse_boolean(val
);
501 c
->cpu_accounting
= r
;
502 } else if ((val
= startswith(l
, "exec-cgroup-context-io-accounting="))) {
503 r
= parse_boolean(val
);
506 c
->io_accounting
= r
;
507 } else if ((val
= startswith(l
, "exec-cgroup-context-block-io-accounting="))) {
508 r
= parse_boolean(val
);
511 c
->blockio_accounting
= r
;
512 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-accounting="))) {
513 r
= parse_boolean(val
);
516 c
->memory_accounting
= r
;
517 } else if ((val
= startswith(l
, "exec-cgroup-context-tasks-accounting="))) {
518 r
= parse_boolean(val
);
521 c
->tasks_accounting
= r
;
522 } else if ((val
= startswith(l
, "exec-cgroup-context-ip-accounting="))) {
523 r
= parse_boolean(val
);
526 c
->ip_accounting
= r
;
527 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-oom-group="))) {
528 r
= parse_boolean(val
);
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
);
536 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-cpu-weight="))) {
537 r
= safe_atou64(val
, &c
->startup_cpu_weight
);
540 } else if ((val
= startswith(l
, "exec-cgroup-context-cpu-shares="))) {
541 r
= safe_atou64(val
, &c
->cpu_shares
);
544 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-cpu-shares="))) {
545 r
= safe_atou64(val
, &c
->startup_cpu_shares
);
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
);
552 } else if ((val
= startswith(l
, "exec-cgroup-context-cpu-quota-period-usec="))) {
553 r
= deserialize_usec(val
, &c
->cpu_quota_period_usec
);
556 } else if ((val
= startswith(l
, "exec-cgroup-context-allowed-cpus="))) {
557 if (c
->cpuset_cpus
.set
)
558 return -EINVAL
; /* duplicated */
560 r
= parse_cpu_set_full(
565 /* filename= */ NULL
,
570 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-allowed-cpus="))) {
571 if (c
->startup_cpuset_cpus
.set
)
572 return -EINVAL
; /* duplicated */
574 r
= parse_cpu_set_full(
576 &c
->startup_cpuset_cpus
,
579 /* filename= */ NULL
,
584 } else if ((val
= startswith(l
, "exec-cgroup-context-allowed-memory-nodes="))) {
585 if (c
->cpuset_mems
.set
)
586 return -EINVAL
; /* duplicated */
588 r
= parse_cpu_set_full(
593 /* filename= */ NULL
,
598 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-allowed-memory-nodes="))) {
599 if (c
->startup_cpuset_mems
.set
)
600 return -EINVAL
; /* duplicated */
602 r
= parse_cpu_set_full(
604 &c
->startup_cpuset_mems
,
607 /* filename= */ NULL
,
612 } else if ((val
= startswith(l
, "exec-cgroup-context-io-weight="))) {
613 r
= safe_atou64(val
, &c
->io_weight
);
616 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-io-weight="))) {
617 r
= safe_atou64(val
, &c
->startup_io_weight
);
620 } else if ((val
= startswith(l
, "exec-cgroup-context-block-io-weight="))) {
621 r
= safe_atou64(val
, &c
->blockio_weight
);
624 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-block-io-weight="))) {
625 r
= safe_atou64(val
, &c
->startup_blockio_weight
);
628 } else if ((val
= startswith(l
, "exec-cgroup-context-default-memory-min="))) {
629 r
= safe_atou64(val
, &c
->default_memory_min
);
632 } else if ((val
= startswith(l
, "exec-cgroup-context-default-memory-low="))) {
633 r
= safe_atou64(val
, &c
->default_memory_low
);
636 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-min="))) {
637 r
= safe_atou64(val
, &c
->memory_min
);
640 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-low="))) {
641 r
= safe_atou64(val
, &c
->memory_low
);
644 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-low="))) {
645 r
= safe_atou64(val
, &c
->startup_memory_low
);
648 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-high="))) {
649 r
= safe_atou64(val
, &c
->memory_high
);
652 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-high="))) {
653 r
= safe_atou64(val
, &c
->startup_memory_high
);
656 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-max="))) {
657 r
= safe_atou64(val
, &c
->memory_max
);
660 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-max="))) {
661 r
= safe_atou64(val
, &c
->startup_memory_max
);
664 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-swap-max="))) {
665 r
= safe_atou64(val
, &c
->memory_swap_max
);
668 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-swap-max="))) {
669 r
= safe_atou64(val
, &c
->startup_memory_swap_max
);
672 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-zswap-max="))) {
673 r
= safe_atou64(val
, &c
->memory_zswap_max
);
676 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-zswap-max="))) {
677 r
= safe_atou64(val
, &c
->startup_memory_zswap_max
);
680 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-limit="))) {
681 r
= safe_atou64(val
, &c
->memory_limit
);
684 } else if ((val
= startswith(l
, "exec-cgroup-context-tasks-max-value="))) {
685 r
= safe_atou64(val
, &c
->tasks_max
.value
);
688 } else if ((val
= startswith(l
, "exec-cgroup-context-tasks-max-scale="))) {
689 r
= safe_atou64(val
, &c
->tasks_max
.scale
);
692 } else if ((val
= startswith(l
, "exec-cgroup-context-default-memory-min-set="))) {
693 r
= parse_boolean(val
);
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
);
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
);
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
);
711 c
->memory_min_set
= r
;
712 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-low-set="))) {
713 r
= parse_boolean(val
);
716 c
->memory_low_set
= r
;
717 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-low-set="))) {
718 r
= parse_boolean(val
);
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
);
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
);
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
);
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
);
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)
746 } else if ((val
= startswith(l
, "exec-cgroup-context-disable-controllers="))) {
747 r
= cg_mask_from_string(val
, &c
->disable_controllers
);
750 } else if ((val
= startswith(l
, "exec-cgroup-context-delegate-controllers="))) {
751 r
= cg_mask_from_string(val
, &c
->delegate_controllers
);
754 } else if ((val
= startswith(l
, "exec-cgroup-context-delegate="))) {
755 r
= parse_boolean(val
);
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)
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)
767 } else if ((val
= startswith(l
, "exec-cgroup-context-managed-oom-memory-pressure-limit="))) {
768 r
= safe_atou32(val
, &c
->moom_mem_pressure_limit
);
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)
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)
779 } else if ((val
= startswith(l
, "exec-cgroup-context-delegate-subgroup="))) {
780 r
= free_and_strdup(&c
->delegate_subgroup
, val
);
783 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-pressure-threshold-usec="))) {
784 r
= deserialize_usec(val
, &c
->memory_pressure_threshold_usec
);
787 } else if ((val
= startswith(l
, "exec-cgroup-context-device-allow="))) {
788 _cleanup_free_
char *path
= NULL
, *rwm
= NULL
;
789 CGroupDevicePermissions p
;
791 r
= extract_many_words(&val
, " ", 0, &path
, &rwm
, NULL
);
797 p
= isempty(rwm
) ? 0 : cgroup_device_permissions_from_string(rwm
);
801 r
= cgroup_context_add_or_update_device_allow(c
, path
, p
);
804 } else if ((val
= startswith(l
, "exec-cgroup-context-io-device-weight="))) {
805 _cleanup_free_
char *path
= NULL
, *weight
= NULL
;
806 CGroupIODeviceWeight
*a
= NULL
;
808 r
= extract_many_words(&val
, " ", 0, &path
, &weight
, NULL
);
814 LIST_FOREACH(device_weights
, b
, c
->io_device_weights
)
815 if (path_equal(b
->path
, path
)) {
821 a
= new0(CGroupIODeviceWeight
, 1);
823 return log_oom_debug();
825 a
->path
= TAKE_PTR(path
);
827 LIST_PREPEND(device_weights
, c
->io_device_weights
, a
);
830 r
= safe_atou64(weight
, &a
->weight
);
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
;
837 r
= extract_many_words(&val
, " ", 0, &path
, &target
, NULL
);
843 LIST_FOREACH(device_latencies
, b
, c
->io_device_latencies
)
844 if (path_equal(b
->path
, path
)) {
850 a
= new0(CGroupIODeviceLatency
, 1);
852 return log_oom_debug();
854 a
->path
= TAKE_PTR(path
);
856 LIST_PREPEND(device_latencies
, c
->io_device_latencies
, a
);
859 r
= deserialize_usec(target
, &a
->target_usec
);
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
;
867 r
= extract_many_words(&val
, "= ", 0, &type
, &path
, &limits
, NULL
);
873 t
= cgroup_io_limit_type_from_string(type
);
877 LIST_FOREACH(device_limits
, i
, c
->io_device_limits
)
878 if (path_equal(path
, i
->path
)) {
884 limit
= new0(CGroupIODeviceLimit
, 1);
886 return log_oom_debug();
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
];
892 LIST_PREPEND(device_limits
, c
->io_device_limits
, limit
);
895 r
= safe_atou64(limits
, &limit
->limits
[t
]);
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
;
902 r
= extract_many_words(&val
, " ", 0, &path
, &weight
, NULL
);
908 a
= new0(CGroupBlockIODeviceWeight
, 1);
910 return log_oom_debug();
912 a
->path
= TAKE_PTR(path
);
914 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, a
);
916 r
= safe_atou64(weight
, &a
->weight
);
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
;
923 r
= extract_many_words(&val
, " ", 0, &path
, &bw
, NULL
);
929 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
)
930 if (path_equal(b
->path
, path
)) {
936 a
= new0(CGroupBlockIODeviceBandwidth
, 1);
938 return log_oom_debug();
940 a
->path
= TAKE_PTR(path
);
941 a
->wbps
= CGROUP_LIMIT_MAX
;
943 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, a
);
946 r
= safe_atou64(bw
, &a
->rbps
);
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
;
953 r
= extract_many_words(&val
, " ", 0, &path
, &bw
, NULL
);
959 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
)
960 if (path_equal(b
->path
, path
)) {
966 a
= new0(CGroupBlockIODeviceBandwidth
, 1);
968 return log_oom_debug();
970 a
->path
= TAKE_PTR(path
);
971 a
->rbps
= CGROUP_LIMIT_MAX
;
973 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, a
);
976 r
= safe_atou64(bw
, &a
->wbps
);
979 } else if ((val
= startswith(l
, "exec-cgroup-context-ip-address-allow="))) {
980 struct in_addr_prefix a
;
982 r
= in_addr_prefix_from_string_auto(val
, &a
.family
, &a
.address
, &a
.prefixlen
);
986 r
= in_addr_prefix_add(&c
->ip_address_allow
, &a
);
989 } else if ((val
= startswith(l
, "exec-cgroup-context-ip-address-deny="))) {
990 struct in_addr_prefix a
;
992 r
= in_addr_prefix_from_string_auto(val
, &a
.family
, &a
.address
, &a
.prefixlen
);
996 r
= in_addr_prefix_add(&c
->ip_address_deny
, &a
);
999 } else if ((val
= startswith(l
, "exec-cgroup-context-ip-address-allow-reduced="))) {
1000 r
= parse_boolean(val
);
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
);
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
);
1013 } else if ((val
= startswith(l
, "exec-cgroup-context-ip-egress-filter-path="))) {
1014 r
= deserialize_strv(val
, &c
->ip_filters_egress
);
1017 } else if ((val
= startswith(l
, "exec-cgroup-context-bpf-program="))) {
1018 _cleanup_free_
char *type
= NULL
, *path
= NULL
;
1021 r
= extract_many_words(&val
, " ", 0, &type
, &path
, NULL
);
1027 r
= safe_atou32(type
, &t
);
1031 r
= cgroup_context_add_bpf_foreign_program(c
, t
, path
);
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
;
1039 r
= parse_socket_bind_item(val
, &af
, &ip_protocol
, &nr_ports
, &port_min
);
1043 item
= new(CGroupSocketBindItem
, 1);
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
,
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
;
1059 r
= parse_socket_bind_item(val
, &af
, &ip_protocol
, &nr_ports
, &port_min
);
1063 item
= new(CGroupSocketBindItem
, 1);
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
,
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
);
1079 r
= set_put_strdup(&c
->restrict_network_interfaces
, val
);
1082 } else if ((val
= startswith(l
, "exec-cgroup-context-restrict-network-interfaces-is-allow-list="))) {
1083 r
= parse_boolean(val
);
1086 c
->restrict_network_interfaces_is_allow_list
= r
;
1088 log_warning("Failed to parse serialized line, ignoring: %s", l
);
1094 static int exec_runtime_serialize(const ExecRuntime
*rt
, FILE *f
, FDSet
*fds
) {
1101 fputc('\n', f
); /* End marker */
1106 r
= serialize_item(f
, "exec-runtime-id", rt
->shared
->id
);
1110 r
= serialize_item(f
, "exec-runtime-tmp-dir", rt
->shared
->tmp_dir
);
1114 r
= serialize_item(f
, "exec-runtime-var-tmp-dir", rt
->shared
->var_tmp_dir
);
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);
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);
1131 if (rt
->dynamic_creds
) {
1132 r
= dynamic_user_serialize_one(rt
->dynamic_creds
->user
, "exec-runtime-dynamic-creds-user", f
, fds
);
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);
1141 } else if (rt
->dynamic_creds
) {
1142 r
= dynamic_user_serialize_one(rt
->dynamic_creds
->group
, "exec-runtime-dynamic-creds-group", f
, fds
);
1147 r
= serialize_item(f
, "exec-runtime-ephemeral-copy", rt
->ephemeral_copy
);
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);
1157 fputc('\n', f
); /* End marker */
1162 static int exec_runtime_deserialize(ExecRuntime
*rt
, FILE *f
, FDSet
*fds
) {
1167 assert(rt
->dynamic_creds
);
1172 _cleanup_free_
char *l
= NULL
;
1175 r
= deserialize_read_line(f
, &l
);
1178 if (r
== 0) /* eof or end marker */
1181 if ((val
= startswith(l
, "exec-runtime-id="))) {
1182 r
= free_and_strdup(&rt
->shared
->id
, val
);
1185 } else if ((val
= startswith(l
, "exec-runtime-tmp-dir="))) {
1186 r
= free_and_strdup(&rt
->shared
->tmp_dir
, val
);
1189 } else if ((val
= startswith(l
, "exec-runtime-var-tmp-dir="))) {
1190 r
= free_and_strdup(&rt
->shared
->var_tmp_dir
, val
);
1193 } else if ((val
= startswith(l
, "exec-runtime-netns-storage-socket="))) {
1195 r
= deserialize_fd_many(fds
, val
, 2, rt
->shared
->netns_storage_socket
);
1199 } else if ((val
= startswith(l
, "exec-runtime-ipcns-storage-socket="))) {
1201 r
= deserialize_fd_many(fds
, val
, 2, rt
->shared
->ipcns_storage_socket
);
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
);
1214 continue; /* Nothing to do */
1216 if (!rt
->dynamic_creds
->user
)
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
);
1224 } else if ((val
= startswith(l
, "exec-runtime-ephemeral-storage-socket="))) {
1226 r
= deserialize_fd_many(fds
, val
, 2, rt
->ephemeral_storage_socket
);
1230 log_warning("Failed to parse serialized line, ignoring: %s", l
);
1236 static bool exec_parameters_is_idle_pipe_set(const ExecParameters
*p
) {
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;
1246 static int exec_parameters_serialize(const ExecParameters
*p
, const ExecContext
*c
, FILE *f
, FDSet
*fds
) {
1255 r
= serialize_item(f
, "exec-parameters-runtime-scope", runtime_scope_to_string(p
->runtime_scope
));
1259 r
= serialize_strv(f
, "exec-parameters-environment", p
->environment
);
1264 if (p
->n_socket_fds
> 0) {
1265 r
= serialize_item_format(f
, "exec-parameters-n-socket-fds", "%zu", p
->n_socket_fds
);
1270 if (p
->n_storage_fds
> 0) {
1271 r
= serialize_item_format(f
, "exec-parameters-n-storage-fds", "%zu", p
->n_storage_fds
);
1276 r
= serialize_fd_many(f
, fds
, "exec-parameters-fds", p
->fds
, p
->n_socket_fds
+ p
->n_storage_fds
);
1281 r
= serialize_strv(f
, "exec-parameters-fd-names", p
->fd_names
);
1285 if (p
->flags
!= 0) {
1286 r
= serialize_item_format(f
, "exec-parameters-flags", "%u", (unsigned) p
->flags
);
1291 r
= serialize_bool_elide(f
, "exec-parameters-selinux-context-net", p
->selinux_context_net
);
1295 if (p
->cgroup_supported
!= 0) {
1296 r
= serialize_item_format(f
, "exec-parameters-cgroup-supported", "%u", (unsigned) p
->cgroup_supported
);
1301 r
= serialize_item(f
, "exec-parameters-cgroup-path", p
->cgroup_path
);
1305 r
= serialize_item_format(f
, "exec-parameters-cgroup-id", "%" PRIu64
, p
->cgroup_id
);
1309 for (ExecDirectoryType dt
= 0; dt
< _EXEC_DIRECTORY_TYPE_MAX
; dt
++) {
1310 _cleanup_free_
char *key
= NULL
;
1312 key
= strjoin("exec-parameters-prefix-directories-", exec_directory_type_to_string(dt
));
1314 return log_oom_debug();
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
));
1323 r
= serialize_item(f
, "exec-parameters-received-credentials-directory", p
->received_credentials_directory
);
1327 r
= serialize_item(f
, "exec-parameters-received-encrypted-credentials-directory", p
->received_encrypted_credentials_directory
);
1331 r
= serialize_item(f
, "exec-parameters-confirm-spawn", p
->confirm_spawn
);
1335 r
= serialize_bool_elide(f
, "exec-parameters-shall-confirm-spawn", p
->shall_confirm_spawn
);
1339 if (p
->watchdog_usec
> 0) {
1340 r
= serialize_usec(f
, "exec-parameters-watchdog-usec", p
->watchdog_usec
);
1345 if (exec_parameters_is_idle_pipe_set(p
)) {
1346 r
= serialize_fd_many(f
, fds
, "exec-parameters-idle-pipe", p
->idle_pipe
, 4);
1351 r
= serialize_fd(f
, fds
, "exec-parameters-stdin-fd", p
->stdin_fd
);
1355 r
= serialize_fd(f
, fds
, "exec-parameters-stdout-fd", p
->stdout_fd
);
1359 r
= serialize_fd(f
, fds
, "exec-parameters-stderr-fd", p
->stderr_fd
);
1363 r
= serialize_fd(f
, fds
, "exec-parameters-exec-fd", p
->exec_fd
);
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
);
1373 r
= serialize_item(f
, "exec-parameters-notify-socket", p
->notify_socket
);
1377 LIST_FOREACH(open_files
, file
, p
->open_files
) {
1378 _cleanup_free_
char *ofs
= NULL
;
1380 r
= open_file_to_string(file
, &ofs
);
1384 r
= serialize_item(f
, "exec-parameters-open-file", ofs
);
1389 r
= serialize_item(f
, "exec-parameters-fallback-smack-process-label", p
->fallback_smack_process_label
);
1393 r
= serialize_fd(f
, fds
, "exec-parameters-user-lookup-fd", p
->user_lookup_fd
);
1397 r
= serialize_strv(f
, "exec-parameters-files-env", p
->files_env
);
1401 r
= serialize_item(f
, "exec-parameters-unit-id", p
->unit_id
);
1405 r
= serialize_item(f
, "exec-parameters-invocation-id-string", p
->invocation_id_string
);
1409 fputc('\n', f
); /* End marker */
1414 static int exec_parameters_deserialize(ExecParameters
*p
, FILE *f
, FDSet
*fds
) {
1421 nr_open
= read_nr_open();
1423 nr_open
= HIGH_RLIMIT_NOFILE
;
1424 assert(nr_open
> 0); /* For compilers/static analyzers */
1427 _cleanup_free_
char *l
= NULL
;
1430 r
= deserialize_read_line(f
, &l
);
1433 if (r
== 0) /* eof or end marker */
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
);
1444 } else if ((val
= startswith(l
, "exec-parameters-n-socket-fds="))) {
1446 return -EINVAL
; /* Already received */
1448 r
= safe_atozu(val
, &p
->n_socket_fds
);
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="))) {
1456 return -EINVAL
; /* Already received */
1458 r
= safe_atozu(val
, &p
->n_storage_fds
);
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 */
1474 return -EINVAL
; /* duplicated */
1476 p
->fds
= new(int, p
->n_socket_fds
+ p
->n_storage_fds
);
1478 return log_oom_debug();
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
)
1484 r
= deserialize_fd_many(fds
, val
, p
->n_socket_fds
+ p
->n_storage_fds
, p
->fds
);
1488 } else if ((val
= startswith(l
, "exec-parameters-fd-names="))) {
1489 r
= deserialize_strv(val
, &p
->fd_names
);
1492 } else if ((val
= startswith(l
, "exec-parameters-flags="))) {
1495 r
= safe_atou(val
, &flags
);
1499 } else if ((val
= startswith(l
, "exec-parameters-selinux-context-net="))) {
1500 r
= parse_boolean(val
);
1504 p
->selinux_context_net
= r
;
1505 } else if ((val
= startswith(l
, "exec-parameters-cgroup-supported="))) {
1506 unsigned cgroup_supported
;
1508 r
= safe_atou(val
, &cgroup_supported
);
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
);
1516 } else if ((val
= startswith(l
, "exec-parameters-cgroup-id="))) {
1517 r
= safe_atou64(val
, &p
->cgroup_id
);
1520 } else if ((val
= startswith(l
, "exec-parameters-prefix-directories-"))) {
1521 _cleanup_free_
char *type
= NULL
, *prefix
= NULL
;
1522 ExecDirectoryType dt
;
1524 r
= extract_many_words(&val
, "= ", 0, &type
, &prefix
, NULL
);
1530 dt
= exec_directory_type_from_string(type
);
1535 p
->prefix
= new0(char*, _EXEC_DIRECTORY_TYPE_MAX
+1);
1537 return log_oom_debug();
1540 if (isempty(prefix
))
1541 p
->prefix
[dt
] = mfree(p
->prefix
[dt
]);
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
);
1548 } else if ((val
= startswith(l
, "exec-parameters-received-encrypted-credentials-directory="))) {
1549 r
= free_and_strdup(&p
->received_encrypted_credentials_directory
, val
);
1552 } else if ((val
= startswith(l
, "exec-parameters-confirm-spawn="))) {
1553 r
= free_and_strdup(&p
->confirm_spawn
, val
);
1556 } else if ((val
= startswith(l
, "exec-parameters-shall-confirm-spawn="))) {
1557 r
= parse_boolean(val
);
1561 p
->shall_confirm_spawn
= r
;
1562 } else if ((val
= startswith(l
, "exec-parameters-watchdog-usec="))) {
1563 r
= deserialize_usec(val
, &p
->watchdog_usec
);
1566 } else if ((val
= startswith(l
, "exec-parameters-idle-pipe="))) {
1568 return -EINVAL
; /* duplicated */
1570 p
->idle_pipe
= new(int, 4);
1572 return log_oom_debug();
1574 p
->idle_pipe
[0] = p
->idle_pipe
[1] = p
->idle_pipe
[2] = p
->idle_pipe
[3] = -EBADF
;
1576 r
= deserialize_fd_many(fds
, val
, 4, p
->idle_pipe
);
1580 } else if ((val
= startswith(l
, "exec-parameters-stdin-fd="))) {
1583 fd
= deserialize_fd(fds
, val
);
1589 } else if ((val
= startswith(l
, "exec-parameters-stdout-fd="))) {
1592 fd
= deserialize_fd(fds
, val
);
1598 } else if ((val
= startswith(l
, "exec-parameters-stderr-fd="))) {
1601 fd
= deserialize_fd(fds
, val
);
1606 } else if ((val
= startswith(l
, "exec-parameters-exec-fd="))) {
1609 fd
= deserialize_fd(fds
, val
);
1614 } else if ((val
= startswith(l
, "exec-parameters-bpf-outer-map-fd="))) {
1617 fd
= deserialize_fd(fds
, val
);
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
);
1626 } else if ((val
= startswith(l
, "exec-parameters-open-file="))) {
1627 OpenFile
*of
= NULL
;
1629 r
= open_file_parse(val
, &of
);
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
);
1638 } else if ((val
= startswith(l
, "exec-parameters-user-lookup-fd="))) {
1641 fd
= deserialize_fd(fds
, val
);
1645 p
->user_lookup_fd
= fd
;
1646 } else if ((val
= startswith(l
, "exec-parameters-files-env="))) {
1647 r
= deserialize_strv(val
, &p
->files_env
);
1650 } else if ((val
= startswith(l
, "exec-parameters-unit-id="))) {
1651 r
= free_and_strdup(&p
->unit_id
, val
);
1654 } else if ((val
= startswith(l
, "exec-parameters-invocation-id-string="))) {
1655 if (strlen(val
) > SD_ID128_STRING_MAX
- 1)
1658 r
= sd_id128_from_string(val
, &p
->invocation_id
);
1662 sd_id128_to_string(p
->invocation_id
, p
->invocation_id_string
);
1664 log_warning("Failed to parse serialized line, ignoring: %s", l
);
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
)
1675 static int serialize_std_out_err(const ExecContext
*c
, FILE *f
, int fileno
) {
1681 assert(IN_SET(fileno
, STDOUT_FILENO
, STDERR_FILENO
));
1683 type
= fileno
== STDOUT_FILENO
? "output" : "error";
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
];
1692 case EXEC_OUTPUT_FILE
:
1693 key
= strjoina("exec-context-std-", type
, "-file");
1694 value
= c
->stdio_file
[fileno
];
1698 case EXEC_OUTPUT_FILE_APPEND
:
1699 key
= strjoina("exec-context-std-", type
, "-file-append");
1700 value
= c
->stdio_file
[fileno
];
1704 case EXEC_OUTPUT_FILE_TRUNCATE
:
1705 key
= strjoina("exec-context-std-", type
, "-file-truncate");
1706 value
= c
->stdio_file
[fileno
];
1714 return serialize_item(f
, key
, value
);
1717 static int exec_context_serialize(const ExecContext
*c
, FILE *f
) {
1725 r
= serialize_strv(f
, "exec-context-environment", c
->environment
);
1729 r
= serialize_strv(f
, "exec-context-environment-files", c
->environment_files
);
1733 r
= serialize_strv(f
, "exec-context-pass-environment", c
->pass_environment
);
1737 r
= serialize_strv(f
, "exec-context-unset-environment", c
->unset_environment
);
1741 r
= serialize_item(f
, "exec-context-working-directory", c
->working_directory
);
1745 r
= serialize_item(f
, "exec-context-root-directory", c
->root_directory
);
1749 r
= serialize_item(f
, "exec-context-root-image", c
->root_image
);
1753 if (c
->root_image_options
) {
1754 _cleanup_free_
char *options
= NULL
;
1756 LIST_FOREACH(mount_options
, o
, c
->root_image_options
) {
1757 if (isempty(o
->options
))
1760 _cleanup_free_
char *escaped
= NULL
;
1761 escaped
= shell_escape(o
->options
, ":");
1763 return log_oom_debug();
1765 if (!strextend(&options
,
1767 partition_designator_to_string(o
->partition_designator
),
1770 return log_oom_debug();
1773 r
= serialize_item(f
, "exec-context-root-image-options", options
);
1778 r
= serialize_item(f
, "exec-context-root-verity", c
->root_verity
);
1782 r
= serialize_item(f
, "exec-context-root-hash-path", c
->root_hash_path
);
1786 r
= serialize_item(f
, "exec-context-root-hash-sig-path", c
->root_hash_sig_path
);
1790 r
= serialize_item_hexmem(f
, "exec-context-root-hash", c
->root_hash
, c
->root_hash_size
);
1794 r
= serialize_item_base64mem(f
, "exec-context-root-hash-sig", c
->root_hash_sig
, c
->root_hash_sig_size
);
1798 r
= serialize_bool_elide(f
, "exec-context-root-ephemeral", c
->root_ephemeral
);
1802 r
= serialize_item_format(f
, "exec-context-umask", "%04o", c
->umask
);
1806 r
= serialize_bool_elide(f
, "exec-context-non-blocking", c
->non_blocking
);
1810 r
= serialize_item_tristate(f
, "exec-context-private-mounts", c
->private_mounts
);
1814 r
= serialize_item_tristate(f
, "exec-context-memory-ksm", c
->memory_ksm
);
1818 r
= serialize_bool_elide(f
, "exec-context-private-tmp", c
->private_tmp
);
1822 r
= serialize_bool_elide(f
, "exec-context-private-devices", c
->private_devices
);
1826 r
= serialize_bool_elide(f
, "exec-context-protect-kernel-tunables", c
->protect_kernel_tunables
);
1830 r
= serialize_bool_elide(f
, "exec-context-protect-kernel-modules", c
->protect_kernel_modules
);
1834 r
= serialize_bool_elide(f
, "exec-context-protect-kernel-logs", c
->protect_kernel_logs
);
1838 r
= serialize_bool_elide(f
, "exec-context-protect-clock", c
->protect_clock
);
1842 r
= serialize_bool_elide(f
, "exec-context-protect-control-groups", c
->protect_control_groups
);
1846 r
= serialize_bool_elide(f
, "exec-context-private-network", c
->private_network
);
1850 r
= serialize_bool_elide(f
, "exec-context-private-users", c
->private_users
);
1854 r
= serialize_bool_elide(f
, "exec-context-private-ipc", c
->private_ipc
);
1858 r
= serialize_bool_elide(f
, "exec-context-remove-ipc", c
->remove_ipc
);
1862 r
= serialize_item(f
, "exec-context-protect-home", protect_home_to_string(c
->protect_home
));
1866 r
= serialize_item(f
, "exec-context-protect-system", protect_system_to_string(c
->protect_system
));
1870 if (c
->mount_apivfs_set
) {
1871 r
= serialize_bool(f
, "exec-context-mount-api-vfs", c
->mount_apivfs
);
1876 r
= serialize_bool_elide(f
, "exec-context-same-pgrp", c
->same_pgrp
);
1880 r
= serialize_bool_elide(f
, "exec-context-cpu-sched-reset-on-fork", c
->cpu_sched_reset_on_fork
);
1884 r
= serialize_bool(f
, "exec-context-ignore-sigpipe", c
->ignore_sigpipe
);
1888 r
= serialize_bool_elide(f
, "exec-context-memory-deny-write-execute", c
->memory_deny_write_execute
);
1892 r
= serialize_bool_elide(f
, "exec-context-restrict-realtime", c
->restrict_realtime
);
1896 r
= serialize_bool_elide(f
, "exec-context-restrict-suid-sgid", c
->restrict_suid_sgid
);
1900 r
= serialize_item(f
, "exec-context-keyring-mode", exec_keyring_mode_to_string(c
->keyring_mode
));
1904 r
= serialize_bool_elide(f
, "exec-context-protect-hostname", c
->protect_hostname
);
1908 r
= serialize_item(f
, "exec-context-protect-proc", protect_proc_to_string(c
->protect_proc
));
1912 r
= serialize_item(f
, "exec-context-proc-subset", proc_subset_to_string(c
->proc_subset
));
1916 r
= serialize_item(f
, "exec-context-runtime-directory-preserve-mode", exec_preserve_mode_to_string(c
->runtime_directory_preserve_mode
));
1920 for (ExecDirectoryType dt
= 0; dt
< _EXEC_DIRECTORY_TYPE_MAX
; dt
++) {
1921 _cleanup_free_
char *key
= NULL
, *value
= NULL
;
1923 key
= strjoin("exec-context-directories-", exec_directory_type_to_string(dt
));
1925 return log_oom_debug();
1927 if (asprintf(&value
, "%04o", c
->directories
[dt
].mode
) < 0)
1928 return log_oom_debug();
1930 FOREACH_ARRAY(i
, c
->directories
[dt
].items
, c
->directories
[dt
].n_items
) {
1931 _cleanup_free_
char *path_escaped
= NULL
;
1933 path_escaped
= shell_escape(i
->path
, ":" WHITESPACE
);
1935 return log_oom_debug();
1937 if (!strextend(&value
, " ", path_escaped
))
1938 return log_oom_debug();
1940 if (!strextend(&value
, ":", yes_no(i
->only_create
)))
1941 return log_oom_debug();
1943 STRV_FOREACH(d
, i
->symlinks
) {
1944 _cleanup_free_
char *link_escaped
= NULL
;
1946 link_escaped
= shell_escape(*d
, ":" WHITESPACE
);
1948 return log_oom_debug();
1950 if (!strextend(&value
, ":", link_escaped
))
1951 return log_oom_debug();
1955 r
= serialize_item(f
, key
, value
);
1960 r
= serialize_usec(f
, "exec-context-timeout-clean-usec", c
->timeout_clean_usec
);
1965 r
= serialize_item_format(f
, "exec-context-nice", "%i", c
->nice
);
1970 r
= serialize_bool_elide(f
, "exec-context-working-directory-missing-ok", c
->working_directory_missing_ok
);
1974 r
= serialize_bool_elide(f
, "exec-context-working-directory-home", c
->working_directory_home
);
1978 if (c
->oom_score_adjust_set
) {
1979 r
= serialize_item_format(f
, "exec-context-oom-score-adjust", "%i", c
->oom_score_adjust
);
1984 if (c
->coredump_filter_set
) {
1985 r
= serialize_item_format(f
, "exec-context-coredump-filter", "%"PRIx64
, c
->coredump_filter
);
1990 for (unsigned i
= 0; i
< RLIM_NLIMITS
; i
++) {
1991 _cleanup_free_
char *key
= NULL
, *limit
= NULL
;
1996 key
= strjoin("exec-context-limit-", rlimit_to_string(i
));
1998 return log_oom_debug();
2000 r
= rlimit_format(c
->rlimit
[i
], &limit
);
2004 r
= serialize_item(f
, key
, limit
);
2009 if (c
->ioprio_set
) {
2010 r
= serialize_item_format(f
, "exec-context-ioprio", "%d", c
->ioprio
);
2015 if (c
->cpu_sched_set
) {
2016 _cleanup_free_
char *policy_str
= NULL
;
2018 r
= sched_policy_to_string_alloc(c
->cpu_sched_policy
, &policy_str
);
2022 r
= serialize_item(f
, "exec-context-cpu-scheduling-policy", policy_str
);
2026 r
= serialize_item_format(f
, "exec-context-cpu-scheduling-priority", "%i", c
->cpu_sched_priority
);
2030 r
= serialize_bool_elide(f
, "exec-context-cpu-scheduling-reset-on-fork", c
->cpu_sched_reset_on_fork
);
2035 if (c
->cpu_set
.set
) {
2036 _cleanup_free_
char *affinity
= NULL
;
2038 affinity
= cpu_set_to_range_string(&c
->cpu_set
);
2040 return log_oom_debug();
2042 r
= serialize_item(f
, "exec-context-cpu-affinity", affinity
);
2047 if (mpol_is_valid(numa_policy_get_type(&c
->numa_policy
))) {
2048 _cleanup_free_
char *nodes
= NULL
;
2050 nodes
= cpu_set_to_range_string(&c
->numa_policy
.nodes
);
2052 return log_oom_debug();
2055 r
= serialize_item(f
, "exec-context-numa-mask", nodes
);
2060 r
= serialize_item_format(f
, "exec-context-numa-policy", "%d", c
->numa_policy
.type
);
2065 r
= serialize_bool_elide(f
, "exec-context-cpu-affinity-from-numa", c
->cpu_affinity_from_numa
);
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
);
2075 r
= serialize_item(f
, "exec-context-std-input", exec_input_to_string(c
->std_input
));
2079 r
= serialize_item(f
, "exec-context-std-output", exec_output_to_string(c
->std_output
));
2083 r
= serialize_item(f
, "exec-context-std-error", exec_output_to_string(c
->std_error
));
2087 r
= serialize_bool_elide(f
, "exec-context-stdio-as-fds", c
->stdio_as_fds
);
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
]);
2098 case EXEC_INPUT_FILE
:
2099 r
= serialize_item(f
, "exec-context-std-input-file", c
->stdio_file
[STDIN_FILENO
]);
2108 r
= serialize_std_out_err(c
, f
, STDOUT_FILENO
);
2112 r
= serialize_std_out_err(c
, f
, STDERR_FILENO
);
2116 r
= serialize_item_base64mem(f
, "exec-context-stdin-data", c
->stdin_data
, c
->stdin_data_size
);
2120 r
= serialize_item(f
, "exec-context-tty-path", c
->tty_path
);
2124 r
= serialize_bool_elide(f
, "exec-context-tty-reset", c
->tty_reset
);
2128 r
= serialize_bool_elide(f
, "exec-context-tty-vhangup", c
->tty_vhangup
);
2132 r
= serialize_bool_elide(f
, "exec-context-tty-vt-disallocate", c
->tty_vt_disallocate
);
2136 r
= serialize_item_format(f
, "exec-context-tty-rows", "%u", c
->tty_rows
);
2140 r
= serialize_item_format(f
, "exec-context-tty-columns", "%u", c
->tty_cols
);
2144 r
= serialize_item_format(f
, "exec-context-syslog-priority", "%i", c
->syslog_priority
);
2148 r
= serialize_bool(f
, "exec-context-syslog-level-prefix", c
->syslog_level_prefix
);
2152 r
= serialize_item(f
, "exec-context-syslog-identifier", c
->syslog_identifier
);
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
);
2162 if (c
->log_ratelimit_interval_usec
> 0) {
2163 r
= serialize_usec(f
, "exec-context-log-ratelimit-interval-usec", c
->log_ratelimit_interval_usec
);
2168 if (c
->log_ratelimit_burst
> 0) {
2169 r
= serialize_item_format(f
, "exec-context-log-ratelimit-burst", "%u", c
->log_ratelimit_burst
);
2174 r
= serialize_string_set(f
, "exec-context-log-filter-allowed-patterns", c
->log_filter_allowed_patterns
);
2178 r
= serialize_string_set(f
, "exec-context-log-filter-denied-patterns", c
->log_filter_denied_patterns
);
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
);
2188 r
= serialize_item(f
, "exec-context-log-namespace", c
->log_namespace
);
2192 if (c
->secure_bits
!= 0) {
2193 r
= serialize_item_format(f
, "exec-context-secure-bits", "%d", c
->secure_bits
);
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
);
2204 if (c
->capability_ambient_set
!= 0) {
2205 r
= serialize_item_format(f
, "exec-context-capability-ambient-set", "%" PRIu64
, c
->capability_ambient_set
);
2211 r
= serialize_item(f
, "exec-context-user", c
->user
);
2216 r
= serialize_item(f
, "exec-context-group", c
->group
);
2220 r
= serialize_bool_elide(f
, "exec-context-dynamic-user", c
->dynamic_user
);
2224 r
= serialize_strv(f
, "exec-context-supplementary-groups", c
->supplementary_groups
);
2228 r
= serialize_item_tristate(f
, "exec-context-set-login-environment", c
->set_login_environment
);
2232 r
= serialize_item(f
, "exec-context-pam-name", c
->pam_name
);
2236 r
= serialize_strv(f
, "exec-context-read-write-paths", c
->read_write_paths
);
2240 r
= serialize_strv(f
, "exec-context-read-only-paths", c
->read_only_paths
);
2244 r
= serialize_strv(f
, "exec-context-inaccessible-paths", c
->inaccessible_paths
);
2248 r
= serialize_strv(f
, "exec-context-exec-paths", c
->exec_paths
);
2252 r
= serialize_strv(f
, "exec-context-no-exec-paths", c
->no_exec_paths
);
2256 r
= serialize_strv(f
, "exec-context-exec-search-path", c
->exec_search_path
);
2260 r
= serialize_item_format(f
, "exec-context-mount-propagation-flag", "%lu", c
->mount_propagation_flag
);
2264 FOREACH_ARRAY(mount
, c
->bind_mounts
, c
->n_bind_mounts
) {
2265 _cleanup_free_
char *src_escaped
= NULL
, *dst_escaped
= NULL
;
2267 src_escaped
= shell_escape(mount
->source
, ":" WHITESPACE
);
2269 return log_oom_debug();
2271 dst_escaped
= shell_escape(mount
->destination
, ":" WHITESPACE
);
2273 return log_oom_debug();
2275 r
= serialize_item_format(f
,
2276 mount
->read_only
? "exec-context-bind-read-only-path" : "exec-context-bind-path",
2278 mount
->ignore_enoent
? "-" : "",
2281 mount
->recursive
? "rbind" : "norbind");
2286 FOREACH_ARRAY(tmpfs
, c
->temporary_filesystems
, c
->n_temporary_filesystems
) {
2287 _cleanup_free_
char *escaped
= NULL
;
2289 if (!isempty(tmpfs
->options
)) {
2290 escaped
= shell_escape(tmpfs
->options
, ":");
2292 return log_oom_debug();
2295 r
= serialize_item_format(f
, "exec-context-temporary-filesystems", "%s%s%s",
2297 isempty(escaped
) ? "" : ":",
2303 r
= serialize_item(f
, "exec-context-utmp-id", c
->utmp_id
);
2307 r
= serialize_item(f
, "exec-context-utmp-mode", exec_utmp_mode_to_string(c
->utmp_mode
));
2311 r
= serialize_bool_elide(f
, "exec-context-no-new-privileges", c
->no_new_privileges
);
2315 r
= serialize_bool_elide(f
, "exec-context-selinux-context-ignore", c
->selinux_context_ignore
);
2319 r
= serialize_bool_elide(f
, "exec-context-apparmor-profile-ignore", c
->apparmor_profile_ignore
);
2323 r
= serialize_bool_elide(f
, "exec-context-smack-process-label-ignore", c
->smack_process_label_ignore
);
2327 if (c
->selinux_context
) {
2328 r
= serialize_item_format(f
, "exec-context-selinux-context",
2330 c
->selinux_context_ignore
? "-" : "",
2331 c
->selinux_context
);
2336 if (c
->apparmor_profile
) {
2337 r
= serialize_item_format(f
, "exec-context-apparmor-profile",
2339 c
->apparmor_profile_ignore
? "-" : "",
2340 c
->apparmor_profile
);
2345 if (c
->smack_process_label
) {
2346 r
= serialize_item_format(f
, "exec-context-smack-process-label",
2348 c
->smack_process_label_ignore
? "-" : "",
2349 c
->smack_process_label
);
2354 if (c
->personality
!= PERSONALITY_INVALID
) {
2355 r
= serialize_item(f
, "exec-context-personality", personality_to_string(c
->personality
));
2360 r
= serialize_bool_elide(f
, "exec-context-lock-personality", c
->lock_personality
);
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
));
2374 if (!set_isempty(c
->syscall_archs
)) {
2376 SET_FOREACH(id
, c
->syscall_archs
) {
2377 r
= serialize_item_format(f
, "exec-context-syscall-archs", "%u", PTR_TO_UINT(id
) - 1);
2383 if (c
->syscall_errno
> 0) {
2384 r
= serialize_item_format(f
, "exec-context-syscall-errno", "%d", c
->syscall_errno
);
2389 r
= serialize_bool_elide(f
, "exec-context-syscall-allow-list", c
->syscall_allow_list
);
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
));
2402 r
= serialize_bool_elide(f
, "exec-context-syscall-log-allow-list", c
->syscall_log_allow_list
);
2407 if (c
->restrict_namespaces
!= NAMESPACE_FLAGS_INITIAL
) {
2408 r
= serialize_item_format(f
, "exec-context-restrict-namespaces", "%lu", c
->restrict_namespaces
);
2414 if (exec_context_restrict_filesystems_set(c
)) {
2416 SET_FOREACH(fs
, c
->restrict_filesystems
) {
2417 r
= serialize_item(f
, "exec-context-restrict-filesystems", fs
);
2423 r
= serialize_bool_elide(f
, "exec-context-restrict-filesystems-allow-list", c
->restrict_filesystems_allow_list
);
2428 if (!set_isempty(c
->address_families
)) {
2431 SET_FOREACH(afp
, c
->address_families
) {
2432 int af
= PTR_TO_INT(afp
);
2434 if (af
<= 0 || af
>= af_max())
2437 r
= serialize_item_format(f
, "exec-context-address-families", "%d", af
);
2443 r
= serialize_bool_elide(f
, "exec-context-address-families-allow-list", c
->address_families_allow_list
);
2447 r
= serialize_item(f
, "exec-context-network-namespace-path", c
->network_namespace_path
);
2451 r
= serialize_item(f
, "exec-context-ipc-namespace-path", c
->ipc_namespace_path
);
2455 FOREACH_ARRAY(mount
, c
->mount_images
, c
->n_mount_images
) {
2456 _cleanup_free_
char *s
= NULL
, *source_escaped
= NULL
, *dest_escaped
= NULL
;
2458 source_escaped
= shell_escape(mount
->source
, WHITESPACE
);
2459 if (!source_escaped
)
2460 return log_oom_debug();
2462 dest_escaped
= shell_escape(mount
->destination
, WHITESPACE
);
2464 return log_oom_debug();
2466 s
= strjoin(mount
->ignore_enoent
? "-" : "",
2471 return log_oom_debug();
2473 LIST_FOREACH(mount_options
, o
, mount
->mount_options
) {
2474 _cleanup_free_
char *escaped
= NULL
;
2476 if (isempty(o
->options
))
2479 escaped
= shell_escape(o
->options
, ":");
2481 return log_oom_debug();
2485 partition_designator_to_string(o
->partition_designator
),
2488 return log_oom_debug();
2491 r
= serialize_item(f
, "exec-context-mount-image", s
);
2496 FOREACH_ARRAY(mount
, c
->extension_images
, c
->n_extension_images
) {
2497 _cleanup_free_
char *s
= NULL
, *source_escaped
= NULL
;
2499 source_escaped
= shell_escape(mount
->source
, ":" WHITESPACE
);
2500 if (!source_escaped
)
2501 return log_oom_debug();
2503 s
= strjoin(mount
->ignore_enoent
? "-" : "",
2506 return log_oom_debug();
2508 LIST_FOREACH(mount_options
, o
, mount
->mount_options
) {
2509 _cleanup_free_
char *escaped
= NULL
;
2511 if (isempty(o
->options
))
2514 escaped
= shell_escape(o
->options
, ":");
2516 return log_oom_debug();
2520 partition_designator_to_string(o
->partition_designator
),
2523 return log_oom_debug();
2526 r
= serialize_item(f
, "exec-context-extension-image", s
);
2531 r
= serialize_strv(f
, "exec-context-extension-directories", c
->extension_directories
);
2535 ExecSetCredential
*sc
;
2536 HASHMAP_FOREACH(sc
, c
->set_credentials
) {
2537 _cleanup_free_
char *data
= NULL
;
2539 if (base64mem(sc
->data
, sc
->size
, &data
) < 0)
2540 return log_oom_debug();
2542 r
= serialize_item_format(f
, "exec-context-set-credentials", "%s %s %s", sc
->id
, yes_no(sc
->encrypted
), data
);
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
);
2554 if (!set_isempty(c
->import_credentials
)) {
2556 SET_FOREACH(ic
, c
->import_credentials
) {
2557 r
= serialize_item(f
, "exec-context-import-credentials", ic
);
2563 r
= serialize_image_policy(f
, "exec-context-root-image-policy", c
->root_image_policy
);
2567 r
= serialize_image_policy(f
, "exec-context-mount-image-policy", c
->mount_image_policy
);
2571 r
= serialize_image_policy(f
, "exec-context-extension-image-policy", c
->extension_image_policy
);
2575 fputc('\n', f
); /* End marker */
2580 static int exec_context_deserialize(ExecContext
*c
, FILE *f
) {
2589 _cleanup_free_
char *l
= NULL
;
2592 r
= deserialize_read_line(f
, &l
);
2595 if (r
== 0) /* eof or end marker */
2598 if ((val
= startswith(l
, "exec-context-environment="))) {
2599 r
= deserialize_strv(val
, &c
->environment
);
2602 } else if ((val
= startswith(l
, "exec-context-environment-files="))) {
2603 r
= deserialize_strv(val
, &c
->environment_files
);
2606 } else if ((val
= startswith(l
, "exec-context-pass-environment="))) {
2607 r
= deserialize_strv(val
, &c
->pass_environment
);
2610 } else if ((val
= startswith(l
, "exec-context-unset-environment="))) {
2611 r
= deserialize_strv(val
, &c
->unset_environment
);
2614 } else if ((val
= startswith(l
, "exec-context-working-directory="))) {
2615 r
= free_and_strdup(&c
->working_directory
, val
);
2618 } else if ((val
= startswith(l
, "exec-context-root-directory="))) {
2619 r
= free_and_strdup(&c
->root_directory
, val
);
2622 } else if ((val
= startswith(l
, "exec-context-root-image="))) {
2623 r
= free_and_strdup(&c
->root_image
, val
);
2626 } else if ((val
= startswith(l
, "exec-context-root-image-options="))) {
2628 _cleanup_free_
char *word
= NULL
, *mount_options
= NULL
, *partition
= NULL
;
2629 PartitionDesignator partition_designator
;
2630 MountOptions
*o
= NULL
;
2633 r
= extract_first_word(&val
, &word
, NULL
, 0);
2640 r
= extract_many_words(&p
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
, NULL
);
2646 partition_designator
= partition_designator_from_string(partition
);
2647 if (partition_designator
< 0)
2650 o
= new(MountOptions
, 1);
2652 return log_oom_debug();
2653 *o
= (MountOptions
) {
2654 .partition_designator
= partition_designator
,
2655 .options
= TAKE_PTR(mount_options
),
2657 LIST_APPEND(mount_options
, c
->root_image_options
, o
);
2659 } else if ((val
= startswith(l
, "exec-context-root-verity="))) {
2660 r
= free_and_strdup(&c
->root_verity
, val
);
2663 } else if ((val
= startswith(l
, "exec-context-root-hash-path="))) {
2664 r
= free_and_strdup(&c
->root_hash_path
, val
);
2667 } else if ((val
= startswith(l
, "exec-context-root-hash-sig-path="))) {
2668 r
= free_and_strdup(&c
->root_hash_sig_path
, val
);
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
);
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
);
2681 } else if ((val
= startswith(l
, "exec-context-root-ephemeral="))) {
2682 r
= parse_boolean(val
);
2685 c
->root_ephemeral
= r
;
2686 } else if ((val
= startswith(l
, "exec-context-umask="))) {
2687 r
= parse_mode(val
, &c
->umask
);
2690 } else if ((val
= startswith(l
, "exec-context-private-non-blocking="))) {
2691 r
= parse_boolean(val
);
2694 c
->non_blocking
= r
;
2695 } else if ((val
= startswith(l
, "exec-context-private-mounts="))) {
2696 r
= safe_atoi(val
, &c
->private_mounts
);
2699 } else if ((val
= startswith(l
, "exec-context-memory-ksm="))) {
2700 r
= safe_atoi(val
, &c
->memory_ksm
);
2703 } else if ((val
= startswith(l
, "exec-context-private-tmp="))) {
2704 r
= parse_boolean(val
);
2708 } else if ((val
= startswith(l
, "exec-context-private-devices="))) {
2709 r
= parse_boolean(val
);
2712 c
->private_devices
= r
;
2713 } else if ((val
= startswith(l
, "exec-context-protect-kernel-tunables="))) {
2714 r
= parse_boolean(val
);
2717 c
->protect_kernel_tunables
= r
;
2718 } else if ((val
= startswith(l
, "exec-context-protect-kernel-modules="))) {
2719 r
= parse_boolean(val
);
2722 c
->protect_kernel_modules
= r
;
2723 } else if ((val
= startswith(l
, "exec-context-protect-kernel-logs="))) {
2724 r
= parse_boolean(val
);
2727 c
->protect_kernel_logs
= r
;
2728 } else if ((val
= startswith(l
, "exec-context-protect-clock="))) {
2729 r
= parse_boolean(val
);
2732 c
->protect_clock
= r
;
2733 } else if ((val
= startswith(l
, "exec-context-protect-control-groups="))) {
2734 r
= parse_boolean(val
);
2737 c
->protect_control_groups
= r
;
2738 } else if ((val
= startswith(l
, "exec-context-private-network="))) {
2739 r
= parse_boolean(val
);
2742 c
->private_network
= r
;
2743 } else if ((val
= startswith(l
, "exec-context-private-users="))) {
2744 r
= parse_boolean(val
);
2747 c
->private_users
= r
;
2748 } else if ((val
= startswith(l
, "exec-context-private-ipc="))) {
2749 r
= parse_boolean(val
);
2753 } else if ((val
= startswith(l
, "exec-context-remove-ipc="))) {
2754 r
= parse_boolean(val
);
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)
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)
2766 } else if ((val
= startswith(l
, "exec-context-mount-api-vfs="))) {
2767 r
= parse_boolean(val
);
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
);
2777 } else if ((val
= startswith(l
, "exec-context-cpu-sched-reset-on-fork="))) {
2778 r
= parse_boolean(val
);
2781 c
->cpu_sched_reset_on_fork
= r
;
2782 } else if ((val
= startswith(l
, "exec-context-non-blocking="))) {
2783 r
= parse_boolean(val
);
2786 c
->non_blocking
= r
;
2787 } else if ((val
= startswith(l
, "exec-context-ignore-sigpipe="))) {
2788 r
= parse_boolean(val
);
2791 c
->ignore_sigpipe
= r
;
2792 } else if ((val
= startswith(l
, "exec-context-memory-deny-write-execute="))) {
2793 r
= parse_boolean(val
);
2796 c
->memory_deny_write_execute
= r
;
2797 } else if ((val
= startswith(l
, "exec-context-restrict-realtime="))) {
2798 r
= parse_boolean(val
);
2801 c
->restrict_realtime
= r
;
2802 } else if ((val
= startswith(l
, "exec-context-restrict-suid-sgid="))) {
2803 r
= parse_boolean(val
);
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)
2811 } else if ((val
= startswith(l
, "exec-context-protect-hostname="))) {
2812 r
= parse_boolean(val
);
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)
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)
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)
2828 } else if ((val
= startswith(l
, "exec-context-directories-"))) {
2829 _cleanup_free_
char *type
= NULL
, *mode
= NULL
;
2830 ExecDirectoryType dt
;
2832 r
= extract_many_words(&val
, "= ", 0, &type
, &mode
, NULL
);
2835 if (r
== 0 || !mode
)
2838 dt
= exec_directory_type_from_string(type
);
2842 r
= parse_mode(mode
, &c
->directories
[dt
].mode
);
2847 _cleanup_free_
char *tuple
= NULL
, *path
= NULL
, *only_create
= NULL
;
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
);
2858 r
= extract_many_words(&p
, ":", EXTRACT_UNESCAPE_SEPARATORS
, &path
, &only_create
, NULL
);
2864 r
= exec_directory_add(&c
->directories
[dt
], path
, NULL
);
2868 r
= parse_boolean(only_create
);
2871 c
->directories
[dt
].items
[c
->directories
[dt
].n_items
- 1].only_create
= r
;
2877 _cleanup_free_
char *link
= NULL
;
2879 r
= extract_first_word(&p
, &link
, ":", EXTRACT_UNESCAPE_SEPARATORS
);
2885 r
= strv_consume(&c
->directories
[dt
].items
[c
->directories
[dt
].n_items
- 1].symlinks
, TAKE_PTR(link
));
2890 } else if ((val
= startswith(l
, "exec-context-timeout-clean-usec="))) {
2891 r
= deserialize_usec(val
, &c
->timeout_clean_usec
);
2894 } else if ((val
= startswith(l
, "exec-context-nice="))) {
2895 r
= safe_atoi(val
, &c
->nice
);
2899 } else if ((val
= startswith(l
, "exec-context-working-directory-missing-ok="))) {
2900 r
= parse_boolean(val
);
2903 c
->working_directory_missing_ok
= r
;
2904 } else if ((val
= startswith(l
, "exec-context-working-directory-home="))) {
2905 r
= parse_boolean(val
);
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
);
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
);
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
;
2924 r
= extract_first_word(&val
, &limit
, "=", 0);
2930 type
= rlimit_from_string(limit
);
2934 if (!c
->rlimit
[type
]) {
2935 rlimit
= new0(struct rlimit
, 1);
2937 return log_oom_debug();
2939 r
= rlimit_parse(type
, val
, rlimit
);
2943 c
->rlimit
[type
] = TAKE_PTR(rlimit
);
2945 r
= rlimit_parse(type
, val
, c
->rlimit
[type
]);
2949 } else if ((val
= startswith(l
, "exec-context-ioprio="))) {
2950 r
= safe_atoi(val
, &c
->ioprio
);
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)
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
);
2963 c
->cpu_sched_set
= true;
2964 } else if ((val
= startswith(l
, "exec-context-cpu-scheduling-reset-on-fork="))) {
2965 r
= parse_boolean(val
);
2968 c
->cpu_sched_reset_on_fork
= r
;
2969 c
->cpu_sched_set
= true;
2970 } else if ((val
= startswith(l
, "exec-context-cpu-affinity="))) {
2972 return -EINVAL
; /* duplicated */
2974 r
= parse_cpu_set(val
, &c
->cpu_set
);
2977 } else if ((val
= startswith(l
, "exec-context-numa-mask="))) {
2978 if (c
->numa_policy
.nodes
.set
)
2979 return -EINVAL
; /* duplicated */
2981 r
= parse_cpu_set(val
, &c
->numa_policy
.nodes
);
2984 } else if ((val
= startswith(l
, "exec-context-numa-policy="))) {
2985 r
= safe_atoi(val
, &c
->numa_policy
.type
);
2988 } else if ((val
= startswith(l
, "exec-context-cpu-affinity-from-numa="))) {
2989 r
= parse_boolean(val
);
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
);
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
);
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
);
3018 } else if ((val
= startswith(l
, "exec-context-std-output-fd-name="))) {
3019 r
= free_and_strdup(&c
->stdio_fdname
[STDOUT_FILENO
], val
);
3022 } else if ((val
= startswith(l
, "exec-context-std-error-fd-name="))) {
3023 r
= free_and_strdup(&c
->stdio_fdname
[STDERR_FILENO
], val
);
3026 } else if ((val
= startswith(l
, "exec-context-std-input-file="))) {
3027 r
= free_and_strdup(&c
->stdio_file
[STDIN_FILENO
], val
);
3030 } else if ((val
= startswith(l
, "exec-context-std-output-file="))) {
3031 r
= free_and_strdup(&c
->stdio_file
[STDOUT_FILENO
], val
);
3034 } else if ((val
= startswith(l
, "exec-context-std-output-file-append="))) {
3035 r
= free_and_strdup(&c
->stdio_file
[STDOUT_FILENO
], val
);
3038 } else if ((val
= startswith(l
, "exec-context-std-output-file-truncate="))) {
3039 r
= free_and_strdup(&c
->stdio_file
[STDOUT_FILENO
], val
);
3042 } else if ((val
= startswith(l
, "exec-context-std-error-file="))) {
3043 r
= free_and_strdup(&c
->stdio_file
[STDERR_FILENO
], val
);
3046 } else if ((val
= startswith(l
, "exec-context-std-error-file-append="))) {
3047 r
= free_and_strdup(&c
->stdio_file
[STDERR_FILENO
], val
);
3050 } else if ((val
= startswith(l
, "exec-context-std-error-file-truncate="))) {
3051 r
= free_and_strdup(&c
->stdio_file
[STDERR_FILENO
], val
);
3054 } else if ((val
= startswith(l
, "exec-context-stdin-data="))) {
3056 return -EINVAL
; /* duplicated */
3058 r
= unbase64mem(val
, &c
->stdin_data
, &c
->stdin_data_size
);
3061 } else if ((val
= startswith(l
, "exec-context-tty-path="))) {
3062 r
= free_and_strdup(&c
->tty_path
, val
);
3065 } else if ((val
= startswith(l
, "exec-context-tty-reset="))) {
3066 r
= parse_boolean(val
);
3070 } else if ((val
= startswith(l
, "exec-context-tty-vhangup="))) {
3071 r
= parse_boolean(val
);
3075 } else if ((val
= startswith(l
, "exec-context-tty-vt-disallocate="))) {
3076 r
= parse_boolean(val
);
3079 c
->tty_vt_disallocate
= r
;
3080 } else if ((val
= startswith(l
, "exec-context-tty-rows="))) {
3081 r
= safe_atou(val
, &c
->tty_rows
);
3084 } else if ((val
= startswith(l
, "exec-context-tty-columns="))) {
3085 r
= safe_atou(val
, &c
->tty_cols
);
3088 } else if ((val
= startswith(l
, "exec-context-syslog-priority="))) {
3089 r
= safe_atoi(val
, &c
->syslog_priority
);
3092 } else if ((val
= startswith(l
, "exec-context-syslog-level-prefix="))) {
3093 r
= parse_boolean(val
);
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
);
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
);
3106 } else if ((val
= startswith(l
, "exec-context-log-ratelimit-interval-usec="))) {
3107 r
= deserialize_usec(val
, &c
->log_ratelimit_interval_usec
);
3110 } else if ((val
= startswith(l
, "exec-context-log-ratelimit-burst="))) {
3111 r
= safe_atou(val
, &c
->log_ratelimit_burst
);
3114 } else if ((val
= startswith(l
, "exec-context-log-filter-allowed-patterns="))) {
3115 r
= set_put_strdup(&c
->log_filter_allowed_patterns
, val
);
3118 } else if ((val
= startswith(l
, "exec-context-log-filter-denied-patterns="))) {
3119 r
= set_put_strdup(&c
->log_filter_denied_patterns
, val
);
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();
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
);
3133 } else if ((val
= startswith(l
, "exec-context-secure-bits="))) {
3134 r
= safe_atoi(val
, &c
->secure_bits
);
3137 } else if ((val
= startswith(l
, "exec-context-capability-bounding-set="))) {
3138 r
= safe_atou64(val
, &c
->capability_bounding_set
);
3141 } else if ((val
= startswith(l
, "exec-context-capability-ambient-set="))) {
3142 r
= safe_atou64(val
, &c
->capability_ambient_set
);
3145 } else if ((val
= startswith(l
, "exec-context-user="))) {
3146 r
= free_and_strdup(&c
->user
, val
);
3149 } else if ((val
= startswith(l
, "exec-context-group="))) {
3150 r
= free_and_strdup(&c
->group
, val
);
3153 } else if ((val
= startswith(l
, "exec-context-dynamic-user="))) {
3154 r
= parse_boolean(val
);
3157 c
->dynamic_user
= r
;
3158 } else if ((val
= startswith(l
, "exec-context-supplementary-groups="))) {
3159 r
= deserialize_strv(val
, &c
->supplementary_groups
);
3162 } else if ((val
= startswith(l
, "exec-context-set-login-environment="))) {
3163 r
= safe_atoi(val
, &c
->set_login_environment
);
3166 } else if ((val
= startswith(l
, "exec-context-pam-name="))) {
3167 r
= free_and_strdup(&c
->pam_name
, val
);
3170 } else if ((val
= startswith(l
, "exec-context-read-write-paths="))) {
3171 r
= deserialize_strv(val
, &c
->read_write_paths
);
3174 } else if ((val
= startswith(l
, "exec-context-read-only-paths="))) {
3175 r
= deserialize_strv(val
, &c
->read_only_paths
);
3178 } else if ((val
= startswith(l
, "exec-context-inaccessible-paths="))) {
3179 r
= deserialize_strv(val
, &c
->inaccessible_paths
);
3182 } else if ((val
= startswith(l
, "exec-context-exec-paths="))) {
3183 r
= deserialize_strv(val
, &c
->exec_paths
);
3186 } else if ((val
= startswith(l
, "exec-context-no-exec-paths="))) {
3187 r
= deserialize_strv(val
, &c
->no_exec_paths
);
3190 } else if ((val
= startswith(l
, "exec-context-exec-search-path="))) {
3191 r
= deserialize_strv(val
, &c
->exec_search_path
);
3194 } else if ((val
= startswith(l
, "exec-context-mount-propagation-flag="))) {
3195 r
= safe_atolu(val
, &c
->mount_propagation_flag
);
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
;
3203 r
= extract_first_word(&val
,
3206 EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
|EXTRACT_UNESCAPE_SEPARATORS
);
3214 ignore_enoent
= true;
3218 if (val
&& val
[-1] == ':') {
3219 r
= extract_first_word(&val
,
3222 EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
|EXTRACT_UNESCAPE_SEPARATORS
);
3230 if (val
&& val
[-1] == ':') {
3231 _cleanup_free_
char *options
= NULL
;
3233 r
= extract_first_word(&val
, &options
, NULL
, EXTRACT_UNQUOTE
);
3237 if (isempty(options
) || streq(options
, "rbind"))
3239 else if (streq(options
, "norbind"))
3247 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
3253 .ignore_enoent
= ignore_enoent
,
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
;
3262 r
= extract_first_word(&val
,
3265 EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
|EXTRACT_UNESCAPE_SEPARATORS
);
3273 ignore_enoent
= true;
3277 if (val
&& val
[-1] == ':') {
3278 r
= extract_first_word(&val
,
3281 EXTRACT_UNQUOTE
|EXTRACT_DONT_COALESCE_SEPARATORS
|EXTRACT_UNESCAPE_SEPARATORS
);
3289 if (val
&& val
[-1] == ':') {
3290 _cleanup_free_
char *options
= NULL
;
3292 r
= extract_first_word(&val
, &options
, NULL
, EXTRACT_UNQUOTE
);
3296 if (isempty(options
) || streq(options
, "rbind"))
3298 else if (streq(options
, "norbind"))
3306 r
= bind_mount_add(&c
->bind_mounts
, &c
->n_bind_mounts
,
3312 .ignore_enoent
= ignore_enoent
,
3315 return log_oom_debug();
3316 } else if ((val
= startswith(l
, "exec-context-temporary-filesystems="))) {
3317 _cleanup_free_
char *path
= NULL
, *options
= NULL
;
3319 r
= extract_many_words(&val
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &path
, &options
, NULL
);
3325 r
= temporary_filesystem_add(&c
->temporary_filesystems
, &c
->n_temporary_filesystems
, path
, options
);
3327 return log_oom_debug();
3328 } else if ((val
= startswith(l
, "exec-context-utmp-id="))) {
3329 r
= free_and_strdup(&c
->utmp_id
, val
);
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
);
3340 c
->no_new_privileges
= r
;
3341 } else if ((val
= startswith(l
, "exec-context-selinux-context-ignore="))) {
3342 r
= parse_boolean(val
);
3345 c
->selinux_context_ignore
= r
;
3346 } else if ((val
= startswith(l
, "exec-context-apparmor-profile-ignore="))) {
3347 r
= parse_boolean(val
);
3350 c
->apparmor_profile_ignore
= r
;
3351 } else if ((val
= startswith(l
, "exec-context-smack-process-label-ignore="))) {
3352 r
= parse_boolean(val
);
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;
3362 r
= free_and_strdup(&c
->selinux_context
, val
);
3365 } else if ((val
= startswith(l
, "exec-context-apparmor-profile="))) {
3366 if (val
[0] == '-') {
3367 c
->apparmor_profile_ignore
= true;
3371 r
= free_and_strdup(&c
->apparmor_profile
, val
);
3374 } else if ((val
= startswith(l
, "exec-context-smack-process-label="))) {
3375 if (val
[0] == '-') {
3376 c
->smack_process_label_ignore
= true;
3380 r
= free_and_strdup(&c
->smack_process_label
, val
);
3383 } else if ((val
= startswith(l
, "exec-context-personality="))) {
3384 c
->personality
= personality_from_string(val
);
3385 if (c
->personality
== PERSONALITY_INVALID
)
3387 } else if ((val
= startswith(l
, "exec-context-lock-personality="))) {
3388 r
= parse_boolean(val
);
3391 c
->lock_personality
= r
;
3393 } else if ((val
= startswith(l
, "exec-context-syscall-filter="))) {
3394 _cleanup_free_
char *s_id
= NULL
, *s_errno_num
= NULL
;
3397 r
= extract_many_words(&val
, NULL
, 0, &s_id
, &s_errno_num
, NULL
);
3403 r
= safe_atoi(s_id
, &id
);
3407 r
= safe_atoi(s_errno_num
, &errno_num
);
3411 r
= hashmap_ensure_put(&c
->syscall_filter
, NULL
, INT_TO_PTR(id
+ 1), INT_TO_PTR(errno_num
));
3414 } else if ((val
= startswith(l
, "exec-context-syscall-archs="))) {
3417 r
= safe_atou(val
, &id
);
3421 r
= set_ensure_put(&c
->syscall_archs
, NULL
, UINT_TO_PTR(id
+ 1));
3424 } else if ((val
= startswith(l
, "exec-context-syscall-errno="))) {
3425 r
= safe_atoi(val
, &c
->syscall_errno
);
3428 } else if ((val
= startswith(l
, "exec-context-syscall-allow-list="))) {
3429 r
= parse_boolean(val
);
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
;
3437 r
= extract_many_words(&val
, " ", 0, &s_id
, &s_errno_num
, NULL
);
3443 r
= safe_atoi(s_id
, &id
);
3447 r
= safe_atoi(s_errno_num
, &errno_num
);
3451 r
= hashmap_ensure_put(&c
->syscall_log
, NULL
, INT_TO_PTR(id
+ 1), INT_TO_PTR(errno_num
));
3454 } else if ((val
= startswith(l
, "exec-context-syscall-log-allow-list="))) {
3455 r
= parse_boolean(val
);
3458 c
->syscall_log_allow_list
= r
;
3460 } else if ((val
= startswith(l
, "exec-context-restrict-namespaces="))) {
3461 r
= safe_atolu(val
, &c
->restrict_namespaces
);
3464 } else if ((val
= startswith(l
, "exec-context-restrict-filesystems="))) {
3465 r
= set_ensure_allocated(&c
->restrict_filesystems
, &string_hash_ops
);
3469 r
= set_put_strdup(&c
->restrict_filesystems
, val
);
3472 } else if ((val
= startswith(l
, "exec-context-restrict-filesystems-allow-list="))) {
3473 r
= parse_boolean(val
);
3476 c
->restrict_filesystems_allow_list
= r
;
3477 } else if ((val
= startswith(l
, "exec-context-address-families="))) {
3480 r
= safe_atoi(val
, &af
);
3484 r
= set_ensure_put(&c
->address_families
, NULL
, INT_TO_PTR(af
));
3487 } else if ((val
= startswith(l
, "exec-context-address-families-allow-list="))) {
3488 r
= parse_boolean(val
);
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
);
3496 } else if ((val
= startswith(l
, "exec-context-ipc-namespace-path="))) {
3497 r
= free_and_strdup(&c
->ipc_namespace_path
, val
);
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;
3506 r
= extract_many_words(&val
,
3508 EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
,
3523 if (isempty(destination
))
3527 _cleanup_free_
char *tuple
= NULL
, *partition
= NULL
, *opts
= NULL
;
3528 PartitionDesignator partition_designator
;
3529 MountOptions
*o
= NULL
;
3532 r
= extract_first_word(&val
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
3539 r
= extract_many_words(&p
,
3541 EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
,
3550 o
= new(MountOptions
, 1);
3552 return log_oom_debug();
3553 *o
= (MountOptions
) {
3554 .partition_designator
= PARTITION_ROOT
,
3555 .options
= TAKE_PTR(partition
),
3557 LIST_APPEND(mount_options
, options
, o
);
3562 partition_designator
= partition_designator_from_string(partition
);
3563 if (partition_designator
< 0)
3566 o
= new(MountOptions
, 1);
3568 return log_oom_debug();
3569 *o
= (MountOptions
) {
3570 .partition_designator
= partition_designator
,
3571 .options
= TAKE_PTR(opts
),
3573 LIST_APPEND(mount_options
, options
, o
);
3576 r
= mount_image_add(&c
->mount_images
, &c
->n_mount_images
,
3579 .destination
= destination
,
3580 .mount_options
= options
,
3581 .ignore_enoent
= permissive
,
3582 .type
= MOUNT_IMAGE_DISCRETE
,
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;
3592 r
= extract_first_word(&val
,
3595 EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
);
3608 _cleanup_free_
char *tuple
= NULL
, *partition
= NULL
, *opts
= NULL
;
3609 PartitionDesignator partition_designator
;
3610 MountOptions
*o
= NULL
;
3613 r
= extract_first_word(&val
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
3620 r
= extract_many_words(&p
,
3622 EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
,
3631 o
= new(MountOptions
, 1);
3633 return log_oom_debug();
3634 *o
= (MountOptions
) {
3635 .partition_designator
= PARTITION_ROOT
,
3636 .options
= TAKE_PTR(partition
),
3638 LIST_APPEND(mount_options
, options
, o
);
3643 partition_designator
= partition_designator_from_string(partition
);
3644 if (partition_designator
< 0)
3647 o
= new(MountOptions
, 1);
3649 return log_oom_debug();
3650 *o
= (MountOptions
) {
3651 .partition_designator
= partition_designator
,
3652 .options
= TAKE_PTR(opts
),
3654 LIST_APPEND(mount_options
, options
, o
);
3657 r
= mount_image_add(&c
->extension_images
, &c
->n_extension_images
,
3660 .mount_options
= options
,
3661 .ignore_enoent
= permissive
,
3662 .type
= MOUNT_IMAGE_EXTENSION
,
3665 return log_oom_debug();
3666 } else if ((val
= startswith(l
, "exec-context-extension-directories="))) {
3667 r
= deserialize_strv(val
, &c
->extension_directories
);
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
;
3674 r
= extract_many_words(&val
, " ", 0, &id
, &encrypted
, &data
, NULL
);
3680 r
= parse_boolean(encrypted
);
3684 sc
= new(ExecSetCredential
, 1);
3688 *sc
= (ExecSetCredential
) {
3693 r
= unbase64mem(data
, &sc
->data
, &sc
->size
);
3697 r
= hashmap_ensure_put(&c
->set_credentials
, &exec_set_credential_hash_ops
, sc
->id
, 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
;
3706 r
= extract_many_words(&val
, " ", 0, &id
, &encrypted
, &path
, NULL
);
3712 r
= parse_boolean(encrypted
);
3716 lc
= new(ExecLoadCredential
, 1);
3720 *lc
= (ExecLoadCredential
) {
3722 .path
= TAKE_PTR(path
),
3726 r
= hashmap_ensure_put(&c
->load_credentials
, &exec_load_credential_hash_ops
, lc
->id
, lc
);
3731 } else if ((val
= startswith(l
, "exec-context-import-credentials="))) {
3732 r
= set_ensure_allocated(&c
->import_credentials
, &string_hash_ops
);
3736 r
= set_put_strdup(&c
->import_credentials
, val
);
3739 } else if ((val
= startswith(l
, "exec-context-root-image-policy="))) {
3740 if (c
->root_image_policy
)
3741 return -EINVAL
; /* duplicated */
3743 r
= image_policy_from_string(val
, &c
->root_image_policy
);
3746 } else if ((val
= startswith(l
, "exec-context-mount-image-policy="))) {
3747 if (c
->mount_image_policy
)
3748 return -EINVAL
; /* duplicated */
3750 r
= image_policy_from_string(val
, &c
->mount_image_policy
);
3753 } else if ((val
= startswith(l
, "exec-context-extension-image-policy="))) {
3754 if (c
->extension_image_policy
)
3755 return -EINVAL
; /* duplicated */
3757 r
= image_policy_from_string(val
, &c
->extension_image_policy
);
3761 log_warning("Failed to parse serialized line, ignoring: %s", l
);
3767 static int exec_command_serialize(const ExecCommand
*c
, FILE *f
) {
3773 r
= serialize_item(f
, "exec-command-path", c
->path
);
3777 r
= serialize_strv(f
, "exec-command-argv", c
->argv
);
3781 r
= serialize_item_format(f
, "exec-command-flags", "%d", (int) c
->flags
);
3785 fputc('\n', f
); /* End marker */
3790 static int exec_command_deserialize(ExecCommand
*c
, FILE *f
) {
3797 _cleanup_free_
char *l
= NULL
;
3800 r
= deserialize_read_line(f
, &l
);
3803 if (r
== 0) /* eof or end marker */
3806 if ((val
= startswith(l
, "exec-command-path="))) {
3807 r
= free_and_strdup(&c
->path
, val
);
3810 } else if ((val
= startswith(l
, "exec-command-argv="))) {
3811 r
= deserialize_strv(val
, &c
->argv
);
3814 } else if ((val
= startswith(l
, "exec-command-flags="))) {
3815 r
= safe_atoi(val
, &c
->flags
);
3819 log_warning("Failed to parse serialized line, ignoring: %s", l
);
3826 int exec_serialize_invocation(
3829 const ExecContext
*ctx
,
3830 const ExecCommand
*cmd
,
3831 const ExecParameters
*p
,
3832 const ExecRuntime
*rt
,
3833 const CGroupContext
*cg
) {
3840 r
= exec_context_serialize(ctx
, f
);
3842 return log_debug_errno(r
, "Failed to serialize context: %m");
3844 r
= exec_command_serialize(cmd
, f
);
3846 return log_debug_errno(r
, "Failed to serialize command: %m");
3848 r
= exec_parameters_serialize(p
, ctx
, f
, fds
);
3850 return log_debug_errno(r
, "Failed to serialize parameters: %m");
3852 r
= exec_runtime_serialize(rt
, f
, fds
);
3854 return log_debug_errno(r
, "Failed to serialize runtime: %m");
3856 r
= exec_cgroup_context_serialize(cg
, f
);
3858 return log_debug_errno(r
, "Failed to serialize cgroup context: %m");
3863 int exec_deserialize_invocation(
3870 CGroupContext
*cg
) {
3877 r
= exec_context_deserialize(ctx
, f
);
3879 return log_debug_errno(r
, "Failed to deserialize context: %m");
3881 r
= exec_command_deserialize(cmd
, f
);
3883 return log_debug_errno(r
, "Failed to deserialize command: %m");
3885 r
= exec_parameters_deserialize(p
, f
, fds
);
3887 return log_debug_errno(r
, "Failed to deserialize parameters: %m");
3889 r
= exec_runtime_deserialize(rt
, f
, fds
);
3891 return log_debug_errno(r
, "Failed to deserialize runtime: %m");
3893 r
= exec_cgroup_context_deserialize(cg
, f
);
3895 return log_debug_errno(r
, "Failed to deserialize cgroup context: %m");