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 r
= serialize_bool(f
, "exec-cgroup-context-memory-zswap-writeback", c
->memory_zswap_writeback
);
237 if (c
->memory_limit
!= CGROUP_LIMIT_MAX
) {
238 r
= serialize_item_format(f
, "exec-cgroup-context-memory-limit", "%" PRIu64
, c
->memory_limit
);
243 if (c
->tasks_max
.value
!= UINT64_MAX
) {
244 r
= serialize_item_format(f
, "exec-cgroup-context-tasks-max-value", "%" PRIu64
, c
->tasks_max
.value
);
249 if (c
->tasks_max
.scale
> 0) {
250 r
= serialize_item_format(f
, "exec-cgroup-context-tasks-max-scale", "%" PRIu64
, c
->tasks_max
.scale
);
255 r
= serialize_bool_elide(f
, "exec-cgroup-context-default-memory-min-set", c
->default_memory_min_set
);
259 r
= serialize_bool_elide(f
, "exec-cgroup-context-default-memory-low-set", c
->default_memory_low_set
);
263 r
= serialize_bool_elide(f
, "exec-cgroup-context-default-startup-memory-low-set", c
->default_startup_memory_low_set
);
267 r
= serialize_bool_elide(f
, "exec-cgroup-context-memory-min-set", c
->memory_min_set
);
271 r
= serialize_bool_elide(f
, "exec-cgroup-context-memory-low-set", c
->memory_low_set
);
275 r
= serialize_bool_elide(f
, "exec-cgroup-context-startup-memory-low-set", c
->startup_memory_low_set
);
279 r
= serialize_bool_elide(f
, "exec-cgroup-context-startup-memory-high-set", c
->startup_memory_high_set
);
283 r
= serialize_bool_elide(f
, "exec-cgroup-context-startup-memory-max-set", c
->startup_memory_max_set
);
287 r
= serialize_bool_elide(f
, "exec-cgroup-context-startup-memory-swap-max-set", c
->startup_memory_swap_max_set
);
291 r
= serialize_bool_elide(f
, "exec-cgroup-context-startup-memory-zswap-max-set", c
->startup_memory_zswap_max_set
);
295 r
= serialize_item(f
, "exec-cgroup-context-device-policy", cgroup_device_policy_to_string(c
->device_policy
));
299 r
= cg_mask_to_string(c
->disable_controllers
, &disable_controllers_str
);
303 r
= serialize_item(f
, "exec-cgroup-context-disable-controllers", disable_controllers_str
);
307 r
= cg_mask_to_string(c
->delegate_controllers
, &delegate_controllers_str
);
311 r
= serialize_item(f
, "exec-cgroup-context-delegate-controllers", delegate_controllers_str
);
315 r
= serialize_bool_elide(f
, "exec-cgroup-context-delegate", c
->delegate
);
319 r
= serialize_item(f
, "exec-cgroup-context-managed-oom-swap", managed_oom_mode_to_string(c
->moom_swap
));
323 r
= serialize_item(f
, "exec-cgroup-context-managed-oom-memory-pressure", managed_oom_mode_to_string(c
->moom_mem_pressure
));
327 r
= serialize_item_format(f
, "exec-cgroup-context-managed-oom-memory-pressure-limit", "%" PRIu32
, c
->moom_mem_pressure_limit
);
331 r
= serialize_item(f
, "exec-cgroup-context-managed-oom-preference", managed_oom_preference_to_string(c
->moom_preference
));
335 r
= serialize_item(f
, "exec-cgroup-context-memory-pressure-watch", cgroup_pressure_watch_to_string(c
->memory_pressure_watch
));
339 r
= serialize_item(f
, "exec-cgroup-context-delegate-subgroup", c
->delegate_subgroup
);
343 if (c
->memory_pressure_threshold_usec
!= USEC_INFINITY
) {
344 r
= serialize_usec(f
, "exec-cgroup-context-memory-pressure-threshold-usec", c
->memory_pressure_threshold_usec
);
349 LIST_FOREACH(device_allow
, a
, c
->device_allow
) {
350 r
= serialize_item_format(f
, "exec-cgroup-context-device-allow", "%s %s",
352 cgroup_device_permissions_to_string(a
->permissions
));
357 LIST_FOREACH(device_weights
, iw
, c
->io_device_weights
) {
358 r
= serialize_item_format(f
, "exec-cgroup-context-io-device-weight", "%s %" PRIu64
,
365 LIST_FOREACH(device_latencies
, l
, c
->io_device_latencies
) {
366 r
= serialize_item_format(f
, "exec-cgroup-context-io-device-latency-target-usec", "%s " USEC_FMT
,
373 LIST_FOREACH(device_limits
, il
, c
->io_device_limits
)
374 for (CGroupIOLimitType type
= 0; type
< _CGROUP_IO_LIMIT_TYPE_MAX
; type
++) {
375 _cleanup_free_
char *key
= NULL
;
377 if (il
->limits
[type
] == cgroup_io_limit_defaults
[type
])
380 key
= strjoin("exec-cgroup-context-io-device-limit-", cgroup_io_limit_type_to_string(type
));
384 r
= serialize_item_format(f
, key
, "%s %" PRIu64
, il
->path
, il
->limits
[type
]);
389 LIST_FOREACH(device_weights
, w
, c
->blockio_device_weights
) {
390 r
= serialize_item_format(f
, "exec-cgroup-context-blockio-device-weight", "%s %" PRIu64
,
397 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
) {
398 if (b
->rbps
!= CGROUP_LIMIT_MAX
) {
399 r
= serialize_item_format(f
, "exec-cgroup-context-blockio-read-bandwidth", "%s %" PRIu64
,
405 if (b
->wbps
!= CGROUP_LIMIT_MAX
) {
406 r
= serialize_item_format(f
, "exec-cgroup-context-blockio-write-bandwidth", "%s %" PRIu64
,
414 SET_FOREACH(iaai
, c
->ip_address_allow
) {
415 r
= serialize_item(f
,
416 "exec-cgroup-context-ip-address-allow",
417 IN_ADDR_PREFIX_TO_STRING(iaai
->family
, &iaai
->address
, iaai
->prefixlen
));
421 SET_FOREACH(iaai
, c
->ip_address_deny
) {
422 r
= serialize_item(f
,
423 "exec-cgroup-context-ip-address-deny",
424 IN_ADDR_PREFIX_TO_STRING(iaai
->family
, &iaai
->address
, iaai
->prefixlen
));
429 r
= serialize_bool_elide(f
, "exec-cgroup-context-ip-address-allow-reduced", c
->ip_address_allow_reduced
);
433 r
= serialize_bool_elide(f
, "exec-cgroup-context-ip-address-deny-reduced", c
->ip_address_deny_reduced
);
437 r
= serialize_strv(f
, "exec-cgroup-context-ip-ingress-filter-path=", c
->ip_filters_ingress
);
441 r
= serialize_strv(f
, "exec-cgroup-context-ip-egress-filter-path=", c
->ip_filters_egress
);
445 LIST_FOREACH(programs
, p
, c
->bpf_foreign_programs
) {
446 r
= serialize_item_format(f
, "exec-cgroup-context-bpf-program", "%" PRIu32
" %s",
453 LIST_FOREACH(socket_bind_items
, bi
, c
->socket_bind_allow
) {
454 fprintf(f
, "exec-cgroup-context-socket-bind-allow=");
455 cgroup_context_dump_socket_bind_item(bi
, f
);
459 LIST_FOREACH(socket_bind_items
, bi
, c
->socket_bind_deny
) {
460 fprintf(f
, "exec-cgroup-context-socket-bind-deny=");
461 cgroup_context_dump_socket_bind_item(bi
, f
);
465 SET_FOREACH(iface
, c
->restrict_network_interfaces
) {
466 r
= serialize_item(f
, "exec-cgroup-context-restrict-network-interfaces", iface
);
471 r
= serialize_bool_elide(
473 "exec-cgroup-context-restrict-network-interfaces-is-allow-list",
474 c
->restrict_network_interfaces_is_allow_list
);
478 fputc('\n', f
); /* End marker */
483 static int exec_cgroup_context_deserialize(CGroupContext
*c
, FILE *f
) {
492 _cleanup_free_
char *l
= NULL
;
495 r
= deserialize_read_line(f
, &l
);
498 if (r
== 0) /* eof or end marker */
501 if ((val
= startswith(l
, "exec-cgroup-context-cpu-accounting="))) {
502 r
= parse_boolean(val
);
505 c
->cpu_accounting
= r
;
506 } else if ((val
= startswith(l
, "exec-cgroup-context-io-accounting="))) {
507 r
= parse_boolean(val
);
510 c
->io_accounting
= r
;
511 } else if ((val
= startswith(l
, "exec-cgroup-context-block-io-accounting="))) {
512 r
= parse_boolean(val
);
515 c
->blockio_accounting
= r
;
516 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-accounting="))) {
517 r
= parse_boolean(val
);
520 c
->memory_accounting
= r
;
521 } else if ((val
= startswith(l
, "exec-cgroup-context-tasks-accounting="))) {
522 r
= parse_boolean(val
);
525 c
->tasks_accounting
= r
;
526 } else if ((val
= startswith(l
, "exec-cgroup-context-ip-accounting="))) {
527 r
= parse_boolean(val
);
530 c
->ip_accounting
= r
;
531 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-oom-group="))) {
532 r
= parse_boolean(val
);
535 c
->memory_oom_group
= r
;
536 } else if ((val
= startswith(l
, "exec-cgroup-context-cpu-weight="))) {
537 r
= safe_atou64(val
, &c
->cpu_weight
);
540 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-cpu-weight="))) {
541 r
= safe_atou64(val
, &c
->startup_cpu_weight
);
544 } else if ((val
= startswith(l
, "exec-cgroup-context-cpu-shares="))) {
545 r
= safe_atou64(val
, &c
->cpu_shares
);
548 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-cpu-shares="))) {
549 r
= safe_atou64(val
, &c
->startup_cpu_shares
);
552 } else if ((val
= startswith(l
, "exec-cgroup-context-cpu-quota-per-sec-usec="))) {
553 r
= deserialize_usec(val
, &c
->cpu_quota_per_sec_usec
);
556 } else if ((val
= startswith(l
, "exec-cgroup-context-cpu-quota-period-usec="))) {
557 r
= deserialize_usec(val
, &c
->cpu_quota_period_usec
);
560 } else if ((val
= startswith(l
, "exec-cgroup-context-allowed-cpus="))) {
561 if (c
->cpuset_cpus
.set
)
562 return -EINVAL
; /* duplicated */
564 r
= parse_cpu_set_full(
569 /* filename= */ NULL
,
574 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-allowed-cpus="))) {
575 if (c
->startup_cpuset_cpus
.set
)
576 return -EINVAL
; /* duplicated */
578 r
= parse_cpu_set_full(
580 &c
->startup_cpuset_cpus
,
583 /* filename= */ NULL
,
588 } else if ((val
= startswith(l
, "exec-cgroup-context-allowed-memory-nodes="))) {
589 if (c
->cpuset_mems
.set
)
590 return -EINVAL
; /* duplicated */
592 r
= parse_cpu_set_full(
597 /* filename= */ NULL
,
602 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-allowed-memory-nodes="))) {
603 if (c
->startup_cpuset_mems
.set
)
604 return -EINVAL
; /* duplicated */
606 r
= parse_cpu_set_full(
608 &c
->startup_cpuset_mems
,
611 /* filename= */ NULL
,
616 } else if ((val
= startswith(l
, "exec-cgroup-context-io-weight="))) {
617 r
= safe_atou64(val
, &c
->io_weight
);
620 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-io-weight="))) {
621 r
= safe_atou64(val
, &c
->startup_io_weight
);
624 } else if ((val
= startswith(l
, "exec-cgroup-context-block-io-weight="))) {
625 r
= safe_atou64(val
, &c
->blockio_weight
);
628 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-block-io-weight="))) {
629 r
= safe_atou64(val
, &c
->startup_blockio_weight
);
632 } else if ((val
= startswith(l
, "exec-cgroup-context-default-memory-min="))) {
633 r
= safe_atou64(val
, &c
->default_memory_min
);
636 } else if ((val
= startswith(l
, "exec-cgroup-context-default-memory-low="))) {
637 r
= safe_atou64(val
, &c
->default_memory_low
);
640 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-min="))) {
641 r
= safe_atou64(val
, &c
->memory_min
);
644 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-low="))) {
645 r
= safe_atou64(val
, &c
->memory_low
);
648 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-low="))) {
649 r
= safe_atou64(val
, &c
->startup_memory_low
);
652 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-high="))) {
653 r
= safe_atou64(val
, &c
->memory_high
);
656 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-high="))) {
657 r
= safe_atou64(val
, &c
->startup_memory_high
);
660 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-max="))) {
661 r
= safe_atou64(val
, &c
->memory_max
);
664 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-max="))) {
665 r
= safe_atou64(val
, &c
->startup_memory_max
);
668 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-swap-max="))) {
669 r
= safe_atou64(val
, &c
->memory_swap_max
);
672 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-swap-max="))) {
673 r
= safe_atou64(val
, &c
->startup_memory_swap_max
);
676 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-zswap-max="))) {
677 r
= safe_atou64(val
, &c
->memory_zswap_max
);
680 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-zswap-max="))) {
681 r
= safe_atou64(val
, &c
->startup_memory_zswap_max
);
684 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-zswap-writeback="))) {
685 r
= parse_boolean(val
);
688 c
->memory_zswap_writeback
= r
;
689 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-limit="))) {
690 r
= safe_atou64(val
, &c
->memory_limit
);
693 } else if ((val
= startswith(l
, "exec-cgroup-context-tasks-max-value="))) {
694 r
= safe_atou64(val
, &c
->tasks_max
.value
);
697 } else if ((val
= startswith(l
, "exec-cgroup-context-tasks-max-scale="))) {
698 r
= safe_atou64(val
, &c
->tasks_max
.scale
);
701 } else if ((val
= startswith(l
, "exec-cgroup-context-default-memory-min-set="))) {
702 r
= parse_boolean(val
);
705 c
->default_memory_min_set
= r
;
706 } else if ((val
= startswith(l
, "exec-cgroup-context-default-memory-low-set="))) {
707 r
= parse_boolean(val
);
710 c
->default_memory_low_set
= r
;
711 } else if ((val
= startswith(l
, "exec-cgroup-context-default-startup-memory-low-set="))) {
712 r
= parse_boolean(val
);
715 c
->default_startup_memory_low_set
= r
;
716 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-min-set="))) {
717 r
= parse_boolean(val
);
720 c
->memory_min_set
= r
;
721 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-low-set="))) {
722 r
= parse_boolean(val
);
725 c
->memory_low_set
= r
;
726 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-low-set="))) {
727 r
= parse_boolean(val
);
730 c
->startup_memory_low_set
= r
;
731 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-high-set="))) {
732 r
= parse_boolean(val
);
735 c
->startup_memory_high_set
= r
;
736 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-max-set="))) {
737 r
= parse_boolean(val
);
740 c
->startup_memory_max_set
= r
;
741 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-swap-max-set="))) {
742 r
= parse_boolean(val
);
745 c
->startup_memory_swap_max_set
= r
;
746 } else if ((val
= startswith(l
, "exec-cgroup-context-startup-memory-zswap-max-set="))) {
747 r
= parse_boolean(val
);
750 c
->startup_memory_zswap_max_set
= r
;
751 } else if ((val
= startswith(l
, "exec-cgroup-context-device-policy="))) {
752 c
->device_policy
= cgroup_device_policy_from_string(val
);
753 if (c
->device_policy
< 0)
755 } else if ((val
= startswith(l
, "exec-cgroup-context-disable-controllers="))) {
756 r
= cg_mask_from_string(val
, &c
->disable_controllers
);
759 } else if ((val
= startswith(l
, "exec-cgroup-context-delegate-controllers="))) {
760 r
= cg_mask_from_string(val
, &c
->delegate_controllers
);
763 } else if ((val
= startswith(l
, "exec-cgroup-context-delegate="))) {
764 r
= parse_boolean(val
);
768 } else if ((val
= startswith(l
, "exec-cgroup-context-managed-oom-swap="))) {
769 c
->moom_swap
= managed_oom_mode_from_string(val
);
770 if (c
->moom_swap
< 0)
772 } else if ((val
= startswith(l
, "exec-cgroup-context-managed-oom-memory-pressure="))) {
773 c
->moom_mem_pressure
= managed_oom_mode_from_string(val
);
774 if (c
->moom_mem_pressure
< 0)
776 } else if ((val
= startswith(l
, "exec-cgroup-context-managed-oom-memory-pressure-limit="))) {
777 r
= safe_atou32(val
, &c
->moom_mem_pressure_limit
);
780 } else if ((val
= startswith(l
, "exec-cgroup-context-managed-oom-preference="))) {
781 c
->moom_preference
= managed_oom_preference_from_string(val
);
782 if (c
->moom_preference
< 0)
784 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-pressure-watch="))) {
785 c
->memory_pressure_watch
= cgroup_pressure_watch_from_string(val
);
786 if (c
->memory_pressure_watch
< 0)
788 } else if ((val
= startswith(l
, "exec-cgroup-context-delegate-subgroup="))) {
789 r
= free_and_strdup(&c
->delegate_subgroup
, val
);
792 } else if ((val
= startswith(l
, "exec-cgroup-context-memory-pressure-threshold-usec="))) {
793 r
= deserialize_usec(val
, &c
->memory_pressure_threshold_usec
);
796 } else if ((val
= startswith(l
, "exec-cgroup-context-device-allow="))) {
797 _cleanup_free_
char *path
= NULL
, *rwm
= NULL
;
798 CGroupDevicePermissions p
;
800 r
= extract_many_words(&val
, " ", 0, &path
, &rwm
);
806 p
= isempty(rwm
) ? 0 : cgroup_device_permissions_from_string(rwm
);
810 r
= cgroup_context_add_or_update_device_allow(c
, path
, p
);
813 } else if ((val
= startswith(l
, "exec-cgroup-context-io-device-weight="))) {
814 _cleanup_free_
char *path
= NULL
, *weight
= NULL
;
815 CGroupIODeviceWeight
*a
= NULL
;
817 r
= extract_many_words(&val
, " ", 0, &path
, &weight
);
823 LIST_FOREACH(device_weights
, b
, c
->io_device_weights
)
824 if (path_equal(b
->path
, path
)) {
830 a
= new0(CGroupIODeviceWeight
, 1);
832 return log_oom_debug();
834 a
->path
= TAKE_PTR(path
);
836 LIST_PREPEND(device_weights
, c
->io_device_weights
, a
);
839 r
= safe_atou64(weight
, &a
->weight
);
842 } else if ((val
= startswith(l
, "exec-cgroup-context-io-device-latency-target-usec="))) {
843 _cleanup_free_
char *path
= NULL
, *target
= NULL
;
844 CGroupIODeviceLatency
*a
= NULL
;
846 r
= extract_many_words(&val
, " ", 0, &path
, &target
);
852 LIST_FOREACH(device_latencies
, b
, c
->io_device_latencies
)
853 if (path_equal(b
->path
, path
)) {
859 a
= new0(CGroupIODeviceLatency
, 1);
861 return log_oom_debug();
863 a
->path
= TAKE_PTR(path
);
865 LIST_PREPEND(device_latencies
, c
->io_device_latencies
, a
);
868 r
= deserialize_usec(target
, &a
->target_usec
);
871 } else if ((val
= startswith(l
, "exec-cgroup-context-io-device-limit-"))) {
872 _cleanup_free_
char *type
= NULL
, *path
= NULL
, *limits
= NULL
;
873 CGroupIODeviceLimit
*limit
= NULL
;
876 r
= extract_many_words(&val
, "= ", 0, &type
, &path
, &limits
);
882 t
= cgroup_io_limit_type_from_string(type
);
886 LIST_FOREACH(device_limits
, i
, c
->io_device_limits
)
887 if (path_equal(path
, i
->path
)) {
893 limit
= new0(CGroupIODeviceLimit
, 1);
895 return log_oom_debug();
897 limit
->path
= TAKE_PTR(path
);
898 for (CGroupIOLimitType i
= 0; i
< _CGROUP_IO_LIMIT_TYPE_MAX
; i
++)
899 limit
->limits
[i
] = cgroup_io_limit_defaults
[i
];
901 LIST_PREPEND(device_limits
, c
->io_device_limits
, limit
);
904 r
= safe_atou64(limits
, &limit
->limits
[t
]);
907 } else if ((val
= startswith(l
, "exec-cgroup-context-block-io-device-weight="))) {
908 _cleanup_free_
char *path
= NULL
, *weight
= NULL
;
909 CGroupBlockIODeviceWeight
*a
= NULL
;
911 r
= extract_many_words(&val
, " ", 0, &path
, &weight
);
917 a
= new0(CGroupBlockIODeviceWeight
, 1);
919 return log_oom_debug();
921 a
->path
= TAKE_PTR(path
);
923 LIST_PREPEND(device_weights
, c
->blockio_device_weights
, a
);
925 r
= safe_atou64(weight
, &a
->weight
);
928 } else if ((val
= startswith(l
, "exec-cgroup-context-block-io-read-bandwidth="))) {
929 _cleanup_free_
char *path
= NULL
, *bw
= NULL
;
930 CGroupBlockIODeviceBandwidth
*a
= NULL
;
932 r
= extract_many_words(&val
, " ", 0, &path
, &bw
);
938 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
)
939 if (path_equal(b
->path
, path
)) {
945 a
= new0(CGroupBlockIODeviceBandwidth
, 1);
947 return log_oom_debug();
949 a
->path
= TAKE_PTR(path
);
950 a
->wbps
= CGROUP_LIMIT_MAX
;
952 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, a
);
955 r
= safe_atou64(bw
, &a
->rbps
);
958 } else if ((val
= startswith(l
, "exec-cgroup-context-block-io-write-bandwidth="))) {
959 _cleanup_free_
char *path
= NULL
, *bw
= NULL
;
960 CGroupBlockIODeviceBandwidth
*a
= NULL
;
962 r
= extract_many_words(&val
, " ", 0, &path
, &bw
);
968 LIST_FOREACH(device_bandwidths
, b
, c
->blockio_device_bandwidths
)
969 if (path_equal(b
->path
, path
)) {
975 a
= new0(CGroupBlockIODeviceBandwidth
, 1);
977 return log_oom_debug();
979 a
->path
= TAKE_PTR(path
);
980 a
->rbps
= CGROUP_LIMIT_MAX
;
982 LIST_PREPEND(device_bandwidths
, c
->blockio_device_bandwidths
, a
);
985 r
= safe_atou64(bw
, &a
->wbps
);
988 } else if ((val
= startswith(l
, "exec-cgroup-context-ip-address-allow="))) {
989 struct in_addr_prefix a
;
991 r
= in_addr_prefix_from_string_auto(val
, &a
.family
, &a
.address
, &a
.prefixlen
);
995 r
= in_addr_prefix_add(&c
->ip_address_allow
, &a
);
998 } else if ((val
= startswith(l
, "exec-cgroup-context-ip-address-deny="))) {
999 struct in_addr_prefix a
;
1001 r
= in_addr_prefix_from_string_auto(val
, &a
.family
, &a
.address
, &a
.prefixlen
);
1005 r
= in_addr_prefix_add(&c
->ip_address_deny
, &a
);
1008 } else if ((val
= startswith(l
, "exec-cgroup-context-ip-address-allow-reduced="))) {
1009 r
= parse_boolean(val
);
1012 c
->ip_address_allow_reduced
= r
;
1013 } else if ((val
= startswith(l
, "exec-cgroup-context-ip-address-deny-reduced="))) {
1014 r
= parse_boolean(val
);
1017 c
->ip_address_deny_reduced
= r
;
1018 } else if ((val
= startswith(l
, "exec-cgroup-context-ip-ingress-filter-path="))) {
1019 r
= deserialize_strv(val
, &c
->ip_filters_ingress
);
1022 } else if ((val
= startswith(l
, "exec-cgroup-context-ip-egress-filter-path="))) {
1023 r
= deserialize_strv(val
, &c
->ip_filters_egress
);
1026 } else if ((val
= startswith(l
, "exec-cgroup-context-bpf-program="))) {
1027 _cleanup_free_
char *type
= NULL
, *path
= NULL
;
1030 r
= extract_many_words(&val
, " ", 0, &type
, &path
);
1036 r
= safe_atou32(type
, &t
);
1040 r
= cgroup_context_add_bpf_foreign_program(c
, t
, path
);
1043 } else if ((val
= startswith(l
, "exec-cgroup-context-socket-bind-allow="))) {
1044 CGroupSocketBindItem
*item
;
1045 uint16_t nr_ports
, port_min
;
1046 int af
, ip_protocol
;
1048 r
= parse_socket_bind_item(val
, &af
, &ip_protocol
, &nr_ports
, &port_min
);
1052 item
= new(CGroupSocketBindItem
, 1);
1054 return log_oom_debug();
1055 *item
= (CGroupSocketBindItem
) {
1056 .address_family
= af
,
1057 .ip_protocol
= ip_protocol
,
1058 .nr_ports
= nr_ports
,
1059 .port_min
= port_min
,
1062 LIST_PREPEND(socket_bind_items
, c
->socket_bind_allow
, item
);
1063 } else if ((val
= startswith(l
, "exec-cgroup-context-socket-bind-deny="))) {
1064 CGroupSocketBindItem
*item
;
1065 uint16_t nr_ports
, port_min
;
1066 int af
, ip_protocol
;
1068 r
= parse_socket_bind_item(val
, &af
, &ip_protocol
, &nr_ports
, &port_min
);
1072 item
= new(CGroupSocketBindItem
, 1);
1074 return log_oom_debug();
1075 *item
= (CGroupSocketBindItem
) {
1076 .address_family
= af
,
1077 .ip_protocol
= ip_protocol
,
1078 .nr_ports
= nr_ports
,
1079 .port_min
= port_min
,
1082 LIST_PREPEND(socket_bind_items
, c
->socket_bind_deny
, item
);
1083 } else if ((val
= startswith(l
, "exec-cgroup-context-restrict-network-interfaces="))) {
1084 r
= set_ensure_allocated(&c
->restrict_network_interfaces
, &string_hash_ops
);
1088 r
= set_put_strdup(&c
->restrict_network_interfaces
, val
);
1091 } else if ((val
= startswith(l
, "exec-cgroup-context-restrict-network-interfaces-is-allow-list="))) {
1092 r
= parse_boolean(val
);
1095 c
->restrict_network_interfaces_is_allow_list
= r
;
1097 log_warning("Failed to parse serialized line, ignoring: %s", l
);
1103 static int exec_runtime_serialize(const ExecRuntime
*rt
, FILE *f
, FDSet
*fds
) {
1110 fputc('\n', f
); /* End marker */
1115 r
= serialize_item(f
, "exec-runtime-id", rt
->shared
->id
);
1119 r
= serialize_item(f
, "exec-runtime-tmp-dir", rt
->shared
->tmp_dir
);
1123 r
= serialize_item(f
, "exec-runtime-var-tmp-dir", rt
->shared
->var_tmp_dir
);
1127 if (rt
->shared
->netns_storage_socket
[0] >= 0 && rt
->shared
->netns_storage_socket
[1] >= 0) {
1128 r
= serialize_fd_many(f
, fds
, "exec-runtime-netns-storage-socket", rt
->shared
->netns_storage_socket
, 2);
1133 if (rt
->shared
->ipcns_storage_socket
[0] >= 0 && rt
->shared
->ipcns_storage_socket
[1] >= 0) {
1134 r
= serialize_fd_many(f
, fds
, "exec-runtime-ipcns-storage-socket", rt
->shared
->ipcns_storage_socket
, 2);
1140 if (rt
->dynamic_creds
) {
1141 r
= dynamic_user_serialize_one(rt
->dynamic_creds
->user
, "exec-runtime-dynamic-creds-user", f
, fds
);
1146 if (rt
->dynamic_creds
&& rt
->dynamic_creds
->group
&& rt
->dynamic_creds
->group
== rt
->dynamic_creds
->user
) {
1147 r
= serialize_bool(f
, "exec-runtime-dynamic-creds-group-copy", true);
1150 } else if (rt
->dynamic_creds
) {
1151 r
= dynamic_user_serialize_one(rt
->dynamic_creds
->group
, "exec-runtime-dynamic-creds-group", f
, fds
);
1156 r
= serialize_item(f
, "exec-runtime-ephemeral-copy", rt
->ephemeral_copy
);
1160 if (rt
->ephemeral_storage_socket
[0] >= 0 && rt
->ephemeral_storage_socket
[1] >= 0) {
1161 r
= serialize_fd_many(f
, fds
, "exec-runtime-ephemeral-storage-socket", rt
->ephemeral_storage_socket
, 2);
1166 fputc('\n', f
); /* End marker */
1171 static int exec_runtime_deserialize(ExecRuntime
*rt
, FILE *f
, FDSet
*fds
) {
1176 assert(rt
->dynamic_creds
);
1181 _cleanup_free_
char *l
= NULL
;
1184 r
= deserialize_read_line(f
, &l
);
1187 if (r
== 0) /* eof or end marker */
1190 if ((val
= startswith(l
, "exec-runtime-id="))) {
1191 r
= free_and_strdup(&rt
->shared
->id
, val
);
1194 } else if ((val
= startswith(l
, "exec-runtime-tmp-dir="))) {
1195 r
= free_and_strdup(&rt
->shared
->tmp_dir
, val
);
1198 } else if ((val
= startswith(l
, "exec-runtime-var-tmp-dir="))) {
1199 r
= free_and_strdup(&rt
->shared
->var_tmp_dir
, val
);
1202 } else if ((val
= startswith(l
, "exec-runtime-netns-storage-socket="))) {
1204 r
= deserialize_fd_many(fds
, val
, 2, rt
->shared
->netns_storage_socket
);
1208 } else if ((val
= startswith(l
, "exec-runtime-ipcns-storage-socket="))) {
1210 r
= deserialize_fd_many(fds
, val
, 2, rt
->shared
->ipcns_storage_socket
);
1214 } else if ((val
= startswith(l
, "exec-runtime-dynamic-creds-user=")))
1215 dynamic_user_deserialize_one(/* m= */ NULL
, val
, fds
, &rt
->dynamic_creds
->user
);
1216 else if ((val
= startswith(l
, "exec-runtime-dynamic-creds-group=")))
1217 dynamic_user_deserialize_one(/* m= */ NULL
, val
, fds
, &rt
->dynamic_creds
->group
);
1218 else if ((val
= startswith(l
, "exec-runtime-dynamic-creds-group-copy="))) {
1219 r
= parse_boolean(val
);
1223 continue; /* Nothing to do */
1225 if (!rt
->dynamic_creds
->user
)
1228 rt
->dynamic_creds
->group
= dynamic_user_ref(rt
->dynamic_creds
->user
);
1229 } else if ((val
= startswith(l
, "exec-runtime-ephemeral-copy="))) {
1230 r
= free_and_strdup(&rt
->ephemeral_copy
, val
);
1233 } else if ((val
= startswith(l
, "exec-runtime-ephemeral-storage-socket="))) {
1235 r
= deserialize_fd_many(fds
, val
, 2, rt
->ephemeral_storage_socket
);
1239 log_warning("Failed to parse serialized line, ignoring: %s", l
);
1245 static bool exec_parameters_is_idle_pipe_set(const ExecParameters
*p
) {
1248 return p
->idle_pipe
&&
1249 p
->idle_pipe
[0] >= 0 &&
1250 p
->idle_pipe
[1] >= 0 &&
1251 p
->idle_pipe
[2] >= 0 &&
1252 p
->idle_pipe
[3] >= 0;
1255 static int exec_parameters_serialize(const ExecParameters
*p
, const ExecContext
*c
, FILE *f
, FDSet
*fds
) {
1264 r
= serialize_item(f
, "exec-parameters-runtime-scope", runtime_scope_to_string(p
->runtime_scope
));
1268 r
= serialize_strv(f
, "exec-parameters-environment", p
->environment
);
1273 if (p
->n_socket_fds
> 0) {
1274 r
= serialize_item_format(f
, "exec-parameters-n-socket-fds", "%zu", p
->n_socket_fds
);
1279 if (p
->n_storage_fds
> 0) {
1280 r
= serialize_item_format(f
, "exec-parameters-n-storage-fds", "%zu", p
->n_storage_fds
);
1285 r
= serialize_fd_many(f
, fds
, "exec-parameters-fds", p
->fds
, p
->n_socket_fds
+ p
->n_storage_fds
);
1290 r
= serialize_strv(f
, "exec-parameters-fd-names", p
->fd_names
);
1294 if (p
->flags
!= 0) {
1295 r
= serialize_item_format(f
, "exec-parameters-flags", "%u", (unsigned) p
->flags
);
1300 r
= serialize_bool_elide(f
, "exec-parameters-selinux-context-net", p
->selinux_context_net
);
1304 if (p
->cgroup_supported
!= 0) {
1305 r
= serialize_item_format(f
, "exec-parameters-cgroup-supported", "%u", (unsigned) p
->cgroup_supported
);
1310 r
= serialize_item(f
, "exec-parameters-cgroup-path", p
->cgroup_path
);
1314 r
= serialize_item_format(f
, "exec-parameters-cgroup-id", "%" PRIu64
, p
->cgroup_id
);
1318 for (ExecDirectoryType dt
= 0; dt
< _EXEC_DIRECTORY_TYPE_MAX
; dt
++) {
1319 _cleanup_free_
char *key
= NULL
;
1321 key
= strjoin("exec-parameters-prefix-directories-", exec_directory_type_to_string(dt
));
1323 return log_oom_debug();
1325 /* Always serialize, even an empty prefix, as this is a fixed array and we always expect
1326 * to have all elements (unless fuzzing is happening, hence the NULL check). */
1327 r
= serialize_item(f
, key
, strempty(p
->prefix
? p
->prefix
[dt
] : NULL
));
1332 r
= serialize_item(f
, "exec-parameters-received-credentials-directory", p
->received_credentials_directory
);
1336 r
= serialize_item(f
, "exec-parameters-received-encrypted-credentials-directory", p
->received_encrypted_credentials_directory
);
1340 r
= serialize_item(f
, "exec-parameters-confirm-spawn", p
->confirm_spawn
);
1344 r
= serialize_bool_elide(f
, "exec-parameters-shall-confirm-spawn", p
->shall_confirm_spawn
);
1348 if (p
->watchdog_usec
> 0) {
1349 r
= serialize_usec(f
, "exec-parameters-watchdog-usec", p
->watchdog_usec
);
1354 if (exec_parameters_is_idle_pipe_set(p
)) {
1355 r
= serialize_fd_many(f
, fds
, "exec-parameters-idle-pipe", p
->idle_pipe
, 4);
1360 r
= serialize_fd(f
, fds
, "exec-parameters-stdin-fd", p
->stdin_fd
);
1364 r
= serialize_fd(f
, fds
, "exec-parameters-stdout-fd", p
->stdout_fd
);
1368 r
= serialize_fd(f
, fds
, "exec-parameters-stderr-fd", p
->stderr_fd
);
1372 r
= serialize_fd(f
, fds
, "exec-parameters-exec-fd", p
->exec_fd
);
1376 if (c
&& exec_context_restrict_filesystems_set(c
)) {
1377 r
= serialize_fd(f
, fds
, "exec-parameters-bpf-outer-map-fd", p
->bpf_restrict_fs_map_fd
);
1382 r
= serialize_item(f
, "exec-parameters-notify-socket", p
->notify_socket
);
1386 LIST_FOREACH(open_files
, file
, p
->open_files
) {
1387 _cleanup_free_
char *ofs
= NULL
;
1389 r
= open_file_to_string(file
, &ofs
);
1393 r
= serialize_item(f
, "exec-parameters-open-file", ofs
);
1398 r
= serialize_item(f
, "exec-parameters-fallback-smack-process-label", p
->fallback_smack_process_label
);
1402 r
= serialize_fd(f
, fds
, "exec-parameters-user-lookup-fd", p
->user_lookup_fd
);
1406 r
= serialize_strv(f
, "exec-parameters-files-env", p
->files_env
);
1410 r
= serialize_item(f
, "exec-parameters-unit-id", p
->unit_id
);
1414 r
= serialize_item(f
, "exec-parameters-invocation-id-string", p
->invocation_id_string
);
1418 fputc('\n', f
); /* End marker */
1423 static int exec_parameters_deserialize(ExecParameters
*p
, FILE *f
, FDSet
*fds
) {
1430 nr_open
= read_nr_open();
1432 nr_open
= HIGH_RLIMIT_NOFILE
;
1433 assert(nr_open
> 0); /* For compilers/static analyzers */
1436 _cleanup_free_
char *l
= NULL
;
1439 r
= deserialize_read_line(f
, &l
);
1442 if (r
== 0) /* eof or end marker */
1445 if ((val
= startswith(l
, "exec-parameters-runtime-scope="))) {
1446 p
->runtime_scope
= runtime_scope_from_string(val
);
1447 if (p
->runtime_scope
< 0)
1448 return p
->runtime_scope
;
1449 } else if ((val
= startswith(l
, "exec-parameters-environment="))) {
1450 r
= deserialize_strv(val
, &p
->environment
);
1453 } else if ((val
= startswith(l
, "exec-parameters-n-socket-fds="))) {
1455 return -EINVAL
; /* Already received */
1457 r
= safe_atozu(val
, &p
->n_socket_fds
);
1461 if (p
->n_socket_fds
> (size_t) nr_open
)
1462 return -EINVAL
; /* too many, someone is playing games with us */
1463 } else if ((val
= startswith(l
, "exec-parameters-n-storage-fds="))) {
1465 return -EINVAL
; /* Already received */
1467 r
= safe_atozu(val
, &p
->n_storage_fds
);
1471 if (p
->n_storage_fds
> (size_t) nr_open
)
1472 return -EINVAL
; /* too many, someone is playing games with us */
1473 } else if ((val
= startswith(l
, "exec-parameters-fds="))) {
1474 if (p
->n_socket_fds
+ p
->n_storage_fds
== 0)
1475 return log_warning_errno(
1476 SYNTHETIC_ERRNO(EINVAL
),
1477 "Got exec-parameters-fds= without "
1478 "prior exec-parameters-n-socket-fds= or exec-parameters-n-storage-fds=");
1479 if (p
->n_socket_fds
+ p
->n_storage_fds
> (size_t) nr_open
)
1480 return -EINVAL
; /* too many, someone is playing games with us */
1483 return -EINVAL
; /* duplicated */
1485 p
->fds
= new(int, p
->n_socket_fds
+ p
->n_storage_fds
);
1487 return log_oom_debug();
1489 /* Ensure we don't leave any FD uninitialized on error, it makes the fuzzer sad */
1490 FOREACH_ARRAY(i
, p
->fds
, p
->n_socket_fds
+ p
->n_storage_fds
)
1493 r
= deserialize_fd_many(fds
, val
, p
->n_socket_fds
+ p
->n_storage_fds
, p
->fds
);
1497 } else if ((val
= startswith(l
, "exec-parameters-fd-names="))) {
1498 r
= deserialize_strv(val
, &p
->fd_names
);
1501 } else if ((val
= startswith(l
, "exec-parameters-flags="))) {
1504 r
= safe_atou(val
, &flags
);
1508 } else if ((val
= startswith(l
, "exec-parameters-selinux-context-net="))) {
1509 r
= parse_boolean(val
);
1513 p
->selinux_context_net
= r
;
1514 } else if ((val
= startswith(l
, "exec-parameters-cgroup-supported="))) {
1515 unsigned cgroup_supported
;
1517 r
= safe_atou(val
, &cgroup_supported
);
1520 p
->cgroup_supported
= cgroup_supported
;
1521 } else if ((val
= startswith(l
, "exec-parameters-cgroup-path="))) {
1522 r
= free_and_strdup(&p
->cgroup_path
, val
);
1525 } else if ((val
= startswith(l
, "exec-parameters-cgroup-id="))) {
1526 r
= safe_atou64(val
, &p
->cgroup_id
);
1529 } else if ((val
= startswith(l
, "exec-parameters-prefix-directories-"))) {
1530 _cleanup_free_
char *type
= NULL
, *prefix
= NULL
;
1531 ExecDirectoryType dt
;
1533 r
= extract_many_words(&val
, "= ", 0, &type
, &prefix
);
1539 dt
= exec_directory_type_from_string(type
);
1544 p
->prefix
= new0(char*, _EXEC_DIRECTORY_TYPE_MAX
+1);
1546 return log_oom_debug();
1549 if (isempty(prefix
))
1550 p
->prefix
[dt
] = mfree(p
->prefix
[dt
]);
1552 free_and_replace(p
->prefix
[dt
], prefix
);
1553 } else if ((val
= startswith(l
, "exec-parameters-received-credentials-directory="))) {
1554 r
= free_and_strdup(&p
->received_credentials_directory
, val
);
1557 } else if ((val
= startswith(l
, "exec-parameters-received-encrypted-credentials-directory="))) {
1558 r
= free_and_strdup(&p
->received_encrypted_credentials_directory
, val
);
1561 } else if ((val
= startswith(l
, "exec-parameters-confirm-spawn="))) {
1562 r
= free_and_strdup(&p
->confirm_spawn
, val
);
1565 } else if ((val
= startswith(l
, "exec-parameters-shall-confirm-spawn="))) {
1566 r
= parse_boolean(val
);
1570 p
->shall_confirm_spawn
= r
;
1571 } else if ((val
= startswith(l
, "exec-parameters-watchdog-usec="))) {
1572 r
= deserialize_usec(val
, &p
->watchdog_usec
);
1575 } else if ((val
= startswith(l
, "exec-parameters-idle-pipe="))) {
1577 return -EINVAL
; /* duplicated */
1579 p
->idle_pipe
= new(int, 4);
1581 return log_oom_debug();
1583 p
->idle_pipe
[0] = p
->idle_pipe
[1] = p
->idle_pipe
[2] = p
->idle_pipe
[3] = -EBADF
;
1585 r
= deserialize_fd_many(fds
, val
, 4, p
->idle_pipe
);
1589 } else if ((val
= startswith(l
, "exec-parameters-stdin-fd="))) {
1592 fd
= deserialize_fd(fds
, val
);
1598 } else if ((val
= startswith(l
, "exec-parameters-stdout-fd="))) {
1601 fd
= deserialize_fd(fds
, val
);
1607 } else if ((val
= startswith(l
, "exec-parameters-stderr-fd="))) {
1610 fd
= deserialize_fd(fds
, val
);
1615 } else if ((val
= startswith(l
, "exec-parameters-exec-fd="))) {
1618 fd
= deserialize_fd(fds
, val
);
1623 } else if ((val
= startswith(l
, "exec-parameters-bpf-outer-map-fd="))) {
1626 fd
= deserialize_fd(fds
, val
);
1630 p
->bpf_restrict_fs_map_fd
= fd
;
1631 } else if ((val
= startswith(l
, "exec-parameters-notify-socket="))) {
1632 r
= free_and_strdup(&p
->notify_socket
, val
);
1635 } else if ((val
= startswith(l
, "exec-parameters-open-file="))) {
1636 OpenFile
*of
= NULL
;
1638 r
= open_file_parse(val
, &of
);
1642 LIST_APPEND(open_files
, p
->open_files
, of
);
1643 } else if ((val
= startswith(l
, "exec-parameters-fallback-smack-process-label="))) {
1644 r
= free_and_strdup(&p
->fallback_smack_process_label
, val
);
1647 } else if ((val
= startswith(l
, "exec-parameters-user-lookup-fd="))) {
1650 fd
= deserialize_fd(fds
, val
);
1654 p
->user_lookup_fd
= fd
;
1655 } else if ((val
= startswith(l
, "exec-parameters-files-env="))) {
1656 r
= deserialize_strv(val
, &p
->files_env
);
1659 } else if ((val
= startswith(l
, "exec-parameters-unit-id="))) {
1660 r
= free_and_strdup(&p
->unit_id
, val
);
1663 } else if ((val
= startswith(l
, "exec-parameters-invocation-id-string="))) {
1664 if (strlen(val
) > SD_ID128_STRING_MAX
- 1)
1667 r
= sd_id128_from_string(val
, &p
->invocation_id
);
1671 sd_id128_to_string(p
->invocation_id
, p
->invocation_id_string
);
1673 log_warning("Failed to parse serialized line, ignoring: %s", l
);
1676 /* Bail out if we got exec-parameters-n-{socket/storage}-fds= but no corresponding
1677 * exec-parameters-fds= */
1678 if (p
->n_socket_fds
+ p
->n_storage_fds
> 0 && !p
->fds
)
1684 static int serialize_std_out_err(const ExecContext
*c
, FILE *f
, int fileno
) {
1690 assert(IN_SET(fileno
, STDOUT_FILENO
, STDERR_FILENO
));
1692 type
= fileno
== STDOUT_FILENO
? "output" : "error";
1694 switch (fileno
== STDOUT_FILENO
? c
->std_output
: c
->std_error
) {
1695 case EXEC_OUTPUT_NAMED_FD
:
1696 key
= strjoina("exec-context-std-", type
, "-fd-name");
1697 value
= c
->stdio_fdname
[fileno
];
1701 case EXEC_OUTPUT_FILE
:
1702 key
= strjoina("exec-context-std-", type
, "-file");
1703 value
= c
->stdio_file
[fileno
];
1707 case EXEC_OUTPUT_FILE_APPEND
:
1708 key
= strjoina("exec-context-std-", type
, "-file-append");
1709 value
= c
->stdio_file
[fileno
];
1713 case EXEC_OUTPUT_FILE_TRUNCATE
:
1714 key
= strjoina("exec-context-std-", type
, "-file-truncate");
1715 value
= c
->stdio_file
[fileno
];
1723 return serialize_item(f
, key
, value
);
1726 static int exec_context_serialize(const ExecContext
*c
, FILE *f
) {
1734 r
= serialize_strv(f
, "exec-context-environment", c
->environment
);
1738 r
= serialize_strv(f
, "exec-context-environment-files", c
->environment_files
);
1742 r
= serialize_strv(f
, "exec-context-pass-environment", c
->pass_environment
);
1746 r
= serialize_strv(f
, "exec-context-unset-environment", c
->unset_environment
);
1750 r
= serialize_item(f
, "exec-context-working-directory", c
->working_directory
);
1754 r
= serialize_item(f
, "exec-context-root-directory", c
->root_directory
);
1758 r
= serialize_item(f
, "exec-context-root-image", c
->root_image
);
1762 if (c
->root_image_options
) {
1763 _cleanup_free_
char *options
= NULL
;
1765 LIST_FOREACH(mount_options
, o
, c
->root_image_options
) {
1766 if (isempty(o
->options
))
1769 _cleanup_free_
char *escaped
= NULL
;
1770 escaped
= shell_escape(o
->options
, ":");
1772 return log_oom_debug();
1774 if (!strextend(&options
,
1776 partition_designator_to_string(o
->partition_designator
),
1779 return log_oom_debug();
1782 r
= serialize_item(f
, "exec-context-root-image-options", options
);
1787 r
= serialize_item(f
, "exec-context-root-verity", c
->root_verity
);
1791 r
= serialize_item(f
, "exec-context-root-hash-path", c
->root_hash_path
);
1795 r
= serialize_item(f
, "exec-context-root-hash-sig-path", c
->root_hash_sig_path
);
1799 r
= serialize_item_hexmem(f
, "exec-context-root-hash", c
->root_hash
, c
->root_hash_size
);
1803 r
= serialize_item_base64mem(f
, "exec-context-root-hash-sig", c
->root_hash_sig
, c
->root_hash_sig_size
);
1807 r
= serialize_bool_elide(f
, "exec-context-root-ephemeral", c
->root_ephemeral
);
1811 r
= serialize_item_format(f
, "exec-context-umask", "%04o", c
->umask
);
1815 r
= serialize_bool_elide(f
, "exec-context-non-blocking", c
->non_blocking
);
1819 r
= serialize_item_tristate(f
, "exec-context-private-mounts", c
->private_mounts
);
1823 r
= serialize_item_tristate(f
, "exec-context-memory-ksm", c
->memory_ksm
);
1827 r
= serialize_bool_elide(f
, "exec-context-private-tmp", c
->private_tmp
);
1831 r
= serialize_bool_elide(f
, "exec-context-private-devices", c
->private_devices
);
1835 r
= serialize_bool_elide(f
, "exec-context-protect-kernel-tunables", c
->protect_kernel_tunables
);
1839 r
= serialize_bool_elide(f
, "exec-context-protect-kernel-modules", c
->protect_kernel_modules
);
1843 r
= serialize_bool_elide(f
, "exec-context-protect-kernel-logs", c
->protect_kernel_logs
);
1847 r
= serialize_bool_elide(f
, "exec-context-protect-clock", c
->protect_clock
);
1851 r
= serialize_bool_elide(f
, "exec-context-protect-control-groups", c
->protect_control_groups
);
1855 r
= serialize_bool_elide(f
, "exec-context-private-network", c
->private_network
);
1859 r
= serialize_bool_elide(f
, "exec-context-private-users", c
->private_users
);
1863 r
= serialize_bool_elide(f
, "exec-context-private-ipc", c
->private_ipc
);
1867 r
= serialize_bool_elide(f
, "exec-context-remove-ipc", c
->remove_ipc
);
1871 r
= serialize_item(f
, "exec-context-protect-home", protect_home_to_string(c
->protect_home
));
1875 r
= serialize_item(f
, "exec-context-protect-system", protect_system_to_string(c
->protect_system
));
1879 if (c
->mount_apivfs_set
) {
1880 r
= serialize_bool(f
, "exec-context-mount-api-vfs", c
->mount_apivfs
);
1885 r
= serialize_bool_elide(f
, "exec-context-same-pgrp", c
->same_pgrp
);
1889 r
= serialize_bool(f
, "exec-context-ignore-sigpipe", c
->ignore_sigpipe
);
1893 r
= serialize_bool_elide(f
, "exec-context-memory-deny-write-execute", c
->memory_deny_write_execute
);
1897 r
= serialize_bool_elide(f
, "exec-context-restrict-realtime", c
->restrict_realtime
);
1901 r
= serialize_bool_elide(f
, "exec-context-restrict-suid-sgid", c
->restrict_suid_sgid
);
1905 r
= serialize_item(f
, "exec-context-keyring-mode", exec_keyring_mode_to_string(c
->keyring_mode
));
1909 r
= serialize_bool_elide(f
, "exec-context-protect-hostname", c
->protect_hostname
);
1913 r
= serialize_item(f
, "exec-context-protect-proc", protect_proc_to_string(c
->protect_proc
));
1917 r
= serialize_item(f
, "exec-context-proc-subset", proc_subset_to_string(c
->proc_subset
));
1921 r
= serialize_item(f
, "exec-context-runtime-directory-preserve-mode", exec_preserve_mode_to_string(c
->runtime_directory_preserve_mode
));
1925 for (ExecDirectoryType dt
= 0; dt
< _EXEC_DIRECTORY_TYPE_MAX
; dt
++) {
1926 _cleanup_free_
char *key
= NULL
, *value
= NULL
;
1928 key
= strjoin("exec-context-directories-", exec_directory_type_to_string(dt
));
1930 return log_oom_debug();
1932 if (asprintf(&value
, "%04o", c
->directories
[dt
].mode
) < 0)
1933 return log_oom_debug();
1935 FOREACH_ARRAY(i
, c
->directories
[dt
].items
, c
->directories
[dt
].n_items
) {
1936 _cleanup_free_
char *path_escaped
= NULL
;
1938 path_escaped
= shell_escape(i
->path
, ":" WHITESPACE
);
1940 return log_oom_debug();
1942 if (!strextend(&value
, " ", path_escaped
))
1943 return log_oom_debug();
1945 if (!strextend(&value
, ":", yes_no(i
->only_create
)))
1946 return log_oom_debug();
1948 STRV_FOREACH(d
, i
->symlinks
) {
1949 _cleanup_free_
char *link_escaped
= NULL
;
1951 link_escaped
= shell_escape(*d
, ":" WHITESPACE
);
1953 return log_oom_debug();
1955 if (!strextend(&value
, ":", link_escaped
))
1956 return log_oom_debug();
1960 r
= serialize_item(f
, key
, value
);
1965 r
= serialize_usec(f
, "exec-context-timeout-clean-usec", c
->timeout_clean_usec
);
1970 r
= serialize_item_format(f
, "exec-context-nice", "%i", c
->nice
);
1975 r
= serialize_bool_elide(f
, "exec-context-working-directory-missing-ok", c
->working_directory_missing_ok
);
1979 r
= serialize_bool_elide(f
, "exec-context-working-directory-home", c
->working_directory_home
);
1983 if (c
->oom_score_adjust_set
) {
1984 r
= serialize_item_format(f
, "exec-context-oom-score-adjust", "%i", c
->oom_score_adjust
);
1989 if (c
->coredump_filter_set
) {
1990 r
= serialize_item_format(f
, "exec-context-coredump-filter", "%"PRIx64
, c
->coredump_filter
);
1995 for (unsigned i
= 0; i
< RLIM_NLIMITS
; i
++) {
1996 _cleanup_free_
char *key
= NULL
, *limit
= NULL
;
2001 key
= strjoin("exec-context-limit-", rlimit_to_string(i
));
2003 return log_oom_debug();
2005 r
= rlimit_format(c
->rlimit
[i
], &limit
);
2009 r
= serialize_item(f
, key
, limit
);
2014 if (c
->ioprio_set
) {
2015 r
= serialize_item_format(f
, "exec-context-ioprio", "%d", c
->ioprio
);
2020 if (c
->cpu_sched_set
) {
2021 _cleanup_free_
char *policy_str
= NULL
;
2023 r
= sched_policy_to_string_alloc(c
->cpu_sched_policy
, &policy_str
);
2027 r
= serialize_item(f
, "exec-context-cpu-scheduling-policy", policy_str
);
2031 r
= serialize_item_format(f
, "exec-context-cpu-scheduling-priority", "%i", c
->cpu_sched_priority
);
2035 r
= serialize_bool_elide(f
, "exec-context-cpu-scheduling-reset-on-fork", c
->cpu_sched_reset_on_fork
);
2040 if (c
->cpu_set
.set
) {
2041 _cleanup_free_
char *affinity
= NULL
;
2043 affinity
= cpu_set_to_range_string(&c
->cpu_set
);
2045 return log_oom_debug();
2047 r
= serialize_item(f
, "exec-context-cpu-affinity", affinity
);
2052 if (mpol_is_valid(numa_policy_get_type(&c
->numa_policy
))) {
2053 _cleanup_free_
char *nodes
= NULL
;
2055 nodes
= cpu_set_to_range_string(&c
->numa_policy
.nodes
);
2057 return log_oom_debug();
2060 r
= serialize_item(f
, "exec-context-numa-mask", nodes
);
2065 r
= serialize_item_format(f
, "exec-context-numa-policy", "%d", c
->numa_policy
.type
);
2070 r
= serialize_bool_elide(f
, "exec-context-cpu-affinity-from-numa", c
->cpu_affinity_from_numa
);
2074 if (c
->timer_slack_nsec
!= NSEC_INFINITY
) {
2075 r
= serialize_item_format(f
, "exec-context-timer-slack-nsec", NSEC_FMT
, c
->timer_slack_nsec
);
2080 r
= serialize_item(f
, "exec-context-std-input", exec_input_to_string(c
->std_input
));
2084 r
= serialize_item(f
, "exec-context-std-output", exec_output_to_string(c
->std_output
));
2088 r
= serialize_item(f
, "exec-context-std-error", exec_output_to_string(c
->std_error
));
2092 r
= serialize_bool_elide(f
, "exec-context-stdio-as-fds", c
->stdio_as_fds
);
2096 switch (c
->std_input
) {
2097 case EXEC_INPUT_NAMED_FD
:
2098 r
= serialize_item(f
, "exec-context-std-input-fd-name", c
->stdio_fdname
[STDIN_FILENO
]);
2103 case EXEC_INPUT_FILE
:
2104 r
= serialize_item(f
, "exec-context-std-input-file", c
->stdio_file
[STDIN_FILENO
]);
2113 r
= serialize_std_out_err(c
, f
, STDOUT_FILENO
);
2117 r
= serialize_std_out_err(c
, f
, STDERR_FILENO
);
2121 r
= serialize_item_base64mem(f
, "exec-context-stdin-data", c
->stdin_data
, c
->stdin_data_size
);
2125 r
= serialize_item(f
, "exec-context-tty-path", c
->tty_path
);
2129 r
= serialize_bool_elide(f
, "exec-context-tty-reset", c
->tty_reset
);
2133 r
= serialize_bool_elide(f
, "exec-context-tty-vhangup", c
->tty_vhangup
);
2137 r
= serialize_bool_elide(f
, "exec-context-tty-vt-disallocate", c
->tty_vt_disallocate
);
2141 r
= serialize_item_format(f
, "exec-context-tty-rows", "%u", c
->tty_rows
);
2145 r
= serialize_item_format(f
, "exec-context-tty-columns", "%u", c
->tty_cols
);
2149 r
= serialize_item_format(f
, "exec-context-syslog-priority", "%i", c
->syslog_priority
);
2153 r
= serialize_bool(f
, "exec-context-syslog-level-prefix", c
->syslog_level_prefix
);
2157 r
= serialize_item(f
, "exec-context-syslog-identifier", c
->syslog_identifier
);
2161 /* This is also passed to executor as an argument. So, the information should be redundant in general.
2162 * But, let's keep this as is for consistency with other elements of ExecContext. See exec_spawn(). */
2163 r
= serialize_item_format(f
, "exec-context-log-level-max", "%d", c
->log_level_max
);
2167 if (c
->log_ratelimit_interval_usec
> 0) {
2168 r
= serialize_usec(f
, "exec-context-log-ratelimit-interval-usec", c
->log_ratelimit_interval_usec
);
2173 if (c
->log_ratelimit_burst
> 0) {
2174 r
= serialize_item_format(f
, "exec-context-log-ratelimit-burst", "%u", c
->log_ratelimit_burst
);
2179 r
= serialize_string_set(f
, "exec-context-log-filter-allowed-patterns", c
->log_filter_allowed_patterns
);
2183 r
= serialize_string_set(f
, "exec-context-log-filter-denied-patterns", c
->log_filter_denied_patterns
);
2187 FOREACH_ARRAY(field
, c
->log_extra_fields
, c
->n_log_extra_fields
) {
2188 r
= serialize_item(f
, "exec-context-log-extra-fields", field
->iov_base
);
2193 r
= serialize_item(f
, "exec-context-log-namespace", c
->log_namespace
);
2197 if (c
->secure_bits
!= 0) {
2198 r
= serialize_item_format(f
, "exec-context-secure-bits", "%d", c
->secure_bits
);
2203 if (c
->capability_bounding_set
!= CAP_MASK_UNSET
) {
2204 r
= serialize_item_format(f
, "exec-context-capability-bounding-set", "%" PRIu64
, c
->capability_bounding_set
);
2209 if (c
->capability_ambient_set
!= 0) {
2210 r
= serialize_item_format(f
, "exec-context-capability-ambient-set", "%" PRIu64
, c
->capability_ambient_set
);
2216 r
= serialize_item(f
, "exec-context-user", c
->user
);
2221 r
= serialize_item(f
, "exec-context-group", c
->group
);
2225 r
= serialize_bool_elide(f
, "exec-context-dynamic-user", c
->dynamic_user
);
2229 r
= serialize_strv(f
, "exec-context-supplementary-groups", c
->supplementary_groups
);
2233 r
= serialize_item_tristate(f
, "exec-context-set-login-environment", c
->set_login_environment
);
2237 r
= serialize_item(f
, "exec-context-pam-name", c
->pam_name
);
2241 r
= serialize_strv(f
, "exec-context-read-write-paths", c
->read_write_paths
);
2245 r
= serialize_strv(f
, "exec-context-read-only-paths", c
->read_only_paths
);
2249 r
= serialize_strv(f
, "exec-context-inaccessible-paths", c
->inaccessible_paths
);
2253 r
= serialize_strv(f
, "exec-context-exec-paths", c
->exec_paths
);
2257 r
= serialize_strv(f
, "exec-context-no-exec-paths", c
->no_exec_paths
);
2261 r
= serialize_strv(f
, "exec-context-exec-search-path", c
->exec_search_path
);
2265 r
= serialize_item_format(f
, "exec-context-mount-propagation-flag", "%lu", c
->mount_propagation_flag
);
2269 FOREACH_ARRAY(mount
, c
->bind_mounts
, c
->n_bind_mounts
) {
2270 _cleanup_free_
char *src_escaped
= NULL
, *dst_escaped
= NULL
;
2272 src_escaped
= shell_escape(mount
->source
, ":" WHITESPACE
);
2274 return log_oom_debug();
2276 dst_escaped
= shell_escape(mount
->destination
, ":" WHITESPACE
);
2278 return log_oom_debug();
2280 r
= serialize_item_format(f
,
2281 mount
->read_only
? "exec-context-bind-read-only-path" : "exec-context-bind-path",
2283 mount
->ignore_enoent
? "-" : "",
2286 mount
->recursive
? "rbind" : "norbind");
2291 FOREACH_ARRAY(tmpfs
, c
->temporary_filesystems
, c
->n_temporary_filesystems
) {
2292 _cleanup_free_
char *escaped
= NULL
;
2294 if (!isempty(tmpfs
->options
)) {
2295 escaped
= shell_escape(tmpfs
->options
, ":");
2297 return log_oom_debug();
2300 r
= serialize_item_format(f
, "exec-context-temporary-filesystems", "%s%s%s",
2302 isempty(escaped
) ? "" : ":",
2308 r
= serialize_item(f
, "exec-context-utmp-id", c
->utmp_id
);
2312 r
= serialize_item(f
, "exec-context-utmp-mode", exec_utmp_mode_to_string(c
->utmp_mode
));
2316 r
= serialize_bool_elide(f
, "exec-context-no-new-privileges", c
->no_new_privileges
);
2320 r
= serialize_bool_elide(f
, "exec-context-selinux-context-ignore", c
->selinux_context_ignore
);
2324 r
= serialize_bool_elide(f
, "exec-context-apparmor-profile-ignore", c
->apparmor_profile_ignore
);
2328 r
= serialize_bool_elide(f
, "exec-context-smack-process-label-ignore", c
->smack_process_label_ignore
);
2332 if (c
->selinux_context
) {
2333 r
= serialize_item_format(f
, "exec-context-selinux-context",
2335 c
->selinux_context_ignore
? "-" : "",
2336 c
->selinux_context
);
2341 if (c
->apparmor_profile
) {
2342 r
= serialize_item_format(f
, "exec-context-apparmor-profile",
2344 c
->apparmor_profile_ignore
? "-" : "",
2345 c
->apparmor_profile
);
2350 if (c
->smack_process_label
) {
2351 r
= serialize_item_format(f
, "exec-context-smack-process-label",
2353 c
->smack_process_label_ignore
? "-" : "",
2354 c
->smack_process_label
);
2359 if (c
->personality
!= PERSONALITY_INVALID
) {
2360 r
= serialize_item(f
, "exec-context-personality", personality_to_string(c
->personality
));
2365 r
= serialize_bool_elide(f
, "exec-context-lock-personality", c
->lock_personality
);
2370 if (!hashmap_isempty(c
->syscall_filter
)) {
2371 void *errno_num
, *id
;
2372 HASHMAP_FOREACH_KEY(errno_num
, id
, c
->syscall_filter
) {
2373 r
= serialize_item_format(f
, "exec-context-syscall-filter", "%d %d", PTR_TO_INT(id
) - 1, PTR_TO_INT(errno_num
));
2379 if (!set_isempty(c
->syscall_archs
)) {
2381 SET_FOREACH(id
, c
->syscall_archs
) {
2382 r
= serialize_item_format(f
, "exec-context-syscall-archs", "%u", PTR_TO_UINT(id
) - 1);
2388 if (c
->syscall_errno
> 0) {
2389 r
= serialize_item_format(f
, "exec-context-syscall-errno", "%d", c
->syscall_errno
);
2394 r
= serialize_bool_elide(f
, "exec-context-syscall-allow-list", c
->syscall_allow_list
);
2398 if (!hashmap_isempty(c
->syscall_log
)) {
2399 void *errno_num
, *id
;
2400 HASHMAP_FOREACH_KEY(errno_num
, id
, c
->syscall_log
) {
2401 r
= serialize_item_format(f
, "exec-context-syscall-log", "%d %d", PTR_TO_INT(id
) - 1, PTR_TO_INT(errno_num
));
2407 r
= serialize_bool_elide(f
, "exec-context-syscall-log-allow-list", c
->syscall_log_allow_list
);
2412 if (c
->restrict_namespaces
!= NAMESPACE_FLAGS_INITIAL
) {
2413 r
= serialize_item_format(f
, "exec-context-restrict-namespaces", "%lu", c
->restrict_namespaces
);
2419 if (exec_context_restrict_filesystems_set(c
)) {
2421 SET_FOREACH(fs
, c
->restrict_filesystems
) {
2422 r
= serialize_item(f
, "exec-context-restrict-filesystems", fs
);
2428 r
= serialize_bool_elide(f
, "exec-context-restrict-filesystems-allow-list", c
->restrict_filesystems_allow_list
);
2433 if (!set_isempty(c
->address_families
)) {
2436 SET_FOREACH(afp
, c
->address_families
) {
2437 int af
= PTR_TO_INT(afp
);
2439 if (af
<= 0 || af
>= af_max())
2442 r
= serialize_item_format(f
, "exec-context-address-families", "%d", af
);
2448 r
= serialize_bool_elide(f
, "exec-context-address-families-allow-list", c
->address_families_allow_list
);
2452 r
= serialize_item(f
, "exec-context-network-namespace-path", c
->network_namespace_path
);
2456 r
= serialize_item(f
, "exec-context-ipc-namespace-path", c
->ipc_namespace_path
);
2460 FOREACH_ARRAY(mount
, c
->mount_images
, c
->n_mount_images
) {
2461 _cleanup_free_
char *s
= NULL
, *source_escaped
= NULL
, *dest_escaped
= NULL
;
2463 source_escaped
= shell_escape(mount
->source
, WHITESPACE
);
2464 if (!source_escaped
)
2465 return log_oom_debug();
2467 dest_escaped
= shell_escape(mount
->destination
, WHITESPACE
);
2469 return log_oom_debug();
2471 s
= strjoin(mount
->ignore_enoent
? "-" : "",
2476 return log_oom_debug();
2478 LIST_FOREACH(mount_options
, o
, mount
->mount_options
) {
2479 _cleanup_free_
char *escaped
= NULL
;
2481 if (isempty(o
->options
))
2484 escaped
= shell_escape(o
->options
, ":");
2486 return log_oom_debug();
2490 partition_designator_to_string(o
->partition_designator
),
2493 return log_oom_debug();
2496 r
= serialize_item(f
, "exec-context-mount-image", s
);
2501 FOREACH_ARRAY(mount
, c
->extension_images
, c
->n_extension_images
) {
2502 _cleanup_free_
char *s
= NULL
, *source_escaped
= NULL
;
2504 source_escaped
= shell_escape(mount
->source
, ":" WHITESPACE
);
2505 if (!source_escaped
)
2506 return log_oom_debug();
2508 s
= strjoin(mount
->ignore_enoent
? "-" : "",
2511 return log_oom_debug();
2513 LIST_FOREACH(mount_options
, o
, mount
->mount_options
) {
2514 _cleanup_free_
char *escaped
= NULL
;
2516 if (isempty(o
->options
))
2519 escaped
= shell_escape(o
->options
, ":");
2521 return log_oom_debug();
2525 partition_designator_to_string(o
->partition_designator
),
2528 return log_oom_debug();
2531 r
= serialize_item(f
, "exec-context-extension-image", s
);
2536 r
= serialize_strv(f
, "exec-context-extension-directories", c
->extension_directories
);
2540 ExecSetCredential
*sc
;
2541 HASHMAP_FOREACH(sc
, c
->set_credentials
) {
2542 _cleanup_free_
char *data
= NULL
;
2544 if (base64mem(sc
->data
, sc
->size
, &data
) < 0)
2545 return log_oom_debug();
2547 r
= serialize_item_format(f
, "exec-context-set-credentials", "%s %s %s", sc
->id
, yes_no(sc
->encrypted
), data
);
2552 ExecLoadCredential
*lc
;
2553 HASHMAP_FOREACH(lc
, c
->load_credentials
) {
2554 r
= serialize_item_format(f
, "exec-context-load-credentials", "%s %s %s", lc
->id
, yes_no(lc
->encrypted
), lc
->path
);
2559 if (!set_isempty(c
->import_credentials
)) {
2561 SET_FOREACH(ic
, c
->import_credentials
) {
2562 r
= serialize_item(f
, "exec-context-import-credentials", ic
);
2568 r
= serialize_image_policy(f
, "exec-context-root-image-policy", c
->root_image_policy
);
2572 r
= serialize_image_policy(f
, "exec-context-mount-image-policy", c
->mount_image_policy
);
2576 r
= serialize_image_policy(f
, "exec-context-extension-image-policy", c
->extension_image_policy
);
2580 fputc('\n', f
); /* End marker */
2585 static int exec_context_deserialize(ExecContext
*c
, FILE *f
) {
2594 _cleanup_free_
char *l
= NULL
;
2597 r
= deserialize_read_line(f
, &l
);
2600 if (r
== 0) /* eof or end marker */
2603 if ((val
= startswith(l
, "exec-context-environment="))) {
2604 r
= deserialize_strv(val
, &c
->environment
);
2607 } else if ((val
= startswith(l
, "exec-context-environment-files="))) {
2608 r
= deserialize_strv(val
, &c
->environment_files
);
2611 } else if ((val
= startswith(l
, "exec-context-pass-environment="))) {
2612 r
= deserialize_strv(val
, &c
->pass_environment
);
2615 } else if ((val
= startswith(l
, "exec-context-unset-environment="))) {
2616 r
= deserialize_strv(val
, &c
->unset_environment
);
2619 } else if ((val
= startswith(l
, "exec-context-working-directory="))) {
2620 r
= free_and_strdup(&c
->working_directory
, val
);
2623 } else if ((val
= startswith(l
, "exec-context-root-directory="))) {
2624 r
= free_and_strdup(&c
->root_directory
, val
);
2627 } else if ((val
= startswith(l
, "exec-context-root-image="))) {
2628 r
= free_and_strdup(&c
->root_image
, val
);
2631 } else if ((val
= startswith(l
, "exec-context-root-image-options="))) {
2633 _cleanup_free_
char *word
= NULL
, *mount_options
= NULL
, *partition
= NULL
;
2634 PartitionDesignator partition_designator
;
2635 MountOptions
*o
= NULL
;
2638 r
= extract_first_word(&val
, &word
, NULL
, 0);
2645 r
= extract_many_words(&p
, ":", EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
, &partition
, &mount_options
);
2651 partition_designator
= partition_designator_from_string(partition
);
2652 if (partition_designator
< 0)
2655 o
= new(MountOptions
, 1);
2657 return log_oom_debug();
2658 *o
= (MountOptions
) {
2659 .partition_designator
= partition_designator
,
2660 .options
= TAKE_PTR(mount_options
),
2662 LIST_APPEND(mount_options
, c
->root_image_options
, o
);
2664 } else if ((val
= startswith(l
, "exec-context-root-verity="))) {
2665 r
= free_and_strdup(&c
->root_verity
, val
);
2668 } else if ((val
= startswith(l
, "exec-context-root-hash-path="))) {
2669 r
= free_and_strdup(&c
->root_hash_path
, val
);
2672 } else if ((val
= startswith(l
, "exec-context-root-hash-sig-path="))) {
2673 r
= free_and_strdup(&c
->root_hash_sig_path
, val
);
2676 } else if ((val
= startswith(l
, "exec-context-root-hash="))) {
2677 c
->root_hash
= mfree(c
->root_hash
);
2678 r
= unhexmem(val
, &c
->root_hash
, &c
->root_hash_size
);
2681 } else if ((val
= startswith(l
, "exec-context-root-hash-sig="))) {
2682 c
->root_hash_sig
= mfree(c
->root_hash_sig
);
2683 r
= unbase64mem(val
, &c
->root_hash_sig
, &c
->root_hash_sig_size
);
2686 } else if ((val
= startswith(l
, "exec-context-root-ephemeral="))) {
2687 r
= parse_boolean(val
);
2690 c
->root_ephemeral
= r
;
2691 } else if ((val
= startswith(l
, "exec-context-umask="))) {
2692 r
= parse_mode(val
, &c
->umask
);
2695 } else if ((val
= startswith(l
, "exec-context-private-non-blocking="))) {
2696 r
= parse_boolean(val
);
2699 c
->non_blocking
= r
;
2700 } else if ((val
= startswith(l
, "exec-context-private-mounts="))) {
2701 r
= safe_atoi(val
, &c
->private_mounts
);
2704 } else if ((val
= startswith(l
, "exec-context-memory-ksm="))) {
2705 r
= safe_atoi(val
, &c
->memory_ksm
);
2708 } else if ((val
= startswith(l
, "exec-context-private-tmp="))) {
2709 r
= parse_boolean(val
);
2713 } else if ((val
= startswith(l
, "exec-context-private-devices="))) {
2714 r
= parse_boolean(val
);
2717 c
->private_devices
= r
;
2718 } else if ((val
= startswith(l
, "exec-context-protect-kernel-tunables="))) {
2719 r
= parse_boolean(val
);
2722 c
->protect_kernel_tunables
= r
;
2723 } else if ((val
= startswith(l
, "exec-context-protect-kernel-modules="))) {
2724 r
= parse_boolean(val
);
2727 c
->protect_kernel_modules
= r
;
2728 } else if ((val
= startswith(l
, "exec-context-protect-kernel-logs="))) {
2729 r
= parse_boolean(val
);
2732 c
->protect_kernel_logs
= r
;
2733 } else if ((val
= startswith(l
, "exec-context-protect-clock="))) {
2734 r
= parse_boolean(val
);
2737 c
->protect_clock
= r
;
2738 } else if ((val
= startswith(l
, "exec-context-protect-control-groups="))) {
2739 r
= parse_boolean(val
);
2742 c
->protect_control_groups
= r
;
2743 } else if ((val
= startswith(l
, "exec-context-private-network="))) {
2744 r
= parse_boolean(val
);
2747 c
->private_network
= r
;
2748 } else if ((val
= startswith(l
, "exec-context-private-users="))) {
2749 r
= parse_boolean(val
);
2752 c
->private_users
= r
;
2753 } else if ((val
= startswith(l
, "exec-context-private-ipc="))) {
2754 r
= parse_boolean(val
);
2758 } else if ((val
= startswith(l
, "exec-context-remove-ipc="))) {
2759 r
= parse_boolean(val
);
2763 } else if ((val
= startswith(l
, "exec-context-protect-home="))) {
2764 c
->protect_home
= protect_home_from_string(val
);
2765 if (c
->protect_home
< 0)
2767 } else if ((val
= startswith(l
, "exec-context-protect-system="))) {
2768 c
->protect_system
= protect_system_from_string(val
);
2769 if (c
->protect_system
< 0)
2771 } else if ((val
= startswith(l
, "exec-context-mount-api-vfs="))) {
2772 r
= parse_boolean(val
);
2775 c
->mount_apivfs
= r
;
2776 c
->mount_apivfs_set
= true;
2777 } else if ((val
= startswith(l
, "exec-context-same-pgrp="))) {
2778 r
= parse_boolean(val
);
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
);
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
);
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
);
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
);
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
);
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
,
3522 if (isempty(destination
))
3526 _cleanup_free_
char *tuple
= NULL
, *partition
= NULL
, *opts
= NULL
;
3527 PartitionDesignator partition_designator
;
3528 MountOptions
*o
= NULL
;
3531 r
= extract_first_word(&val
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
3538 r
= extract_many_words(&p
,
3540 EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
,
3548 o
= new(MountOptions
, 1);
3550 return log_oom_debug();
3551 *o
= (MountOptions
) {
3552 .partition_designator
= PARTITION_ROOT
,
3553 .options
= TAKE_PTR(partition
),
3555 LIST_APPEND(mount_options
, options
, o
);
3560 partition_designator
= partition_designator_from_string(partition
);
3561 if (partition_designator
< 0)
3564 o
= new(MountOptions
, 1);
3566 return log_oom_debug();
3567 *o
= (MountOptions
) {
3568 .partition_designator
= partition_designator
,
3569 .options
= TAKE_PTR(opts
),
3571 LIST_APPEND(mount_options
, options
, o
);
3574 r
= mount_image_add(&c
->mount_images
, &c
->n_mount_images
,
3577 .destination
= destination
,
3578 .mount_options
= options
,
3579 .ignore_enoent
= permissive
,
3580 .type
= MOUNT_IMAGE_DISCRETE
,
3583 return log_oom_debug();
3584 } else if ((val
= startswith(l
, "exec-context-extension-image="))) {
3585 _cleanup_(mount_options_free_allp
) MountOptions
*options
= NULL
;
3586 _cleanup_free_
char *source
= NULL
;
3587 bool permissive
= false;
3590 r
= extract_first_word(&val
,
3593 EXTRACT_UNQUOTE
|EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
);
3606 _cleanup_free_
char *tuple
= NULL
, *partition
= NULL
, *opts
= NULL
;
3607 PartitionDesignator partition_designator
;
3608 MountOptions
*o
= NULL
;
3611 r
= extract_first_word(&val
, &tuple
, NULL
, EXTRACT_UNQUOTE
|EXTRACT_RETAIN_ESCAPE
);
3618 r
= extract_many_words(&p
,
3620 EXTRACT_CUNESCAPE
|EXTRACT_UNESCAPE_SEPARATORS
,
3628 o
= new(MountOptions
, 1);
3630 return log_oom_debug();
3631 *o
= (MountOptions
) {
3632 .partition_designator
= PARTITION_ROOT
,
3633 .options
= TAKE_PTR(partition
),
3635 LIST_APPEND(mount_options
, options
, o
);
3640 partition_designator
= partition_designator_from_string(partition
);
3641 if (partition_designator
< 0)
3644 o
= new(MountOptions
, 1);
3646 return log_oom_debug();
3647 *o
= (MountOptions
) {
3648 .partition_designator
= partition_designator
,
3649 .options
= TAKE_PTR(opts
),
3651 LIST_APPEND(mount_options
, options
, o
);
3654 r
= mount_image_add(&c
->extension_images
, &c
->n_extension_images
,
3657 .mount_options
= options
,
3658 .ignore_enoent
= permissive
,
3659 .type
= MOUNT_IMAGE_EXTENSION
,
3662 return log_oom_debug();
3663 } else if ((val
= startswith(l
, "exec-context-extension-directories="))) {
3664 r
= deserialize_strv(val
, &c
->extension_directories
);
3667 } else if ((val
= startswith(l
, "exec-context-set-credentials="))) {
3668 _cleanup_(exec_set_credential_freep
) ExecSetCredential
*sc
= NULL
;
3669 _cleanup_free_
char *id
= NULL
, *encrypted
= NULL
, *data
= NULL
;
3671 r
= extract_many_words(&val
, " ", 0, &id
, &encrypted
, &data
);
3677 r
= parse_boolean(encrypted
);
3681 sc
= new(ExecSetCredential
, 1);
3685 *sc
= (ExecSetCredential
) {
3690 r
= unbase64mem(data
, &sc
->data
, &sc
->size
);
3694 r
= hashmap_ensure_put(&c
->set_credentials
, &exec_set_credential_hash_ops
, sc
->id
, sc
);
3699 } else if ((val
= startswith(l
, "exec-context-load-credentials="))) {
3700 _cleanup_(exec_load_credential_freep
) ExecLoadCredential
*lc
= NULL
;
3701 _cleanup_free_
char *id
= NULL
, *encrypted
= NULL
, *path
= NULL
;
3703 r
= extract_many_words(&val
, " ", 0, &id
, &encrypted
, &path
);
3709 r
= parse_boolean(encrypted
);
3713 lc
= new(ExecLoadCredential
, 1);
3717 *lc
= (ExecLoadCredential
) {
3719 .path
= TAKE_PTR(path
),
3723 r
= hashmap_ensure_put(&c
->load_credentials
, &exec_load_credential_hash_ops
, lc
->id
, lc
);
3728 } else if ((val
= startswith(l
, "exec-context-import-credentials="))) {
3729 r
= set_ensure_allocated(&c
->import_credentials
, &string_hash_ops
);
3733 r
= set_put_strdup(&c
->import_credentials
, val
);
3736 } else if ((val
= startswith(l
, "exec-context-root-image-policy="))) {
3737 if (c
->root_image_policy
)
3738 return -EINVAL
; /* duplicated */
3740 r
= image_policy_from_string(val
, &c
->root_image_policy
);
3743 } else if ((val
= startswith(l
, "exec-context-mount-image-policy="))) {
3744 if (c
->mount_image_policy
)
3745 return -EINVAL
; /* duplicated */
3747 r
= image_policy_from_string(val
, &c
->mount_image_policy
);
3750 } else if ((val
= startswith(l
, "exec-context-extension-image-policy="))) {
3751 if (c
->extension_image_policy
)
3752 return -EINVAL
; /* duplicated */
3754 r
= image_policy_from_string(val
, &c
->extension_image_policy
);
3758 log_warning("Failed to parse serialized line, ignoring: %s", l
);
3764 static int exec_command_serialize(const ExecCommand
*c
, FILE *f
) {
3770 r
= serialize_item(f
, "exec-command-path", c
->path
);
3774 r
= serialize_strv(f
, "exec-command-argv", c
->argv
);
3778 r
= serialize_item_format(f
, "exec-command-flags", "%d", (int) c
->flags
);
3782 fputc('\n', f
); /* End marker */
3787 static int exec_command_deserialize(ExecCommand
*c
, FILE *f
) {
3794 _cleanup_free_
char *l
= NULL
;
3797 r
= deserialize_read_line(f
, &l
);
3800 if (r
== 0) /* eof or end marker */
3803 if ((val
= startswith(l
, "exec-command-path="))) {
3804 r
= free_and_strdup(&c
->path
, val
);
3807 } else if ((val
= startswith(l
, "exec-command-argv="))) {
3808 r
= deserialize_strv(val
, &c
->argv
);
3811 } else if ((val
= startswith(l
, "exec-command-flags="))) {
3812 r
= safe_atoi(val
, &c
->flags
);
3816 log_warning("Failed to parse serialized line, ignoring: %s", l
);
3823 int exec_serialize_invocation(
3826 const ExecContext
*ctx
,
3827 const ExecCommand
*cmd
,
3828 const ExecParameters
*p
,
3829 const ExecRuntime
*rt
,
3830 const CGroupContext
*cg
) {
3837 r
= exec_context_serialize(ctx
, f
);
3839 return log_debug_errno(r
, "Failed to serialize context: %m");
3841 r
= exec_command_serialize(cmd
, f
);
3843 return log_debug_errno(r
, "Failed to serialize command: %m");
3845 r
= exec_parameters_serialize(p
, ctx
, f
, fds
);
3847 return log_debug_errno(r
, "Failed to serialize parameters: %m");
3849 r
= exec_runtime_serialize(rt
, f
, fds
);
3851 return log_debug_errno(r
, "Failed to serialize runtime: %m");
3853 r
= exec_cgroup_context_serialize(cg
, f
);
3855 return log_debug_errno(r
, "Failed to serialize cgroup context: %m");
3860 int exec_deserialize_invocation(
3867 CGroupContext
*cg
) {
3874 r
= exec_context_deserialize(ctx
, f
);
3876 return log_debug_errno(r
, "Failed to deserialize context: %m");
3878 r
= exec_command_deserialize(cmd
, f
);
3880 return log_debug_errno(r
, "Failed to deserialize command: %m");
3882 r
= exec_parameters_deserialize(p
, f
, fds
);
3884 return log_debug_errno(r
, "Failed to deserialize parameters: %m");
3886 r
= exec_runtime_deserialize(rt
, f
, fds
);
3888 return log_debug_errno(r
, "Failed to deserialize runtime: %m");
3890 r
= exec_cgroup_context_deserialize(cg
, f
);
3892 return log_debug_errno(r
, "Failed to deserialize cgroup context: %m");