core: Use a subdirectory of /run/ for PrivateDevices=

When we're starting early boot services such as systemd-userdbd.service,
/tmp might not yet be mounted, so let's use a directory in /run instead
which is guaranteed to be available.
This commit is contained in:
Daan De Meyer
2023-10-02 12:23:13 +02:00
parent 4a9e03aa6b
commit cd7f3702eb
5 changed files with 50 additions and 16 deletions
+1
View File
@@ -3307,6 +3307,7 @@ static int apply_mount_namespace(
extension_dir,
root_dir || root_image ? params->notify_socket : NULL,
host_os_release_stage,
params->runtime_scope,
error_path);
/* If we couldn't set up the namespace this is probably due to a missing capability. setup_namespace() reports
+45 -16
View File
@@ -909,7 +909,19 @@ add_symlink:
return 0;
}
static int mount_private_dev(MountEntry *m) {
static char *settle_runtime_dir(RuntimeScope scope) {
char *runtime_dir;
if (scope != RUNTIME_SCOPE_USER)
return strdup("/run/");
if (asprintf(&runtime_dir, "/run/user/" UID_FMT, geteuid()) < 0)
return NULL;
return runtime_dir;
}
static int mount_private_dev(MountEntry *m, RuntimeScope scope) {
static const char devnodes[] =
"/dev/null\0"
"/dev/zero\0"
@@ -918,13 +930,21 @@ static int mount_private_dev(MountEntry *m) {
"/dev/urandom\0"
"/dev/tty\0";
char temporary_mount[] = "/tmp/namespace-dev-XXXXXX";
_cleanup_free_ char *runtime_dir = NULL, *temporary_mount = NULL;
const char *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
bool can_mknod = true;
int r;
assert(m);
runtime_dir = settle_runtime_dir(scope);
if (!runtime_dir)
return log_oom_debug();
temporary_mount = path_join(runtime_dir, "systemd/namespace-dev-XXXXXX");
if (!temporary_mount)
return log_oom_debug();
if (!mkdtemp(temporary_mount))
return log_debug_errno(errno, "Failed to create temporary directory '%s': %m", temporary_mount);
@@ -1364,7 +1384,8 @@ static int apply_one_mount(
MountEntry *m,
const ImagePolicy *mount_image_policy,
const ImagePolicy *extension_image_policy,
const NamespaceInfo *ns_info) {
const NamespaceInfo *ns_info,
RuntimeScope scope) {
_cleanup_free_ char *inaccessible = NULL;
bool rbind = true, make = false;
@@ -1379,8 +1400,7 @@ static int apply_one_mount(
switch (m->mode) {
case INACCESSIBLE: {
_cleanup_free_ char *tmp = NULL;
const char *runtime_dir;
_cleanup_free_ char *runtime_dir = NULL;
struct stat target;
/* First, get rid of everything that is below if there
@@ -1396,14 +1416,14 @@ static int apply_one_mount(
mount_entry_path(m));
}
if (geteuid() == 0)
runtime_dir = "/run";
else {
if (asprintf(&tmp, "/run/user/" UID_FMT, geteuid()) < 0)
return -ENOMEM;
runtime_dir = tmp;
}
/* We don't pass the literal runtime scope through here but one based purely on our UID. This
* means that the root user's --user services will use the host's inaccessible inodes rather
* then root's private ones. This is preferable since it means device nodes that are
* overmounted to make them inaccessible will be overmounted with a device node, rather than
* an AF_UNIX socket inode. */
runtime_dir = settle_runtime_dir(geteuid() == 0 ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER);
if (!runtime_dir)
return log_oom_debug();
r = mode_to_inaccessible_node(runtime_dir, target.st_mode, &inaccessible);
if (r < 0)
@@ -1523,7 +1543,7 @@ static int apply_one_mount(
break;
case PRIVATE_DEV:
return mount_private_dev(m);
return mount_private_dev(m, scope);
case BIND_DEV:
return mount_bind_dev(m);
@@ -1824,6 +1844,7 @@ static int apply_mounts(
const NamespaceInfo *ns_info,
MountEntry *mounts,
size_t *n_mounts,
RuntimeScope scope,
char **symlinks,
char **error_path) {
@@ -1875,7 +1896,7 @@ static int apply_mounts(
break;
}
r = apply_one_mount(root, m, mount_image_policy, extension_image_policy, ns_info);
r = apply_one_mount(root, m, mount_image_policy, extension_image_policy, ns_info, scope);
if (r < 0) {
if (error_path && mount_entry_path(m))
*error_path = strdup(mount_entry_path(m));
@@ -2030,6 +2051,7 @@ int setup_namespace(
const char *extension_dir,
const char *notify_socket,
const char *host_os_release_stage,
RuntimeScope scope,
char **error_path) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
@@ -2490,7 +2512,14 @@ int setup_namespace(
(void) base_filesystem_create(root, UID_INVALID, GID_INVALID);
/* Now make the magic happen */
r = apply_mounts(root, mount_image_policy, extension_image_policy, ns_info, mounts, &n_mounts, symlinks, error_path);
r = apply_mounts(root,
mount_image_policy,
extension_image_policy,
ns_info,
mounts, &n_mounts,
scope,
symlinks,
error_path);
if (r < 0)
goto finish;
+2
View File
@@ -16,6 +16,7 @@ typedef struct MountImage MountImage;
#include "fs-util.h"
#include "macro.h"
#include "namespace-util.h"
#include "runtime-scope.h"
#include "string-util.h"
typedef enum ProtectHome {
@@ -134,6 +135,7 @@ int setup_namespace(
const char *extension_dir,
const char *notify_socket,
const char *host_os_release_stage,
RuntimeScope scope,
char **error_path);
#define RUN_SYSTEMD_EMPTY "/run/systemd/empty"
+1
View File
@@ -206,6 +206,7 @@ TEST(protect_kernel_logs) {
NULL,
NULL,
NULL,
RUNTIME_SCOPE_SYSTEM,
NULL);
assert_se(r == 0);
+1
View File
@@ -108,6 +108,7 @@ int main(int argc, char *argv[]) {
NULL,
NULL,
NULL,
RUNTIME_SCOPE_SYSTEM,
NULL);
if (r < 0) {
log_error_errno(r, "Failed to set up namespace: %m");