namespace: properly handle bind mounts from the host
Before this patch we had an ordering problem: if we have no namespacing enabled except for two bind mounts that intend to swap /a and /b via bind mounts, then we'd execute the bind mount binding /b to /a, followed by thebind mount from /a to /b, thus having the effect that /b is now visible in both /a and /b, which was not intended. With this change, as soon as any bind mount is configured we'll put together the service mount namespace in a temporary directory instead of operating directly in the root. This solves the problem in a straightforward fashion: the source of bind mounts will always refer to the host, and thus be unaffected from the bind mounts we already created.
This commit is contained in:
+40
-22
@@ -31,6 +31,7 @@
|
||||
#include "dev-setup.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "label.h"
|
||||
#include "loop-util.h"
|
||||
#include "loopback-setup.h"
|
||||
#include "missing.h"
|
||||
@@ -904,6 +905,7 @@ int setup_namespace(
|
||||
MountEntry *m, *mounts = NULL;
|
||||
size_t root_hash_size = 0;
|
||||
bool make_slave = false;
|
||||
const char *root;
|
||||
unsigned n_mounts;
|
||||
int r = 0;
|
||||
|
||||
@@ -935,18 +937,25 @@ int setup_namespace(
|
||||
r = dissected_image_decrypt(dissected_image, NULL, root_hash, root_hash_size, dissect_image_flags, &decrypted_image);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!root_directory) {
|
||||
/* Create a mount point for the image, if it's still missing. We use the same mount point for
|
||||
* all images, which is safe, since they all live in their own namespaces after all, and hence
|
||||
* won't see each other. */
|
||||
root_directory = "/run/systemd/unit-root";
|
||||
(void) mkdir(root_directory, 0700);
|
||||
}
|
||||
}
|
||||
|
||||
if (root_directory)
|
||||
root = root_directory;
|
||||
else if (root_image || n_bind_mounts > 0) {
|
||||
|
||||
/* If we are booting from an image, create a mount point for the image, if it's still missing. We use
|
||||
* the same mount point for all images, which is safe, since they all live in their own namespaces
|
||||
* after all, and hence won't see each other. We also use such a root directory whenever there are bind
|
||||
* mounts configured, so that their source mounts are never obstructed by mounts we already applied
|
||||
* while we are applying them. */
|
||||
|
||||
root = "/run/systemd/unit-root";
|
||||
(void) mkdir_label(root, 0700);
|
||||
} else
|
||||
root = NULL;
|
||||
|
||||
n_mounts = namespace_calculate_mounts(
|
||||
root_directory,
|
||||
root,
|
||||
ns_info,
|
||||
read_write_paths,
|
||||
read_only_paths,
|
||||
@@ -956,7 +965,7 @@ int setup_namespace(
|
||||
protect_home, protect_system);
|
||||
|
||||
/* Set mount slave mode */
|
||||
if (root_directory || n_mounts > 0)
|
||||
if (root || n_mounts > 0)
|
||||
make_slave = true;
|
||||
|
||||
if (n_mounts > 0) {
|
||||
@@ -1025,7 +1034,7 @@ int setup_namespace(
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
if (namespace_info_mount_apivfs(root_directory, ns_info)) {
|
||||
if (namespace_info_mount_apivfs(root, ns_info)) {
|
||||
r = append_static_mounts(&m, apivfs_table, ELEMENTSOF(apivfs_table), ns_info->ignore_protect_paths);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
@@ -1034,14 +1043,14 @@ int setup_namespace(
|
||||
assert(mounts + n_mounts == m);
|
||||
|
||||
/* Prepend the root directory where that's necessary */
|
||||
r = prefix_where_needed(mounts, n_mounts, root_directory);
|
||||
r = prefix_where_needed(mounts, n_mounts, root);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
qsort(mounts, n_mounts, sizeof(MountEntry), mount_path_compare);
|
||||
|
||||
drop_duplicates(mounts, &n_mounts);
|
||||
drop_outside_root(root_directory, mounts, &n_mounts);
|
||||
drop_outside_root(root, mounts, &n_mounts);
|
||||
drop_inaccessible(mounts, &n_mounts);
|
||||
drop_nop(mounts, &n_mounts);
|
||||
}
|
||||
@@ -1061,11 +1070,12 @@ int setup_namespace(
|
||||
}
|
||||
|
||||
/* Try to set up the new root directory before mounting anything there */
|
||||
if (root_directory)
|
||||
(void) base_filesystem_create(root_directory, UID_INVALID, GID_INVALID);
|
||||
if (root)
|
||||
(void) base_filesystem_create(root, UID_INVALID, GID_INVALID);
|
||||
|
||||
if (root_image) {
|
||||
r = dissected_image_mount(dissected_image, root_directory, dissect_image_flags);
|
||||
/* A root image is specified, mount it to the right place */
|
||||
r = dissected_image_mount(dissected_image, root, dissect_image_flags);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
@@ -1079,16 +1089,24 @@ int setup_namespace(
|
||||
|
||||
} else if (root_directory) {
|
||||
|
||||
/* Turn directory into bind mount, if it isn't one yet */
|
||||
r = path_is_mount_point(root_directory, NULL, AT_SYMLINK_FOLLOW);
|
||||
/* A root directory is specified. Turn its directory into bind mount, if it isn't one yet. */
|
||||
r = path_is_mount_point(root, NULL, AT_SYMLINK_FOLLOW);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
if (r == 0) {
|
||||
if (mount(root_directory, root_directory, NULL, MS_BIND|MS_REC, NULL) < 0) {
|
||||
if (mount(root, root, NULL, MS_BIND|MS_REC, NULL) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (root) {
|
||||
|
||||
/* Let's mount the main root directory to the root directory to use */
|
||||
if (mount("/", root, NULL, MS_BIND|MS_REC, NULL) < 0) {
|
||||
r = -errno;
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
|
||||
if (n_mounts > 0) {
|
||||
@@ -1106,7 +1124,7 @@ int setup_namespace(
|
||||
|
||||
/* First round, add in all special mounts we need */
|
||||
for (m = mounts; m < mounts + n_mounts; ++m) {
|
||||
r = apply_mount(root_directory, m, tmp_dir, var_tmp_dir);
|
||||
r = apply_mount(root, m, tmp_dir, var_tmp_dir);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
@@ -1125,9 +1143,9 @@ int setup_namespace(
|
||||
}
|
||||
}
|
||||
|
||||
if (root_directory) {
|
||||
if (root) {
|
||||
/* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
|
||||
r = mount_move_root(root_directory);
|
||||
r = mount_move_root(root);
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user