mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-02-26 09:57:26 +03:00
Merge pull request #9658 from LukeShu/to-upstream/misc-cleanup
nspawn: Miscellaneous touch-up
This commit is contained in:
commit
1d2d351319
@ -2384,10 +2384,9 @@ int cg_kernel_controllers(Set **ret) {
|
|||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
/* Determines the full list of kernel-known controllers. Might
|
/* Determines the full list of kernel-known controllers. Might include controllers we don't actually support
|
||||||
* include controllers we don't actually support, arbitrary
|
* and controllers that aren't currently accessible (because not mounted). This does not include "name="
|
||||||
* named hierarchies and controllers that aren't currently
|
* pseudo-controllers. */
|
||||||
* accessible (because not mounted). */
|
|
||||||
|
|
||||||
controllers = set_new(&string_hash_ops);
|
controllers = set_new(&string_hash_ops);
|
||||||
if (!controllers)
|
if (!controllers)
|
||||||
|
@ -5,12 +5,16 @@
|
|||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
|
#include "fs-util.h"
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
#include "mount-util.h"
|
#include "mount-util.h"
|
||||||
#include "nspawn-cgroup.h"
|
#include "nspawn-cgroup.h"
|
||||||
|
#include "nspawn-mount.h"
|
||||||
|
#include "path-util.h"
|
||||||
#include "rm-rf.h"
|
#include "rm-rf.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
|
#include "user-util.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
static int chown_cgroup_path(const char *path, uid_t uid_shift) {
|
static int chown_cgroup_path(const char *path, uid_t uid_shift) {
|
||||||
@ -71,7 +75,7 @@ int chown_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t arg_uid_shift) {
|
int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift) {
|
||||||
_cleanup_free_ char *cgroup = NULL;
|
_cleanup_free_ char *cgroup = NULL;
|
||||||
char tree[] = "/tmp/unifiedXXXXXX", pid_string[DECIMAL_STR_MAX(pid) + 1];
|
char tree[] = "/tmp/unifiedXXXXXX", pid_string[DECIMAL_STR_MAX(pid) + 1];
|
||||||
bool undo_mount = false;
|
bool undo_mount = false;
|
||||||
@ -125,7 +129,7 @@ int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t arg_uid_shift)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn = strjoina(tree, cgroup);
|
fn = strjoina(tree, cgroup);
|
||||||
r = chown_cgroup_path(fn, arg_uid_shift);
|
r = chown_cgroup_path(fn, uid_shift);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_error_errno(r, "Failed to chown() cgroup %s: %m", fn);
|
log_error_errno(r, "Failed to chown() cgroup %s: %m", fn);
|
||||||
finish:
|
finish:
|
||||||
@ -188,3 +192,416 @@ int create_subcgroup(pid_t pid, bool keep_unit, CGroupUnified unified_requested)
|
|||||||
(void) cg_enable_everywhere(supported, supported, cgroup);
|
(void) cg_enable_everywhere(supported, supported, cgroup);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Retrieve existing subsystems. This function is called in a new cgroup
|
||||||
|
* namespace.
|
||||||
|
*/
|
||||||
|
static int get_process_controllers(Set **ret) {
|
||||||
|
_cleanup_set_free_free_ Set *controllers = NULL;
|
||||||
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
controllers = set_new(&string_hash_ops);
|
||||||
|
if (!controllers)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
f = fopen("/proc/self/cgroup", "re");
|
||||||
|
if (!f)
|
||||||
|
return errno == ENOENT ? -ESRCH : -errno;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *line = NULL;
|
||||||
|
char *e, *l;
|
||||||
|
|
||||||
|
r = read_line(f, LONG_LINE_MAX, &line);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
l = strchr(line, ':');
|
||||||
|
if (!l)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
l++;
|
||||||
|
e = strchr(l, ':');
|
||||||
|
if (!e)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
*e = 0;
|
||||||
|
|
||||||
|
if (STR_IN_SET(l, "", "name=systemd", "name=unified"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
r = set_put_strdup(controllers, l);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret = TAKE_PTR(controllers);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mount_legacy_cgroup_hierarchy(
|
||||||
|
const char *dest,
|
||||||
|
const char *controller,
|
||||||
|
const char *hierarchy,
|
||||||
|
bool read_only) {
|
||||||
|
|
||||||
|
const char *to, *fstype, *opts;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
to = strjoina(strempty(dest), "/sys/fs/cgroup/", hierarchy);
|
||||||
|
|
||||||
|
r = path_is_mount_point(to, dest, 0);
|
||||||
|
if (r < 0 && r != -ENOENT)
|
||||||
|
return log_error_errno(r, "Failed to determine if %s is mounted already: %m", to);
|
||||||
|
if (r > 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
mkdir_p(to, 0755);
|
||||||
|
|
||||||
|
/* The superblock mount options of the mount point need to be
|
||||||
|
* identical to the hosts', and hence writable... */
|
||||||
|
if (streq(controller, SYSTEMD_CGROUP_CONTROLLER_HYBRID)) {
|
||||||
|
fstype = "cgroup2";
|
||||||
|
opts = NULL;
|
||||||
|
} else if (streq(controller, SYSTEMD_CGROUP_CONTROLLER_LEGACY)) {
|
||||||
|
fstype = "cgroup";
|
||||||
|
opts = "none,name=systemd,xattr";
|
||||||
|
} else {
|
||||||
|
fstype = "cgroup";
|
||||||
|
opts = controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = mount_verbose(LOG_ERR, "cgroup", to, fstype, MS_NOSUID|MS_NOEXEC|MS_NODEV, opts);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* ... hence let's only make the bind mount read-only, not the superblock. */
|
||||||
|
if (read_only) {
|
||||||
|
r = mount_verbose(LOG_ERR, NULL, to, NULL,
|
||||||
|
MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mount a legacy cgroup hierarchy when cgroup namespaces are supported. */
|
||||||
|
static int mount_legacy_cgns_supported(
|
||||||
|
const char *dest,
|
||||||
|
CGroupUnified unified_requested,
|
||||||
|
bool userns,
|
||||||
|
uid_t uid_shift,
|
||||||
|
uid_t uid_range,
|
||||||
|
const char *selinux_apifs_context) {
|
||||||
|
|
||||||
|
_cleanup_set_free_free_ Set *controllers = NULL;
|
||||||
|
const char *cgroup_root = "/sys/fs/cgroup", *c;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
(void) mkdir_p(cgroup_root, 0755);
|
||||||
|
|
||||||
|
/* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
|
||||||
|
r = path_is_mount_point(cgroup_root, dest, AT_SYMLINK_FOLLOW);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
|
||||||
|
if (r == 0) {
|
||||||
|
_cleanup_free_ char *options = NULL;
|
||||||
|
|
||||||
|
/* When cgroup namespaces are enabled and user namespaces are
|
||||||
|
* used then the mount of the cgroupfs is done *inside* the new
|
||||||
|
* user namespace. We're root in the new user namespace and the
|
||||||
|
* kernel will happily translate our uid/gid to the correct
|
||||||
|
* uid/gid as seen from e.g. /proc/1/mountinfo. So we simply
|
||||||
|
* pass uid 0 and not uid_shift to tmpfs_patch_options().
|
||||||
|
*/
|
||||||
|
r = tmpfs_patch_options("mode=755", 0, selinux_apifs_context, &options);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = mount_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
|
||||||
|
MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = cg_all_unified();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r > 0)
|
||||||
|
goto skip_controllers;
|
||||||
|
|
||||||
|
r = get_process_controllers(&controllers);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to determine cgroup controllers: %m");
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ const char *controller = NULL;
|
||||||
|
|
||||||
|
controller = set_steal_first(controllers);
|
||||||
|
if (!controller)
|
||||||
|
break;
|
||||||
|
|
||||||
|
r = mount_legacy_cgroup_hierarchy("", controller, controller, !userns);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* When multiple hierarchies are co-mounted, make their
|
||||||
|
* constituting individual hierarchies a symlink to the
|
||||||
|
* co-mount.
|
||||||
|
*/
|
||||||
|
c = controller;
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *target = NULL, *tok = NULL;
|
||||||
|
|
||||||
|
r = extract_first_word(&c, &tok, ",", 0);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to extract co-mounted cgroup controller: %m");
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (streq(controller, tok))
|
||||||
|
break;
|
||||||
|
|
||||||
|
target = prefix_root("/sys/fs/cgroup/", tok);
|
||||||
|
if (!target)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = symlink_idempotent(controller, target);
|
||||||
|
if (r == -EINVAL)
|
||||||
|
return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_controllers:
|
||||||
|
if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
|
||||||
|
r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!userns)
|
||||||
|
return mount_verbose(LOG_ERR, NULL, cgroup_root, NULL,
|
||||||
|
MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mount legacy cgroup hierarchy when cgroup namespaces are unsupported. */
|
||||||
|
static int mount_legacy_cgns_unsupported(
|
||||||
|
const char *dest,
|
||||||
|
CGroupUnified unified_requested,
|
||||||
|
bool userns,
|
||||||
|
uid_t uid_shift,
|
||||||
|
uid_t uid_range,
|
||||||
|
const char *selinux_apifs_context) {
|
||||||
|
|
||||||
|
_cleanup_set_free_free_ Set *controllers = NULL;
|
||||||
|
const char *cgroup_root;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
cgroup_root = prefix_roota(dest, "/sys/fs/cgroup");
|
||||||
|
|
||||||
|
(void) mkdir_p(cgroup_root, 0755);
|
||||||
|
|
||||||
|
/* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
|
||||||
|
r = path_is_mount_point(cgroup_root, dest, AT_SYMLINK_FOLLOW);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
|
||||||
|
if (r == 0) {
|
||||||
|
_cleanup_free_ char *options = NULL;
|
||||||
|
|
||||||
|
r = tmpfs_patch_options("mode=755", uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &options);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = mount_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
|
||||||
|
MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = cg_all_unified();
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r > 0)
|
||||||
|
goto skip_controllers;
|
||||||
|
|
||||||
|
r = cg_kernel_controllers(&controllers);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to determine cgroup controllers: %m");
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *controller = NULL, *origin = NULL, *combined = NULL;
|
||||||
|
|
||||||
|
controller = set_steal_first(controllers);
|
||||||
|
if (!controller)
|
||||||
|
break;
|
||||||
|
|
||||||
|
origin = prefix_root("/sys/fs/cgroup/", controller);
|
||||||
|
if (!origin)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = readlink_malloc(origin, &combined);
|
||||||
|
if (r == -EINVAL) {
|
||||||
|
/* Not a symbolic link, but directly a single cgroup hierarchy */
|
||||||
|
|
||||||
|
r = mount_legacy_cgroup_hierarchy(dest, controller, controller, true);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
} else if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to read link %s: %m", origin);
|
||||||
|
else {
|
||||||
|
_cleanup_free_ char *target = NULL;
|
||||||
|
|
||||||
|
target = prefix_root(dest, origin);
|
||||||
|
if (!target)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
/* A symbolic link, a combination of controllers in one hierarchy */
|
||||||
|
|
||||||
|
if (!filename_is_valid(combined)) {
|
||||||
|
log_warning("Ignoring invalid combined hierarchy %s.", combined);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = mount_legacy_cgroup_hierarchy(dest, combined, combined, true);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = symlink_idempotent(combined, target);
|
||||||
|
if (r == -EINVAL)
|
||||||
|
return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_controllers:
|
||||||
|
if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
|
||||||
|
r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return mount_verbose(LOG_ERR, NULL, cgroup_root, NULL,
|
||||||
|
MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mount_unified_cgroups(const char *dest) {
|
||||||
|
const char *p;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(dest);
|
||||||
|
|
||||||
|
p = prefix_roota(dest, "/sys/fs/cgroup");
|
||||||
|
|
||||||
|
(void) mkdir_p(p, 0755);
|
||||||
|
|
||||||
|
r = path_is_mount_point(p, dest, AT_SYMLINK_FOLLOW);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to determine if %s is mounted already: %m", p);
|
||||||
|
if (r > 0) {
|
||||||
|
p = prefix_roota(dest, "/sys/fs/cgroup/cgroup.procs");
|
||||||
|
if (access(p, F_OK) >= 0)
|
||||||
|
return 0;
|
||||||
|
if (errno != ENOENT)
|
||||||
|
return log_error_errno(errno, "Failed to determine if mount point %s contains the unified cgroup hierarchy: %m", p);
|
||||||
|
|
||||||
|
log_error("%s is already mounted but not a unified cgroup hierarchy. Refusing.", p);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mount_verbose(LOG_ERR, "cgroup", p, "cgroup2", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mount_cgroups(
|
||||||
|
const char *dest,
|
||||||
|
CGroupUnified unified_requested,
|
||||||
|
bool userns,
|
||||||
|
uid_t uid_shift,
|
||||||
|
uid_t uid_range,
|
||||||
|
const char *selinux_apifs_context,
|
||||||
|
bool use_cgns) {
|
||||||
|
|
||||||
|
if (unified_requested >= CGROUP_UNIFIED_ALL)
|
||||||
|
return mount_unified_cgroups(dest);
|
||||||
|
if (use_cgns)
|
||||||
|
return mount_legacy_cgns_supported(dest, unified_requested, userns, uid_shift, uid_range, selinux_apifs_context);
|
||||||
|
|
||||||
|
return mount_legacy_cgns_unsupported(dest, unified_requested, userns, uid_shift, uid_range, selinux_apifs_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mount_systemd_cgroup_writable_one(const char *root, const char *own) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(root);
|
||||||
|
assert(own);
|
||||||
|
|
||||||
|
/* Make our own cgroup a (writable) bind mount */
|
||||||
|
r = mount_verbose(LOG_ERR, own, own, NULL, MS_BIND, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* And then remount the systemd cgroup root read-only */
|
||||||
|
return mount_verbose(LOG_ERR, NULL, root, NULL,
|
||||||
|
MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mount_systemd_cgroup_writable(
|
||||||
|
const char *dest,
|
||||||
|
CGroupUnified unified_requested) {
|
||||||
|
|
||||||
|
_cleanup_free_ char *own_cgroup_path = NULL;
|
||||||
|
const char *root, *own;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(dest);
|
||||||
|
|
||||||
|
r = cg_pid_get_path(NULL, 0, &own_cgroup_path);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to determine our own cgroup path: %m");
|
||||||
|
|
||||||
|
/* If we are living in the top-level, then there's nothing to do... */
|
||||||
|
if (path_equal(own_cgroup_path, "/"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (unified_requested >= CGROUP_UNIFIED_ALL) {
|
||||||
|
|
||||||
|
root = prefix_roota(dest, "/sys/fs/cgroup");
|
||||||
|
own = strjoina(root, own_cgroup_path);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
|
||||||
|
root = prefix_roota(dest, "/sys/fs/cgroup/unified");
|
||||||
|
own = strjoina(root, own_cgroup_path);
|
||||||
|
|
||||||
|
r = mount_systemd_cgroup_writable_one(root, own);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
root = prefix_roota(dest, "/sys/fs/cgroup/systemd");
|
||||||
|
own = strjoina(root, own_cgroup_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mount_systemd_cgroup_writable_one(root, own);
|
||||||
|
}
|
||||||
|
@ -9,3 +9,6 @@
|
|||||||
int chown_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift);
|
int chown_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift);
|
||||||
int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift);
|
int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift);
|
||||||
int create_subcgroup(pid_t pid, bool keep_unit, CGroupUnified unified_requested);
|
int create_subcgroup(pid_t pid, bool keep_unit, CGroupUnified unified_requested);
|
||||||
|
|
||||||
|
int mount_cgroups(const char *dest, CGroupUnified unified_requested, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context, bool use_cgns);
|
||||||
|
int mount_systemd_cgroup_writable(const char *dest, CGroupUnified unified_requested);
|
||||||
|
@ -327,19 +327,15 @@ int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_onl
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tmpfs_patch_options(
|
int tmpfs_patch_options(
|
||||||
const char *options,
|
const char *options,
|
||||||
bool userns,
|
uid_t uid_shift,
|
||||||
uid_t uid_shift, uid_t uid_range,
|
|
||||||
bool patch_ids,
|
|
||||||
const char *selinux_apifs_context,
|
const char *selinux_apifs_context,
|
||||||
char **ret) {
|
char **ret) {
|
||||||
|
|
||||||
char *buf = NULL;
|
char *buf = NULL;
|
||||||
|
|
||||||
if ((userns && uid_shift != 0) || patch_ids) {
|
if (uid_shift != UID_INVALID) {
|
||||||
assert(uid_shift != UID_INVALID);
|
|
||||||
|
|
||||||
if (asprintf(&buf, "%s%suid=" UID_FMT ",gid=" UID_FMT,
|
if (asprintf(&buf, "%s%suid=" UID_FMT ",gid=" UID_FMT,
|
||||||
strempty(options), options ? "," : "",
|
strempty(options), options ? "," : "",
|
||||||
uid_shift, uid_shift) < 0)
|
uid_shift, uid_shift) < 0)
|
||||||
@ -433,16 +429,14 @@ int mount_sysfs(const char *dest, MountSettingsMask mount_settings) {
|
|||||||
/* Create mountpoint for cgroups. Otherwise we are not allowed since we
|
/* Create mountpoint for cgroups. Otherwise we are not allowed since we
|
||||||
* remount /sys read-only.
|
* remount /sys read-only.
|
||||||
*/
|
*/
|
||||||
if (cg_ns_supported()) {
|
x = prefix_roota(top, "/fs/cgroup");
|
||||||
x = prefix_roota(top, "/fs/cgroup");
|
(void) mkdir_p(x, 0755);
|
||||||
(void) mkdir_p(x, 0755);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mount_verbose(LOG_ERR, NULL, top, NULL,
|
return mount_verbose(LOG_ERR, NULL, top, NULL,
|
||||||
MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT|extra_flags, NULL);
|
MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT|extra_flags, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mkdir_userns(const char *path, mode_t mode, MountSettingsMask mask, uid_t uid_shift) {
|
static int mkdir_userns(const char *path, mode_t mode, uid_t uid_shift) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(path);
|
assert(path);
|
||||||
@ -451,10 +445,7 @@ static int mkdir_userns(const char *path, mode_t mode, MountSettingsMask mask, u
|
|||||||
if (r < 0 && r != -EEXIST)
|
if (r < 0 && r != -EEXIST)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if ((mask & MOUNT_USE_USERNS) == 0)
|
if (uid_shift == UID_INVALID)
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (mask & MOUNT_IN_USERNS)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (lchown(path, uid_shift, uid_shift) < 0)
|
if (lchown(path, uid_shift, uid_shift) < 0)
|
||||||
@ -463,7 +454,7 @@ static int mkdir_userns(const char *path, mode_t mode, MountSettingsMask mask, u
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mkdir_userns_p(const char *prefix, const char *path, mode_t mode, MountSettingsMask mask, uid_t uid_shift) {
|
static int mkdir_userns_p(const char *prefix, const char *path, mode_t mode, uid_t uid_shift) {
|
||||||
const char *p, *e;
|
const char *p, *e;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -490,17 +481,17 @@ static int mkdir_userns_p(const char *prefix, const char *path, mode_t mode, Mou
|
|||||||
if (prefix && path_startswith(prefix, t))
|
if (prefix && path_startswith(prefix, t))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = mkdir_userns(t, mode, mask, uid_shift);
|
r = mkdir_userns(t, mode, uid_shift);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mkdir_userns(path, mode, mask, uid_shift);
|
return mkdir_userns(path, mode, uid_shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mount_all(const char *dest,
|
int mount_all(const char *dest,
|
||||||
MountSettingsMask mount_settings,
|
MountSettingsMask mount_settings,
|
||||||
uid_t uid_shift, uid_t uid_range,
|
uid_t uid_shift,
|
||||||
const char *selinux_apifs_context) {
|
const char *selinux_apifs_context) {
|
||||||
|
|
||||||
#define PROC_INACCESSIBLE(path) \
|
#define PROC_INACCESSIBLE(path) \
|
||||||
@ -634,7 +625,7 @@ int mount_all(const char *dest,
|
|||||||
if (what && r > 0)
|
if (what && r > 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = mkdir_userns_p(dest, where, 0755, mount_settings, uid_shift);
|
r = mkdir_userns_p(dest, where, 0755, (use_userns && !in_userns) ? uid_shift : UID_INVALID);
|
||||||
if (r < 0 && r != -EEXIST) {
|
if (r < 0 && r != -EEXIST) {
|
||||||
if (fatal && r != -EROFS)
|
if (fatal && r != -EROFS)
|
||||||
return log_error_errno(r, "Failed to create directory %s: %m", where);
|
return log_error_errno(r, "Failed to create directory %s: %m", where);
|
||||||
@ -649,10 +640,7 @@ int mount_all(const char *dest,
|
|||||||
|
|
||||||
o = mount_table[k].options;
|
o = mount_table[k].options;
|
||||||
if (streq_ptr(mount_table[k].type, "tmpfs")) {
|
if (streq_ptr(mount_table[k].type, "tmpfs")) {
|
||||||
if (in_userns)
|
r = tmpfs_patch_options(o, in_userns ? 0 : uid_shift, selinux_apifs_context, &options);
|
||||||
r = tmpfs_patch_options(o, use_userns, 0, uid_range, true, selinux_apifs_context, &options);
|
|
||||||
else
|
|
||||||
r = tmpfs_patch_options(o, use_userns, uid_shift, uid_range, false, selinux_apifs_context, &options);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
@ -755,7 +743,7 @@ static int mount_tmpfs(
|
|||||||
return log_error_errno(r, "Creating mount point for tmpfs %s failed: %m", where);
|
return log_error_errno(r, "Creating mount point for tmpfs %s failed: %m", where);
|
||||||
}
|
}
|
||||||
|
|
||||||
r = tmpfs_patch_options(m->options, userns, uid_shift, uid_range, false, selinux_apifs_context, &buf);
|
r = tmpfs_patch_options(m->options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
options = r > 0 ? buf : m->options;
|
options = r > 0 ? buf : m->options;
|
||||||
@ -860,419 +848,6 @@ int mount_custom(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve existing subsystems. This function is called in a new cgroup
|
|
||||||
* namespace.
|
|
||||||
*/
|
|
||||||
static int get_process_controllers(Set **ret) {
|
|
||||||
_cleanup_set_free_free_ Set *controllers = NULL;
|
|
||||||
_cleanup_fclose_ FILE *f = NULL;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(ret);
|
|
||||||
|
|
||||||
controllers = set_new(&string_hash_ops);
|
|
||||||
if (!controllers)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
f = fopen("/proc/self/cgroup", "re");
|
|
||||||
if (!f)
|
|
||||||
return errno == ENOENT ? -ESRCH : -errno;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
_cleanup_free_ char *line = NULL;
|
|
||||||
char *e, *l;
|
|
||||||
|
|
||||||
r = read_line(f, LONG_LINE_MAX, &line);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
if (r == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
l = strchr(line, ':');
|
|
||||||
if (!l)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
l++;
|
|
||||||
e = strchr(l, ':');
|
|
||||||
if (!e)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
*e = 0;
|
|
||||||
|
|
||||||
if (STR_IN_SET(l, "", "name=systemd", "name=unified"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
r = set_put_strdup(controllers, l);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
*ret = TAKE_PTR(controllers);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mount_legacy_cgroup_hierarchy(
|
|
||||||
const char *dest,
|
|
||||||
const char *controller,
|
|
||||||
const char *hierarchy,
|
|
||||||
bool read_only) {
|
|
||||||
|
|
||||||
const char *to, *fstype, *opts;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
to = strjoina(strempty(dest), "/sys/fs/cgroup/", hierarchy);
|
|
||||||
|
|
||||||
r = path_is_mount_point(to, dest, 0);
|
|
||||||
if (r < 0 && r != -ENOENT)
|
|
||||||
return log_error_errno(r, "Failed to determine if %s is mounted already: %m", to);
|
|
||||||
if (r > 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
mkdir_p(to, 0755);
|
|
||||||
|
|
||||||
/* The superblock mount options of the mount point need to be
|
|
||||||
* identical to the hosts', and hence writable... */
|
|
||||||
if (streq(controller, SYSTEMD_CGROUP_CONTROLLER_HYBRID)) {
|
|
||||||
fstype = "cgroup2";
|
|
||||||
opts = NULL;
|
|
||||||
} else if (streq(controller, SYSTEMD_CGROUP_CONTROLLER_LEGACY)) {
|
|
||||||
fstype = "cgroup";
|
|
||||||
opts = "none,name=systemd,xattr";
|
|
||||||
} else {
|
|
||||||
fstype = "cgroup";
|
|
||||||
opts = controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = mount_verbose(LOG_ERR, "cgroup", to, fstype, MS_NOSUID|MS_NOEXEC|MS_NODEV, opts);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
/* ... hence let's only make the bind mount read-only, not the superblock. */
|
|
||||||
if (read_only) {
|
|
||||||
r = mount_verbose(LOG_ERR, NULL, to, NULL,
|
|
||||||
MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, NULL);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mount a legacy cgroup hierarchy when cgroup namespaces are supported. */
|
|
||||||
static int mount_legacy_cgns_supported(
|
|
||||||
const char *dest,
|
|
||||||
CGroupUnified unified_requested,
|
|
||||||
bool userns,
|
|
||||||
uid_t uid_shift,
|
|
||||||
uid_t uid_range,
|
|
||||||
const char *selinux_apifs_context) {
|
|
||||||
|
|
||||||
_cleanup_set_free_free_ Set *controllers = NULL;
|
|
||||||
const char *cgroup_root = "/sys/fs/cgroup", *c;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
(void) mkdir_p(cgroup_root, 0755);
|
|
||||||
|
|
||||||
/* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
|
|
||||||
r = path_is_mount_point(cgroup_root, dest, AT_SYMLINK_FOLLOW);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
|
|
||||||
if (r == 0) {
|
|
||||||
_cleanup_free_ char *options = NULL;
|
|
||||||
|
|
||||||
/* When cgroup namespaces are enabled and user namespaces are
|
|
||||||
* used then the mount of the cgroupfs is done *inside* the new
|
|
||||||
* user namespace. We're root in the new user namespace and the
|
|
||||||
* kernel will happily translate our uid/gid to the correct
|
|
||||||
* uid/gid as seen from e.g. /proc/1/mountinfo. So we simply
|
|
||||||
* pass uid 0 and not uid_shift to tmpfs_patch_options().
|
|
||||||
*/
|
|
||||||
r = tmpfs_patch_options("mode=755", userns, 0, uid_range, true, selinux_apifs_context, &options);
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
r = mount_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
|
|
||||||
MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = cg_all_unified();
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
if (r > 0)
|
|
||||||
goto skip_controllers;
|
|
||||||
|
|
||||||
r = get_process_controllers(&controllers);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to determine cgroup controllers: %m");
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
_cleanup_free_ const char *controller = NULL;
|
|
||||||
|
|
||||||
controller = set_steal_first(controllers);
|
|
||||||
if (!controller)
|
|
||||||
break;
|
|
||||||
|
|
||||||
r = mount_legacy_cgroup_hierarchy("", controller, controller, !userns);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
/* When multiple hierarchies are co-mounted, make their
|
|
||||||
* constituting individual hierarchies a symlink to the
|
|
||||||
* co-mount.
|
|
||||||
*/
|
|
||||||
c = controller;
|
|
||||||
for (;;) {
|
|
||||||
_cleanup_free_ char *target = NULL, *tok = NULL;
|
|
||||||
|
|
||||||
r = extract_first_word(&c, &tok, ",", 0);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to extract co-mounted cgroup controller: %m");
|
|
||||||
if (r == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (streq(controller, tok))
|
|
||||||
break;
|
|
||||||
|
|
||||||
target = prefix_root("/sys/fs/cgroup/", tok);
|
|
||||||
if (!target)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
r = symlink_idempotent(controller, target);
|
|
||||||
if (r == -EINVAL)
|
|
||||||
return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
skip_controllers:
|
|
||||||
if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
|
|
||||||
r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = mount_legacy_cgroup_hierarchy("", SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (!userns)
|
|
||||||
return mount_verbose(LOG_ERR, NULL, cgroup_root, NULL,
|
|
||||||
MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Mount legacy cgroup hierarchy when cgroup namespaces are unsupported. */
|
|
||||||
static int mount_legacy_cgns_unsupported(
|
|
||||||
const char *dest,
|
|
||||||
CGroupUnified unified_requested,
|
|
||||||
bool userns,
|
|
||||||
uid_t uid_shift,
|
|
||||||
uid_t uid_range,
|
|
||||||
const char *selinux_apifs_context) {
|
|
||||||
|
|
||||||
_cleanup_set_free_free_ Set *controllers = NULL;
|
|
||||||
const char *cgroup_root;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
cgroup_root = prefix_roota(dest, "/sys/fs/cgroup");
|
|
||||||
|
|
||||||
(void) mkdir_p(cgroup_root, 0755);
|
|
||||||
|
|
||||||
/* Mount a tmpfs to /sys/fs/cgroup if it's not mounted there yet. */
|
|
||||||
r = path_is_mount_point(cgroup_root, dest, AT_SYMLINK_FOLLOW);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to determine if /sys/fs/cgroup is already mounted: %m");
|
|
||||||
if (r == 0) {
|
|
||||||
_cleanup_free_ char *options = NULL;
|
|
||||||
|
|
||||||
r = tmpfs_patch_options("mode=755", userns, uid_shift, uid_range, false, selinux_apifs_context, &options);
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
r = mount_verbose(LOG_ERR, "tmpfs", cgroup_root, "tmpfs",
|
|
||||||
MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, options);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = cg_all_unified();
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
if (r > 0)
|
|
||||||
goto skip_controllers;
|
|
||||||
|
|
||||||
r = cg_kernel_controllers(&controllers);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to determine cgroup controllers: %m");
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
_cleanup_free_ char *controller = NULL, *origin = NULL, *combined = NULL;
|
|
||||||
|
|
||||||
controller = set_steal_first(controllers);
|
|
||||||
if (!controller)
|
|
||||||
break;
|
|
||||||
|
|
||||||
origin = prefix_root("/sys/fs/cgroup/", controller);
|
|
||||||
if (!origin)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
r = readlink_malloc(origin, &combined);
|
|
||||||
if (r == -EINVAL) {
|
|
||||||
/* Not a symbolic link, but directly a single cgroup hierarchy */
|
|
||||||
|
|
||||||
r = mount_legacy_cgroup_hierarchy(dest, controller, controller, true);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
} else if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to read link %s: %m", origin);
|
|
||||||
else {
|
|
||||||
_cleanup_free_ char *target = NULL;
|
|
||||||
|
|
||||||
target = prefix_root(dest, origin);
|
|
||||||
if (!target)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
/* A symbolic link, a combination of controllers in one hierarchy */
|
|
||||||
|
|
||||||
if (!filename_is_valid(combined)) {
|
|
||||||
log_warning("Ignoring invalid combined hierarchy %s.", combined);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = mount_legacy_cgroup_hierarchy(dest, combined, combined, true);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = symlink_idempotent(combined, target);
|
|
||||||
if (r == -EINVAL)
|
|
||||||
return log_error_errno(r, "Invalid existing symlink for combined hierarchy: %m");
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to create symlink for combined hierarchy: %m");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
skip_controllers:
|
|
||||||
if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
|
|
||||||
r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_HYBRID, "unified", false);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = mount_legacy_cgroup_hierarchy(dest, SYSTEMD_CGROUP_CONTROLLER_LEGACY, "systemd", false);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
return mount_verbose(LOG_ERR, NULL, cgroup_root, NULL,
|
|
||||||
MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mount_unified_cgroups(const char *dest) {
|
|
||||||
const char *p;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(dest);
|
|
||||||
|
|
||||||
p = prefix_roota(dest, "/sys/fs/cgroup");
|
|
||||||
|
|
||||||
(void) mkdir_p(p, 0755);
|
|
||||||
|
|
||||||
r = path_is_mount_point(p, dest, AT_SYMLINK_FOLLOW);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to determine if %s is mounted already: %m", p);
|
|
||||||
if (r > 0) {
|
|
||||||
p = prefix_roota(dest, "/sys/fs/cgroup/cgroup.procs");
|
|
||||||
if (access(p, F_OK) >= 0)
|
|
||||||
return 0;
|
|
||||||
if (errno != ENOENT)
|
|
||||||
return log_error_errno(errno, "Failed to determine if mount point %s contains the unified cgroup hierarchy: %m", p);
|
|
||||||
|
|
||||||
log_error("%s is already mounted but not a unified cgroup hierarchy. Refusing.", p);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mount_verbose(LOG_ERR, "cgroup", p, "cgroup2", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int mount_cgroups(
|
|
||||||
const char *dest,
|
|
||||||
CGroupUnified unified_requested,
|
|
||||||
bool userns,
|
|
||||||
uid_t uid_shift,
|
|
||||||
uid_t uid_range,
|
|
||||||
const char *selinux_apifs_context,
|
|
||||||
bool use_cgns) {
|
|
||||||
|
|
||||||
if (unified_requested >= CGROUP_UNIFIED_ALL)
|
|
||||||
return mount_unified_cgroups(dest);
|
|
||||||
if (use_cgns)
|
|
||||||
return mount_legacy_cgns_supported(dest, unified_requested, userns, uid_shift, uid_range, selinux_apifs_context);
|
|
||||||
|
|
||||||
return mount_legacy_cgns_unsupported(dest, unified_requested, userns, uid_shift, uid_range, selinux_apifs_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mount_systemd_cgroup_writable_one(const char *root, const char *own) {
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(root);
|
|
||||||
assert(own);
|
|
||||||
|
|
||||||
/* Make our own cgroup a (writable) bind mount */
|
|
||||||
r = mount_verbose(LOG_ERR, own, own, NULL, MS_BIND, NULL);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
/* And then remount the systemd cgroup root read-only */
|
|
||||||
return mount_verbose(LOG_ERR, NULL, root, NULL,
|
|
||||||
MS_BIND|MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int mount_systemd_cgroup_writable(
|
|
||||||
const char *dest,
|
|
||||||
CGroupUnified unified_requested) {
|
|
||||||
|
|
||||||
_cleanup_free_ char *own_cgroup_path = NULL;
|
|
||||||
const char *root, *own;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(dest);
|
|
||||||
|
|
||||||
r = cg_pid_get_path(NULL, 0, &own_cgroup_path);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to determine our own cgroup path: %m");
|
|
||||||
|
|
||||||
/* If we are living in the top-level, then there's nothing to do... */
|
|
||||||
if (path_equal(own_cgroup_path, "/"))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (unified_requested >= CGROUP_UNIFIED_ALL) {
|
|
||||||
|
|
||||||
root = prefix_roota(dest, "/sys/fs/cgroup");
|
|
||||||
own = strjoina(root, own_cgroup_path);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (unified_requested >= CGROUP_UNIFIED_SYSTEMD) {
|
|
||||||
root = prefix_roota(dest, "/sys/fs/cgroup/unified");
|
|
||||||
own = strjoina(root, own_cgroup_path);
|
|
||||||
|
|
||||||
r = mount_systemd_cgroup_writable_one(root, own);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
root = prefix_roota(dest, "/sys/fs/cgroup/systemd");
|
|
||||||
own = strjoina(root, own_cgroup_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return mount_systemd_cgroup_writable_one(root, own);
|
|
||||||
}
|
|
||||||
|
|
||||||
int setup_volatile_state(
|
int setup_volatile_state(
|
||||||
const char *directory,
|
const char *directory,
|
||||||
VolatileMode mode,
|
VolatileMode mode,
|
||||||
@ -1301,7 +876,7 @@ int setup_volatile_state(
|
|||||||
return log_error_errno(errno, "Failed to create %s: %m", directory);
|
return log_error_errno(errno, "Failed to create %s: %m", directory);
|
||||||
|
|
||||||
options = "mode=755";
|
options = "mode=755";
|
||||||
r = tmpfs_patch_options(options, userns, uid_shift, uid_range, false, selinux_apifs_context, &buf);
|
r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
@ -1334,7 +909,7 @@ int setup_volatile(
|
|||||||
return log_error_errno(errno, "Failed to create temporary directory: %m");
|
return log_error_errno(errno, "Failed to create temporary directory: %m");
|
||||||
|
|
||||||
options = "mode=755";
|
options = "mode=755";
|
||||||
r = tmpfs_patch_options(options, userns, uid_shift, uid_range, false, selinux_apifs_context, &buf);
|
r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
|
@ -43,12 +43,9 @@ int bind_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only);
|
|||||||
int tmpfs_mount_parse(CustomMount **l, size_t *n, const char *s);
|
int tmpfs_mount_parse(CustomMount **l, size_t *n, const char *s);
|
||||||
int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only);
|
int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only);
|
||||||
|
|
||||||
int mount_all(const char *dest, MountSettingsMask mount_settings, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
|
int mount_all(const char *dest, MountSettingsMask mount_settings, uid_t uid_shift, const char *selinux_apifs_context);
|
||||||
int mount_sysfs(const char *dest, MountSettingsMask mount_settings);
|
int mount_sysfs(const char *dest, MountSettingsMask mount_settings);
|
||||||
|
|
||||||
int mount_cgroups(const char *dest, CGroupUnified unified_requested, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context, bool use_cgns);
|
|
||||||
int mount_systemd_cgroup_writable(const char *dest, CGroupUnified unified_requested);
|
|
||||||
|
|
||||||
int mount_custom(const char *dest, CustomMount *mounts, size_t n, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
|
int mount_custom(const char *dest, CustomMount *mounts, size_t n, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
|
||||||
|
|
||||||
int setup_volatile(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
|
int setup_volatile(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
|
||||||
@ -56,3 +53,5 @@ int setup_volatile_state(const char *directory, VolatileMode mode, bool userns,
|
|||||||
|
|
||||||
int pivot_root_parse(char **pivot_root_new, char **pivot_root_old, const char *s);
|
int pivot_root_parse(char **pivot_root_new, char **pivot_root_old, const char *s);
|
||||||
int setup_pivot_root(const char *directory, const char *pivot_root_new, const char *pivot_root_old);
|
int setup_pivot_root(const char *directory, const char *pivot_root_new, const char *pivot_root_old);
|
||||||
|
|
||||||
|
int tmpfs_patch_options(const char *options,uid_t uid_shift, const char *selinux_apifs_context, char **ret);
|
||||||
|
@ -2558,7 +2558,6 @@ static int inner_child(
|
|||||||
r = mount_all(NULL,
|
r = mount_all(NULL,
|
||||||
arg_mount_settings | MOUNT_IN_USERNS,
|
arg_mount_settings | MOUNT_IN_USERNS,
|
||||||
arg_uid_shift,
|
arg_uid_shift,
|
||||||
arg_uid_range,
|
|
||||||
arg_selinux_apifs_context);
|
arg_selinux_apifs_context);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -2990,7 +2989,6 @@ static int outer_child(
|
|||||||
r = mount_all(directory,
|
r = mount_all(directory,
|
||||||
arg_mount_settings,
|
arg_mount_settings,
|
||||||
arg_uid_shift,
|
arg_uid_shift,
|
||||||
arg_uid_range,
|
|
||||||
arg_selinux_apifs_context);
|
arg_selinux_apifs_context);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user