1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2015 Lennart Poettering
8 #include "alloc-util.h"
10 #include "conf-parser.h"
11 #include "cpu-set-util.h"
12 #include "hostname-util.h"
13 #include "nspawn-network.h"
14 #include "nspawn-settings.h"
15 #include "parse-util.h"
16 #include "process-util.h"
17 #include "rlimit-util.h"
18 #include "socket-util.h"
19 #include "string-util.h"
21 #include "user-util.h"
24 int settings_load(FILE *f
, const char *path
, Settings
**ret
) {
25 _cleanup_(settings_freep
) Settings
*s
= NULL
;
31 s
= new0(Settings
, 1);
35 s
->start_mode
= _START_MODE_INVALID
;
36 s
->personality
= PERSONALITY_INVALID
;
37 s
->userns_mode
= _USER_NAMESPACE_MODE_INVALID
;
38 s
->uid_shift
= UID_INVALID
;
39 s
->uid_range
= UID_INVALID
;
40 s
->no_new_privileges
= -1;
43 s
->volatile_mode
= _VOLATILE_MODE_INVALID
;
46 s
->private_network
= -1;
49 r
= config_parse(NULL
, path
, f
,
53 config_item_perf_lookup
, nspawn_gperf_lookup
,
59 /* Make sure that if userns_mode is set, userns_chown is set to something appropriate, and vice versa. Either
60 * both fields shall be initialized or neither. */
61 if (s
->userns_mode
== USER_NAMESPACE_PICK
)
62 s
->userns_chown
= true;
63 else if (s
->userns_mode
!= _USER_NAMESPACE_MODE_INVALID
&& s
->userns_chown
< 0)
64 s
->userns_chown
= false;
66 if (s
->userns_chown
>= 0 && s
->userns_mode
== _USER_NAMESPACE_MODE_INVALID
)
67 s
->userns_mode
= USER_NAMESPACE_NO
;
74 Settings
* settings_free(Settings
*s
) {
79 strv_free(s
->parameters
);
80 strv_free(s
->environment
);
82 free(s
->pivot_root_new
);
83 free(s
->pivot_root_old
);
84 free(s
->working_directory
);
85 strv_free(s
->syscall_whitelist
);
86 strv_free(s
->syscall_blacklist
);
87 rlimit_free_all(s
->rlimit
);
89 s
->cpuset
= cpu_set_mfree(s
->cpuset
);
91 strv_free(s
->network_interfaces
);
92 strv_free(s
->network_macvlan
);
93 strv_free(s
->network_ipvlan
);
94 strv_free(s
->network_veth_extra
);
95 free(s
->network_bridge
);
96 free(s
->network_zone
);
97 expose_port_free_all(s
->expose_ports
);
99 custom_mount_free_all(s
->custom_mounts
, s
->n_custom_mounts
);
103 bool settings_private_network(Settings
*s
) {
107 s
->private_network
> 0 ||
108 s
->network_veth
> 0 ||
111 s
->network_interfaces
||
112 s
->network_macvlan
||
114 s
->network_veth_extra
;
117 bool settings_network_veth(Settings
*s
) {
121 s
->network_veth
> 0 ||
126 DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode
, volatile_mode
, VolatileMode
, "Failed to parse volatile mode");
128 int config_parse_expose_port(
130 const char *filename
,
133 unsigned section_line
,
147 r
= expose_port_parse(&s
->expose_ports
, rvalue
);
149 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Duplicate port specification, ignoring: %s", rvalue
);
153 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse host port %s: %m", rvalue
);
160 int config_parse_capability(
162 const char *filename
,
165 unsigned section_line
,
172 uint64_t u
= 0, *result
= data
;
180 _cleanup_free_
char *word
= NULL
;
183 r
= extract_first_word(&rvalue
, &word
, NULL
, 0);
185 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to extract capability string, ignoring: %s", rvalue
);
191 cap
= capability_from_name(word
);
193 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Failed to parse capability, ignoring: %s", word
);
197 u
|= UINT64_C(1) << cap
;
207 int config_parse_id128(
209 const char *filename
,
212 unsigned section_line
,
219 sd_id128_t t
, *result
= data
;
226 r
= sd_id128_from_string(rvalue
, &t
);
228 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse 128bit ID/UUID, ignoring: %s", rvalue
);
236 int config_parse_pivot_root(
238 const char *filename
,
241 unsigned section_line
,
248 Settings
*settings
= data
;
255 r
= pivot_root_parse(&settings
->pivot_root_new
, &settings
->pivot_root_old
, rvalue
);
257 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid pivot root mount specification %s: %m", rvalue
);
264 int config_parse_bind(
266 const char *filename
,
269 unsigned section_line
,
276 Settings
*settings
= data
;
283 r
= bind_mount_parse(&settings
->custom_mounts
, &settings
->n_custom_mounts
, rvalue
, ltype
);
285 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid bind mount specification %s: %m", rvalue
);
292 int config_parse_tmpfs(
294 const char *filename
,
297 unsigned section_line
,
304 Settings
*settings
= data
;
311 r
= tmpfs_mount_parse(&settings
->custom_mounts
, &settings
->n_custom_mounts
, rvalue
);
313 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid temporary file system specification %s: %m", rvalue
);
320 int config_parse_overlay(
322 const char *filename
,
325 unsigned section_line
,
332 Settings
*settings
= data
;
339 r
= overlay_mount_parse(&settings
->custom_mounts
, &settings
->n_custom_mounts
, rvalue
, ltype
);
341 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid overlay file system specification %s, ignoring: %m", rvalue
);
346 int config_parse_veth_extra(
348 const char *filename
,
351 unsigned section_line
,
358 Settings
*settings
= data
;
365 r
= veth_extra_parse(&settings
->network_veth_extra
, rvalue
);
367 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Invalid extra virtual Ethernet link specification %s: %m", rvalue
);
374 int config_parse_network_zone(
376 const char *filename
,
379 unsigned section_line
,
386 Settings
*settings
= data
;
387 _cleanup_free_
char *j
= NULL
;
393 j
= strappend("vz-", rvalue
);
394 if (!ifname_valid(j
)) {
395 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid network zone name %s, ignoring: %m", rvalue
);
399 free_and_replace(settings
->network_zone
, j
);
404 int config_parse_boot(
406 const char *filename
,
409 unsigned section_line
,
416 Settings
*settings
= data
;
423 r
= parse_boolean(rvalue
);
425 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse Boot= parameter %s, ignoring: %m", rvalue
);
430 if (settings
->start_mode
== START_PID2
)
433 settings
->start_mode
= START_BOOT
;
435 if (settings
->start_mode
== START_BOOT
)
438 if (settings
->start_mode
< 0)
439 settings
->start_mode
= START_PID1
;
445 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
449 int config_parse_pid2(
451 const char *filename
,
454 unsigned section_line
,
461 Settings
*settings
= data
;
468 r
= parse_boolean(rvalue
);
470 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse ProcessTwo= parameter %s, ignoring: %m", rvalue
);
475 if (settings
->start_mode
== START_BOOT
)
478 settings
->start_mode
= START_PID2
;
480 if (settings
->start_mode
== START_PID2
)
483 if (settings
->start_mode
< 0)
484 settings
->start_mode
= START_PID1
;
490 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
494 int config_parse_private_users(
496 const char *filename
,
499 unsigned section_line
,
506 Settings
*settings
= data
;
513 r
= parse_boolean(rvalue
);
515 /* no: User namespacing off */
516 settings
->userns_mode
= USER_NAMESPACE_NO
;
517 settings
->uid_shift
= UID_INVALID
;
518 settings
->uid_range
= UINT32_C(0x10000);
520 /* yes: User namespacing on, UID range is read from root dir */
521 settings
->userns_mode
= USER_NAMESPACE_FIXED
;
522 settings
->uid_shift
= UID_INVALID
;
523 settings
->uid_range
= UINT32_C(0x10000);
524 } else if (streq(rvalue
, "pick")) {
525 /* pick: User namespacing on, UID range is picked randomly */
526 settings
->userns_mode
= USER_NAMESPACE_PICK
;
527 settings
->uid_shift
= UID_INVALID
;
528 settings
->uid_range
= UINT32_C(0x10000);
530 const char *range
, *shift
;
533 /* anything else: User namespacing on, UID range is explicitly configured */
535 range
= strchr(rvalue
, ':');
537 shift
= strndupa(rvalue
, range
- rvalue
);
540 r
= safe_atou32(range
, &rn
);
541 if (r
< 0 || rn
<= 0) {
542 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "UID/GID range invalid, ignoring: %s", range
);
547 rn
= UINT32_C(0x10000);
550 r
= parse_uid(shift
, &sh
);
552 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "UID/GID shift invalid, ignoring: %s", range
);
556 settings
->userns_mode
= USER_NAMESPACE_FIXED
;
557 settings
->uid_shift
= sh
;
558 settings
->uid_range
= rn
;
564 int config_parse_syscall_filter(
566 const char *filename
,
569 unsigned section_line
,
576 Settings
*settings
= data
;
585 negative
= rvalue
[0] == '~';
586 items
= negative
? rvalue
+ 1 : rvalue
;
589 _cleanup_free_
char *word
= NULL
;
591 r
= extract_first_word(&items
, &word
, NULL
, 0);
597 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse SystemCallFilter= parameter %s, ignoring: %m", rvalue
);
602 r
= strv_extend(&settings
->syscall_blacklist
, word
);
604 r
= strv_extend(&settings
->syscall_whitelist
, word
);
612 int config_parse_hostname(
614 const char *filename
,
617 unsigned section_line
,
629 if (!hostname_is_valid(rvalue
, false)) {
630 log_syntax(unit
, LOG_ERR
, filename
, line
, 0, "Invalid hostname, ignoring: %s", rvalue
);
634 if (free_and_strdup(s
, empty_to_null(rvalue
)) < 0)
640 int config_parse_oom_score_adjust(
642 const char *filename
,
645 unsigned section_line
,
652 Settings
*settings
= data
;
658 if (isempty(rvalue
)) {
659 settings
->oom_score_adjust_set
= false;
663 r
= parse_oom_score_adjust(rvalue
, &oa
);
665 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "OOM score adjust value out of range, ignoring: %s", rvalue
);
669 log_syntax(unit
, LOG_ERR
, filename
, line
, r
, "Failed to parse the OOM score adjust value, ignoring: %s", rvalue
);
673 settings
->oom_score_adjust
= oa
;
674 settings
->oom_score_adjust_set
= true;
679 int config_parse_cpu_affinity(
681 const char *filename
,
684 unsigned section_line
,
691 _cleanup_cpu_free_ cpu_set_t
*cpuset
= NULL
;
692 Settings
*settings
= data
;
698 ncpus
= parse_cpu_set_and_warn(rvalue
, &cpuset
, unit
, filename
, line
, lvalue
);
703 /* An empty assignment resets the CPU list */
704 settings
->cpuset
= cpu_set_mfree(settings
->cpuset
);
705 settings
->cpuset_ncpus
= 0;
709 if (!settings
->cpuset
) {
710 settings
->cpuset
= TAKE_PTR(cpuset
);
711 settings
->cpuset_ncpus
= (unsigned) ncpus
;
715 if (settings
->cpuset_ncpus
< (unsigned) ncpus
) {
716 CPU_OR_S(CPU_ALLOC_SIZE(settings
->cpuset_ncpus
), cpuset
, settings
->cpuset
, cpuset
);
717 CPU_FREE(settings
->cpuset
);
718 settings
->cpuset
= TAKE_PTR(cpuset
);
719 settings
->cpuset_ncpus
= (unsigned) ncpus
;
723 CPU_OR_S(CPU_ALLOC_SIZE((unsigned) ncpus
), settings
->cpuset
, settings
->cpuset
, cpuset
);