From af964954c6a44bd664efe89052ced9584a966baa Mon Sep 17 00:00:00 2001 From: Djalal Harouni Date: Sun, 6 Nov 2016 23:31:55 +0100 Subject: core: on DynamicUser= make sure that protecting sensitive paths is enforced (#4596) This adds a variable that is always set to false to make sure that protect paths inside sandbox are always enforced and not ignored. The only case when it is set to true is on DynamicUser=no and RootDirectory=/chroot is set. This allows users to use more our sandbox features inside RootDirectory= The only exception is ProtectSystem=full|strict and when DynamicUser=yes is implied. Currently RootDirectory= is not fully compatible with these due to two reasons: * /chroot/usr|etc has to be present on ProtectSystem=full * /chroot// has to be a mount point on ProtectSystem=strict. --- src/core/execute.c | 9 +++++++++ src/core/namespace.c | 47 +++++++++++++++++++++++++++++------------------ src/core/namespace.h | 1 + 3 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/core/execute.c b/src/core/execute.c index 8015aa2cb9..f666f7c6ce 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2034,6 +2034,7 @@ static int apply_mount_namespace(Unit *u, const ExecContext *context, char *tmp = NULL, *var = NULL; const char *root_dir = NULL; NameSpaceInfo ns_info = { + .ignore_protect_paths = false, .private_dev = context->private_devices, .protect_control_groups = context->protect_control_groups, .protect_kernel_tunables = context->protect_kernel_tunables, @@ -2060,6 +2061,14 @@ static int apply_mount_namespace(Unit *u, const ExecContext *context, if (params->flags & EXEC_APPLY_CHROOT) root_dir = context->root_directory; + /* + * If DynamicUser=no and RootDirectory= is set then lets pass a relaxed + * sandbox info, otherwise enforce it, don't ignore protected paths and + * fail if we are enable to apply the sandbox inside the mount namespace. + */ + if (!context->dynamic_user && root_dir) + ns_info.ignore_protect_paths = true; + r = setup_namespace(root_dir, &ns_info, rw, context->read_only_paths, context->inaccessible_paths, diff --git a/src/core/namespace.c b/src/core/namespace.c index f361e139ac..308e4d768e 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -200,13 +200,15 @@ static int append_mounts(BindMount **p, char **strv, MountMode mode) { return 0; } -static int append_target_mounts(BindMount **p, const char *root_directory, const TargetMount *mounts, const size_t size) { +static int append_target_mounts(BindMount **p, const char *root_directory, + const TargetMount *mounts, const size_t size, bool ignore_protect) { unsigned i; assert(p); assert(mounts); for (i = 0; i < size; i++) { + bool ignore; /* * Here we assume that the ignore field is set during * declaration we do not support "-" at the beginning. @@ -221,27 +223,33 @@ static int append_target_mounts(BindMount **p, const char *root_directory, const if (!path_is_absolute(path)) return -EINVAL; - set_bind_mount((*p)++, path, m->mode, m->ignore); + /* + * Ignore paths if they are not present. First we use our + * static tables otherwise fallback to Unit context. + */ + ignore = m->ignore || ignore_protect; + + set_bind_mount((*p)++, path, m->mode, ignore); } return 0; } -static int append_protect_kernel_tunables(BindMount **p, const char *root_directory) { +static int append_protect_kernel_tunables(BindMount **p, const char *root_directory, bool ignore_protect) { assert(p); return append_target_mounts(p, root_directory, protect_kernel_tunables_table, - ELEMENTSOF(protect_kernel_tunables_table)); + ELEMENTSOF(protect_kernel_tunables_table), ignore_protect); } -static int append_protect_kernel_modules(BindMount **p, const char *root_directory) { +static int append_protect_kernel_modules(BindMount **p, const char *root_directory, bool ignore_protect) { assert(p); return append_target_mounts(p, root_directory, protect_kernel_modules_table, - ELEMENTSOF(protect_kernel_modules_table)); + ELEMENTSOF(protect_kernel_modules_table), ignore_protect); } -static int append_protect_home(BindMount **p, const char *root_directory, ProtectHome protect_home) { +static int append_protect_home(BindMount **p, const char *root_directory, ProtectHome protect_home, bool ignore_protect) { int r = 0; assert(p); @@ -252,11 +260,12 @@ static int append_protect_home(BindMount **p, const char *root_directory, Protec switch (protect_home) { case PROTECT_HOME_READ_ONLY: r = append_target_mounts(p, root_directory, protect_home_read_only_table, - ELEMENTSOF(protect_home_read_only_table)); + ELEMENTSOF(protect_home_read_only_table), + ignore_protect); break; case PROTECT_HOME_YES: r = append_target_mounts(p, root_directory, protect_home_yes_table, - ELEMENTSOF(protect_home_yes_table)); + ELEMENTSOF(protect_home_yes_table), ignore_protect); break; default: r = -EINVAL; @@ -266,7 +275,7 @@ static int append_protect_home(BindMount **p, const char *root_directory, Protec return r; } -static int append_protect_system(BindMount **p, const char *root_directory, ProtectSystem protect_system) { +static int append_protect_system(BindMount **p, const char *root_directory, ProtectSystem protect_system, bool ignore_protect) { int r = 0; assert(p); @@ -277,15 +286,15 @@ static int append_protect_system(BindMount **p, const char *root_directory, Prot switch (protect_system) { case PROTECT_SYSTEM_STRICT: r = append_target_mounts(p, root_directory, protect_system_strict_table, - ELEMENTSOF(protect_system_strict_table)); + ELEMENTSOF(protect_system_strict_table), ignore_protect); break; case PROTECT_SYSTEM_YES: r = append_target_mounts(p, root_directory, protect_system_yes_table, - ELEMENTSOF(protect_system_yes_table)); + ELEMENTSOF(protect_system_yes_table), ignore_protect); break; case PROTECT_SYSTEM_FULL: r = append_target_mounts(p, root_directory, protect_system_full_table, - ELEMENTSOF(protect_system_full_table)); + ELEMENTSOF(protect_system_full_table), ignore_protect); break; default: r = -EINVAL; @@ -614,7 +623,6 @@ static int apply_mount( return log_debug_errno(r, "Failed to determine whether %s is already a mount point: %m", m->path); 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 = m->path; break; @@ -801,13 +809,15 @@ int setup_namespace( } if (ns_info->protect_kernel_tunables) { - r = append_protect_kernel_tunables(&m, root_directory); + r = append_protect_kernel_tunables(&m, root_directory, + ns_info->ignore_protect_paths); if (r < 0) goto finish; } if (ns_info->protect_kernel_modules) { - r = append_protect_kernel_modules(&m, root_directory); + r = append_protect_kernel_modules(&m, root_directory, + ns_info->ignore_protect_paths); if (r < 0) goto finish; } @@ -818,11 +828,12 @@ int setup_namespace( goto finish; } - r = append_protect_home(&m, root_directory, protect_home); + r = append_protect_home(&m, root_directory, protect_home, + ns_info->ignore_protect_paths); if (r < 0) goto finish; - r = append_protect_system(&m, root_directory, protect_system); + r = append_protect_system(&m, root_directory, protect_system, false); if (r < 0) goto finish; diff --git a/src/core/namespace.h b/src/core/namespace.h index 6310638e9a..2c278fd457 100644 --- a/src/core/namespace.h +++ b/src/core/namespace.h @@ -44,6 +44,7 @@ typedef enum ProtectSystem { } ProtectSystem; struct NameSpaceInfo { + bool ignore_protect_paths:1; bool private_dev:1; bool protect_control_groups:1; bool protect_kernel_tunables:1; -- cgit v1.2.3-54-g00ecf