summaryrefslogtreecommitdiff
path: root/src/nspawn
diff options
context:
space:
mode:
Diffstat (limited to 'src/nspawn')
-rw-r--r--src/nspawn/nspawn-cgroup.c1
-rw-r--r--src/nspawn/nspawn-mount.c17
-rw-r--r--src/nspawn/nspawn-patch-uid.c7
-rw-r--r--src/nspawn/nspawn-register.c10
-rw-r--r--src/nspawn/nspawn-register.h2
-rw-r--r--src/nspawn/nspawn-seccomp.c11
-rw-r--r--src/nspawn/nspawn-settings.c16
-rw-r--r--src/nspawn/nspawn-setuid.c1
-rw-r--r--src/nspawn/nspawn-stub-pid1.c8
-rw-r--r--src/nspawn/nspawn.c295
-rw-r--r--src/nspawn/test-patch-uid.c2
11 files changed, 221 insertions, 149 deletions
diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c
index 0462b46413..f5048d9473 100644
--- a/src/nspawn/nspawn-cgroup.c
+++ b/src/nspawn/nspawn-cgroup.c
@@ -3,6 +3,7 @@
#include <sys/mount.h>
#include "alloc-util.h"
+#include "cgroup-setup.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-util.h"
diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c
index 7fae2117a2..30b09e3333 100644
--- a/src/nspawn/nspawn-mount.c
+++ b/src/nspawn/nspawn-mount.c
@@ -636,7 +636,7 @@ int mount_all(const char *dest,
if (!tmpfs_tmp && (bool)(mount_table[k].mount_settings & MOUNT_APPLY_TMPFS_TMP))
continue;
- r = chase_symlinks(mount_table[k].where, dest, CHASE_NONEXISTENT|CHASE_PREFIX_ROOT, &where);
+ r = chase_symlinks(mount_table[k].where, dest, CHASE_NONEXISTENT|CHASE_PREFIX_ROOT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].where);
@@ -706,8 +706,9 @@ static int parse_mount_bind_options(const char *options, unsigned long *mount_fl
else if (streq(word, "norbind"))
flags &= ~MS_REC;
else {
- log_error("Invalid bind mount option: %s", word);
- return -EINVAL;
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "Invalid bind mount option: %s",
+ word);
}
}
@@ -736,7 +737,7 @@ static int mount_bind(const char *dest, CustomMount *m) {
if (stat(m->source, &source_st) < 0)
return log_error_errno(errno, "Failed to stat %s: %m", m->source);
- r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where);
+ r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
if (r > 0) { /* Path exists already? */
@@ -797,7 +798,7 @@ static int mount_tmpfs(
assert(dest);
assert(m);
- r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where);
+ r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
if (r == 0) { /* Doesn't exist yet? */
@@ -837,7 +838,7 @@ static int mount_overlay(const char *dest, CustomMount *m) {
assert(dest);
assert(m);
- r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where);
+ r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
if (r == 0) { /* Doesn't exist yet? */
@@ -880,7 +881,7 @@ static int mount_inaccessible(const char *dest, CustomMount *m) {
assert(dest);
assert(m);
- r = chase_symlinks_and_stat(m->destination, dest, CHASE_PREFIX_ROOT, &where, &st);
+ r = chase_symlinks_and_stat(m->destination, dest, CHASE_PREFIX_ROOT, &where, &st, NULL);
if (r < 0) {
log_full_errno(m->graceful ? LOG_DEBUG : LOG_ERR, r, "Failed to resolve %s/%s: %m", dest, m->destination);
return m->graceful ? 0 : r;
@@ -908,7 +909,7 @@ static int mount_arbitrary(const char *dest, CustomMount *m) {
assert(dest);
assert(m);
- r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where);
+ r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
if (r == 0) { /* Doesn't exist yet? */
diff --git a/src/nspawn/nspawn-patch-uid.c b/src/nspawn/nspawn-patch-uid.c
index 4885744cfc..fc591e2725 100644
--- a/src/nspawn/nspawn-patch-uid.c
+++ b/src/nspawn/nspawn-patch-uid.c
@@ -1,11 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <fcntl.h>
-#include <linux/magic.h>
-#if HAVE_ACL
-#include <sys/acl.h>
-#endif
-#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/vfs.h>
#include <unistd.h>
@@ -14,7 +9,7 @@
#include "dirent-util.h"
#include "fd-util.h"
#include "fs-util.h"
-#include "missing.h"
+#include "missing_magic.h"
#include "nspawn-def.h"
#include "nspawn-patch-uid.h"
#include "stat-util.h"
diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c
index 8e2c329665..9b7ca5e3dd 100644
--- a/src/nspawn/nspawn-register.c
+++ b/src/nspawn/nspawn-register.c
@@ -209,7 +209,7 @@ int register_machine(
return 0;
}
-int terminate_machine(
+int unregister_machine(
sd_bus *bus,
const char *machine_name) {
@@ -223,13 +223,13 @@ int terminate_machine(
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
- "TerminateMachine",
+ "UnregisterMachine",
&error,
NULL,
"s",
machine_name);
if (r < 0)
- log_debug("Failed to terminate machine: %s", bus_error_message(&error, r));
+ log_debug("Failed to unregister machine: %s", bus_error_message(&error, r));
return 0;
}
@@ -258,7 +258,7 @@ int allocate_scope(
if (r < 0)
return log_error_errno(r, "Could not watch job: %m");
- r = unit_name_mangle_with_suffix(machine_name, 0, ".scope", &scope);
+ r = unit_name_mangle_with_suffix(machine_name, "as machine name", 0, ".scope", &scope);
if (r < 0)
return log_error_errno(r, "Failed to mangle scope name: %m");
@@ -350,7 +350,7 @@ int terminate_scope(
_cleanup_free_ char *scope = NULL;
int r;
- r = unit_name_mangle_with_suffix(machine_name, 0, ".scope", &scope);
+ r = unit_name_mangle_with_suffix(machine_name, "to terminate", 0, ".scope", &scope);
if (r < 0)
return log_error_errno(r, "Failed to mangle scope name: %m");
diff --git a/src/nspawn/nspawn-register.h b/src/nspawn/nspawn-register.h
index 65a3ae85a7..07cca7fadc 100644
--- a/src/nspawn/nspawn-register.h
+++ b/src/nspawn/nspawn-register.h
@@ -8,7 +8,7 @@
#include "nspawn-mount.h"
int register_machine(sd_bus *bus, const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, sd_bus_message *properties_message, bool keep_unit, const char *service);
-int terminate_machine(sd_bus *bus, const char *machine_name);
+int unregister_machine(sd_bus *bus, const char *machine_name);
int allocate_scope(sd_bus *bus, const char *machine_name, pid_t pid, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, sd_bus_message *properties_message);
int terminate_scope(sd_bus *bus, const char *machine_name);
diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c
index 9222f2bc84..f94f131f22 100644
--- a/src/nspawn/nspawn-seccomp.c
+++ b/src/nspawn/nspawn-seccomp.c
@@ -123,6 +123,7 @@ static int seccomp_add_default_syscall_filter(
* @cpu-emulation
* @keyring (NB: keyring is not namespaced!)
* @obsolete
+ * @pkey
* @swap
*
* bpf (NB: bpffs is not namespaced!)
@@ -134,18 +135,14 @@ static int seccomp_add_default_syscall_filter(
* nfsservctl
* open_by_handle_at
* perf_event_open
- * pkey_alloc
- * pkey_free
- * pkey_mprotect
* quotactl
*/
};
- int r;
- size_t i;
char **p;
+ int r;
- for (i = 0; i < ELEMENTSOF(whitelist); i++) {
+ for (size_t i = 0; i < ELEMENTSOF(whitelist); i++) {
if (whitelist[i].capability != 0 && (cap_list_retain & (1ULL << whitelist[i].capability)) == 0)
continue;
@@ -155,7 +152,7 @@ static int seccomp_add_default_syscall_filter(
}
STRV_FOREACH(p, syscall_whitelist) {
- r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, false);
+ r = seccomp_add_syscall_filter_item(ctx, *p, SCMP_ACT_ALLOW, syscall_blacklist, true);
if (r < 0)
log_warning_errno(r, "Failed to add rule for system call %s on %s, ignoring: %m",
*p, seccomp_arch_to_string(arch));
diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c
index 3a99736813..5fb5b49bbc 100644
--- a/src/nspawn/nspawn-settings.c
+++ b/src/nspawn/nspawn-settings.c
@@ -275,13 +275,17 @@ int config_parse_capability(
if (r == 0)
break;
- r = capability_from_name(word);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse capability, ignoring: %s", word);
- continue;
- }
+ if (streq(word, "all"))
+ u = (uint64_t) -1;
+ else {
+ r = capability_from_name(word);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse capability, ignoring: %s", word);
+ continue;
+ }
- u |= UINT64_C(1) << r;
+ u |= UINT64_C(1) << r;
+ }
}
if (u == 0)
diff --git a/src/nspawn/nspawn-setuid.c b/src/nspawn/nspawn-setuid.c
index 3c302d6487..cb2b2272b6 100644
--- a/src/nspawn/nspawn-setuid.c
+++ b/src/nspawn/nspawn-setuid.c
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <fcntl.h>
-#include <grp.h>
#include <sys/types.h>
#include <unistd.h>
diff --git a/src/nspawn/nspawn-stub-pid1.c b/src/nspawn/nspawn-stub-pid1.c
index ebf4f0f523..d86dd23185 100644
--- a/src/nspawn/nspawn-stub-pid1.c
+++ b/src/nspawn/nspawn-stub-pid1.c
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <sys/ioctl.h>
#include <sys/reboot.h>
#include <sys/wait.h>
#include <sys/prctl.h>
@@ -9,7 +10,6 @@
#include "exit-status.h"
#include "fd-util.h"
#include "log.h"
-#include "missing.h"
#include "nspawn-stub-pid1.h"
#include "process-util.h"
#include "signal-util.h"
@@ -53,6 +53,12 @@ int stub_pid1(sd_id128_t uuid) {
assert_se(sigfillset(&fullmask) >= 0);
assert_se(sigprocmask(SIG_BLOCK, &fullmask, &oldmask) >= 0);
+ /* Surrender the terminal this stub may control so that child processes can have a controlling terminal
+ * without resorting to setsid hacks. */
+ r = ioctl(STDIN_FILENO, TIOCNOTTY);
+ if (r < 0 && errno != ENOTTY)
+ return log_error_errno(errno, "Failed to surrender controlling terminal: %m");
+
pid = fork();
if (pid < 0)
return log_error_errno(errno, "Failed to fork child pid: %m");
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 2aec8041f0..873a76596f 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -1,22 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#if HAVE_BLKID
-#include <blkid.h>
#endif
#include <errno.h>
#include <getopt.h>
-#include <grp.h>
#include <linux/fs.h>
#include <linux/loop.h>
-#include <pwd.h>
-#include <sched.h>
#if HAVE_SELINUX
#include <selinux/selinux.h>
#endif
-#include <signal.h>
-#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <sys/file.h>
#include <sys/personality.h>
#include <sys/prctl.h>
@@ -58,7 +51,7 @@
#include "machine-image.h"
#include "macro.h"
#include "main-func.h"
-#include "missing.h"
+#include "missing_sched.h"
#include "mkdir.h"
#include "mount-util.h"
#include "mountpoint-util.h"
@@ -103,6 +96,7 @@
#include "terminal-util.h"
#include "tmpfile-util.h"
#include "umask-util.h"
+#include "unit-name.h"
#include "user-util.h"
#include "util.h"
@@ -261,6 +255,30 @@ STATIC_DESTRUCTOR_REGISTER(arg_seccomp, seccomp_releasep);
STATIC_DESTRUCTOR_REGISTER(arg_cpu_set, cpu_set_reset);
STATIC_DESTRUCTOR_REGISTER(arg_sysctl, strv_freep);
+static int handle_arg_console(const char *arg) {
+ if (streq(arg, "help")) {
+ puts("interactive\n"
+ "read-only\n"
+ "passive\n"
+ "pipe");
+ return 0;
+ }
+
+ if (streq(arg, "interactive"))
+ arg_console_mode = CONSOLE_INTERACTIVE;
+ else if (streq(arg, "read-only"))
+ arg_console_mode = CONSOLE_READ_ONLY;
+ else if (streq(arg, "passive"))
+ arg_console_mode = CONSOLE_PASSIVE;
+ else if (streq(arg, "pipe"))
+ arg_console_mode = CONSOLE_PIPE;
+ else
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown console mode: %s", optarg);
+
+ arg_settings_mask |= SETTING_CONSOLE_MODE;
+ return 1;
+}
+
static int help(void) {
_cleanup_free_ char *link = NULL;
int r;
@@ -272,7 +290,7 @@ static int help(void) {
return log_oom();
printf("%1$s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
- "Spawn a command or OS in a light-weight container.\n\n"
+ "%5$sSpawn a command or OS in a light-weight container.%6$s\n\n"
" -h --help Show this help\n"
" --version Print version string\n"
" -q --quiet Do not show status information\n"
@@ -387,7 +405,9 @@ static int help(void) {
"\nSee the %2$s for details.\n"
, program_invocation_short_name
, link
- , ansi_underline(), ansi_normal());
+ , ansi_underline(), ansi_normal()
+ , ansi_highlight(), ansi_normal()
+ );
return 0;
}
@@ -412,15 +432,22 @@ static int custom_mount_check_all(void) {
}
static int detect_unified_cgroup_hierarchy_from_environment(void) {
- const char *e;
+ const char *e, *var = "SYSTEMD_NSPAWN_UNIFIED_HIERARCHY";
int r;
/* Allow the user to control whether the unified hierarchy is used */
- e = getenv("UNIFIED_CGROUP_HIERARCHY");
- if (e) {
+
+ e = getenv(var);
+ if (!e) {
+ /* $UNIFIED_CGROUP_HIERARCHY has been renamed to $SYSTEMD_NSPAWN_UNIFIED_HIERARCHY. */
+ var = "UNIFIED_CGROUP_HIERARCHY";
+ e = getenv(var);
+ }
+
+ if (!isempty(e)) {
r = parse_boolean(e);
if (r < 0)
- return log_error_errno(r, "Failed to parse $UNIFIED_CGROUP_HIERARCHY.");
+ return log_error_errno(r, "Failed to parse $%s: %m", var);
if (r > 0)
arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_ALL;
else
@@ -433,8 +460,8 @@ static int detect_unified_cgroup_hierarchy_from_environment(void) {
static int detect_unified_cgroup_hierarchy_from_image(const char *directory) {
int r;
- /* Let's inherit the mode to use from the host system, but let's take into consideration what systemd in the
- * image actually supports. */
+ /* Let's inherit the mode to use from the host system, but let's take into consideration what systemd
+ * in the image actually supports. */
r = cg_all_unified();
if (r < 0)
return log_error_errno(r, "Failed to determine whether we are in all unified mode.");
@@ -467,58 +494,106 @@ static int detect_unified_cgroup_hierarchy_from_image(const char *directory) {
return 0;
}
-static void parse_share_ns_env(const char *name, unsigned long ns_flag) {
+static int parse_capability_spec(const char *spec, uint64_t *ret_mask) {
+ uint64_t mask = 0;
+ int r;
+
+ for (;;) {
+ _cleanup_free_ char *t = NULL;
+
+ r = extract_first_word(&spec, &t, ",", 0);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse capability %s.", t);
+ if (r == 0)
+ break;
+
+ if (streq(t, "help")) {
+ for (int i = 0; i < capability_list_length(); i++) {
+ const char *name;
+
+ name = capability_to_name(i);
+ if (name)
+ puts(name);
+ }
+
+ return 0; /* quit */
+ }
+
+ if (streq(t, "all"))
+ mask = (uint64_t) -1;
+ else {
+ r = capability_from_name(t);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse capability %s.", t);
+
+ mask |= 1ULL << r;
+ }
+ }
+
+ *ret_mask = mask;
+ return 1; /* continue */
+}
+
+static int parse_share_ns_env(const char *name, unsigned long ns_flag) {
int r;
r = getenv_bool(name);
if (r == -ENXIO)
- return;
+ return 0;
if (r < 0)
- log_warning_errno(r, "Failed to parse %s from environment, defaulting to false.", name);
+ return log_error_errno(r, "Failed to parse $%s: %m", name);
arg_clone_ns_flags = (arg_clone_ns_flags & ~ns_flag) | (r > 0 ? 0 : ns_flag);
arg_settings_mask |= SETTING_CLONE_NS_FLAGS;
+ return 0;
}
-static void parse_mount_settings_env(void) {
+static int parse_mount_settings_env(void) {
const char *e;
int r;
r = getenv_bool("SYSTEMD_NSPAWN_TMPFS_TMP");
+ if (r < 0 && r != -ENXIO)
+ return log_error_errno(r, "Failed to parse $SYSTEMD_NSPAWN_TMPFS_TMP: %m");
if (r >= 0)
SET_FLAG(arg_mount_settings, MOUNT_APPLY_TMPFS_TMP, r > 0);
- else if (r != -ENXIO)
- log_warning_errno(r, "Failed to parse $SYSTEMD_NSPAWN_TMPFS_TMP, ignoring: %m");
e = getenv("SYSTEMD_NSPAWN_API_VFS_WRITABLE");
- if (!e)
- return;
-
- if (streq(e, "network")) {
+ if (streq_ptr(e, "network"))
arg_mount_settings |= MOUNT_APPLY_APIVFS_RO|MOUNT_APPLY_APIVFS_NETNS;
- return;
- }
- r = parse_boolean(e);
- if (r < 0) {
- log_warning_errno(r, "Failed to parse SYSTEMD_NSPAWN_API_VFS_WRITABLE from environment, ignoring.");
- return;
+ else if (e) {
+ r = parse_boolean(e);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse $SYSTEMD_NSPAWN_API_VFS_WRITABLE: %m");
+
+ SET_FLAG(arg_mount_settings, MOUNT_APPLY_APIVFS_RO, r == 0);
+ SET_FLAG(arg_mount_settings, MOUNT_APPLY_APIVFS_NETNS, false);
}
- SET_FLAG(arg_mount_settings, MOUNT_APPLY_APIVFS_RO, r == 0);
- SET_FLAG(arg_mount_settings, MOUNT_APPLY_APIVFS_NETNS, false);
+ return 0;
}
-static void parse_environment(void) {
+static int parse_environment(void) {
const char *e;
int r;
- parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_IPC", CLONE_NEWIPC);
- parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_PID", CLONE_NEWPID);
- parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_UTS", CLONE_NEWUTS);
- parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_SYSTEM", CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS);
+ r = parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_IPC", CLONE_NEWIPC);
+ if (r < 0)
+ return r;
+ r = parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_PID", CLONE_NEWPID);
+ if (r < 0)
+ return r;
+ r = parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_NS_UTS", CLONE_NEWUTS);
+ if (r < 0)
+ return r;
+ r = parse_share_ns_env("SYSTEMD_NSPAWN_SHARE_SYSTEM", CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS);
+ if (r < 0)
+ return r;
- parse_mount_settings_env();
+ r = parse_mount_settings_env();
+ if (r < 0)
+ return r;
/* SYSTEMD_NSPAWN_USE_CGNS=0 can be used to disable CLONE_NEWCGROUP use,
* even if it is supported. If not supported, it has no effect. */
@@ -528,7 +603,7 @@ static void parse_environment(void) {
r = getenv_bool("SYSTEMD_NSPAWN_USE_CGNS");
if (r < 0) {
if (r != -ENXIO)
- log_warning_errno(r, "Failed to parse $SYSTEMD_NSPAWN_USE_CGNS, ignoring: %m");
+ return log_error_errno(r, "Failed to parse $SYSTEMD_NSPAWN_USE_CGNS: %m");
arg_use_cgns = true;
} else {
@@ -541,7 +616,7 @@ static void parse_environment(void) {
if (e)
arg_container_service_name = e;
- detect_unified_cgroup_hierarchy_from_environment();
+ return detect_unified_cgroup_hierarchy_from_environment();
}
static int parse_argv(int argc, char *argv[]) {
@@ -662,7 +737,6 @@ static int parse_argv(int argc, char *argv[]) {
};
int c, r;
- const char *p;
uint64_t plus = 0, minus = 0;
bool mask_all_settings = false, mask_no_settings = false;
@@ -847,13 +921,17 @@ static int parse_argv(int argc, char *argv[]) {
arg_settings_mask |= SETTING_MACHINE_ID;
break;
- case 'S':
- r = free_and_strdup(&arg_slice, optarg);
+ case 'S': {
+ _cleanup_free_ char *mangled = NULL;
+
+ r = unit_name_mangle_with_suffix(optarg, NULL, UNIT_NAME_MANGLE_WARN, ".slice", &mangled);
if (r < 0)
return log_oom();
+ free_and_replace(arg_slice, mangled);
arg_settings_mask |= SETTING_SLICE;
break;
+ }
case 'M':
if (isempty(optarg))
@@ -900,37 +978,18 @@ static int parse_argv(int argc, char *argv[]) {
case ARG_CAPABILITY:
case ARG_DROP_CAPABILITY: {
- p = optarg;
- for (;;) {
- _cleanup_free_ char *t = NULL;
-
- r = extract_first_word(&p, &t, ",", 0);
- if (r < 0)
- return log_error_errno(r, "Failed to parse capability %s.", t);
- if (r == 0)
- break;
-
- if (streq(t, "all")) {
- if (c == ARG_CAPABILITY)
- plus = (uint64_t) -1;
- else
- minus = (uint64_t) -1;
- } else {
- r = capability_from_name(t);
- if (r < 0)
- return log_error_errno(r, "Failed to parse capability %s.", t);
-
- if (c == ARG_CAPABILITY)
- plus |= 1ULL << r;
- else
- minus |= 1ULL << r;
- }
- }
+ uint64_t m;
+ r = parse_capability_spec(optarg, &m);
+ if (r <= 0)
+ return r;
+ if (c == ARG_CAPABILITY)
+ plus |= m;
+ else
+ minus |= m;
arg_settings_mask |= SETTING_CAPABILITY;
break;
}
-
case ARG_NO_NEW_PRIVILEGES:
r = parse_boolean(optarg);
if (r < 0)
@@ -1369,29 +1428,16 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_CONSOLE:
- if (streq(optarg, "interactive"))
- arg_console_mode = CONSOLE_INTERACTIVE;
- else if (streq(optarg, "read-only"))
- arg_console_mode = CONSOLE_READ_ONLY;
- else if (streq(optarg, "passive"))
- arg_console_mode = CONSOLE_PASSIVE;
- else if (streq(optarg, "pipe"))
- arg_console_mode = CONSOLE_PIPE;
- else if (streq(optarg, "help"))
- puts("interactive\n"
- "read-only\n"
- "passive\n"
- "pipe");
- else
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown console mode: %s", optarg);
-
- arg_settings_mask |= SETTING_CONSOLE_MODE;
+ r = handle_arg_console(optarg);
+ if (r <= 0)
+ return r;
break;
case 'P':
case ARG_PIPE:
- arg_console_mode = CONSOLE_PIPE;
- arg_settings_mask |= SETTING_CONSOLE_MODE;
+ r = handle_arg_console("pipe");
+ if (r <= 0)
+ return r;
break;
case ARG_NO_PAGER:
@@ -1424,7 +1470,9 @@ static int parse_argv(int argc, char *argv[]) {
arg_caps_retain = (arg_caps_retain | plus | (arg_private_network ? UINT64_C(1) << CAP_NET_ADMIN : 0)) & ~minus;
/* Make sure to parse environment before we reset the settings mask below */
- parse_environment();
+ r = parse_environment();
+ if (r < 0)
+ return r;
/* Load all settings from .nspawn files */
if (mask_no_settings)
@@ -1440,6 +1488,25 @@ static int parse_argv(int argc, char *argv[]) {
static int verify_arguments(void) {
int r;
+ if (arg_start_mode == START_PID2 && arg_unified_cgroup_hierarchy == CGROUP_UNIFIED_UNKNOWN) {
+ /* If we are running the stub init in the container, we don't need to look at what the init
+ * in the container supports, because we are not using it. Let's immediately pick the right
+ * setting based on the host system configuration.
+ *
+ * We only do this, if the user didn't use an environment variable to override the detection.
+ */
+
+ r = cg_all_unified();
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine whether we are in all unified mode.");
+ if (r > 0)
+ arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_ALL;
+ else if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) > 0)
+ arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_SYSTEMD;
+ else
+ arg_unified_cgroup_hierarchy = CGROUP_UNIFIED_NONE;
+ }
+
if (arg_userns_mode != USER_NAMESPACE_NO)
arg_mount_settings |= MOUNT_USE_USERNS;
@@ -1616,7 +1683,7 @@ static int setup_timezone(const char *dest) {
if (m == TIMEZONE_OFF)
return 0;
- r = chase_symlinks("/etc", dest, CHASE_PREFIX_ROOT, &etc);
+ r = chase_symlinks("/etc", dest, CHASE_PREFIX_ROOT, &etc, NULL);
if (r < 0) {
log_warning_errno(r, "Failed to resolve /etc path in container, ignoring: %m");
return 0;
@@ -1647,7 +1714,7 @@ static int setup_timezone(const char *dest) {
return 0; /* Already pointing to the right place? Then do nothing .. */
check = strjoina(dest, "/usr/share/zoneinfo/", z);
- r = chase_symlinks(check, dest, 0, NULL);
+ r = chase_symlinks(check, dest, 0, NULL, NULL);
if (r < 0)
log_debug_errno(r, "Timezone %s does not exist (or is not accessible) in container, not creating symlink: %m", z);
else {
@@ -1674,7 +1741,7 @@ static int setup_timezone(const char *dest) {
_cleanup_free_ char *resolved = NULL;
int found;
- found = chase_symlinks(where, dest, CHASE_NONEXISTENT, &resolved);
+ found = chase_symlinks(where, dest, CHASE_NONEXISTENT, &resolved, NULL);
if (found < 0) {
log_warning_errno(found, "Failed to resolve /etc/localtime path in container, ignoring: %m");
return 0;
@@ -1780,7 +1847,7 @@ static int setup_resolv_conf(const char *dest) {
if (m == RESOLV_CONF_OFF)
return 0;
- r = chase_symlinks("/etc", dest, CHASE_PREFIX_ROOT, &etc);
+ r = chase_symlinks("/etc", dest, CHASE_PREFIX_ROOT, &etc, NULL);
if (r < 0) {
log_warning_errno(r, "Failed to resolve /etc path in container, ignoring: %m");
return 0;
@@ -1804,7 +1871,7 @@ static int setup_resolv_conf(const char *dest) {
_cleanup_free_ char *resolved = NULL;
int found;
- found = chase_symlinks(where, dest, CHASE_NONEXISTENT, &resolved);
+ found = chase_symlinks(where, dest, CHASE_NONEXISTENT, &resolved, NULL);
if (found < 0) {
log_warning_errno(found, "Failed to resolve /etc/resolv.conf path in container, ignoring: %m");
return 0;
@@ -2333,7 +2400,8 @@ static int drop_capabilities(uid_t uid) {
/* If we're not using OCI, proceed with mangled capabilities (so we don't error out)
* in order to maintain the same behavior as systemd < 242. */
if (capability_quintet_mangle(&q))
- log_warning("Some capabilities will not be set because they are not in the current bounding set.");
+ log_full(arg_quiet ? LOG_DEBUG : LOG_WARNING,
+ "Some capabilities will not be set because they are not in the current bounding set.");
}
@@ -2681,12 +2749,11 @@ static int chase_symlinks_and_update(char **p, unsigned flags) {
if (!*p)
return 0;
- r = chase_symlinks(*p, NULL, flags, &chased);
+ r = chase_symlinks(*p, NULL, flags, &chased, NULL);
if (r < 0)
return log_error_errno(r, "Failed to resolve path %s: %m", *p);
- free_and_replace(*p, chased);
- return r; /* r might be an fd here in case we ever use CHASE_OPEN in flags */
+ return free_and_replace(*p, chased);
}
static int determine_uid_shift(const char *directory) {
@@ -3725,6 +3792,7 @@ static int merge_settings(Settings *settings, const char *path) {
if ((arg_settings_mask & SETTING_CAPABILITY) == 0) {
uint64_t plus, minus;
+ uint64_t network_minus = 0;
/* Note that we copy both the simple plus/minus caps here, and the full quintet from the
* Settings structure */
@@ -3736,14 +3804,16 @@ static int merge_settings(Settings *settings, const char *path) {
if (settings_private_network(settings))
plus |= UINT64_C(1) << CAP_NET_ADMIN;
else
- minus |= UINT64_C(1) << CAP_NET_ADMIN;
+ network_minus |= UINT64_C(1) << CAP_NET_ADMIN;
}
if (!arg_settings_trusted && plus != 0) {
if (settings->capability != 0)
log_warning("Ignoring Capability= setting, file %s is not trusted.", path);
- } else
+ } else {
+ arg_caps_retain &= ~network_minus;
arg_caps_retain |= plus;
+ }
arg_caps_retain &= ~minus;
@@ -4567,12 +4637,8 @@ static int run_container(
}
/* Kill if it is not dead yet anyway */
- if (bus) {
- if (arg_register)
- terminate_machine(bus, arg_machine);
- else if (!arg_keep_unit)
- terminate_scope(bus, arg_machine);
- }
+ if (!arg_register && !arg_keep_unit && bus)
+ terminate_scope(bus, arg_machine);
/* Normally redundant, but better safe than sorry */
(void) kill(*pid, SIGKILL);
@@ -4580,6 +4646,10 @@ static int run_container(
r = wait_for_container(*pid, &container_status);
*pid = 0;
+ /* Tell machined that we are gone. */
+ if (bus)
+ (void) unregister_machine(bus, arg_machine);
+
if (r < 0)
/* We failed to wait for the container, or the container exited abnormally. */
return r;
@@ -4720,7 +4790,7 @@ static int run(int argc, char *argv[]) {
if (r < 0)
goto finish;
- r = cg_unified_flush();
+ r = cg_unified();
if (r < 0) {
log_error_errno(r, "Failed to determine whether the unified cgroups hierarchy is used: %m");
goto finish;
@@ -4730,9 +4800,8 @@ static int run(int argc, char *argv[]) {
if (r < 0)
goto finish;
- r = detect_unified_cgroup_hierarchy_from_environment();
- if (r < 0)
- goto finish;
+ /* Reapply environment settings. */
+ (void) detect_unified_cgroup_hierarchy_from_environment();
/* Ignore SIGPIPE here, because we use splice() on the ptyfwd stuff and that will generate SIGPIPE if
* the result is closed. Note that the container payload child will reset signal mask+handler anyway,
diff --git a/src/nspawn/test-patch-uid.c b/src/nspawn/test-patch-uid.c
index b50f0990d8..a6829629b4 100644
--- a/src/nspawn/test-patch-uid.c
+++ b/src/nspawn/test-patch-uid.c
@@ -5,8 +5,8 @@
#include "log.h"
#include "nspawn-patch-uid.h"
#include "user-util.h"
+#include "string-util.h"
#include "tests.h"
-#include "util.h"
int main(int argc, char *argv[]) {
uid_t shift, range;