nspawn: cleanup and chown the synced cgroup hierarchy (#4223)
Fixes: #4181
This commit is contained in:
parent
c1a9199ec4
commit
f0bef277a4
|
@ -2514,6 +2514,20 @@ int cg_blkio_weight_parse(const char *s, uint64_t *ret) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_cgroup_fs(const struct statfs *s) {
|
||||||
|
return is_fs_type(s, CGROUP_SUPER_MAGIC) ||
|
||||||
|
is_fs_type(s, CGROUP2_SUPER_MAGIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fd_is_cgroup_fs(int fd) {
|
||||||
|
struct statfs s;
|
||||||
|
|
||||||
|
if (fstatfs(fd, &s) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
return is_cgroup_fs(&s);
|
||||||
|
}
|
||||||
|
|
||||||
static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
|
static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
|
||||||
[CGROUP_CONTROLLER_CPU] = "cpu",
|
[CGROUP_CONTROLLER_CPU] = "cpu",
|
||||||
[CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
|
[CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <sys/statfs.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "def.h"
|
#include "def.h"
|
||||||
|
@ -254,3 +255,6 @@ CGroupController cgroup_controller_from_string(const char *s) _pure_;
|
||||||
int cg_weight_parse(const char *s, uint64_t *ret);
|
int cg_weight_parse(const char *s, uint64_t *ret);
|
||||||
int cg_cpu_shares_parse(const char *s, uint64_t *ret);
|
int cg_cpu_shares_parse(const char *s, uint64_t *ret);
|
||||||
int cg_blkio_weight_parse(const char *s, uint64_t *ret);
|
int cg_blkio_weight_parse(const char *s, uint64_t *ret);
|
||||||
|
|
||||||
|
bool is_cgroup_fs(const struct statfs *s);
|
||||||
|
bool fd_is_cgroup_fs(int fd);
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "btrfs-util.h"
|
#include "btrfs-util.h"
|
||||||
|
#include "cgroup-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
@ -36,9 +37,14 @@
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
|
|
||||||
|
static bool is_physical_fs(const struct statfs *sfs) {
|
||||||
|
return !is_temporary_fs(sfs) && !is_cgroup_fs(sfs);
|
||||||
|
}
|
||||||
|
|
||||||
int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
|
int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
|
||||||
_cleanup_closedir_ DIR *d = NULL;
|
_cleanup_closedir_ DIR *d = NULL;
|
||||||
int ret = 0, r;
|
int ret = 0, r;
|
||||||
|
struct statfs sfs;
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
@ -47,13 +53,13 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
|
||||||
|
|
||||||
if (!(flags & REMOVE_PHYSICAL)) {
|
if (!(flags & REMOVE_PHYSICAL)) {
|
||||||
|
|
||||||
r = fd_is_temporary_fs(fd);
|
r = fstatfs(fd, &sfs);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
safe_close(fd);
|
safe_close(fd);
|
||||||
return r;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!r) {
|
if (is_physical_fs(&sfs)) {
|
||||||
/* We refuse to clean physical file systems
|
/* We refuse to clean physical file systems
|
||||||
* with this call, unless explicitly
|
* with this call, unless explicitly
|
||||||
* requested. This is extra paranoia just to
|
* requested. This is extra paranoia just to
|
||||||
|
@ -210,7 +216,7 @@ int rm_rf(const char *path, RemoveFlags flags) {
|
||||||
if (statfs(path, &s) < 0)
|
if (statfs(path, &s) < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
if (!is_temporary_fs(&s)) {
|
if (is_physical_fs(&s)) {
|
||||||
log_error("Attempted to remove disk file system, and we can't allow that.");
|
log_error("Attempted to remove disk file system, and we can't allow that.");
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,27 +25,18 @@
|
||||||
#include "mkdir.h"
|
#include "mkdir.h"
|
||||||
#include "mount-util.h"
|
#include "mount-util.h"
|
||||||
#include "nspawn-cgroup.h"
|
#include "nspawn-cgroup.h"
|
||||||
|
#include "rm-rf.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
int chown_cgroup(pid_t pid, uid_t uid_shift) {
|
static int chown_cgroup_path(const char *path, uid_t uid_shift) {
|
||||||
_cleanup_free_ char *path = NULL, *fs = NULL;
|
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
const char *fn;
|
const char *fn;
|
||||||
int r;
|
|
||||||
|
|
||||||
r = cg_pid_get_path(NULL, pid, &path);
|
fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to get container cgroup path: %m");
|
|
||||||
|
|
||||||
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, path, NULL, &fs);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to get file system path for container cgroup: %m");
|
|
||||||
|
|
||||||
fd = open(fs, O_RDONLY|O_CLOEXEC|O_DIRECTORY);
|
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return log_error_errno(errno, "Failed to open %s: %m", fs);
|
return -errno;
|
||||||
|
|
||||||
FOREACH_STRING(fn,
|
FOREACH_STRING(fn,
|
||||||
".",
|
".",
|
||||||
|
@ -63,7 +54,27 @@ int chown_cgroup(pid_t pid, uid_t uid_shift) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sync_cgroup(pid_t pid, CGroupUnified unified_requested) {
|
int chown_cgroup(pid_t pid, uid_t uid_shift) {
|
||||||
|
_cleanup_free_ char *path = NULL, *fs = NULL;
|
||||||
|
_cleanup_close_ int fd = -1;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = cg_pid_get_path(NULL, pid, &path);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to get container cgroup path: %m");
|
||||||
|
|
||||||
|
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, path, NULL, &fs);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to get file system path for container cgroup: %m");
|
||||||
|
|
||||||
|
r = chown_cgroup_path(fs, uid_shift);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to chown() cgroup %s: %m", fs);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t arg_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;
|
||||||
|
@ -101,14 +112,26 @@ int sync_cgroup(pid_t pid, CGroupUnified unified_requested) {
|
||||||
|
|
||||||
undo_mount = true;
|
undo_mount = true;
|
||||||
|
|
||||||
|
/* If nspawn dies abruptly the cgroup hierarchy created below
|
||||||
|
* its unit isn't cleaned up. So, let's remove it
|
||||||
|
* https://github.com/systemd/systemd/pull/4223#issuecomment-252519810 */
|
||||||
|
fn = strjoina(tree, cgroup);
|
||||||
|
(void) rm_rf(fn, REMOVE_ROOT|REMOVE_ONLY_DIRECTORIES);
|
||||||
|
|
||||||
fn = strjoina(tree, cgroup, "/cgroup.procs");
|
fn = strjoina(tree, cgroup, "/cgroup.procs");
|
||||||
(void) mkdir_parents(fn, 0755);
|
(void) mkdir_parents(fn, 0755);
|
||||||
|
|
||||||
sprintf(pid_string, PID_FMT, pid);
|
sprintf(pid_string, PID_FMT, pid);
|
||||||
r = write_string_file(fn, pid_string, 0);
|
r = write_string_file(fn, pid_string, 0);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to move process: %m");
|
log_error_errno(r, "Failed to move process: %m");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn = strjoina(tree, cgroup);
|
||||||
|
r = chown_cgroup_path(fn, arg_uid_shift);
|
||||||
|
if (r < 0)
|
||||||
|
log_error_errno(r, "Failed to chown() cgroup %s: %m", fn);
|
||||||
finish:
|
finish:
|
||||||
if (undo_mount)
|
if (undo_mount)
|
||||||
(void) umount_verbose(tree);
|
(void) umount_verbose(tree);
|
||||||
|
|
|
@ -25,5 +25,5 @@
|
||||||
#include "cgroup-util.h"
|
#include "cgroup-util.h"
|
||||||
|
|
||||||
int chown_cgroup(pid_t pid, uid_t uid_shift);
|
int chown_cgroup(pid_t pid, uid_t uid_shift);
|
||||||
int sync_cgroup(pid_t pid, CGroupUnified unified_requested);
|
int sync_cgroup(pid_t pid, CGroupUnified unified_requested, uid_t uid_shift);
|
||||||
int create_subcgroup(pid_t pid, CGroupUnified unified_requested);
|
int create_subcgroup(pid_t pid, CGroupUnified unified_requested);
|
||||||
|
|
|
@ -3879,7 +3879,7 @@ static int run(int master,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sync_cgroup(*pid, arg_unified_cgroup_hierarchy);
|
r = sync_cgroup(*pid, arg_unified_cgroup_hierarchy, arg_uid_shift);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "formats-util.h"
|
#include "formats-util.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
|
#include "stat-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "test-helper.h"
|
#include "test-helper.h"
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
|
@ -309,6 +310,28 @@ static void test_mask_supported(void) {
|
||||||
printf("'%s' is supported: %s\n", cgroup_controller_to_string(c), yes_no(m & CGROUP_CONTROLLER_TO_MASK(c)));
|
printf("'%s' is supported: %s\n", cgroup_controller_to_string(c), yes_no(m & CGROUP_CONTROLLER_TO_MASK(c)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_is_cgroup_fs(void) {
|
||||||
|
struct statfs sfs;
|
||||||
|
assert_se(statfs("/sys/fs/cgroup", &sfs) == 0);
|
||||||
|
if (is_temporary_fs(&sfs))
|
||||||
|
assert_se(statfs("/sys/fs/cgroup/systemd", &sfs) == 0);
|
||||||
|
assert_se(is_cgroup_fs(&sfs));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_fd_is_cgroup_fs(void) {
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = open("/sys/fs/cgroup", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
|
||||||
|
assert_se(fd >= 0);
|
||||||
|
if (fd_is_temporary_fs(fd)) {
|
||||||
|
fd = safe_close(fd);
|
||||||
|
fd = open("/sys/fs/cgroup/systemd", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
|
||||||
|
assert_se(fd >= 0);
|
||||||
|
}
|
||||||
|
assert_se(fd_is_cgroup_fs(fd));
|
||||||
|
fd = safe_close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
test_path_decode_unit();
|
test_path_decode_unit();
|
||||||
test_path_get_unit();
|
test_path_get_unit();
|
||||||
|
@ -324,6 +347,8 @@ int main(void) {
|
||||||
test_slice_to_path();
|
test_slice_to_path();
|
||||||
test_shift_path();
|
test_shift_path();
|
||||||
TEST_REQ_RUNNING_SYSTEMD(test_mask_supported());
|
TEST_REQ_RUNNING_SYSTEMD(test_mask_supported());
|
||||||
|
TEST_REQ_RUNNING_SYSTEMD(test_is_cgroup_fs());
|
||||||
|
TEST_REQ_RUNNING_SYSTEMD(test_fd_is_cgroup_fs());
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue