summaryrefslogtreecommitdiff
path: root/src/core/namespace.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/namespace.c')
-rw-r--r--src/core/namespace.c360
1 files changed, 228 insertions, 132 deletions
diff --git a/src/core/namespace.c b/src/core/namespace.c
index aca47a4d2f..834883267c 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -50,6 +50,8 @@
typedef enum MountMode {
/* This is ordered by priority! */
INACCESSIBLE,
+ BIND_MOUNT,
+ BIND_MOUNT_RECURSIVE,
READONLY,
PRIVATE_TMP,
PRIVATE_VAR_TMP,
@@ -57,13 +59,16 @@ typedef enum MountMode {
READWRITE,
} MountMode;
-typedef struct BindMount {
+typedef struct MountEntry {
const char *path_const; /* Memory allocated on stack or static */
- MountMode mode:6;
+ MountMode mode:5;
bool ignore:1; /* Ignore if path does not exist? */
bool has_prefix:1; /* Already is prefixed by the root dir? */
+ bool read_only:1; /* Shall this mount point be read-only? */
char *path_malloc; /* Use this instead of 'path' if we had to allocate memory */
-} BindMount;
+ const char *source_const; /* The source path, for bind mounts */
+ char *source_malloc;
+} MountEntry;
/*
* The following Protect tables are to protect paths and mark some of them
@@ -74,7 +79,7 @@ typedef struct BindMount {
*/
/* ProtectKernelTunables= option and the related filesystem APIs */
-static const BindMount protect_kernel_tunables_table[] = {
+static const MountEntry protect_kernel_tunables_table[] = {
{ "/proc/sys", READONLY, false },
{ "/proc/sysrq-trigger", READONLY, true },
{ "/proc/latency_stats", READONLY, true },
@@ -93,7 +98,7 @@ static const BindMount protect_kernel_tunables_table[] = {
};
/* ProtectKernelModules= option */
-static const BindMount protect_kernel_modules_table[] = {
+static const MountEntry protect_kernel_modules_table[] = {
#ifdef HAVE_SPLIT_USR
{ "/lib/modules", INACCESSIBLE, true },
#endif
@@ -104,28 +109,28 @@ static const BindMount protect_kernel_modules_table[] = {
* ProtectHome=read-only table, protect $HOME and $XDG_RUNTIME_DIR and rest of
* system should be protected by ProtectSystem=
*/
-static const BindMount protect_home_read_only_table[] = {
+static const MountEntry protect_home_read_only_table[] = {
{ "/home", READONLY, true },
{ "/run/user", READONLY, true },
{ "/root", READONLY, true },
};
/* ProtectHome=yes table */
-static const BindMount protect_home_yes_table[] = {
+static const MountEntry protect_home_yes_table[] = {
{ "/home", INACCESSIBLE, true },
{ "/run/user", INACCESSIBLE, true },
{ "/root", INACCESSIBLE, true },
};
/* ProtectSystem=yes table */
-static const BindMount protect_system_yes_table[] = {
+static const MountEntry protect_system_yes_table[] = {
{ "/usr", READONLY, false },
{ "/boot", READONLY, true },
{ "/efi", READONLY, true },
};
/* ProtectSystem=full includes ProtectSystem=yes */
-static const BindMount protect_system_full_table[] = {
+static const MountEntry protect_system_full_table[] = {
{ "/usr", READONLY, false },
{ "/boot", READONLY, true },
{ "/efi", READONLY, true },
@@ -140,17 +145,17 @@ static const BindMount protect_system_full_table[] = {
* (And of course /home and friends are also left writable, as ProtectHome=
* shall manage those, orthogonally).
*/
-static const BindMount protect_system_strict_table[] = {
- { "/", READONLY, false },
- { "/proc", READWRITE, false }, /* ProtectKernelTunables= */
- { "/sys", READWRITE, false }, /* ProtectKernelTunables= */
- { "/dev", READWRITE, false }, /* PrivateDevices= */
- { "/home", READWRITE, true }, /* ProtectHome= */
- { "/run/user", READWRITE, true }, /* ProtectHome= */
- { "/root", READWRITE, true }, /* ProtectHome= */
+static const MountEntry protect_system_strict_table[] = {
+ { "/", READONLY, false },
+ { "/proc", READWRITE, false }, /* ProtectKernelTunables= */
+ { "/sys", READWRITE, false }, /* ProtectKernelTunables= */
+ { "/dev", READWRITE, false }, /* PrivateDevices= */
+ { "/home", READWRITE, true }, /* ProtectHome= */
+ { "/run/user", READWRITE, true }, /* ProtectHome= */
+ { "/root", READWRITE, true }, /* ProtectHome= */
};
-static const char *bind_mount_path(const BindMount *p) {
+static const char *mount_entry_path(const MountEntry *p) {
assert(p);
/* Returns the path of this bind mount. If the malloc()-allocated ->path_buffer field is set we return that,
@@ -159,7 +164,19 @@ static const char *bind_mount_path(const BindMount *p) {
return p->path_malloc ?: p->path_const;
}
-static int append_access_mounts(BindMount **p, char **strv, MountMode mode) {
+static bool mount_entry_read_only(const MountEntry *p) {
+ assert(p);
+
+ return p->read_only || IN_SET(p->mode, READONLY, INACCESSIBLE);
+}
+
+static const char *mount_entry_source(const MountEntry *p) {
+ assert(p);
+
+ return p->source_malloc ?: p->source_const;
+}
+
+static int append_access_mounts(MountEntry **p, char **strv, MountMode mode) {
char **i;
assert(p);
@@ -183,7 +200,7 @@ static int append_access_mounts(BindMount **p, char **strv, MountMode mode) {
if (!path_is_absolute(e))
return -EINVAL;
- *((*p)++) = (BindMount) {
+ *((*p)++) = (MountEntry) {
.path_const = e,
.mode = mode,
.ignore = ignore,
@@ -194,7 +211,26 @@ static int append_access_mounts(BindMount **p, char **strv, MountMode mode) {
return 0;
}
-static int append_static_mounts(BindMount **p, const BindMount *mounts, unsigned n, bool ignore_protect) {
+static int append_bind_mounts(MountEntry **p, const BindMount *binds, unsigned n) {
+ unsigned i;
+
+ assert(p);
+
+ for (i = 0; i < n; i++) {
+ const BindMount *b = binds + i;
+
+ *((*p)++) = (MountEntry) {
+ .path_const = b->destination,
+ .mode = b->recursive ? BIND_MOUNT_RECURSIVE : BIND_MOUNT,
+ .read_only = b->read_only,
+ .source_const = b->source,
+ };
+ }
+
+ return 0;
+}
+
+static int append_static_mounts(MountEntry **p, const MountEntry *mounts, unsigned n, bool ignore_protect) {
unsigned i;
assert(p);
@@ -203,8 +239,8 @@ static int append_static_mounts(BindMount **p, const BindMount *mounts, unsigned
/* Adds a list of static pre-defined entries */
for (i = 0; i < n; i++)
- *((*p)++) = (BindMount) {
- .path_const = bind_mount_path(mounts+i),
+ *((*p)++) = (MountEntry) {
+ .path_const = mount_entry_path(mounts+i),
.mode = mounts[i].mode,
.ignore = mounts[i].ignore || ignore_protect,
};
@@ -212,7 +248,7 @@ static int append_static_mounts(BindMount **p, const BindMount *mounts, unsigned
return 0;
}
-static int append_protect_home(BindMount **p, ProtectHome protect_home, bool ignore_protect) {
+static int append_protect_home(MountEntry **p, ProtectHome protect_home, bool ignore_protect) {
assert(p);
switch (protect_home) {
@@ -231,7 +267,7 @@ static int append_protect_home(BindMount **p, ProtectHome protect_home, bool ign
}
}
-static int append_protect_system(BindMount **p, ProtectSystem protect_system, bool ignore_protect) {
+static int append_protect_system(MountEntry **p, ProtectSystem protect_system, bool ignore_protect) {
assert(p);
switch (protect_system) {
@@ -254,11 +290,11 @@ static int append_protect_system(BindMount **p, ProtectSystem protect_system, bo
}
static int mount_path_compare(const void *a, const void *b) {
- const BindMount *p = a, *q = b;
+ const MountEntry *p = a, *q = b;
int d;
/* If the paths are not equal, then order prefixes first */
- d = path_compare(bind_mount_path(p), bind_mount_path(q));
+ d = path_compare(mount_entry_path(p), mount_entry_path(q));
if (d != 0)
return d;
@@ -272,7 +308,7 @@ static int mount_path_compare(const void *a, const void *b) {
return 0;
}
-static int prefix_where_needed(BindMount *m, unsigned n, const char *root_directory) {
+static int prefix_where_needed(MountEntry *m, unsigned n, const char *root_directory) {
unsigned i;
/* Prefixes all paths in the bind mount table with the root directory if it is specified and the entry needs
@@ -287,7 +323,7 @@ static int prefix_where_needed(BindMount *m, unsigned n, const char *root_direct
if (m[i].has_prefix)
continue;
- s = prefix_root(root_directory, bind_mount_path(m+i));
+ s = prefix_root(root_directory, mount_entry_path(m+i));
if (!s)
return -ENOMEM;
@@ -300,8 +336,8 @@ static int prefix_where_needed(BindMount *m, unsigned n, const char *root_direct
return 0;
}
-static void drop_duplicates(BindMount *m, unsigned *n) {
- BindMount *f, *t, *previous;
+static void drop_duplicates(MountEntry *m, unsigned *n) {
+ MountEntry *f, *t, *previous;
assert(m);
assert(n);
@@ -312,8 +348,9 @@ static void drop_duplicates(BindMount *m, unsigned *n) {
/* The first one wins (which is the one with the more restrictive mode), see mount_path_compare()
* above. */
- if (previous && path_equal(bind_mount_path(f), bind_mount_path(previous))) {
- log_debug("%s is duplicate.", bind_mount_path(f));
+ if (previous && path_equal(mount_entry_path(f), mount_entry_path(previous))) {
+ log_debug("%s is duplicate.", mount_entry_path(f));
+ previous->read_only = previous->read_only || mount_entry_read_only(f); /* Propagate the read-only flag to the remaining entry */
f->path_malloc = mfree(f->path_malloc);
continue;
}
@@ -326,8 +363,8 @@ static void drop_duplicates(BindMount *m, unsigned *n) {
*n = t - m;
}
-static void drop_inaccessible(BindMount *m, unsigned *n) {
- BindMount *f, *t;
+static void drop_inaccessible(MountEntry *m, unsigned *n) {
+ MountEntry *f, *t;
const char *clear = NULL;
assert(m);
@@ -340,13 +377,13 @@ static void drop_inaccessible(BindMount *m, unsigned *n) {
/* 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(bind_mount_path(f), clear)) {
- log_debug("%s is masked by %s.", bind_mount_path(f), clear);
+ if (clear && path_startswith(mount_entry_path(f), clear)) {
+ log_debug("%s is masked by %s.", mount_entry_path(f), clear);
f->path_malloc = mfree(f->path_malloc);
continue;
}
- clear = f->mode == INACCESSIBLE ? bind_mount_path(f) : NULL;
+ clear = f->mode == INACCESSIBLE ? mount_entry_path(f) : NULL;
*t = *f;
t++;
@@ -355,8 +392,8 @@ static void drop_inaccessible(BindMount *m, unsigned *n) {
*n = t - m;
}
-static void drop_nop(BindMount *m, unsigned *n) {
- BindMount *f, *t;
+static void drop_nop(MountEntry *m, unsigned *n) {
+ MountEntry *f, *t;
assert(m);
assert(n);
@@ -368,12 +405,12 @@ static void drop_nop(BindMount *m, unsigned *n) {
/* Only suppress such subtrees for READONLY and READWRITE entries */
if (IN_SET(f->mode, READONLY, READWRITE)) {
- BindMount *p;
+ MountEntry *p;
bool found = false;
/* Now let's find the first parent of the entry we are looking at. */
for (p = t-1; p >= m; p--) {
- if (path_startswith(bind_mount_path(f), bind_mount_path(p))) {
+ if (path_startswith(mount_entry_path(f), mount_entry_path(p))) {
found = true;
break;
}
@@ -381,7 +418,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", bind_mount_path(f), bind_mount_path(p));
+ log_debug("%s is redundant by %s", mount_entry_path(f), mount_entry_path(p));
f->path_malloc = mfree(f->path_malloc);
continue;
}
@@ -394,8 +431,8 @@ static void drop_nop(BindMount *m, unsigned *n) {
*n = t - m;
}
-static void drop_outside_root(const char *root_directory, BindMount *m, unsigned *n) {
- BindMount *f, *t;
+static void drop_outside_root(const char *root_directory, MountEntry *m, unsigned *n) {
+ MountEntry *f, *t;
assert(m);
assert(n);
@@ -408,8 +445,8 @@ static void drop_outside_root(const char *root_directory, BindMount *m, unsigned
for (f = m, t = m; f < m + *n; f++) {
- if (!path_startswith(bind_mount_path(f), root_directory)) {
- log_debug("%s is outside of root directory.", bind_mount_path(f));
+ if (!path_startswith(mount_entry_path(f), root_directory)) {
+ log_debug("%s is outside of root directory.", mount_entry_path(f));
f->path_malloc = mfree(f->path_malloc);
continue;
}
@@ -421,7 +458,7 @@ static void drop_outside_root(const char *root_directory, BindMount *m, unsigned
*n = t - m;
}
-static int mount_dev(BindMount *m) {
+static int mount_dev(MountEntry *m) {
static const char devnodes[] =
"/dev/null\0"
"/dev/zero\0"
@@ -526,11 +563,11 @@ static int mount_dev(BindMount *m) {
* missing when the service is started with RootDirectory. This is
* consistent with mount units creating the mount points when missing.
*/
- (void) mkdir_p_label(bind_mount_path(m), 0755);
+ (void) mkdir_p_label(mount_entry_path(m), 0755);
/* Unmount everything in old /dev */
- umount_recursive(bind_mount_path(m), 0);
- if (mount(dev, bind_mount_path(m), NULL, MS_MOVE, NULL) < 0) {
+ umount_recursive(mount_entry_path(m), 0);
+ if (mount(dev, mount_entry_path(m), NULL, MS_MOVE, NULL) < 0) {
r = -errno;
goto fail;
}
@@ -560,17 +597,54 @@ fail:
return r;
}
+static int mount_entry_chase(
+ const char *root_directory,
+ MountEntry *m,
+ const char *path,
+ char **location) {
+
+ char *chased;
+ int r;
+
+ assert(m);
+
+ /* Since mount() will always follow symlinks and we need to take the different root directory into account we
+ * chase the symlinks on our own first. This is called for the destination path, as well as the source path (if
+ * that applies). The result is stored in "location". */
+
+ r = chase_symlinks(path, root_directory, 0, &chased);
+ if (r == -ENOENT && m->ignore) {
+ log_debug_errno(r, "Path %s does not exist, ignoring.", path);
+ return 0;
+ }
+ if (r < 0)
+ return log_debug_errno(r, "Failed to follow symlinks on %s: %m", path);
+
+ log_debug("Followed symlinks %s → %s.", path, chased);
+
+ free(*location);
+ *location = chased;
+
+ return 1;
+}
+
static int apply_mount(
- BindMount *m,
+ const char *root_directory,
+ MountEntry *m,
const char *tmp_dir,
const char *var_tmp_dir) {
const char *what;
+ bool rbind = true;
int r;
assert(m);
- log_debug("Applying namespace mount on %s", bind_mount_path(m));
+ r = mount_entry_chase(root_directory, m, mount_entry_path(m), &m->path_malloc);
+ if (r <= 0)
+ return r;
+
+ log_debug("Applying namespace mount on %s", mount_entry_path(m));
switch (m->mode) {
@@ -580,10 +654,10 @@ static int apply_mount(
/* First, get rid of everything that is below if there
* is anything... Then, overmount it with an
* inaccessible path. */
- (void) umount_recursive(bind_mount_path(m), 0);
+ (void) umount_recursive(mount_entry_path(m), 0);
- if (lstat(bind_mount_path(m), &target) < 0)
- return log_debug_errno(errno, "Failed to lstat() %s to determine what to mount over it: %m", bind_mount_path(m));
+ if (lstat(mount_entry_path(m), &target) < 0)
+ return log_debug_errno(errno, "Failed to lstat() %s to determine what to mount over it: %m", mount_entry_path(m));
what = mode_to_inaccessible_node(target.st_mode);
if (!what) {
@@ -595,14 +669,26 @@ static int apply_mount(
case READONLY:
case READWRITE:
-
- r = path_is_mount_point(bind_mount_path(m), NULL, 0);
+ r = path_is_mount_point(mount_entry_path(m), root_directory, 0);
if (r < 0)
- return log_debug_errno(r, "Failed to determine whether %s is already a mount point: %m", bind_mount_path(m));
+ return log_debug_errno(r, "Failed to determine whether %s is already a mount point: %m", mount_entry_path(m));
if (r > 0) /* Nothing to do here, it is already a mount. We just later toggle the MS_RDONLY bit for the mount point if needed. */
return 0;
/* This isn't a mount point yet, let's make it one. */
- what = bind_mount_path(m);
+ what = mount_entry_path(m);
+ break;
+
+ case BIND_MOUNT:
+ rbind = false;
+ /* fallthrough */
+
+ case BIND_MOUNT_RECURSIVE:
+ /* Also chase the source mount */
+ r = mount_entry_chase(root_directory, m, mount_entry_source(m), &m->source_malloc);
+ if (r <= 0)
+ return r;
+
+ what = mount_entry_source(m);
break;
case PRIVATE_TMP:
@@ -622,22 +708,22 @@ static int apply_mount(
assert(what);
- if (mount(what, bind_mount_path(m), NULL, MS_BIND|MS_REC, NULL) < 0)
- return log_debug_errno(errno, "Failed to mount %s to %s: %m", what, bind_mount_path(m));
+ if (mount(what, mount_entry_path(m), NULL, MS_BIND|(rbind ? MS_REC : 0), NULL) < 0)
+ return log_debug_errno(errno, "Failed to mount %s to %s: %m", what, mount_entry_path(m));
- log_debug("Successfully mounted %s to %s", what, bind_mount_path(m));
+ log_debug("Successfully mounted %s to %s", what, mount_entry_path(m));
return 0;
}
-static int make_read_only(BindMount *m, char **blacklist) {
+static int make_read_only(MountEntry *m, char **blacklist) {
int r = 0;
assert(m);
- if (IN_SET(m->mode, INACCESSIBLE, READONLY))
- r = bind_remount_recursive(bind_mount_path(m), true, blacklist);
+ if (mount_entry_read_only(m))
+ r = bind_remount_recursive(mount_entry_path(m), true, blacklist);
else if (m->mode == PRIVATE_DEV) { /* Can be readonly but the submounts can't*/
- if (mount(NULL, bind_mount_path(m), NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL) < 0)
+ if (mount(NULL, mount_entry_path(m), NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL) < 0)
r = -errno;
} else
return 0;
@@ -646,50 +732,9 @@ static int make_read_only(BindMount *m, char **blacklist) {
* already stays this way. This improves compatibility with container managers, where we won't attempt to undo
* read-only mounts already applied. */
- return r;
-}
-
-/* Chase symlinks and remove failed paths from mounts */
-static int chase_all_symlinks(const char *root_directory, BindMount *m, unsigned *n) {
- BindMount *f, *t;
- int r = 0;
-
- assert(m);
- assert(n);
-
- /* Since mount() will always follow symlinks and we need to take the different root directory into account we
- * chase the symlinks on our own first. This call wil do so for all entries and remove all entries where we
- * 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;
- int k;
-
- k = chase_symlinks(bind_mount_path(f), root_directory, 0, &chased);
- if (k < 0) {
- /* Get only real errors */
- if (r >= 0 && (k != -ENOENT || !f->ignore))
- r = k;
-
- /* Doesn't exist or failed? Then remove it and continue! */
- log_debug_errno(k, "Failed to chase symlinks for %s: %m", bind_mount_path(f));
- f->path_malloc = mfree(f->path_malloc);
- continue;
- }
-
- if (!path_equal(bind_mount_path(f), chased)) {
- log_debug("Chased %s → %s", bind_mount_path(f), chased);
-
- free(f->path_malloc);
- f->path_malloc = chased;
- chased = NULL;
- }
-
- *t = *f;
- t++;
- }
+ if (r == -ENOENT && m->ignore)
+ r = 0;
- *n = t - m;
return r;
}
@@ -698,6 +743,8 @@ static unsigned namespace_calculate_mounts(
char** read_write_paths,
char** read_only_paths,
char** inaccessible_paths,
+ const BindMount *bind_mounts,
+ unsigned n_bind_mounts,
const char* tmp_dir,
const char* var_tmp_dir,
ProtectHome protect_home,
@@ -722,6 +769,7 @@ static unsigned namespace_calculate_mounts(
strv_length(read_write_paths) +
strv_length(read_only_paths) +
strv_length(inaccessible_paths) +
+ n_bind_mounts +
ns_info->private_dev +
(ns_info->protect_kernel_tunables ? ELEMENTSOF(protect_kernel_tunables_table) : 0) +
(ns_info->protect_control_groups ? 1 : 0) +
@@ -735,13 +783,15 @@ int setup_namespace(
char** read_write_paths,
char** read_only_paths,
char** inaccessible_paths,
+ const BindMount *bind_mounts,
+ unsigned n_bind_mounts,
const char* tmp_dir,
const char* var_tmp_dir,
ProtectHome protect_home,
ProtectSystem protect_system,
unsigned long mount_flags) {
- BindMount *m, *mounts = NULL;
+ MountEntry *m, *mounts = NULL;
bool make_slave = false;
unsigned n_mounts;
int r = 0;
@@ -749,19 +799,21 @@ int setup_namespace(
if (mount_flags == 0)
mount_flags = MS_SHARED;
- n_mounts = namespace_calculate_mounts(ns_info,
- read_write_paths,
- read_only_paths,
- inaccessible_paths,
- tmp_dir, var_tmp_dir,
- protect_home, protect_system);
+ n_mounts = namespace_calculate_mounts(
+ ns_info,
+ read_write_paths,
+ read_only_paths,
+ inaccessible_paths,
+ bind_mounts, n_bind_mounts,
+ tmp_dir, var_tmp_dir,
+ protect_home, protect_system);
/* Set mount slave mode */
if (root_directory || n_mounts > 0)
make_slave = true;
if (n_mounts > 0) {
- m = mounts = (BindMount *) alloca0(n_mounts * sizeof(BindMount));
+ m = mounts = (MountEntry *) alloca0(n_mounts * sizeof(MountEntry));
r = append_access_mounts(&m, read_write_paths, READWRITE);
if (r < 0)
goto finish;
@@ -774,22 +826,26 @@ int setup_namespace(
if (r < 0)
goto finish;
+ r = append_bind_mounts(&m, bind_mounts, n_bind_mounts);
+ if (r < 0)
+ goto finish;
+
if (tmp_dir) {
- *(m++) = (BindMount) {
+ *(m++) = (MountEntry) {
.path_const = "/tmp",
.mode = PRIVATE_TMP,
};
}
if (var_tmp_dir) {
- *(m++) = (BindMount) {
+ *(m++) = (MountEntry) {
.path_const = "/var/tmp",
.mode = PRIVATE_VAR_TMP,
};
}
if (ns_info->private_dev) {
- *(m++) = (BindMount) {
+ *(m++) = (MountEntry) {
.path_const = "/dev",
.mode = PRIVATE_DEV,
};
@@ -808,7 +864,7 @@ int setup_namespace(
}
if (ns_info->protect_control_groups) {
- *(m++) = (BindMount) {
+ *(m++) = (MountEntry) {
.path_const = "/sys/fs/cgroup",
.mode = READONLY,
};
@@ -829,14 +885,7 @@ int setup_namespace(
if (r < 0)
goto finish;
- /* 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_mounts);
- if (r < 0)
- goto finish;
-
- qsort(mounts, n_mounts, sizeof(BindMount), mount_path_compare);
+ qsort(mounts, n_mounts, sizeof(MountEntry), mount_path_compare);
drop_duplicates(mounts, &n_mounts);
drop_outside_root(root_directory, mounts, &n_mounts);
@@ -877,7 +926,7 @@ int setup_namespace(
/* First round, add in all special mounts we need */
for (m = mounts; m < mounts + n_mounts; ++m) {
- r = apply_mount(m, tmp_dir, var_tmp_dir);
+ r = apply_mount(root_directory, m, tmp_dir, var_tmp_dir);
if (r < 0)
goto finish;
}
@@ -885,7 +934,7 @@ int setup_namespace(
/* Create a blacklist we can pass to bind_mount_recursive() */
blacklist = newa(char*, n_mounts+1);
for (j = 0; j < n_mounts; j++)
- blacklist[j] = (char*) bind_mount_path(mounts+j);
+ blacklist[j] = (char*) mount_entry_path(mounts+j);
blacklist[j] = NULL;
/* Second round, flip the ro bits if necessary. */
@@ -920,6 +969,53 @@ finish:
return r;
}
+void bind_mount_free_many(BindMount *b, unsigned n) {
+ unsigned i;
+
+ assert(b || n == 0);
+
+ for (i = 0; i < n; i++) {
+ free(b[i].source);
+ free(b[i].destination);
+ }
+
+ free(b);
+}
+
+int bind_mount_add(BindMount **b, unsigned *n, const BindMount *item) {
+ _cleanup_free_ char *s = NULL, *d = NULL;
+ BindMount *c;
+
+ assert(b);
+ assert(n);
+ assert(item);
+
+ s = strdup(item->source);
+ if (!s)
+ return -ENOMEM;
+
+ d = strdup(item->destination);
+ if (!d)
+ return -ENOMEM;
+
+ c = realloc_multiply(*b, sizeof(BindMount), *n + 1);
+ if (!c)
+ return -ENOMEM;
+
+ *b = c;
+
+ c[(*n) ++] = (BindMount) {
+ .source = s,
+ .destination = d,
+ .read_only = item->read_only,
+ .recursive = item->recursive,
+ .ignore_enoent = item->ignore_enoent,
+ };
+
+ s = d = NULL;
+ return 0;
+}
+
static int setup_one_tmp_dir(const char *id, const char *prefix, char **path) {
_cleanup_free_ char *x = NULL;
char bid[SD_ID128_STRING_MAX];