summaryrefslogtreecommitdiffstats
path: root/src/shared/mount-setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared/mount-setup.c')
-rw-r--r--src/shared/mount-setup.c285
1 files changed, 145 insertions, 140 deletions
diff --git a/src/shared/mount-setup.c b/src/shared/mount-setup.c
index 1226ca1..ba291bd 100644
--- a/src/shared/mount-setup.c
+++ b/src/shared/mount-setup.c
@@ -69,7 +69,7 @@ static bool check_recursiveprot_supported(void) {
r = mount_option_supported("cgroup2", "memory_recursiveprot", NULL);
if (r < 0)
- log_debug_errno(r, "Failed to determiner whether the 'memory_recursiveprot' mount option is supported, assuming not: %m");
+ log_debug_errno(r, "Failed to determine whether the 'memory_recursiveprot' mount option is supported, assuming not: %m");
else if (r == 0)
log_debug("This kernel version does not support 'memory_recursiveprot', not using mount option.");
@@ -107,16 +107,6 @@ static const MountPoint mount_table[] = {
cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
{ "cgroup2", "/sys/fs/cgroup", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
cg_is_unified_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
- { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP, MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
- cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
- { "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
- { "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
- { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- cg_is_legacy_wanted, MNT_IN_CONTAINER },
- { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
#if ENABLE_PSTORE
{ "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
NULL, MNT_NONE },
@@ -135,8 +125,8 @@ bool mount_point_is_api(const char *path) {
/* Checks if this mount point is considered "API", and hence
* should be ignored */
- for (size_t i = 0; i < ELEMENTSOF(mount_table); i ++)
- if (path_equal(path, mount_table[i].where))
+ FOREACH_ELEMENT(i, mount_table)
+ if (path_equal(path, i->where))
return true;
return path_startswith(path, "/sys/fs/cgroup/");
@@ -167,8 +157,11 @@ static int mount_one(const MountPoint *p, bool relabel) {
int r, priority;
assert(p);
+ assert(p->what);
+ assert(p->where);
+ assert(p->type);
- priority = (p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG;
+ priority = FLAGS_SET(p->mode, MNT_FATAL) ? LOG_ERR : LOG_DEBUG;
if (p->condition_fn && !p->condition_fn())
return 0;
@@ -177,16 +170,16 @@ static int mount_one(const MountPoint *p, bool relabel) {
if (relabel)
(void) label_fix(p->where, LABEL_IGNORE_ENOENT|LABEL_IGNORE_EROFS);
- r = path_is_mount_point(p->where, NULL, AT_SYMLINK_FOLLOW);
+ r = path_is_mount_point_full(p->where, /* root = */ NULL, AT_SYMLINK_FOLLOW);
if (r < 0 && r != -ENOENT) {
log_full_errno(priority, r, "Failed to determine whether %s is a mount point: %m", p->where);
- return (p->mode & MNT_FATAL) ? r : 0;
+ return FLAGS_SET(p->mode, MNT_FATAL) ? r : 0;
}
if (r > 0)
return 0;
/* Skip securityfs in a container */
- if (!(p->mode & MNT_IN_CONTAINER) && detect_container() > 0)
+ if (!FLAGS_SET(p->mode, MNT_IN_CONTAINER) && detect_container() > 0)
return 0;
/* The access mode here doesn't really matter too much, since
@@ -202,44 +195,37 @@ static int mount_one(const MountPoint *p, bool relabel) {
p->type,
strna(p->options));
- if (FLAGS_SET(p->mode, MNT_FOLLOW_SYMLINK))
- r = mount_follow_verbose(priority, p->what, p->where, p->type, p->flags, p->options);
- else
- r = mount_nofollow_verbose(priority, p->what, p->where, p->type, p->flags, p->options);
+ r = mount_verbose_full(priority, p->what, p->where, p->type, p->flags, p->options, FLAGS_SET(p->mode, MNT_FOLLOW_SYMLINK));
if (r < 0)
- return (p->mode & MNT_FATAL) ? r : 0;
+ return FLAGS_SET(p->mode, MNT_FATAL) ? r : 0;
/* Relabel again, since we now mounted something fresh here */
if (relabel)
(void) label_fix(p->where, 0);
- if (p->mode & MNT_CHECK_WRITABLE) {
+ if (FLAGS_SET(p->mode, MNT_CHECK_WRITABLE))
if (access(p->where, W_OK) < 0) {
r = -errno;
(void) umount2(p->where, UMOUNT_NOFOLLOW);
(void) rmdir(p->where);
- log_full_errno(priority, r, "Mount point %s not writable after mounting, undoing: %m", p->where);
- return (p->mode & MNT_FATAL) ? r : 0;
+ log_full_errno(priority, r, "Mount point '%s' not writable after mounting, undoing: %m", p->where);
+ return FLAGS_SET(p->mode, MNT_FATAL) ? r : 0;
}
- }
return 1;
}
static int mount_points_setup(size_t n, bool loaded_policy) {
- int ret = 0, r;
+ int r = 0;
assert(n <= ELEMENTSOF(mount_table));
- FOREACH_ARRAY(mp, mount_table, n) {
- r = mount_one(mp, loaded_policy);
- if (r != 0 && ret >= 0)
- ret = r;
- }
+ FOREACH_ARRAY(mp, mount_table, n)
+ RET_GATHER(r, mount_one(mp, loaded_policy));
- return ret;
+ return r;
}
int mount_setup_early(void) {
@@ -297,81 +283,6 @@ static int symlink_controller(const char *target, const char *alias) {
return 0;
}
-int mount_cgroup_controllers(void) {
- _cleanup_set_free_ Set *controllers = NULL;
- int r;
-
- if (!cg_is_legacy_wanted())
- return 0;
-
- /* Mount all available cgroup controllers that are built into the kernel. */
- r = cg_kernel_controllers(&controllers);
- if (r < 0)
- return log_error_errno(r, "Failed to enumerate cgroup controllers: %m");
-
- for (;;) {
- _cleanup_free_ char *options = NULL, *controller = NULL, *where = NULL;
- const char *other_controller;
- MountPoint p = {
- .what = "cgroup",
- .type = "cgroup",
- .flags = MS_NOSUID|MS_NOEXEC|MS_NODEV,
- .mode = MNT_IN_CONTAINER,
- };
-
- controller = set_steal_first(controllers);
- if (!controller)
- break;
-
- /* Check if we shall mount this together with another controller */
- other_controller = join_with(controller);
- if (other_controller) {
- _cleanup_free_ char *c = NULL;
-
- /* Check if the other controller is actually available in the kernel too */
- c = set_remove(controllers, other_controller);
- if (c) {
-
- /* Join the two controllers into one string, and maintain a stable ordering */
- if (strcmp(controller, other_controller) < 0)
- options = strjoin(controller, ",", other_controller);
- else
- options = strjoin(other_controller, ",", controller);
- if (!options)
- return log_oom();
- }
- }
-
- /* The simple case, where there's only one controller to mount together */
- if (!options)
- options = TAKE_PTR(controller);
-
- where = path_join("/sys/fs/cgroup", options);
- if (!where)
- return log_oom();
-
- p.where = where;
- p.options = options;
-
- r = mount_one(&p, true);
- if (r < 0)
- return r;
-
- /* Create symlinks from the individual controller names, in case we have a joined mount */
- if (controller)
- (void) symlink_controller(options, controller);
- if (other_controller)
- (void) symlink_controller(options, other_controller);
- }
-
- /* Now that we mounted everything, let's make the tmpfs the cgroup file systems are mounted into read-only. */
- (void) mount_nofollow("tmpfs", "/sys/fs/cgroup", "tmpfs",
- MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY,
- "mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP);
-
- return 0;
-}
-
#if HAVE_SELINUX || ENABLE_SMACK
static int relabel_cb(
RecurseDirEvent event,
@@ -415,34 +326,6 @@ static int relabel_tree(const char *path) {
return r;
}
-static int relabel_cgroup_filesystems(void) {
- int r;
- struct statfs st;
-
- r = cg_all_unified();
- if (r == 0) {
- /* Temporarily remount the root cgroup filesystem to give it a proper label. Do this
- only when the filesystem has been already populated by a previous instance of systemd
- running from initrd. Otherwise don't remount anything and leave the filesystem read-write
- for the cgroup filesystems to be mounted inside. */
- if (statfs("/sys/fs/cgroup", &st) < 0)
- return log_error_errno(errno, "Failed to determine mount flags for /sys/fs/cgroup: %m");
-
- if (st.f_flags & ST_RDONLY)
- (void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
-
- (void) label_fix("/sys/fs/cgroup", 0);
- (void) relabel_tree("/sys/fs/cgroup");
-
- if (st.f_flags & ST_RDONLY)
- (void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
-
- } else if (r < 0)
- return log_error_errno(r, "Failed to determine whether we are in all unified mode: %m");
-
- return 0;
-}
-
static int relabel_extra(void) {
_cleanup_strv_free_ char **files = NULL;
int r, c = 0;
@@ -533,14 +416,12 @@ int mount_setup(bool loaded_policy, bool leave_propagation) {
FOREACH_STRING(i, "/dev", "/dev/shm", "/run")
(void) relabel_tree(i);
- (void) relabel_cgroup_filesystems();
-
n_extra = relabel_extra();
after_relabel = now(CLOCK_MONOTONIC);
- log_info("Relabeled /dev, /dev/shm, /run, /sys/fs/cgroup%s in %s.",
- n_extra > 0 ? ", additional files" : "",
+ log_info("Relabeled /dev/, /dev/shm/, /run/%s in %s.",
+ n_extra > 0 ? ", and additional files" : "",
FORMAT_TIMESPAN(after_relabel - before_relabel, 0));
}
#endif
@@ -589,3 +470,127 @@ int mount_setup(bool loaded_policy, bool leave_propagation) {
return 0;
}
+
+static const MountPoint cgroupv1_mount_table[] = {
+ { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP, MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
+ cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
+ { "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", "nsdelegate", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
+ { "cgroup2", "/sys/fs/cgroup/unified", "cgroup2", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ cg_is_hybrid_wanted, MNT_IN_CONTAINER|MNT_CHECK_WRITABLE },
+ { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ cg_is_legacy_wanted, MNT_IN_CONTAINER },
+ { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
+};
+
+static void relabel_cgroup_legacy_hierarchy(void) {
+#if HAVE_SELINUX || ENABLE_SMACK
+ struct statfs st;
+
+ assert(cg_is_legacy_wanted());
+
+ /* Temporarily remount the root cgroup filesystem to give it a proper label. Do this
+ only when the filesystem has been already populated by a previous instance of systemd
+ running from initrd. Otherwise don't remount anything and leave the filesystem read-write
+ for the cgroup filesystems to be mounted inside. */
+ if (statfs("/sys/fs/cgroup", &st) < 0)
+ return (void) log_error_errno(errno, "Failed to determine mount flags for /sys/fs/cgroup/: %m");
+
+ if (st.f_flags & ST_RDONLY)
+ (void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT, NULL);
+
+ (void) label_fix("/sys/fs/cgroup", 0);
+ (void) relabel_tree("/sys/fs/cgroup");
+
+ if (st.f_flags & ST_RDONLY)
+ (void) mount_nofollow(NULL, "/sys/fs/cgroup", NULL, MS_REMOUNT|MS_RDONLY, NULL);
+#endif
+}
+
+int mount_cgroup_legacy_controllers(bool loaded_policy) {
+ _cleanup_set_free_ Set *controllers = NULL;
+ int r;
+
+ if (!cg_is_legacy_wanted())
+ return 0;
+
+ if (!cg_is_legacy_force_enabled())
+ return -ERFKILL;
+
+ FOREACH_ELEMENT(mp, cgroupv1_mount_table) {
+ r = mount_one(mp, loaded_policy);
+ if (r < 0)
+ return r;
+ }
+
+ if (loaded_policy)
+ relabel_cgroup_legacy_hierarchy();
+
+ /* Mount all available cgroup controllers that are built into the kernel. */
+ r = cg_kernel_controllers(&controllers);
+ if (r < 0)
+ return log_error_errno(r, "Failed to enumerate cgroup controllers: %m");
+
+ for (;;) {
+ _cleanup_free_ char *options = NULL, *controller = NULL, *where = NULL;
+ const char *other_controller;
+ MountPoint p = {
+ .what = "cgroup",
+ .type = "cgroup",
+ .flags = MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ .mode = MNT_IN_CONTAINER,
+ };
+
+ controller = set_steal_first(controllers);
+ if (!controller)
+ break;
+
+ /* Check if we shall mount this together with another controller */
+ other_controller = join_with(controller);
+ if (other_controller) {
+ _cleanup_free_ char *c = NULL;
+
+ /* Check if the other controller is actually available in the kernel too */
+ c = set_remove(controllers, other_controller);
+ if (c) {
+
+ /* Join the two controllers into one string, and maintain a stable ordering */
+ if (strcmp(controller, other_controller) < 0)
+ options = strjoin(controller, ",", other_controller);
+ else
+ options = strjoin(other_controller, ",", controller);
+ if (!options)
+ return log_oom();
+ }
+ }
+
+ /* The simple case, where there's only one controller to mount together */
+ if (!options)
+ options = TAKE_PTR(controller);
+
+ where = path_join("/sys/fs/cgroup", options);
+ if (!where)
+ return log_oom();
+
+ p.where = where;
+ p.options = options;
+
+ r = mount_one(&p, true);
+ if (r < 0)
+ return r;
+
+ /* Create symlinks from the individual controller names, in case we have a joined mount */
+ if (controller)
+ (void) symlink_controller(options, controller);
+ if (other_controller)
+ (void) symlink_controller(options, other_controller);
+ }
+
+ /* Now that we mounted everything, let's make the tmpfs the cgroup file systems are mounted into read-only. */
+ (void) mount_nofollow("tmpfs", "/sys/fs/cgroup", "tmpfs",
+ MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY,
+ "mode=0755" TMPFS_LIMITS_SYS_FS_CGROUP);
+
+ return 1;
+}