Systemd/src/core/namespace.c

1447 lines
48 KiB
C
Raw Normal View History

/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <unistd.h>
2010-04-24 05:05:01 +02:00
#include <linux/fs.h>
#include "alloc-util.h"
#include "base-filesystem.h"
#include "dev-setup.h"
#include "fd-util.h"
#include "fs-util.h"
#include "label.h"
#include "loop-util.h"
#include "loopback-setup.h"
#include "missing.h"
#include "mkdir.h"
#include "mount-util.h"
#include "namespace.h"
#include "path-util.h"
#include "selinux-util.h"
#include "socket-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "umask-util.h"
#include "user-util.h"
#include "util.h"
#define DEV_MOUNT_OPTIONS (MS_NOSUID|MS_STRICTATIME|MS_NOEXEC)
typedef enum MountMode {
/* This is ordered by priority! */
INACCESSIBLE,
BIND_MOUNT,
BIND_MOUNT_RECURSIVE,
PRIVATE_TMP,
PRIVATE_VAR_TMP,
PRIVATE_DEV,
BIND_DEV,
execute: make StateDirectory= and friends compatible with DynamicUser=1 and RootDirectory=/RootImage= Let's clean up the interaction of StateDirectory= (and friends) to DynamicUser=1: instead of creating these directories directly below /var/lib, place them in /var/lib/private instead if DynamicUser=1 is set, making that directory 0700 and owned by root:root. This way, if a dynamic UID is later reused, access to the old run's state directory is prohibited for that user. Then, use file system namespacing inside the service to make /var/lib/private a readable tmpfs, hiding all state directories that are not listed in StateDirectory=, and making access to the actual state directory possible. Mount all directories listed in StateDirectory= to the same places inside the service (which means they'll now be mounted into the tmpfs instance). Finally, add a symlink from the state directory name in /var/lib/ to the one in /var/lib/private, so that both the host and the service can access the path under the same location. Here's an example: let's say a service runs with StateDirectory=foo. When DynamicUser=0 is set, it will get the following setup, and no difference between what the unit and what the host sees: /var/lib/foo (created as directory) Now, if DynamicUser=1 is set, we'll instead get this on the host: /var/lib/private (created as directory with mode 0700, root:root) /var/lib/private/foo (created as directory) /var/lib/foo → private/foo (created as symlink) And from inside the unit: /var/lib/private (a tmpfs mount with mode 0755, root:root) /var/lib/private/foo (bind mounted from the host) /var/lib/foo → private/foo (the same symlink as above) This takes inspiration from how container trees are protected below /var/lib/machines: they generally reuse UIDs/GIDs of the host, but because /var/lib/machines itself is set to 0700 host users cannot access files in the container tree even if the UIDs/GIDs are reused. However, for this commit we add one further trick: inside and outside of the unit /var/lib/private is a different thing: outside it is a plain, inaccessible directory, and inside it is a world-readable tmpfs mount with only the whitelisted subdirs below it, bind mounte din. This means, from the outside the dir acts as an access barrier, but from the inside it does not. And the symlink created in /var/lib/foo itself points across the barrier in both cases, so that root and the unit's user always have access to these dirs without knowing the details of this mounting magic. This logic resolves a major shortcoming of DynamicUser=1 units: previously they couldn't safely store persistant data. With this change they can have their own private state, log and data directories, which they can write to, but which are protected from UID recycling. With this change, if RootDirectory= or RootImage= are used it is ensured that the specified state/log/cache directories are always mounted in from the host. This change of semantics I think is much preferable since this means the root directory/image logic can be used easily for read-only resource bundling (as all writable data resides outside of the image). Note that this is a change of behaviour, but given that we haven't released any systemd version with StateDirectory= and friends implemented this should be a safe change to make (in particular as previously it wasn't clear what would actually happen when used in combination). Moreover, by making this change we can later add a "+" modifier to these setings too working similar to the same modifier in ReadOnlyPaths= and friends, making specified paths relative to the container itself.
2017-09-28 18:55:45 +02:00
EMPTY_DIR,
SYSFS,
PROCFS,
READONLY,
READWRITE,
} MountMode;
typedef struct MountEntry {
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
const char *path_const; /* Memory allocated on stack or static */
MountMode mode:5;
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
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? */
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
char *path_malloc; /* Use this instead of 'path' if we had to allocate memory */
const char *source_const; /* The source path, for bind mounts */
char *source_malloc;
} MountEntry;
/* If MountAPIVFS= is used, let's mount /sys and /proc into the it, but only as a fallback if the user hasn't mounted
* something there already. These mounts are hence overriden by any other explicitly configured mounts. */
static const MountEntry apivfs_table[] = {
{ "/proc", PROCFS, false },
{ "/dev", BIND_DEV, false },
{ "/sys", SYSFS, false },
};
/* ProtectKernelTunables= option and the related filesystem APIs */
static const MountEntry protect_kernel_tunables_table[] = {
{ "/proc/sys", READONLY, false },
{ "/proc/sysrq-trigger", READONLY, true },
{ "/proc/latency_stats", READONLY, true },
{ "/proc/mtrr", READONLY, true },
{ "/proc/apm", READONLY, true }, /* Obsolete API, there's no point in permitting access to this, ever */
{ "/proc/acpi", READONLY, true },
{ "/proc/timer_stats", READONLY, true },
{ "/proc/asound", READONLY, true },
{ "/proc/bus", READONLY, true },
{ "/proc/fs", READONLY, true },
{ "/proc/irq", READONLY, true },
{ "/sys", READONLY, false },
{ "/sys/kernel/debug", READONLY, true },
{ "/sys/kernel/tracing", READONLY, true },
{ "/sys/fs/cgroup", READWRITE, false }, /* READONLY is set by ProtectControlGroups= option */
{ "/sys/fs/selinux", READWRITE, true },
};
/* ProtectKernelModules= option */
static const MountEntry protect_kernel_modules_table[] = {
#if HAVE_SPLIT_USR
{ "/lib/modules", INACCESSIBLE, true },
#endif
{ "/usr/lib/modules", INACCESSIBLE, true },
};
/*
* ProtectHome=read-only table, protect $HOME and $XDG_RUNTIME_DIR and rest of
* system should be protected by ProtectSystem=
*/
static const MountEntry protect_home_read_only_table[] = {
{ "/home", READONLY, true },
{ "/run/user", READONLY, true },
{ "/root", READONLY, true },
};
/* ProtectHome=yes table */
static const MountEntry protect_home_yes_table[] = {
{ "/home", INACCESSIBLE, true },
{ "/run/user", INACCESSIBLE, true },
{ "/root", INACCESSIBLE, true },
};
/* ProtectSystem=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 MountEntry protect_system_full_table[] = {
{ "/usr", READONLY, false },
{ "/boot", READONLY, true },
{ "/efi", READONLY, true },
{ "/etc", READONLY, false },
};
/*
* ProtectSystem=strict table. In this strict mode, we mount everything
* read-only, except for /proc, /dev, /sys which are the kernel API VFS,
* which are left writable, but PrivateDevices= + ProtectKernelTunables=
* protect those, and these options should be fully orthogonal.
* (And of course /home and friends are also left writable, as ProtectHome=
* shall manage those, orthogonally).
*/
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 *mount_entry_path(const MountEntry *p) {
assert(p);
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
/* Returns the path of this bind mount. If the malloc()-allocated ->path_buffer field is set we return that,
* otherwise the stack/static ->path field is returned. */
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
return p->path_malloc ?: p->path_const;
}
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 void mount_entry_done(MountEntry *p) {
assert(p);
p->path_malloc = mfree(p->path_malloc);
p->source_malloc = mfree(p->source_malloc);
}
static int append_access_mounts(MountEntry **p, char **strv, MountMode mode) {
char **i;
assert(p);
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
/* Adds a list of user-supplied READWRITE/READONLY/INACCESSIBLE entries */
STRV_FOREACH(i, strv) {
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
bool ignore = false, needs_prefix = false;
const char *e = *i;
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
/* Look for any prefixes */
if (startswith(e, "-")) {
e++;
ignore = true;
}
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
if (startswith(e, "+")) {
e++;
needs_prefix = true;
}
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
if (!path_is_absolute(e))
return -EINVAL;
*((*p)++) = (MountEntry) {
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
.path_const = e,
.mode = mode,
.ignore = ignore,
.has_prefix = !needs_prefix,
};
}
return 0;
}
execute: make StateDirectory= and friends compatible with DynamicUser=1 and RootDirectory=/RootImage= Let's clean up the interaction of StateDirectory= (and friends) to DynamicUser=1: instead of creating these directories directly below /var/lib, place them in /var/lib/private instead if DynamicUser=1 is set, making that directory 0700 and owned by root:root. This way, if a dynamic UID is later reused, access to the old run's state directory is prohibited for that user. Then, use file system namespacing inside the service to make /var/lib/private a readable tmpfs, hiding all state directories that are not listed in StateDirectory=, and making access to the actual state directory possible. Mount all directories listed in StateDirectory= to the same places inside the service (which means they'll now be mounted into the tmpfs instance). Finally, add a symlink from the state directory name in /var/lib/ to the one in /var/lib/private, so that both the host and the service can access the path under the same location. Here's an example: let's say a service runs with StateDirectory=foo. When DynamicUser=0 is set, it will get the following setup, and no difference between what the unit and what the host sees: /var/lib/foo (created as directory) Now, if DynamicUser=1 is set, we'll instead get this on the host: /var/lib/private (created as directory with mode 0700, root:root) /var/lib/private/foo (created as directory) /var/lib/foo → private/foo (created as symlink) And from inside the unit: /var/lib/private (a tmpfs mount with mode 0755, root:root) /var/lib/private/foo (bind mounted from the host) /var/lib/foo → private/foo (the same symlink as above) This takes inspiration from how container trees are protected below /var/lib/machines: they generally reuse UIDs/GIDs of the host, but because /var/lib/machines itself is set to 0700 host users cannot access files in the container tree even if the UIDs/GIDs are reused. However, for this commit we add one further trick: inside and outside of the unit /var/lib/private is a different thing: outside it is a plain, inaccessible directory, and inside it is a world-readable tmpfs mount with only the whitelisted subdirs below it, bind mounte din. This means, from the outside the dir acts as an access barrier, but from the inside it does not. And the symlink created in /var/lib/foo itself points across the barrier in both cases, so that root and the unit's user always have access to these dirs without knowing the details of this mounting magic. This logic resolves a major shortcoming of DynamicUser=1 units: previously they couldn't safely store persistant data. With this change they can have their own private state, log and data directories, which they can write to, but which are protected from UID recycling. With this change, if RootDirectory= or RootImage= are used it is ensured that the specified state/log/cache directories are always mounted in from the host. This change of semantics I think is much preferable since this means the root directory/image logic can be used easily for read-only resource bundling (as all writable data resides outside of the image). Note that this is a change of behaviour, but given that we haven't released any systemd version with StateDirectory= and friends implemented this should be a safe change to make (in particular as previously it wasn't clear what would actually happen when used in combination). Moreover, by making this change we can later add a "+" modifier to these setings too working similar to the same modifier in ReadOnlyPaths= and friends, making specified paths relative to the container itself.
2017-09-28 18:55:45 +02:00
static int append_empty_dir_mounts(MountEntry **p, char **strv) {
char **i;
assert(p);
/* Adds tmpfs mounts to provide readable but empty directories. This is primarily used to implement the
* "/private/" boundary directories for DynamicUser=1. */
STRV_FOREACH(i, strv) {
*((*p)++) = (MountEntry) {
.path_const = *i,
.mode = EMPTY_DIR,
.ignore = false,
.has_prefix = false,
.read_only = true,
};
}
return 0;
}
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);
assert(mounts);
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
/* Adds a list of static pre-defined entries */
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
for (i = 0; i < n; i++)
*((*p)++) = (MountEntry) {
.path_const = mount_entry_path(mounts+i),
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
.mode = mounts[i].mode,
.ignore = mounts[i].ignore || ignore_protect,
};
return 0;
}
static int append_protect_home(MountEntry **p, ProtectHome protect_home, bool ignore_protect) {
assert(p);
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
switch (protect_home) {
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
case PROTECT_HOME_NO:
return 0;
case PROTECT_HOME_READ_ONLY:
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
return append_static_mounts(p, protect_home_read_only_table, ELEMENTSOF(protect_home_read_only_table), ignore_protect);
case PROTECT_HOME_YES:
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
return append_static_mounts(p, protect_home_yes_table, ELEMENTSOF(protect_home_yes_table), ignore_protect);
default:
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
assert_not_reached("Unexpected ProtectHome= value");
}
}
static int append_protect_system(MountEntry **p, ProtectSystem protect_system, bool ignore_protect) {
assert(p);
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
switch (protect_system) {
case PROTECT_SYSTEM_NO:
return 0;
case PROTECT_SYSTEM_STRICT:
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
return append_static_mounts(p, protect_system_strict_table, ELEMENTSOF(protect_system_strict_table), ignore_protect);
case PROTECT_SYSTEM_YES:
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
return append_static_mounts(p, protect_system_yes_table, ELEMENTSOF(protect_system_yes_table), ignore_protect);
case PROTECT_SYSTEM_FULL:
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
return append_static_mounts(p, protect_system_full_table, ELEMENTSOF(protect_system_full_table), ignore_protect);
default:
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
assert_not_reached("Unexpected ProtectSystem= value");
}
}
static int mount_path_compare(const void *a, const void *b) {
const MountEntry *p = a, *q = b;
int d;
/* If the paths are not equal, then order prefixes first */
d = path_compare(mount_entry_path(p), mount_entry_path(q));
if (d != 0)
return d;
/* If the paths are equal, check the mode */
if (p->mode < q->mode)
return -1;
if (p->mode > q->mode)
return 1;
return 0;
}
static int prefix_where_needed(MountEntry *m, unsigned n, const char *root_directory) {
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
unsigned i;
/* Prefixes all paths in the bind mount table with the root directory if it is specified and the entry needs
* that. */
if (!root_directory)
return 0;
for (i = 0; i < n; i++) {
char *s;
if (m[i].has_prefix)
continue;
s = prefix_root(root_directory, mount_entry_path(m+i));
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
if (!s)
return -ENOMEM;
free(m[i].path_malloc);
m[i].path_malloc = s;
m[i].has_prefix = true;
}
return 0;
}
static void drop_duplicates(MountEntry *m, unsigned *n) {
MountEntry *f, *t, *previous;
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 (which is the one with the more restrictive mode), see mount_path_compare()
* above. */
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 */
mount_entry_done(f);
continue;
}
*t = *f;
previous = t;
t++;
}
*n = t - m;
}
static void drop_inaccessible(MountEntry *m, unsigned *n) {
MountEntry *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(mount_entry_path(f), clear)) {
log_debug("%s is masked by %s.", mount_entry_path(f), clear);
mount_entry_done(f);
continue;
}
clear = f->mode == INACCESSIBLE ? mount_entry_path(f) : NULL;
*t = *f;
t++;
}
*n = t - m;
}
static void drop_nop(MountEntry *m, unsigned *n) {
MountEntry *f, *t;
assert(m);
assert(n);
/* Drops all entries which have an immediate parent that has the same type, as they are redundant. Assumes the
* list is ordered by prefixes. */
for (f = m, t = m; f < m + *n; f++) {
/* Only suppress such subtrees for READONLY and READWRITE entries */
if (IN_SET(f->mode, READONLY, READWRITE)) {
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(mount_entry_path(f), mount_entry_path(p))) {
found = true;
break;
}
}
/* 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", mount_entry_path(f), mount_entry_path(p));
mount_entry_done(f);
continue;
}
}
*t = *f;
t++;
}
*n = t - m;
}
static void drop_outside_root(const char *root_directory, MountEntry *m, unsigned *n) {
MountEntry *f, *t;
assert(m);
assert(n);
/* Nothing to do */
if (!root_directory)
return;
/* Drops all mounts that are outside of the root directory. */
for (f = m, t = m; f < m + *n; f++) {
if (!path_startswith(mount_entry_path(f), root_directory)) {
log_debug("%s is outside of root directory.", mount_entry_path(f));
mount_entry_done(f);
continue;
}
*t = *f;
t++;
}
*n = t - m;
}
static int mount_private_dev(MountEntry *m) {
static const char devnodes[] =
"/dev/null\0"
"/dev/zero\0"
"/dev/full\0"
"/dev/random\0"
"/dev/urandom\0"
"/dev/tty\0";
char temporary_mount[] = "/tmp/namespace-dev-XXXXXX";
const char *d, *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
_cleanup_umask_ mode_t u;
int r;
assert(m);
u = umask(0000);
if (!mkdtemp(temporary_mount))
return -errno;
dev = strjoina(temporary_mount, "/dev");
(void) mkdir(dev, 0755);
if (mount("tmpfs", dev, "tmpfs", DEV_MOUNT_OPTIONS, "mode=755") < 0) {
r = -errno;
goto fail;
}
devpts = strjoina(temporary_mount, "/dev/pts");
(void) mkdir(devpts, 0755);
if (mount("/dev/pts", devpts, NULL, MS_BIND, NULL) < 0) {
r = -errno;
goto fail;
}
devptmx = strjoina(temporary_mount, "/dev/ptmx");
if (symlink("pts/ptmx", devptmx) < 0) {
r = -errno;
goto fail;
}
devshm = strjoina(temporary_mount, "/dev/shm");
(void) mkdir(devshm, 01777);
r = mount("/dev/shm", devshm, NULL, MS_BIND, NULL);
if (r < 0) {
r = -errno;
goto fail;
}
devmqueue = strjoina(temporary_mount, "/dev/mqueue");
(void) mkdir(devmqueue, 0755);
(void) mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL);
devhugepages = strjoina(temporary_mount, "/dev/hugepages");
(void) mkdir(devhugepages, 0755);
(void) mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL);
devlog = strjoina(temporary_mount, "/dev/log");
(void) symlink("/run/systemd/journal/dev-log", devlog);
NULSTR_FOREACH(d, devnodes) {
_cleanup_free_ char *dn = NULL;
struct stat st;
r = stat(d, &st);
if (r < 0) {
if (errno == ENOENT)
continue;
r = -errno;
goto fail;
}
if (!S_ISBLK(st.st_mode) &&
!S_ISCHR(st.st_mode)) {
r = -EINVAL;
goto fail;
}
if (st.st_rdev == 0)
continue;
dn = strappend(temporary_mount, d);
if (!dn) {
r = -ENOMEM;
goto fail;
}
mac_selinux_create_file_prepare(d, st.st_mode);
r = mknod(dn, st.st_mode, st.st_rdev);
mac_selinux_create_file_clear();
if (r < 0) {
r = -errno;
goto fail;
}
}
2015-05-21 16:30:58 +02:00
dev_setup(temporary_mount, UID_INVALID, GID_INVALID);
/* Create the /dev directory if missing. It is more likely to be
* missing when the service is started with RootDirectory. This is
* consistent with mount units creating the mount points when missing.
*/
(void) mkdir_p_label(mount_entry_path(m), 0755);
/* Unmount everything in old /dev */
umount_recursive(mount_entry_path(m), 0);
if (mount(dev, mount_entry_path(m), NULL, MS_MOVE, NULL) < 0) {
r = -errno;
goto fail;
}
rmdir(dev);
rmdir(temporary_mount);
return 0;
fail:
if (devpts)
umount(devpts);
if (devshm)
umount(devshm);
if (devhugepages)
umount(devhugepages);
if (devmqueue)
umount(devmqueue);
umount(dev);
rmdir(dev);
rmdir(temporary_mount);
return r;
}
static int mount_bind_dev(MountEntry *m) {
int r;
assert(m);
/* Implements the little brother of mount_private_dev(): simply bind mounts the host's /dev into the service's
* /dev. This is only used when RootDirectory= is set. */
(void) mkdir_p_label(mount_entry_path(m), 0755);
r = path_is_mount_point(mount_entry_path(m), NULL, 0);
if (r < 0)
return log_debug_errno(r, "Unable to determine whether /dev is already mounted: %m");
if (r > 0) /* make this a NOP if /dev is already a mount point */
return 0;
if (mount("/dev", mount_entry_path(m), NULL, MS_BIND|MS_REC, NULL) < 0)
return log_debug_errno(errno, "Failed to bind mount %s: %m", mount_entry_path(m));
return 1;
}
static int mount_sysfs(MountEntry *m) {
int r;
assert(m);
(void) mkdir_p_label(mount_entry_path(m), 0755);
r = path_is_mount_point(mount_entry_path(m), NULL, 0);
if (r < 0)
return log_debug_errno(r, "Unable to determine whether /sys is already mounted: %m");
if (r > 0) /* make this a NOP if /sys is already a mount point */
return 0;
/* Bind mount the host's version so that we get all child mounts of it, too. */
if (mount("/sys", mount_entry_path(m), NULL, MS_BIND|MS_REC, NULL) < 0)
return log_debug_errno(errno, "Failed to mount %s: %m", mount_entry_path(m));
return 1;
}
static int mount_procfs(MountEntry *m) {
int r;
assert(m);
(void) mkdir_p_label(mount_entry_path(m), 0755);
r = path_is_mount_point(mount_entry_path(m), NULL, 0);
if (r < 0)
return log_debug_errno(r, "Unable to determine whether /proc is already mounted: %m");
if (r > 0) /* make this a NOP if /proc is already a mount point */
return 0;
/* Mount a new instance, so that we get the one that matches our user namespace, if we are running in one */
if (mount("proc", mount_entry_path(m), "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL) < 0)
return log_debug_errno(errno, "Failed to mount %s: %m", mount_entry_path(m));
return 1;
}
execute: make StateDirectory= and friends compatible with DynamicUser=1 and RootDirectory=/RootImage= Let's clean up the interaction of StateDirectory= (and friends) to DynamicUser=1: instead of creating these directories directly below /var/lib, place them in /var/lib/private instead if DynamicUser=1 is set, making that directory 0700 and owned by root:root. This way, if a dynamic UID is later reused, access to the old run's state directory is prohibited for that user. Then, use file system namespacing inside the service to make /var/lib/private a readable tmpfs, hiding all state directories that are not listed in StateDirectory=, and making access to the actual state directory possible. Mount all directories listed in StateDirectory= to the same places inside the service (which means they'll now be mounted into the tmpfs instance). Finally, add a symlink from the state directory name in /var/lib/ to the one in /var/lib/private, so that both the host and the service can access the path under the same location. Here's an example: let's say a service runs with StateDirectory=foo. When DynamicUser=0 is set, it will get the following setup, and no difference between what the unit and what the host sees: /var/lib/foo (created as directory) Now, if DynamicUser=1 is set, we'll instead get this on the host: /var/lib/private (created as directory with mode 0700, root:root) /var/lib/private/foo (created as directory) /var/lib/foo → private/foo (created as symlink) And from inside the unit: /var/lib/private (a tmpfs mount with mode 0755, root:root) /var/lib/private/foo (bind mounted from the host) /var/lib/foo → private/foo (the same symlink as above) This takes inspiration from how container trees are protected below /var/lib/machines: they generally reuse UIDs/GIDs of the host, but because /var/lib/machines itself is set to 0700 host users cannot access files in the container tree even if the UIDs/GIDs are reused. However, for this commit we add one further trick: inside and outside of the unit /var/lib/private is a different thing: outside it is a plain, inaccessible directory, and inside it is a world-readable tmpfs mount with only the whitelisted subdirs below it, bind mounte din. This means, from the outside the dir acts as an access barrier, but from the inside it does not. And the symlink created in /var/lib/foo itself points across the barrier in both cases, so that root and the unit's user always have access to these dirs without knowing the details of this mounting magic. This logic resolves a major shortcoming of DynamicUser=1 units: previously they couldn't safely store persistant data. With this change they can have their own private state, log and data directories, which they can write to, but which are protected from UID recycling. With this change, if RootDirectory= or RootImage= are used it is ensured that the specified state/log/cache directories are always mounted in from the host. This change of semantics I think is much preferable since this means the root directory/image logic can be used easily for read-only resource bundling (as all writable data resides outside of the image). Note that this is a change of behaviour, but given that we haven't released any systemd version with StateDirectory= and friends implemented this should be a safe change to make (in particular as previously it wasn't clear what would actually happen when used in combination). Moreover, by making this change we can later add a "+" modifier to these setings too working similar to the same modifier in ReadOnlyPaths= and friends, making specified paths relative to the container itself.
2017-09-28 18:55:45 +02:00
static int mount_empty_dir(MountEntry *m) {
assert(m);
/* First, get rid of everything that is below if there is anything. Then, overmount with our new empty dir */
(void) mkdir_p_label(mount_entry_path(m), 0755);
(void) umount_recursive(mount_entry_path(m), 0);
if (mount("tmpfs", mount_entry_path(m), "tmpfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME, "mode=755") < 0)
return log_debug_errno(errno, "Failed to mount %s: %m", mount_entry_path(m));
return 1;
}
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,
IN_SET(m->mode, BIND_MOUNT, BIND_MOUNT_RECURSIVE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV, BIND_DEV, EMPTY_DIR, SYSFS, PROCFS) ? CHASE_NONEXISTENT : 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(
const char *root_directory,
MountEntry *m,
const char *tmp_dir,
const char *var_tmp_dir) {
bool rbind = true, make = false;
const char *what;
int r;
assert(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) {
case INACCESSIBLE: {
struct stat target;
/* First, get rid of everything that is below if there
* is anything... Then, overmount it with an
* inaccessible path. */
(void) umount_recursive(mount_entry_path(m), 0);
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) {
log_debug("File type not supported for inaccessible mounts. Note that symlinks are not allowed");
return -ELOOP;
}
break;
}
case READONLY:
case READWRITE:
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", mount_entry_path(m));
namespace: rework how ReadWritePaths= is applied Previously, if ReadWritePaths= was nested inside a ReadOnlyPaths= specification, then we'd first recursively apply the ReadOnlyPaths= paths, and make everything below read-only, only in order to then flip the read-only bit again for the subdirs listed in ReadWritePaths= below it. This is not only ugly (as for the dirs in question we first turn on the RO bit, only to turn it off again immediately after), but also problematic in containers, where a container manager might have marked a set of dirs read-only and this code will undo this is ReadWritePaths= is set for any. With this patch behaviour in this regard is altered: ReadOnlyPaths= will not be applied to the children listed in ReadWritePaths= in the first place, so that we do not need to turn off the RO bit for those after all. This means that ReadWritePaths=/ReadOnlyPaths= may only be used to turn on the RO bit, but never to turn it off again. Or to say this differently: if some dirs are marked read-only via some external tool, then ReadWritePaths= will not undo it. This is not only the safer option, but also more in-line with what the man page currently claims: "Entries (files or directories) listed in ReadWritePaths= are accessible from within the namespace with the same access rights as from outside." To implement this change bind_remount_recursive() gained a new "blacklist" string list parameter, which when passed may contain subdirs that shall be excluded from the read-only mounting. A number of functions are updated to add more debug logging to make this more digestable.
2016-09-25 10:40:51 +02:00
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 = mount_entry_path(m);
namespace: rework how ReadWritePaths= is applied Previously, if ReadWritePaths= was nested inside a ReadOnlyPaths= specification, then we'd first recursively apply the ReadOnlyPaths= paths, and make everything below read-only, only in order to then flip the read-only bit again for the subdirs listed in ReadWritePaths= below it. This is not only ugly (as for the dirs in question we first turn on the RO bit, only to turn it off again immediately after), but also problematic in containers, where a container manager might have marked a set of dirs read-only and this code will undo this is ReadWritePaths= is set for any. With this patch behaviour in this regard is altered: ReadOnlyPaths= will not be applied to the children listed in ReadWritePaths= in the first place, so that we do not need to turn off the RO bit for those after all. This means that ReadWritePaths=/ReadOnlyPaths= may only be used to turn on the RO bit, but never to turn it off again. Or to say this differently: if some dirs are marked read-only via some external tool, then ReadWritePaths= will not undo it. This is not only the safer option, but also more in-line with what the man page currently claims: "Entries (files or directories) listed in ReadWritePaths= are accessible from within the namespace with the same access rights as from outside." To implement this change bind_remount_recursive() gained a new "blacklist" string list parameter, which when passed may contain subdirs that shall be excluded from the read-only mounting. A number of functions are updated to add more debug logging to make this more digestable.
2016-09-25 10:40:51 +02:00
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);
make = true;
break;
execute: make StateDirectory= and friends compatible with DynamicUser=1 and RootDirectory=/RootImage= Let's clean up the interaction of StateDirectory= (and friends) to DynamicUser=1: instead of creating these directories directly below /var/lib, place them in /var/lib/private instead if DynamicUser=1 is set, making that directory 0700 and owned by root:root. This way, if a dynamic UID is later reused, access to the old run's state directory is prohibited for that user. Then, use file system namespacing inside the service to make /var/lib/private a readable tmpfs, hiding all state directories that are not listed in StateDirectory=, and making access to the actual state directory possible. Mount all directories listed in StateDirectory= to the same places inside the service (which means they'll now be mounted into the tmpfs instance). Finally, add a symlink from the state directory name in /var/lib/ to the one in /var/lib/private, so that both the host and the service can access the path under the same location. Here's an example: let's say a service runs with StateDirectory=foo. When DynamicUser=0 is set, it will get the following setup, and no difference between what the unit and what the host sees: /var/lib/foo (created as directory) Now, if DynamicUser=1 is set, we'll instead get this on the host: /var/lib/private (created as directory with mode 0700, root:root) /var/lib/private/foo (created as directory) /var/lib/foo → private/foo (created as symlink) And from inside the unit: /var/lib/private (a tmpfs mount with mode 0755, root:root) /var/lib/private/foo (bind mounted from the host) /var/lib/foo → private/foo (the same symlink as above) This takes inspiration from how container trees are protected below /var/lib/machines: they generally reuse UIDs/GIDs of the host, but because /var/lib/machines itself is set to 0700 host users cannot access files in the container tree even if the UIDs/GIDs are reused. However, for this commit we add one further trick: inside and outside of the unit /var/lib/private is a different thing: outside it is a plain, inaccessible directory, and inside it is a world-readable tmpfs mount with only the whitelisted subdirs below it, bind mounte din. This means, from the outside the dir acts as an access barrier, but from the inside it does not. And the symlink created in /var/lib/foo itself points across the barrier in both cases, so that root and the unit's user always have access to these dirs without knowing the details of this mounting magic. This logic resolves a major shortcoming of DynamicUser=1 units: previously they couldn't safely store persistant data. With this change they can have their own private state, log and data directories, which they can write to, but which are protected from UID recycling. With this change, if RootDirectory= or RootImage= are used it is ensured that the specified state/log/cache directories are always mounted in from the host. This change of semantics I think is much preferable since this means the root directory/image logic can be used easily for read-only resource bundling (as all writable data resides outside of the image). Note that this is a change of behaviour, but given that we haven't released any systemd version with StateDirectory= and friends implemented this should be a safe change to make (in particular as previously it wasn't clear what would actually happen when used in combination). Moreover, by making this change we can later add a "+" modifier to these setings too working similar to the same modifier in ReadOnlyPaths= and friends, making specified paths relative to the container itself.
2017-09-28 18:55:45 +02:00
case EMPTY_DIR:
return mount_empty_dir(m);
case PRIVATE_TMP:
what = tmp_dir;
make = true;
break;
case PRIVATE_VAR_TMP:
what = var_tmp_dir;
make = true;
break;
case PRIVATE_DEV:
return mount_private_dev(m);
case BIND_DEV:
return mount_bind_dev(m);
case SYSFS:
return mount_sysfs(m);
case PROCFS:
return mount_procfs(m);
default:
assert_not_reached("Unknown mode");
}
assert(what);
if (mount(what, mount_entry_path(m), NULL, MS_BIND|(rbind ? MS_REC : 0), NULL) < 0) {
bool try_again = false;
r = -errno;
if (r == -ENOENT && make) {
struct stat st;
/* Hmm, either the source or the destination are missing. Let's see if we can create the destination, then try again */
if (stat(what, &st) >= 0) {
(void) mkdir_parents(mount_entry_path(m), 0755);
if (S_ISDIR(st.st_mode))
try_again = mkdir(mount_entry_path(m), 0755) >= 0;
else
try_again = touch(mount_entry_path(m)) >= 0;
}
}
if (try_again) {
if (mount(what, mount_entry_path(m), NULL, MS_BIND|(rbind ? MS_REC : 0), NULL) < 0)
r = -errno;
else
r = 0;
}
if (r < 0)
return log_debug_errno(r, "Failed to mount %s to %s: %m", what, mount_entry_path(m));
}
namespace: rework how ReadWritePaths= is applied Previously, if ReadWritePaths= was nested inside a ReadOnlyPaths= specification, then we'd first recursively apply the ReadOnlyPaths= paths, and make everything below read-only, only in order to then flip the read-only bit again for the subdirs listed in ReadWritePaths= below it. This is not only ugly (as for the dirs in question we first turn on the RO bit, only to turn it off again immediately after), but also problematic in containers, where a container manager might have marked a set of dirs read-only and this code will undo this is ReadWritePaths= is set for any. With this patch behaviour in this regard is altered: ReadOnlyPaths= will not be applied to the children listed in ReadWritePaths= in the first place, so that we do not need to turn off the RO bit for those after all. This means that ReadWritePaths=/ReadOnlyPaths= may only be used to turn on the RO bit, but never to turn it off again. Or to say this differently: if some dirs are marked read-only via some external tool, then ReadWritePaths= will not undo it. This is not only the safer option, but also more in-line with what the man page currently claims: "Entries (files or directories) listed in ReadWritePaths= are accessible from within the namespace with the same access rights as from outside." To implement this change bind_remount_recursive() gained a new "blacklist" string list parameter, which when passed may contain subdirs that shall be excluded from the read-only mounting. A number of functions are updated to add more debug logging to make this more digestable.
2016-09-25 10:40:51 +02:00
log_debug("Successfully mounted %s to %s", what, mount_entry_path(m));
namespace: rework how ReadWritePaths= is applied Previously, if ReadWritePaths= was nested inside a ReadOnlyPaths= specification, then we'd first recursively apply the ReadOnlyPaths= paths, and make everything below read-only, only in order to then flip the read-only bit again for the subdirs listed in ReadWritePaths= below it. This is not only ugly (as for the dirs in question we first turn on the RO bit, only to turn it off again immediately after), but also problematic in containers, where a container manager might have marked a set of dirs read-only and this code will undo this is ReadWritePaths= is set for any. With this patch behaviour in this regard is altered: ReadOnlyPaths= will not be applied to the children listed in ReadWritePaths= in the first place, so that we do not need to turn off the RO bit for those after all. This means that ReadWritePaths=/ReadOnlyPaths= may only be used to turn on the RO bit, but never to turn it off again. Or to say this differently: if some dirs are marked read-only via some external tool, then ReadWritePaths= will not undo it. This is not only the safer option, but also more in-line with what the man page currently claims: "Entries (files or directories) listed in ReadWritePaths= are accessible from within the namespace with the same access rights as from outside." To implement this change bind_remount_recursive() gained a new "blacklist" string list parameter, which when passed may contain subdirs that shall be excluded from the read-only mounting. A number of functions are updated to add more debug logging to make this more digestable.
2016-09-25 10:40:51 +02:00
return 0;
}
static int make_read_only(MountEntry *m, char **blacklist, FILE *proc_self_mountinfo) {
namespace: rework how ReadWritePaths= is applied Previously, if ReadWritePaths= was nested inside a ReadOnlyPaths= specification, then we'd first recursively apply the ReadOnlyPaths= paths, and make everything below read-only, only in order to then flip the read-only bit again for the subdirs listed in ReadWritePaths= below it. This is not only ugly (as for the dirs in question we first turn on the RO bit, only to turn it off again immediately after), but also problematic in containers, where a container manager might have marked a set of dirs read-only and this code will undo this is ReadWritePaths= is set for any. With this patch behaviour in this regard is altered: ReadOnlyPaths= will not be applied to the children listed in ReadWritePaths= in the first place, so that we do not need to turn off the RO bit for those after all. This means that ReadWritePaths=/ReadOnlyPaths= may only be used to turn on the RO bit, but never to turn it off again. Or to say this differently: if some dirs are marked read-only via some external tool, then ReadWritePaths= will not undo it. This is not only the safer option, but also more in-line with what the man page currently claims: "Entries (files or directories) listed in ReadWritePaths= are accessible from within the namespace with the same access rights as from outside." To implement this change bind_remount_recursive() gained a new "blacklist" string list parameter, which when passed may contain subdirs that shall be excluded from the read-only mounting. A number of functions are updated to add more debug logging to make this more digestable.
2016-09-25 10:40:51 +02:00
int r = 0;
assert(m);
assert(proc_self_mountinfo);
if (mount_entry_read_only(m))
r = bind_remount_recursive_with_mountinfo(mount_entry_path(m), true, blacklist, proc_self_mountinfo);
2017-02-24 18:14:02 +01:00
else if (m->mode == PRIVATE_DEV) { /* Superblock can be readonly but the submounts can't */
if (mount(NULL, mount_entry_path(m), NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL) < 0)
namespace: rework how ReadWritePaths= is applied Previously, if ReadWritePaths= was nested inside a ReadOnlyPaths= specification, then we'd first recursively apply the ReadOnlyPaths= paths, and make everything below read-only, only in order to then flip the read-only bit again for the subdirs listed in ReadWritePaths= below it. This is not only ugly (as for the dirs in question we first turn on the RO bit, only to turn it off again immediately after), but also problematic in containers, where a container manager might have marked a set of dirs read-only and this code will undo this is ReadWritePaths= is set for any. With this patch behaviour in this regard is altered: ReadOnlyPaths= will not be applied to the children listed in ReadWritePaths= in the first place, so that we do not need to turn off the RO bit for those after all. This means that ReadWritePaths=/ReadOnlyPaths= may only be used to turn on the RO bit, but never to turn it off again. Or to say this differently: if some dirs are marked read-only via some external tool, then ReadWritePaths= will not undo it. This is not only the safer option, but also more in-line with what the man page currently claims: "Entries (files or directories) listed in ReadWritePaths= are accessible from within the namespace with the same access rights as from outside." To implement this change bind_remount_recursive() gained a new "blacklist" string list parameter, which when passed may contain subdirs that shall be excluded from the read-only mounting. A number of functions are updated to add more debug logging to make this more digestable.
2016-09-25 10:40:51 +02:00
r = -errno;
} else
namespace: rework how ReadWritePaths= is applied Previously, if ReadWritePaths= was nested inside a ReadOnlyPaths= specification, then we'd first recursively apply the ReadOnlyPaths= paths, and make everything below read-only, only in order to then flip the read-only bit again for the subdirs listed in ReadWritePaths= below it. This is not only ugly (as for the dirs in question we first turn on the RO bit, only to turn it off again immediately after), but also problematic in containers, where a container manager might have marked a set of dirs read-only and this code will undo this is ReadWritePaths= is set for any. With this patch behaviour in this regard is altered: ReadOnlyPaths= will not be applied to the children listed in ReadWritePaths= in the first place, so that we do not need to turn off the RO bit for those after all. This means that ReadWritePaths=/ReadOnlyPaths= may only be used to turn on the RO bit, but never to turn it off again. Or to say this differently: if some dirs are marked read-only via some external tool, then ReadWritePaths= will not undo it. This is not only the safer option, but also more in-line with what the man page currently claims: "Entries (files or directories) listed in ReadWritePaths= are accessible from within the namespace with the same access rights as from outside." To implement this change bind_remount_recursive() gained a new "blacklist" string list parameter, which when passed may contain subdirs that shall be excluded from the read-only mounting. A number of functions are updated to add more debug logging to make this more digestable.
2016-09-25 10:40:51 +02:00
return 0;
/* Not that we only turn on the MS_RDONLY flag here, we never turn it off. Something that was marked read-only
* already stays this way. This improves compatibility with container managers, where we won't attempt to undo
* read-only mounts already applied. */
if (r == -ENOENT && m->ignore)
r = 0;
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
return r;
}
static bool namespace_info_mount_apivfs(const char *root_directory, const NameSpaceInfo *ns_info) {
assert(ns_info);
/*
* ProtectControlGroups= and ProtectKernelTunables= imply MountAPIVFS=,
* since to protect the API VFS mounts, they need to be around in the
* first place... and RootDirectory= or RootImage= need to be set.
*/
/* root_directory should point to a mount point */
return root_directory &&
(ns_info->mount_apivfs ||
ns_info->protect_control_groups ||
ns_info->protect_kernel_tunables);
}
static unsigned namespace_calculate_mounts(
const char* root_directory,
const NameSpaceInfo *ns_info,
char** read_write_paths,
char** read_only_paths,
char** inaccessible_paths,
execute: make StateDirectory= and friends compatible with DynamicUser=1 and RootDirectory=/RootImage= Let's clean up the interaction of StateDirectory= (and friends) to DynamicUser=1: instead of creating these directories directly below /var/lib, place them in /var/lib/private instead if DynamicUser=1 is set, making that directory 0700 and owned by root:root. This way, if a dynamic UID is later reused, access to the old run's state directory is prohibited for that user. Then, use file system namespacing inside the service to make /var/lib/private a readable tmpfs, hiding all state directories that are not listed in StateDirectory=, and making access to the actual state directory possible. Mount all directories listed in StateDirectory= to the same places inside the service (which means they'll now be mounted into the tmpfs instance). Finally, add a symlink from the state directory name in /var/lib/ to the one in /var/lib/private, so that both the host and the service can access the path under the same location. Here's an example: let's say a service runs with StateDirectory=foo. When DynamicUser=0 is set, it will get the following setup, and no difference between what the unit and what the host sees: /var/lib/foo (created as directory) Now, if DynamicUser=1 is set, we'll instead get this on the host: /var/lib/private (created as directory with mode 0700, root:root) /var/lib/private/foo (created as directory) /var/lib/foo → private/foo (created as symlink) And from inside the unit: /var/lib/private (a tmpfs mount with mode 0755, root:root) /var/lib/private/foo (bind mounted from the host) /var/lib/foo → private/foo (the same symlink as above) This takes inspiration from how container trees are protected below /var/lib/machines: they generally reuse UIDs/GIDs of the host, but because /var/lib/machines itself is set to 0700 host users cannot access files in the container tree even if the UIDs/GIDs are reused. However, for this commit we add one further trick: inside and outside of the unit /var/lib/private is a different thing: outside it is a plain, inaccessible directory, and inside it is a world-readable tmpfs mount with only the whitelisted subdirs below it, bind mounte din. This means, from the outside the dir acts as an access barrier, but from the inside it does not. And the symlink created in /var/lib/foo itself points across the barrier in both cases, so that root and the unit's user always have access to these dirs without knowing the details of this mounting magic. This logic resolves a major shortcoming of DynamicUser=1 units: previously they couldn't safely store persistant data. With this change they can have their own private state, log and data directories, which they can write to, but which are protected from UID recycling. With this change, if RootDirectory= or RootImage= are used it is ensured that the specified state/log/cache directories are always mounted in from the host. This change of semantics I think is much preferable since this means the root directory/image logic can be used easily for read-only resource bundling (as all writable data resides outside of the image). Note that this is a change of behaviour, but given that we haven't released any systemd version with StateDirectory= and friends implemented this should be a safe change to make (in particular as previously it wasn't clear what would actually happen when used in combination). Moreover, by making this change we can later add a "+" modifier to these setings too working similar to the same modifier in ReadOnlyPaths= and friends, making specified paths relative to the container itself.
2017-09-28 18:55:45 +02:00
char** empty_directories,
const BindMount *bind_mounts,
unsigned n_bind_mounts,
const char* tmp_dir,
const char* var_tmp_dir,
ProtectHome protect_home,
ProtectSystem protect_system) {
unsigned protect_home_cnt;
unsigned protect_system_cnt =
(protect_system == PROTECT_SYSTEM_STRICT ?
ELEMENTSOF(protect_system_strict_table) :
((protect_system == PROTECT_SYSTEM_FULL) ?
ELEMENTSOF(protect_system_full_table) :
((protect_system == PROTECT_SYSTEM_YES) ?
ELEMENTSOF(protect_system_yes_table) : 0)));
protect_home_cnt =
(protect_home == PROTECT_HOME_YES ?
ELEMENTSOF(protect_home_yes_table) :
((protect_home == PROTECT_HOME_READ_ONLY) ?
ELEMENTSOF(protect_home_read_only_table) : 0));
return !!tmp_dir + !!var_tmp_dir +
strv_length(read_write_paths) +
strv_length(read_only_paths) +
strv_length(inaccessible_paths) +
execute: make StateDirectory= and friends compatible with DynamicUser=1 and RootDirectory=/RootImage= Let's clean up the interaction of StateDirectory= (and friends) to DynamicUser=1: instead of creating these directories directly below /var/lib, place them in /var/lib/private instead if DynamicUser=1 is set, making that directory 0700 and owned by root:root. This way, if a dynamic UID is later reused, access to the old run's state directory is prohibited for that user. Then, use file system namespacing inside the service to make /var/lib/private a readable tmpfs, hiding all state directories that are not listed in StateDirectory=, and making access to the actual state directory possible. Mount all directories listed in StateDirectory= to the same places inside the service (which means they'll now be mounted into the tmpfs instance). Finally, add a symlink from the state directory name in /var/lib/ to the one in /var/lib/private, so that both the host and the service can access the path under the same location. Here's an example: let's say a service runs with StateDirectory=foo. When DynamicUser=0 is set, it will get the following setup, and no difference between what the unit and what the host sees: /var/lib/foo (created as directory) Now, if DynamicUser=1 is set, we'll instead get this on the host: /var/lib/private (created as directory with mode 0700, root:root) /var/lib/private/foo (created as directory) /var/lib/foo → private/foo (created as symlink) And from inside the unit: /var/lib/private (a tmpfs mount with mode 0755, root:root) /var/lib/private/foo (bind mounted from the host) /var/lib/foo → private/foo (the same symlink as above) This takes inspiration from how container trees are protected below /var/lib/machines: they generally reuse UIDs/GIDs of the host, but because /var/lib/machines itself is set to 0700 host users cannot access files in the container tree even if the UIDs/GIDs are reused. However, for this commit we add one further trick: inside and outside of the unit /var/lib/private is a different thing: outside it is a plain, inaccessible directory, and inside it is a world-readable tmpfs mount with only the whitelisted subdirs below it, bind mounte din. This means, from the outside the dir acts as an access barrier, but from the inside it does not. And the symlink created in /var/lib/foo itself points across the barrier in both cases, so that root and the unit's user always have access to these dirs without knowing the details of this mounting magic. This logic resolves a major shortcoming of DynamicUser=1 units: previously they couldn't safely store persistant data. With this change they can have their own private state, log and data directories, which they can write to, but which are protected from UID recycling. With this change, if RootDirectory= or RootImage= are used it is ensured that the specified state/log/cache directories are always mounted in from the host. This change of semantics I think is much preferable since this means the root directory/image logic can be used easily for read-only resource bundling (as all writable data resides outside of the image). Note that this is a change of behaviour, but given that we haven't released any systemd version with StateDirectory= and friends implemented this should be a safe change to make (in particular as previously it wasn't clear what would actually happen when used in combination). Moreover, by making this change we can later add a "+" modifier to these setings too working similar to the same modifier in ReadOnlyPaths= and friends, making specified paths relative to the container itself.
2017-09-28 18:55:45 +02:00
strv_length(empty_directories) +
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) +
(ns_info->protect_kernel_modules ? ELEMENTSOF(protect_kernel_modules_table) : 0) +
protect_home_cnt + protect_system_cnt +
(namespace_info_mount_apivfs(root_directory, ns_info) ? ELEMENTSOF(apivfs_table) : 0);
}
int setup_namespace(
const char* root_directory,
const char* root_image,
const NameSpaceInfo *ns_info,
char** read_write_paths,
char** read_only_paths,
char** inaccessible_paths,
execute: make StateDirectory= and friends compatible with DynamicUser=1 and RootDirectory=/RootImage= Let's clean up the interaction of StateDirectory= (and friends) to DynamicUser=1: instead of creating these directories directly below /var/lib, place them in /var/lib/private instead if DynamicUser=1 is set, making that directory 0700 and owned by root:root. This way, if a dynamic UID is later reused, access to the old run's state directory is prohibited for that user. Then, use file system namespacing inside the service to make /var/lib/private a readable tmpfs, hiding all state directories that are not listed in StateDirectory=, and making access to the actual state directory possible. Mount all directories listed in StateDirectory= to the same places inside the service (which means they'll now be mounted into the tmpfs instance). Finally, add a symlink from the state directory name in /var/lib/ to the one in /var/lib/private, so that both the host and the service can access the path under the same location. Here's an example: let's say a service runs with StateDirectory=foo. When DynamicUser=0 is set, it will get the following setup, and no difference between what the unit and what the host sees: /var/lib/foo (created as directory) Now, if DynamicUser=1 is set, we'll instead get this on the host: /var/lib/private (created as directory with mode 0700, root:root) /var/lib/private/foo (created as directory) /var/lib/foo → private/foo (created as symlink) And from inside the unit: /var/lib/private (a tmpfs mount with mode 0755, root:root) /var/lib/private/foo (bind mounted from the host) /var/lib/foo → private/foo (the same symlink as above) This takes inspiration from how container trees are protected below /var/lib/machines: they generally reuse UIDs/GIDs of the host, but because /var/lib/machines itself is set to 0700 host users cannot access files in the container tree even if the UIDs/GIDs are reused. However, for this commit we add one further trick: inside and outside of the unit /var/lib/private is a different thing: outside it is a plain, inaccessible directory, and inside it is a world-readable tmpfs mount with only the whitelisted subdirs below it, bind mounte din. This means, from the outside the dir acts as an access barrier, but from the inside it does not. And the symlink created in /var/lib/foo itself points across the barrier in both cases, so that root and the unit's user always have access to these dirs without knowing the details of this mounting magic. This logic resolves a major shortcoming of DynamicUser=1 units: previously they couldn't safely store persistant data. With this change they can have their own private state, log and data directories, which they can write to, but which are protected from UID recycling. With this change, if RootDirectory= or RootImage= are used it is ensured that the specified state/log/cache directories are always mounted in from the host. This change of semantics I think is much preferable since this means the root directory/image logic can be used easily for read-only resource bundling (as all writable data resides outside of the image). Note that this is a change of behaviour, but given that we haven't released any systemd version with StateDirectory= and friends implemented this should be a safe change to make (in particular as previously it wasn't clear what would actually happen when used in combination). Moreover, by making this change we can later add a "+" modifier to these setings too working similar to the same modifier in ReadOnlyPaths= and friends, making specified paths relative to the container itself.
2017-09-28 18:55:45 +02:00
char** empty_directories,
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,
DissectImageFlags dissect_image_flags) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
_cleanup_free_ void *root_hash = NULL;
MountEntry *m, *mounts = NULL;
size_t root_hash_size = 0;
bool make_slave = false;
const char *root;
unsigned n_mounts;
int r = 0;
assert(ns_info);
if (mount_flags == 0)
mount_flags = MS_SHARED;
if (root_image) {
dissect_image_flags |= DISSECT_IMAGE_REQUIRE_ROOT;
if (protect_system == PROTECT_SYSTEM_STRICT && strv_isempty(read_write_paths))
dissect_image_flags |= DISSECT_IMAGE_READ_ONLY;
r = loop_device_make_by_path(root_image,
dissect_image_flags & DISSECT_IMAGE_READ_ONLY ? O_RDONLY : O_RDWR,
&loop_device);
if (r < 0)
return r;
r = root_hash_load(root_image, &root_hash, &root_hash_size);
if (r < 0)
return r;
r = dissect_image(loop_device->fd, root_hash, root_hash_size, dissect_image_flags, &dissected_image);
if (r < 0)
return r;
r = dissected_image_decrypt(dissected_image, NULL, root_hash, root_hash_size, dissect_image_flags, &decrypted_image);
if (r < 0)
return r;
}
if (root_directory)
root = root_directory;
else if (root_image || n_bind_mounts > 0) {
/* If we are booting from an image, create a mount point for the image, if it's still missing. We use
* the same mount point for all images, which is safe, since they all live in their own namespaces
* after all, and hence won't see each other. We also use such a root directory whenever there are bind
* mounts configured, so that their source mounts are never obstructed by mounts we already applied
* while we are applying them. */
root = "/run/systemd/unit-root";
(void) mkdir_label(root, 0700);
} else
root = NULL;
n_mounts = namespace_calculate_mounts(
root,
ns_info,
read_write_paths,
read_only_paths,
inaccessible_paths,
execute: make StateDirectory= and friends compatible with DynamicUser=1 and RootDirectory=/RootImage= Let's clean up the interaction of StateDirectory= (and friends) to DynamicUser=1: instead of creating these directories directly below /var/lib, place them in /var/lib/private instead if DynamicUser=1 is set, making that directory 0700 and owned by root:root. This way, if a dynamic UID is later reused, access to the old run's state directory is prohibited for that user. Then, use file system namespacing inside the service to make /var/lib/private a readable tmpfs, hiding all state directories that are not listed in StateDirectory=, and making access to the actual state directory possible. Mount all directories listed in StateDirectory= to the same places inside the service (which means they'll now be mounted into the tmpfs instance). Finally, add a symlink from the state directory name in /var/lib/ to the one in /var/lib/private, so that both the host and the service can access the path under the same location. Here's an example: let's say a service runs with StateDirectory=foo. When DynamicUser=0 is set, it will get the following setup, and no difference between what the unit and what the host sees: /var/lib/foo (created as directory) Now, if DynamicUser=1 is set, we'll instead get this on the host: /var/lib/private (created as directory with mode 0700, root:root) /var/lib/private/foo (created as directory) /var/lib/foo → private/foo (created as symlink) And from inside the unit: /var/lib/private (a tmpfs mount with mode 0755, root:root) /var/lib/private/foo (bind mounted from the host) /var/lib/foo → private/foo (the same symlink as above) This takes inspiration from how container trees are protected below /var/lib/machines: they generally reuse UIDs/GIDs of the host, but because /var/lib/machines itself is set to 0700 host users cannot access files in the container tree even if the UIDs/GIDs are reused. However, for this commit we add one further trick: inside and outside of the unit /var/lib/private is a different thing: outside it is a plain, inaccessible directory, and inside it is a world-readable tmpfs mount with only the whitelisted subdirs below it, bind mounte din. This means, from the outside the dir acts as an access barrier, but from the inside it does not. And the symlink created in /var/lib/foo itself points across the barrier in both cases, so that root and the unit's user always have access to these dirs without knowing the details of this mounting magic. This logic resolves a major shortcoming of DynamicUser=1 units: previously they couldn't safely store persistant data. With this change they can have their own private state, log and data directories, which they can write to, but which are protected from UID recycling. With this change, if RootDirectory= or RootImage= are used it is ensured that the specified state/log/cache directories are always mounted in from the host. This change of semantics I think is much preferable since this means the root directory/image logic can be used easily for read-only resource bundling (as all writable data resides outside of the image). Note that this is a change of behaviour, but given that we haven't released any systemd version with StateDirectory= and friends implemented this should be a safe change to make (in particular as previously it wasn't clear what would actually happen when used in combination). Moreover, by making this change we can later add a "+" modifier to these setings too working similar to the same modifier in ReadOnlyPaths= and friends, making specified paths relative to the container itself.
2017-09-28 18:55:45 +02:00
empty_directories,
bind_mounts, n_bind_mounts,
tmp_dir, var_tmp_dir,
protect_home, protect_system);
/* Set mount slave mode */
if (root || n_mounts > 0)
make_slave = true;
if (n_mounts > 0) {
m = mounts = (MountEntry *) alloca0(n_mounts * sizeof(MountEntry));
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
r = append_access_mounts(&m, read_write_paths, READWRITE);
if (r < 0)
goto finish;
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
r = append_access_mounts(&m, read_only_paths, READONLY);
if (r < 0)
goto finish;
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
r = append_access_mounts(&m, inaccessible_paths, INACCESSIBLE);
if (r < 0)
goto finish;
execute: make StateDirectory= and friends compatible with DynamicUser=1 and RootDirectory=/RootImage= Let's clean up the interaction of StateDirectory= (and friends) to DynamicUser=1: instead of creating these directories directly below /var/lib, place them in /var/lib/private instead if DynamicUser=1 is set, making that directory 0700 and owned by root:root. This way, if a dynamic UID is later reused, access to the old run's state directory is prohibited for that user. Then, use file system namespacing inside the service to make /var/lib/private a readable tmpfs, hiding all state directories that are not listed in StateDirectory=, and making access to the actual state directory possible. Mount all directories listed in StateDirectory= to the same places inside the service (which means they'll now be mounted into the tmpfs instance). Finally, add a symlink from the state directory name in /var/lib/ to the one in /var/lib/private, so that both the host and the service can access the path under the same location. Here's an example: let's say a service runs with StateDirectory=foo. When DynamicUser=0 is set, it will get the following setup, and no difference between what the unit and what the host sees: /var/lib/foo (created as directory) Now, if DynamicUser=1 is set, we'll instead get this on the host: /var/lib/private (created as directory with mode 0700, root:root) /var/lib/private/foo (created as directory) /var/lib/foo → private/foo (created as symlink) And from inside the unit: /var/lib/private (a tmpfs mount with mode 0755, root:root) /var/lib/private/foo (bind mounted from the host) /var/lib/foo → private/foo (the same symlink as above) This takes inspiration from how container trees are protected below /var/lib/machines: they generally reuse UIDs/GIDs of the host, but because /var/lib/machines itself is set to 0700 host users cannot access files in the container tree even if the UIDs/GIDs are reused. However, for this commit we add one further trick: inside and outside of the unit /var/lib/private is a different thing: outside it is a plain, inaccessible directory, and inside it is a world-readable tmpfs mount with only the whitelisted subdirs below it, bind mounte din. This means, from the outside the dir acts as an access barrier, but from the inside it does not. And the symlink created in /var/lib/foo itself points across the barrier in both cases, so that root and the unit's user always have access to these dirs without knowing the details of this mounting magic. This logic resolves a major shortcoming of DynamicUser=1 units: previously they couldn't safely store persistant data. With this change they can have their own private state, log and data directories, which they can write to, but which are protected from UID recycling. With this change, if RootDirectory= or RootImage= are used it is ensured that the specified state/log/cache directories are always mounted in from the host. This change of semantics I think is much preferable since this means the root directory/image logic can be used easily for read-only resource bundling (as all writable data resides outside of the image). Note that this is a change of behaviour, but given that we haven't released any systemd version with StateDirectory= and friends implemented this should be a safe change to make (in particular as previously it wasn't clear what would actually happen when used in combination). Moreover, by making this change we can later add a "+" modifier to these setings too working similar to the same modifier in ReadOnlyPaths= and friends, making specified paths relative to the container itself.
2017-09-28 18:55:45 +02:00
r = append_empty_dir_mounts(&m, empty_directories);
if (r < 0)
goto finish;
r = append_bind_mounts(&m, bind_mounts, n_bind_mounts);
if (r < 0)
goto finish;
if (tmp_dir) {
*(m++) = (MountEntry) {
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
.path_const = "/tmp",
.mode = PRIVATE_TMP,
};
}
if (var_tmp_dir) {
*(m++) = (MountEntry) {
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
.path_const = "/var/tmp",
.mode = PRIVATE_VAR_TMP,
};
}
if (ns_info->private_dev) {
*(m++) = (MountEntry) {
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
.path_const = "/dev",
.mode = PRIVATE_DEV,
};
}
if (ns_info->protect_kernel_tunables) {
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
r = append_static_mounts(&m, protect_kernel_tunables_table, ELEMENTSOF(protect_kernel_tunables_table), ns_info->ignore_protect_paths);
if (r < 0)
goto finish;
}
if (ns_info->protect_kernel_modules) {
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
r = append_static_mounts(&m, protect_kernel_modules_table, ELEMENTSOF(protect_kernel_modules_table), ns_info->ignore_protect_paths);
if (r < 0)
goto finish;
}
if (ns_info->protect_control_groups) {
*(m++) = (MountEntry) {
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
.path_const = "/sys/fs/cgroup",
.mode = READONLY,
};
}
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
r = append_protect_home(&m, protect_home, ns_info->ignore_protect_paths);
if (r < 0)
goto finish;
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
r = append_protect_system(&m, protect_system, false);
if (r < 0)
goto finish;
if (namespace_info_mount_apivfs(root, ns_info)) {
r = append_static_mounts(&m, apivfs_table, ELEMENTSOF(apivfs_table), ns_info->ignore_protect_paths);
if (r < 0)
goto finish;
}
assert(mounts + n_mounts == m);
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
/* Prepend the root directory where that's necessary */
r = prefix_where_needed(mounts, n_mounts, root);
namespace: simplify, optimize and extend handling of mounts for namespace This changes a couple of things in the namespace handling: It merges the BindMount and TargetMount structures. They are mostly the same, hence let's just use the same structue, and rely on C's implicit zero initialization of partially initialized structures for the unneeded fields. This reworks memory management of each entry a bit. It now contains one "const" and one "malloc" path. We use the former whenever we can, but use the latter when we have to, which is the case when we have to chase symlinks or prefix a root directory. This means in the common case we don't actually need to allocate any dynamic memory. To make this easy to use we add an accessor function bind_mount_path() which retrieves the right path string from a BindMount structure. While we are at it, also permit "+" as prefix for dirs configured with ReadOnlyPaths= and friends: if specified the root directory of the unit is implicited prefixed. This also drops set_bind_mount() and uses C99 structure initialization instead, which I think is more readable and clarifies what is being done. This drops append_protect_kernel_tunables() and append_protect_kernel_modules() as append_static_mounts() is now simple enough to be called directly. Prefixing with the root dir is now done in an explicit step in prefix_where_needed(). It will prepend the root directory on each entry that doesn't have it prefixed yet. The latter is determined depending on an extra bit in the BindMount structure.
2016-11-15 01:42:54 +01:00
if (r < 0)
goto finish;
qsort(mounts, n_mounts, sizeof(MountEntry), mount_path_compare);
drop_duplicates(mounts, &n_mounts);
drop_outside_root(root, mounts, &n_mounts);
drop_inaccessible(mounts, &n_mounts);
drop_nop(mounts, &n_mounts);
}
if (unshare(CLONE_NEWNS) < 0) {
r = -errno;
goto finish;
}
if (make_slave) {
/* Remount / as SLAVE so that nothing now mounted in the namespace
shows up in the parent */
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
r = -errno;
goto finish;
}
}
/* Try to set up the new root directory before mounting anything there */
if (root)
(void) base_filesystem_create(root, UID_INVALID, GID_INVALID);
if (root_image) {
/* A root image is specified, mount it to the right place */
r = dissected_image_mount(dissected_image, root, dissect_image_flags);
if (r < 0)
goto finish;
if (decrypted_image) {
r = decrypted_image_relinquish(decrypted_image);
if (r < 0)
goto finish;
}
loop_device_relinquish(loop_device);
} else if (root_directory) {
/* A root directory is specified. Turn its directory into bind mount, if it isn't one yet. */
r = path_is_mount_point(root, NULL, AT_SYMLINK_FOLLOW);
if (r < 0)
goto finish;
if (r == 0) {
if (mount(root, root, NULL, MS_BIND|MS_REC, NULL) < 0) {
r = -errno;
goto finish;
}
}
} else if (root) {
/* Let's mount the main root directory to the root directory to use */
if (mount("/", root, NULL, MS_BIND|MS_REC, NULL) < 0) {
r = -errno;
goto finish;
}
}
if (n_mounts > 0) {
_cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
namespace: rework how ReadWritePaths= is applied Previously, if ReadWritePaths= was nested inside a ReadOnlyPaths= specification, then we'd first recursively apply the ReadOnlyPaths= paths, and make everything below read-only, only in order to then flip the read-only bit again for the subdirs listed in ReadWritePaths= below it. This is not only ugly (as for the dirs in question we first turn on the RO bit, only to turn it off again immediately after), but also problematic in containers, where a container manager might have marked a set of dirs read-only and this code will undo this is ReadWritePaths= is set for any. With this patch behaviour in this regard is altered: ReadOnlyPaths= will not be applied to the children listed in ReadWritePaths= in the first place, so that we do not need to turn off the RO bit for those after all. This means that ReadWritePaths=/ReadOnlyPaths= may only be used to turn on the RO bit, but never to turn it off again. Or to say this differently: if some dirs are marked read-only via some external tool, then ReadWritePaths= will not undo it. This is not only the safer option, but also more in-line with what the man page currently claims: "Entries (files or directories) listed in ReadWritePaths= are accessible from within the namespace with the same access rights as from outside." To implement this change bind_remount_recursive() gained a new "blacklist" string list parameter, which when passed may contain subdirs that shall be excluded from the read-only mounting. A number of functions are updated to add more debug logging to make this more digestable.
2016-09-25 10:40:51 +02:00
char **blacklist;
unsigned j;
/* Open /proc/self/mountinfo now as it may become unavailable if we mount anything on top of /proc.
* For example, this is the case with the option: 'InaccessiblePaths=/proc' */
proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
if (!proc_self_mountinfo) {
r = -errno;
goto finish;
}
namespace: rework how ReadWritePaths= is applied Previously, if ReadWritePaths= was nested inside a ReadOnlyPaths= specification, then we'd first recursively apply the ReadOnlyPaths= paths, and make everything below read-only, only in order to then flip the read-only bit again for the subdirs listed in ReadWritePaths= below it. This is not only ugly (as for the dirs in question we first turn on the RO bit, only to turn it off again immediately after), but also problematic in containers, where a container manager might have marked a set of dirs read-only and this code will undo this is ReadWritePaths= is set for any. With this patch behaviour in this regard is altered: ReadOnlyPaths= will not be applied to the children listed in ReadWritePaths= in the first place, so that we do not need to turn off the RO bit for those after all. This means that ReadWritePaths=/ReadOnlyPaths= may only be used to turn on the RO bit, but never to turn it off again. Or to say this differently: if some dirs are marked read-only via some external tool, then ReadWritePaths= will not undo it. This is not only the safer option, but also more in-line with what the man page currently claims: "Entries (files or directories) listed in ReadWritePaths= are accessible from within the namespace with the same access rights as from outside." To implement this change bind_remount_recursive() gained a new "blacklist" string list parameter, which when passed may contain subdirs that shall be excluded from the read-only mounting. A number of functions are updated to add more debug logging to make this more digestable.
2016-09-25 10:40:51 +02:00
/* First round, add in all special mounts we need */
for (m = mounts; m < mounts + n_mounts; ++m) {
r = apply_mount(root, m, tmp_dir, var_tmp_dir);
if (r < 0)
goto finish;
}
namespace: rework how ReadWritePaths= is applied Previously, if ReadWritePaths= was nested inside a ReadOnlyPaths= specification, then we'd first recursively apply the ReadOnlyPaths= paths, and make everything below read-only, only in order to then flip the read-only bit again for the subdirs listed in ReadWritePaths= below it. This is not only ugly (as for the dirs in question we first turn on the RO bit, only to turn it off again immediately after), but also problematic in containers, where a container manager might have marked a set of dirs read-only and this code will undo this is ReadWritePaths= is set for any. With this patch behaviour in this regard is altered: ReadOnlyPaths= will not be applied to the children listed in ReadWritePaths= in the first place, so that we do not need to turn off the RO bit for those after all. This means that ReadWritePaths=/ReadOnlyPaths= may only be used to turn on the RO bit, but never to turn it off again. Or to say this differently: if some dirs are marked read-only via some external tool, then ReadWritePaths= will not undo it. This is not only the safer option, but also more in-line with what the man page currently claims: "Entries (files or directories) listed in ReadWritePaths= are accessible from within the namespace with the same access rights as from outside." To implement this change bind_remount_recursive() gained a new "blacklist" string list parameter, which when passed may contain subdirs that shall be excluded from the read-only mounting. A number of functions are updated to add more debug logging to make this more digestable.
2016-09-25 10:40:51 +02:00
/* 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*) mount_entry_path(mounts+j);
namespace: rework how ReadWritePaths= is applied Previously, if ReadWritePaths= was nested inside a ReadOnlyPaths= specification, then we'd first recursively apply the ReadOnlyPaths= paths, and make everything below read-only, only in order to then flip the read-only bit again for the subdirs listed in ReadWritePaths= below it. This is not only ugly (as for the dirs in question we first turn on the RO bit, only to turn it off again immediately after), but also problematic in containers, where a container manager might have marked a set of dirs read-only and this code will undo this is ReadWritePaths= is set for any. With this patch behaviour in this regard is altered: ReadOnlyPaths= will not be applied to the children listed in ReadWritePaths= in the first place, so that we do not need to turn off the RO bit for those after all. This means that ReadWritePaths=/ReadOnlyPaths= may only be used to turn on the RO bit, but never to turn it off again. Or to say this differently: if some dirs are marked read-only via some external tool, then ReadWritePaths= will not undo it. This is not only the safer option, but also more in-line with what the man page currently claims: "Entries (files or directories) listed in ReadWritePaths= are accessible from within the namespace with the same access rights as from outside." To implement this change bind_remount_recursive() gained a new "blacklist" string list parameter, which when passed may contain subdirs that shall be excluded from the read-only mounting. A number of functions are updated to add more debug logging to make this more digestable.
2016-09-25 10:40:51 +02:00
blacklist[j] = NULL;
/* Second round, flip the ro bits if necessary. */
for (m = mounts; m < mounts + n_mounts; ++m) {
r = make_read_only(m, blacklist, proc_self_mountinfo);
if (r < 0)
goto finish;
}
}
if (root) {
/* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
r = mount_move_root(root);
if (r < 0)
goto finish;
}
/* Remount / as the desired mode. Not that this will not
* reestablish propagation from our side to the host, since
* what's disconnected is disconnected. */
if (mount(NULL, "/", NULL, mount_flags | MS_REC, NULL) < 0) {
r = -errno;
goto finish;
}
r = 0;
finish:
for (m = mounts; m < mounts + n_mounts; m++)
mount_entry_done(m);
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];
sd_id128_t boot_id;
int r;
assert(id);
assert(prefix);
assert(path);
/* We include the boot id in the directory so that after a
* reboot we can easily identify obsolete directories. */
r = sd_id128_get_boot(&boot_id);
if (r < 0)
return r;
x = strjoin(prefix, "/systemd-private-", sd_id128_to_string(boot_id, bid), "-", id, "-XXXXXX");
if (!x)
return -ENOMEM;
RUN_WITH_UMASK(0077)
if (!mkdtemp(x))
return -errno;
RUN_WITH_UMASK(0000) {
char *y;
y = strjoina(x, "/tmp");
if (mkdir(y, 0777 | S_ISVTX) < 0)
return -errno;
}
*path = x;
x = NULL;
return 0;
}
int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) {
char *a, *b;
int r;
assert(id);
assert(tmp_dir);
assert(var_tmp_dir);
r = setup_one_tmp_dir(id, "/tmp", &a);
if (r < 0)
return r;
r = setup_one_tmp_dir(id, "/var/tmp", &b);
if (r < 0) {
char *t;
t = strjoina(a, "/tmp");
rmdir(t);
rmdir(a);
free(a);
return r;
}
*tmp_dir = a;
*var_tmp_dir = b;
return 0;
}
int setup_netns(int netns_storage_socket[2]) {
_cleanup_close_ int netns = -1;
int r, q;
assert(netns_storage_socket);
assert(netns_storage_socket[0] >= 0);
assert(netns_storage_socket[1] >= 0);
/* We use the passed socketpair as a storage buffer for our
2013-11-27 20:31:51 +01:00
* namespace reference fd. Whatever process runs this first
* shall create a new namespace, all others should just join
* it. To serialize that we use a file lock on the socket
* pair.
*
* It's a bit crazy, but hey, works great! */
if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
return -errno;
netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
if (netns == -EAGAIN) {
/* Nothing stored yet, so let's create a new namespace */
if (unshare(CLONE_NEWNET) < 0) {
r = -errno;
goto fail;
}
loopback_setup();
netns = open("/proc/self/ns/net", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (netns < 0) {
r = -errno;
goto fail;
}
r = 1;
} else if (netns < 0) {
r = netns;
goto fail;
} else {
/* Yay, found something, so let's join the namespace */
if (setns(netns, CLONE_NEWNET) < 0) {
r = -errno;
goto fail;
}
r = 0;
}
q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT);
if (q < 0) {
r = q;
goto fail;
}
fail:
2016-07-14 12:28:54 +02:00
(void) lockf(netns_storage_socket[0], F_ULOCK, 0);
return r;
}
static const char *const protect_home_table[_PROTECT_HOME_MAX] = {
[PROTECT_HOME_NO] = "no",
[PROTECT_HOME_YES] = "yes",
[PROTECT_HOME_READ_ONLY] = "read-only",
};
DEFINE_STRING_TABLE_LOOKUP(protect_home, ProtectHome);
static const char *const protect_system_table[_PROTECT_SYSTEM_MAX] = {
[PROTECT_SYSTEM_NO] = "no",
[PROTECT_SYSTEM_YES] = "yes",
[PROTECT_SYSTEM_FULL] = "full",
[PROTECT_SYSTEM_STRICT] = "strict",
};
DEFINE_STRING_TABLE_LOOKUP(protect_system, ProtectSystem);