summaryrefslogtreecommitdiff
path: root/src/nspawn/nspawn.c
diff options
context:
space:
mode:
authorChristian Brauner <brauner@kernel.org>2022-12-05 18:34:00 +0100
committerChristian Brauner (Microsoft) <brauner@kernel.org>2022-12-05 18:35:02 +0100
commite79581ddfefd5d565bb3b497f1e6adae688c8810 (patch)
tree294bd69bad1256e9446702956861dfe209651656 /src/nspawn/nspawn.c
parentb71a0192c040f585397cfc6fc2ca025bf839733d (diff)
downloadsystemd-e79581ddfefd5d565bb3b497f1e6adae688c8810.tar.gz
nspawn: split mount tunnel setup
Before we supported pivot_root() nspawn used to make the rootfs shared before setting up the mount tunnel. So it was safe for it to just turn it into a dependent mount during setup. However, we cannot do this anymore because of the requirements pivot_root() has. After the pivot_root() we will make the rootfs shared recursively. If we turned the mount tunnel into dependent mount before mount_switch_root() this will have the consequence that it becomes a shared mount within the same peer group as the rootfs. So no mounts will propagate into the container from the host anymore. To fix this we split setting up the mount tunnel and making it active into two steps. Setting up the mount tunnel is performed before mount_switch_root() and activating it afterwards. Note that this works because turning a shared mount into a shared mount is a nop. IOW, no new peer group will be allocated. Signed-off-by: Christian Brauner (Microsoft) <brauner@kernel.org>
Diffstat (limited to 'src/nspawn/nspawn.c')
-rw-r--r--src/nspawn/nspawn.c31
1 files changed, 24 insertions, 7 deletions
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 392336dfa5..0d025804fa 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -114,6 +114,7 @@
/* The notify socket inside the container it can use to talk to nspawn using the sd_notify(3) protocol */
#define NSPAWN_NOTIFY_SOCKET_PATH "/run/host/notify"
+#define NSPAWN_MOUNT_TUNNEL "/run/host/incoming"
#define EXIT_FORCE_RESTART 133
@@ -2776,7 +2777,7 @@ static int reset_audit_loginuid(void) {
return 0;
}
-static int setup_propagate(const char *root) {
+static int mount_tunnel_dig(const char *root) {
const char *p, *q;
int r;
@@ -2789,11 +2790,11 @@ static int setup_propagate(const char *root) {
if (r < 0)
return log_error_errno(r, "Failed to create /run/host: %m");
- r = userns_mkdir(root, "/run/host/incoming", 0600, 0, 0);
+ r = userns_mkdir(root, NSPAWN_MOUNT_TUNNEL, 0600, 0, 0);
if (r < 0)
- return log_error_errno(r, "Failed to create /run/host/incoming: %m");
+ return log_error_errno(r, "Failed to create "NSPAWN_MOUNT_TUNNEL": %m");
- q = prefix_roota(root, "/run/host/incoming");
+ q = prefix_roota(root, NSPAWN_MOUNT_TUNNEL);
r = mount_nofollow_verbose(LOG_ERR, p, q, NULL, MS_BIND, NULL);
if (r < 0)
return r;
@@ -2802,8 +2803,17 @@ static int setup_propagate(const char *root) {
if (r < 0)
return r;
- /* machined will MS_MOVE into that directory, and that's only supported for non-shared mounts. */
- return mount_nofollow_verbose(LOG_ERR, NULL, q, NULL, MS_SLAVE, NULL);
+ return 0;
+}
+
+static int mount_tunnel_open(void) {
+ int r;
+
+ r = mount_follow_verbose(LOG_ERR, NULL, NSPAWN_MOUNT_TUNNEL, NULL, MS_SLAVE, NULL);
+ if (r < 0)
+ return r;
+
+ return 0;
}
static int setup_machine_id(const char *directory) {
@@ -3906,7 +3916,7 @@ static int outer_child(
if (r < 0)
return r;
- r = setup_propagate(directory);
+ r = mount_tunnel_dig(directory);
if (r < 0)
return r;
@@ -3983,6 +3993,13 @@ static int outer_child(
if (r < 0)
return log_error_errno(r, "Failed to move root directory: %m");
+ /* We finished setting up the rootfs which is a shared mount. The mount tunnel needs to be a
+ * dependent mount otherwise we can't MS_MOVE mounts that were propagated from the host into
+ * the container. */
+ r = mount_tunnel_open();
+ if (r < 0)
+ return r;
+
if (arg_userns_mode != USER_NAMESPACE_NO) {
/* In order to mount procfs and sysfs in an unprivileged container the kernel
* requires that a fully visible instance is already present in the target mount