nspawn: skip /sys-as-tmpfs if we don't use private-network
Since v3.11/7dc5dbc ("sysfs: Restrict mounting sysfs"), the kernel
doesn't allow mounting sysfs if you don't have CAP_SYS_ADMIN rights over
the network namespace.
So the mounting /sys as a tmpfs code introduced in
d8fc6a000f doesn't work with user
namespaces if we don't use private-net. The reason is that we mount
sysfs inside the container and we're in the network namespace of the host
but we don't have CAP_SYS_ADMIN over that namespace.
To fix that, we mount /sys as a sysfs (instead of tmpfs) if we don't use
private network and ignore the /sys-as-a-tmpfs code if we find that /sys
is already mounted as sysfs.
Fixes #1555
This commit is contained in:
+30
-12
@@ -20,6 +20,7 @@
|
||||
***/
|
||||
|
||||
#include <sys/mount.h>
|
||||
#include <linux/magic.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "rm-rf.h"
|
||||
@@ -218,8 +219,19 @@ static int tmpfs_patch_options(
|
||||
|
||||
int mount_sysfs(const char *dest) {
|
||||
const char *full, *top, *x;
|
||||
int r;
|
||||
|
||||
top = prefix_roota(dest, "/sys");
|
||||
r = path_check_fstype(top, SYSFS_MAGIC);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to determine filesystem type of %s: %m", top);
|
||||
/* /sys might already be mounted as sysfs by the outer child in the
|
||||
* !netns case. In this case, it's all good. Don't touch it because we
|
||||
* don't have the right to do so, see https://github.com/systemd/systemd/issues/1555.
|
||||
*/
|
||||
if (r > 0)
|
||||
return 0;
|
||||
|
||||
full = prefix_roota(top, "/full");
|
||||
|
||||
(void) mkdir(full, 0755);
|
||||
@@ -264,6 +276,7 @@ int mount_sysfs(const char *dest) {
|
||||
|
||||
int mount_all(const char *dest,
|
||||
bool use_userns, bool in_userns,
|
||||
bool use_netns,
|
||||
uid_t uid_shift, uid_t uid_range,
|
||||
const char *selinux_apifs_context) {
|
||||
|
||||
@@ -274,21 +287,23 @@ int mount_all(const char *dest,
|
||||
const char *options;
|
||||
unsigned long flags;
|
||||
bool fatal;
|
||||
bool userns;
|
||||
bool in_userns;
|
||||
bool use_netns;
|
||||
} MountPoint;
|
||||
|
||||
static const MountPoint mount_table[] = {
|
||||
{ "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true, true },
|
||||
{ "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true, true }, /* Bind mount first */
|
||||
{ NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, true, true }, /* Then, make it r/o */
|
||||
{ "tmpfs", "/sys", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false },
|
||||
{ "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true, false },
|
||||
{ "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false },
|
||||
{ "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false },
|
||||
{ "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_STRICTATIME, true, false },
|
||||
{ "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true, true, false },
|
||||
{ "/proc/sys", "/proc/sys", NULL, NULL, MS_BIND, true, true, false }, /* Bind mount first */
|
||||
{ NULL, "/proc/sys", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, true, true, false }, /* Then, make it r/o */
|
||||
{ "tmpfs", "/sys", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false, true },
|
||||
{ "sysfs", "/sys", "sysfs", NULL, MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV, true, false, false },
|
||||
{ "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME, true, false, false },
|
||||
{ "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false, false },
|
||||
{ "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME, true, false, false },
|
||||
{ "tmpfs", "/tmp", "tmpfs", "mode=1777", MS_STRICTATIME, true, false, false },
|
||||
#ifdef HAVE_SELINUX
|
||||
{ "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, false, false }, /* Bind mount first */
|
||||
{ NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, false, false }, /* Then, make it r/o */
|
||||
{ "/sys/fs/selinux", "/sys/fs/selinux", NULL, NULL, MS_BIND, false, false, false }, /* Bind mount first */
|
||||
{ NULL, "/sys/fs/selinux", NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, false, false, false }, /* Then, make it r/o */
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -299,7 +314,10 @@ int mount_all(const char *dest,
|
||||
_cleanup_free_ char *where = NULL, *options = NULL;
|
||||
const char *o;
|
||||
|
||||
if (in_userns != mount_table[k].userns)
|
||||
if (in_userns != mount_table[k].in_userns)
|
||||
continue;
|
||||
|
||||
if (!use_netns && mount_table[k].use_netns)
|
||||
continue;
|
||||
|
||||
where = prefix_root(dest, mount_table[k].where);
|
||||
|
||||
@@ -57,7 +57,7 @@ int tmpfs_mount_parse(CustomMount **l, unsigned *n, const char *s);
|
||||
|
||||
int custom_mount_compare(const void *a, const void *b);
|
||||
|
||||
int mount_all(const char *dest, bool use_userns, bool in_userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
|
||||
int mount_all(const char *dest, bool use_userns, bool in_userns, bool use_netns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
|
||||
int mount_sysfs(const char *dest);
|
||||
|
||||
int mount_cgroups(const char *dest, bool unified_requested, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
|
||||
|
||||
+2
-2
@@ -2450,7 +2450,7 @@ static int inner_child(
|
||||
}
|
||||
}
|
||||
|
||||
r = mount_all(NULL, arg_userns, true, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
|
||||
r = mount_all(NULL, arg_userns, true, arg_uid_shift, arg_private_network, arg_uid_range, arg_selinux_apifs_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -2705,7 +2705,7 @@ static int outer_child(
|
||||
return log_error_errno(r, "Failed to make tree read-only: %m");
|
||||
}
|
||||
|
||||
r = mount_all(directory, arg_userns, false, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
|
||||
r = mount_all(directory, arg_userns, false, arg_private_network, arg_uid_shift, arg_uid_range, arg_selinux_apifs_context);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user