summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/namespace.c44
-rw-r--r--src/test/test-ns.c4
2 files changed, 43 insertions, 5 deletions
diff --git a/src/core/namespace.c b/src/core/namespace.c
index f2768aeb28..102fe576f3 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -116,16 +116,47 @@ static void drop_duplicates(BindMount *m, unsigned *n) {
assert(m);
assert(n);
+ /* Drops duplicate entries. Expects that the array is properly ordered already. */
+
for (f = m, t = m, previous = NULL; f < m+*n; f++) {
- /* The first one wins */
- if (previous && path_equal(f->path, previous->path))
+ /* The first one wins (which is the one with the more restrictive mode), see mount_path_compare()
+ * above. */
+ if (previous && path_equal(f->path, previous->path)) {
+ log_debug("%s is duplicate.", f->path);
continue;
+ }
*t = *f;
-
previous = t;
+ t++;
+ }
+
+ *n = t - m;
+}
+
+static void drop_inaccessible(BindMount *m, unsigned *n) {
+ BindMount *f, *t;
+ const char *clear = NULL;
+
+ assert(m);
+ assert(n);
+
+ /* Drops all entries obstructed by another entry further up the tree. Expects that the array is properly
+ * ordered already. */
+
+ for (f = m, t = m; f < m+*n; f++) {
+
+ /* If we found a path set for INACCESSIBLE earlier, and this entry has it as prefix we should drop
+ * 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);
+ continue;
+ }
+ clear = f->mode == INACCESSIBLE ? f->path : NULL;
+
+ *t = *f;
t++;
}
@@ -282,6 +313,8 @@ static int apply_mount(
assert(m);
+ log_debug("Applying namespace mount on %s", m->path);
+
switch (m->mode) {
case INACCESSIBLE:
@@ -289,7 +322,7 @@ static int apply_mount(
/* First, get rid of everything that is below if there
* is anything... Then, overmount it with an
* inaccessible path. */
- umount_recursive(m->path, 0);
+ (void) umount_recursive(m->path, 0);
if (lstat(m->path, &target) < 0) {
if (m->ignore && errno == ENOENT)
@@ -303,6 +336,7 @@ static int apply_mount(
return -ELOOP;
}
break;
+
case READONLY:
case READWRITE:
/* Nothing to mount here, we just later toggle the
@@ -480,7 +514,9 @@ int setup_namespace(
assert(mounts + n == m);
qsort(mounts, n, sizeof(BindMount), mount_path_compare);
+
drop_duplicates(mounts, &n);
+ drop_inaccessible(mounts, &n);
}
if (n > 0 || root_directory) {
diff --git a/src/test/test-ns.c b/src/test/test-ns.c
index 05f243c75c..03a24620af 100644
--- a/src/test/test-ns.c
+++ b/src/test/test-ns.c
@@ -26,6 +26,7 @@
int main(int argc, char *argv[]) {
const char * const writable[] = {
"/home",
+ "/home/lennart/projects/foobar", /* this should be masked automatically */
NULL
};
@@ -42,11 +43,12 @@ int main(int argc, char *argv[]) {
};
char *root_directory;
char *projects_directory;
-
int r;
char tmp_dir[] = "/tmp/systemd-private-XXXXXX",
var_tmp_dir[] = "/var/tmp/systemd-private-XXXXXX";
+ log_set_max_level(LOG_DEBUG);
+
assert_se(mkdtemp(tmp_dir));
assert_se(mkdtemp(var_tmp_dir));