1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-03-08 20:58:20 +03:00

Merge pull request #4594 from endocode/djalal/fix-rootdir-apply-mntns

core: make RootDirectory= and ProtectKernelModules= work
This commit is contained in:
Evgeny Vereshchagin 2016-11-08 01:53:21 +03:00 committed by GitHub
commit 453a9c7834

View File

@ -58,8 +58,7 @@ typedef enum MountMode {
} MountMode;
typedef struct BindMount {
const char *path; /* stack memory, doesn't need to be freed explicitly */
char *chased; /* malloc()ed memory, needs to be freed */
char *path;
MountMode mode;
bool ignore; /* Ignore if path does not exist */
} BindMount;
@ -155,10 +154,23 @@ static const TargetMount protect_system_strict_table[] = {
{ "/root", READWRITE, true }, /* ProtectHome= */
};
static void set_bind_mount(BindMount **p, const char *path, MountMode mode, bool ignore) {
(*p)->path = path;
(*p)->mode = mode;
(*p)->ignore = ignore;
static void set_bind_mount(BindMount *p, char *path, MountMode mode, bool ignore) {
p->path = path;
p->mode = mode;
p->ignore = ignore;
}
static int append_one_mount(BindMount **p, const char *root_directory,
const char *path, MountMode mode, bool ignore) {
char *lpath;
assert(p);
lpath = prefix_root(root_directory, path);
if (!lpath)
return -ENOMEM;
set_bind_mount((*p)++, lpath, mode, ignore);
return 0;
}
static int append_mounts(BindMount **p, char **strv, MountMode mode) {
@ -168,6 +180,7 @@ static int append_mounts(BindMount **p, char **strv, MountMode mode) {
STRV_FOREACH(i, strv) {
bool ignore = false;
char *path;
if (IN_SET(mode, INACCESSIBLE, READONLY, READWRITE) && startswith(*i, "-")) {
(*i)++;
@ -177,8 +190,11 @@ static int append_mounts(BindMount **p, char **strv, MountMode mode) {
if (!path_is_absolute(*i))
return -EINVAL;
set_bind_mount(p, *i, mode, ignore);
(*p)++;
path = strdup(*i);
if (!path)
return -ENOMEM;
set_bind_mount((*p)++, path, mode, ignore);
}
return 0;
@ -196,13 +212,16 @@ static int append_target_mounts(BindMount **p, const char *root_directory, const
* declaration we do not support "-" at the beginning.
*/
const TargetMount *m = &mounts[i];
const char *path = prefix_roota(root_directory, m->path);
char *path;
path = prefix_root(root_directory, m->path);
if (!path)
return -ENOMEM;
if (!path_is_absolute(path))
return -EINVAL;
set_bind_mount(p, path, m->mode, m->ignore);
(*p)++;
set_bind_mount((*p)++, path, m->mode, m->ignore);
}
return 0;
@ -309,6 +328,7 @@ static void drop_duplicates(BindMount *m, unsigned *n) {
* above. */
if (previous && path_equal(f->path, previous->path)) {
log_debug("%s is duplicate.", f->path);
f->path = mfree(f->path);
continue;
}
@ -336,6 +356,7 @@ static void drop_inaccessible(BindMount *m, unsigned *n) {
* it, as inaccessible paths really should drop the entire subtree. */
if (clear && path_startswith(f->path, clear)) {
log_debug("%s is masked by %s.", f->path, clear);
f->path = mfree(f->path);
continue;
}
@ -375,6 +396,7 @@ static void drop_nop(BindMount *m, unsigned *n) {
/* We found it, let's see if it's the same mode, if so, we can drop this entry */
if (found && p->mode == f->mode) {
log_debug("%s is redundant by %s", f->path, p->path);
f->path = mfree(f->path);
continue;
}
}
@ -401,6 +423,7 @@ static void drop_outside_root(const char *root_directory, BindMount *m, unsigned
if (!path_startswith(f->path, root_directory)) {
log_debug("%s is outside of root directory.", f->path);
f->path = mfree(f->path);
continue;
}
@ -652,18 +675,22 @@ static int chase_all_symlinks(const char *root_directory, BindMount *m, unsigned
* can't resolve the path, and which have been marked for such removal. */
for (f = m, t = m; f < m + *n; f++) {
_cleanup_free_ char *chased = NULL;
r = chase_symlinks(f->path, root_directory, &f->chased);
if (r == -ENOENT && f->ignore) /* Doesn't exist? Then remove it! */
r = chase_symlinks(f->path, root_directory, &chased);
if (r == -ENOENT && f->ignore) {
/* Doesn't exist? Then remove it! */
f->path = mfree(f->path);
continue;
}
if (r < 0)
return log_debug_errno(r, "Failed to chase symlinks for %s: %m", f->path);
if (path_equal(f->path, f->chased))
f->chased = mfree(f->chased);
else {
log_debug("Chased %s → %s", f->path, f->chased);
f->path = f->chased;
if (!path_equal(f->path, chased)) {
log_debug("Chased %s → %s", f->path, chased);
r = free_and_replace(f->path, chased);
if (r < 0)
return r;
}
*t = *f;
@ -724,13 +751,13 @@ int setup_namespace(
BindMount *m, *mounts = NULL;
bool make_slave = false;
unsigned n;
unsigned n_mounts;
int r = 0;
if (mount_flags == 0)
mount_flags = MS_SHARED;
n = namespace_calculate_mounts(ns_info,
n_mounts = namespace_calculate_mounts(ns_info,
read_write_paths,
read_only_paths,
inaccessible_paths,
@ -738,82 +765,82 @@ int setup_namespace(
protect_home, protect_system);
/* Set mount slave mode */
if (root_directory || n > 0)
if (root_directory || n_mounts > 0)
make_slave = true;
if (n > 0) {
m = mounts = (BindMount *) alloca0(n * sizeof(BindMount));
if (n_mounts > 0) {
m = mounts = (BindMount *) alloca0(n_mounts * sizeof(BindMount));
r = append_mounts(&m, read_write_paths, READWRITE);
if (r < 0)
return r;
goto finish;
r = append_mounts(&m, read_only_paths, READONLY);
if (r < 0)
return r;
goto finish;
r = append_mounts(&m, inaccessible_paths, INACCESSIBLE);
if (r < 0)
return r;
goto finish;
if (tmp_dir) {
m->path = prefix_roota(root_directory, "/tmp");
m->mode = PRIVATE_TMP;
m++;
r = append_one_mount(&m, root_directory, "/tmp", PRIVATE_TMP, false);
if (r < 0)
goto finish;
}
if (var_tmp_dir) {
m->path = prefix_roota(root_directory, "/var/tmp");
m->mode = PRIVATE_VAR_TMP;
m++;
r = append_one_mount(&m, root_directory, "/var/tmp", PRIVATE_VAR_TMP, false);
if (r < 0)
goto finish;
}
if (ns_info->private_dev) {
m->path = prefix_roota(root_directory, "/dev");
m->mode = PRIVATE_DEV;
m++;
r = append_one_mount(&m, root_directory, "/dev", PRIVATE_DEV, false);
if (r < 0)
goto finish;
}
if (ns_info->protect_kernel_tunables) {
r = append_protect_kernel_tunables(&m, root_directory);
if (r < 0)
return r;
goto finish;
}
if (ns_info->protect_kernel_modules) {
r = append_protect_kernel_modules(&m, root_directory);
if (r < 0)
return r;
goto finish;
}
if (ns_info->protect_control_groups) {
m->path = prefix_roota(root_directory, "/sys/fs/cgroup");
m->mode = READONLY;
m++;
r = append_one_mount(&m, root_directory, "/sys/fs/cgroup", READONLY, false);
if (r < 0)
goto finish;
}
r = append_protect_home(&m, root_directory, protect_home);
if (r < 0)
return r;
goto finish;
r = append_protect_system(&m, root_directory, protect_system);
if (r < 0)
return r;
goto finish;
assert(mounts + n == m);
assert(mounts + n_mounts == m);
/* Resolve symlinks manually first, as mount() will always follow them relative to the host's
* root. Moreover we want to suppress duplicates based on the resolved paths. This of course is a bit
* racy. */
r = chase_all_symlinks(root_directory, mounts, &n);
r = chase_all_symlinks(root_directory, mounts, &n_mounts);
if (r < 0)
goto finish;
qsort(mounts, n, sizeof(BindMount), mount_path_compare);
qsort(mounts, n_mounts, sizeof(BindMount), mount_path_compare);
drop_duplicates(mounts, &n);
drop_outside_root(root_directory, mounts, &n);
drop_inaccessible(mounts, &n);
drop_nop(mounts, &n);
drop_duplicates(mounts, &n_mounts);
drop_outside_root(root_directory, mounts, &n_mounts);
drop_inaccessible(mounts, &n_mounts);
drop_nop(mounts, &n_mounts);
}
if (unshare(CLONE_NEWNS) < 0) {
@ -843,25 +870,25 @@ int setup_namespace(
}
}
if (n > 0) {
if (n_mounts > 0) {
char **blacklist;
unsigned j;
/* First round, add in all special mounts we need */
for (m = mounts; m < mounts + n; ++m) {
for (m = mounts; m < mounts + n_mounts; ++m) {
r = apply_mount(m, tmp_dir, var_tmp_dir);
if (r < 0)
goto finish;
}
/* Create a blacklist we can pass to bind_mount_recursive() */
blacklist = newa(char*, n+1);
for (j = 0; j < n; j++)
blacklist = newa(char*, n_mounts+1);
for (j = 0; j < n_mounts; j++)
blacklist[j] = (char*) mounts[j].path;
blacklist[j] = NULL;
/* Second round, flip the ro bits if necessary. */
for (m = mounts; m < mounts + n; ++m) {
for (m = mounts; m < mounts + n_mounts; ++m) {
r = make_read_only(m, blacklist);
if (r < 0)
goto finish;
@ -886,8 +913,8 @@ int setup_namespace(
r = 0;
finish:
for (m = mounts; m < mounts + n; m++)
free(m->chased);
for (m = mounts; m < mounts + n_mounts; m++)
free(m->path);
return r;
}