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