core:sandbox: lets make /lib/modules/ inaccessible on ProtectKernelModules=

Lets go further and make /lib/modules/ inaccessible for services that do
not have business with modules, this is a minor improvment but it may
help on setups with custom modules and they are limited... in regard of
kernel auto-load feature.

This change introduce NameSpaceInfo struct which we may embed later
inside ExecContext but for now lets just reduce the argument number to
setup_namespace() and merge ProtectKernelModules feature.
This commit is contained in:
Djalal Harouni 2016-10-12 14:11:16 +02:00
parent ac246d9868
commit c575770b75
5 changed files with 69 additions and 27 deletions

View file

@ -1415,7 +1415,10 @@
kernels. It is recomended to turn this on for most services that do not need special kernels. It is recomended to turn this on for most services that do not need special
file systems or extra kernel modules to work. Default to off. Enabling this option file systems or extra kernel modules to work. Default to off. Enabling this option
removes <constant>CAP_SYS_MODULE</constant> from the capability bounding set for removes <constant>CAP_SYS_MODULE</constant> from the capability bounding set for
the unit, and installs a system call filter to block module system calls. the unit, and installs a system call filter to block module system calls,
also <filename>/usr/lib/modules</filename> is made inaccessible. For this
setting the same restrictions regarding mount propagation and privileges
apply as for <varname>ReadOnlyPaths=</varname> and related calls, see above.
Note that limited automatic module loading due to user configuration or kernel Note that limited automatic module loading due to user configuration or kernel
mapping tables might still happen as side effect of requested user operations, mapping tables might still happen as side effect of requested user operations,
both privileged and unprivileged. To disable module auto-load feature please see both privileged and unprivileged. To disable module auto-load feature please see

View file

@ -1766,6 +1766,7 @@ static bool exec_needs_mount_namespace(
context->protect_system != PROTECT_SYSTEM_NO || context->protect_system != PROTECT_SYSTEM_NO ||
context->protect_home != PROTECT_HOME_NO || context->protect_home != PROTECT_HOME_NO ||
context->protect_kernel_tunables || context->protect_kernel_tunables ||
context->protect_kernel_modules ||
context->protect_control_groups) context->protect_control_groups)
return true; return true;
@ -2493,6 +2494,12 @@ static int exec_child(
if (needs_mount_namespace) { if (needs_mount_namespace) {
_cleanup_free_ char **rw = NULL; _cleanup_free_ char **rw = NULL;
char *tmp = NULL, *var = NULL; char *tmp = NULL, *var = NULL;
NameSpaceInfo ns_info = {
.private_dev = context->private_devices,
.protect_control_groups = context->protect_control_groups,
.protect_kernel_tunables = context->protect_kernel_tunables,
.protect_kernel_modules = context->protect_kernel_modules,
};
/* The runtime struct only contains the parent /* The runtime struct only contains the parent
* of the private /tmp, which is * of the private /tmp, which is
@ -2515,14 +2522,12 @@ static int exec_child(
r = setup_namespace( r = setup_namespace(
(params->flags & EXEC_APPLY_CHROOT) ? context->root_directory : NULL, (params->flags & EXEC_APPLY_CHROOT) ? context->root_directory : NULL,
&ns_info,
rw, rw,
context->read_only_paths, context->read_only_paths,
context->inaccessible_paths, context->inaccessible_paths,
tmp, tmp,
var, var,
context->private_devices,
context->protect_kernel_tunables,
context->protect_control_groups,
context->protect_home, context->protect_home,
context->protect_system, context->protect_system,
context->mount_flags); context->mount_flags);

View file

@ -97,6 +97,14 @@ static const TargetMount protect_kernel_tunables_table[] = {
{ "/sys/fs/cgroup", READWRITE, false }, /* READONLY is set by ProtectControlGroups= option */ { "/sys/fs/cgroup", READWRITE, false }, /* READONLY is set by ProtectControlGroups= option */
}; };
/* ProtectKernelModules= option */
static const TargetMount protect_kernel_modules_table[] = {
#ifdef 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 * ProtectHome=read-only table, protect $HOME and $XDG_RUNTIME_DIR and rest of
* system should be protected by ProtectSystem= * system should be protected by ProtectSystem=
@ -207,6 +215,13 @@ static int append_protect_kernel_tunables(BindMount **p, const char *root_direct
ELEMENTSOF(protect_kernel_tunables_table)); ELEMENTSOF(protect_kernel_tunables_table));
} }
static int append_protect_kernel_modules(BindMount **p, const char *root_directory) {
assert(p);
return append_target_mounts(p, root_directory, protect_kernel_modules_table,
ELEMENTSOF(protect_kernel_modules_table));
}
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) {
int r = 0; int r = 0;
@ -660,14 +675,12 @@ static int chase_all_symlinks(const char *root_directory, BindMount *m, unsigned
} }
static unsigned namespace_calculate_mounts( static unsigned namespace_calculate_mounts(
const NameSpaceInfo *ns_info,
char** read_write_paths, char** read_write_paths,
char** read_only_paths, char** read_only_paths,
char** inaccessible_paths, char** inaccessible_paths,
const char* tmp_dir, const char* tmp_dir,
const char* var_tmp_dir, const char* var_tmp_dir,
bool private_dev,
bool protect_sysctl,
bool protect_cgroups,
ProtectHome protect_home, ProtectHome protect_home,
ProtectSystem protect_system) { ProtectSystem protect_system) {
@ -690,22 +703,21 @@ static unsigned namespace_calculate_mounts(
strv_length(read_write_paths) + strv_length(read_write_paths) +
strv_length(read_only_paths) + strv_length(read_only_paths) +
strv_length(inaccessible_paths) + strv_length(inaccessible_paths) +
private_dev + ns_info->private_dev +
(protect_sysctl ? ELEMENTSOF(protect_kernel_tunables_table) : 0) + (ns_info->protect_kernel_tunables ? ELEMENTSOF(protect_kernel_tunables_table) : 0) +
(protect_cgroups ? 1 : 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; protect_home_cnt + protect_system_cnt;
} }
int setup_namespace( int setup_namespace(
const char* root_directory, const char* root_directory,
const NameSpaceInfo *ns_info,
char** read_write_paths, char** read_write_paths,
char** read_only_paths, char** read_only_paths,
char** inaccessible_paths, char** inaccessible_paths,
const char* tmp_dir, const char* tmp_dir,
const char* var_tmp_dir, const char* var_tmp_dir,
bool private_dev,
bool protect_sysctl,
bool protect_cgroups,
ProtectHome protect_home, ProtectHome protect_home,
ProtectSystem protect_system, ProtectSystem protect_system,
unsigned long mount_flags) { unsigned long mount_flags) {
@ -718,13 +730,12 @@ int setup_namespace(
if (mount_flags == 0) if (mount_flags == 0)
mount_flags = MS_SHARED; mount_flags = MS_SHARED;
n = namespace_calculate_mounts(read_write_paths, n = namespace_calculate_mounts(ns_info,
read_write_paths,
read_only_paths, read_only_paths,
inaccessible_paths, inaccessible_paths,
tmp_dir, var_tmp_dir, tmp_dir, var_tmp_dir,
private_dev, protect_sysctl, protect_home, protect_system);
protect_cgroups, protect_home,
protect_system);
/* Set mount slave mode */ /* Set mount slave mode */
if (root_directory || n > 0) if (root_directory || n > 0)
@ -756,16 +767,25 @@ int setup_namespace(
m++; m++;
} }
if (private_dev) { if (ns_info->private_dev) {
m->path = prefix_roota(root_directory, "/dev"); m->path = prefix_roota(root_directory, "/dev");
m->mode = PRIVATE_DEV; m->mode = PRIVATE_DEV;
m++; m++;
} }
if (protect_sysctl) if (ns_info->protect_kernel_tunables) {
append_protect_kernel_tunables(&m, root_directory); r = append_protect_kernel_tunables(&m, root_directory);
if (r < 0)
return r;
}
if (protect_cgroups) { if (ns_info->protect_kernel_modules) {
r = append_protect_kernel_modules(&m, root_directory);
if (r < 0)
return r;
}
if (ns_info->protect_control_groups) {
m->path = prefix_roota(root_directory, "/sys/fs/cgroup"); m->path = prefix_roota(root_directory, "/sys/fs/cgroup");
m->mode = READONLY; m->mode = READONLY;
m++; m++;

View file

@ -4,6 +4,7 @@
This file is part of systemd. This file is part of systemd.
Copyright 2010 Lennart Poettering Copyright 2010 Lennart Poettering
Copyright 2016 Djalal Harouni
systemd is free software; you can redistribute it and/or modify it 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 under the terms of the GNU Lesser General Public License as published by
@ -19,6 +20,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>. along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/ ***/
typedef struct NameSpaceInfo NameSpaceInfo;
#include <stdbool.h> #include <stdbool.h>
#include "macro.h" #include "macro.h"
@ -40,15 +43,20 @@ typedef enum ProtectSystem {
_PROTECT_SYSTEM_INVALID = -1 _PROTECT_SYSTEM_INVALID = -1
} ProtectSystem; } ProtectSystem;
struct NameSpaceInfo {
bool private_dev:1;
bool protect_control_groups:1;
bool protect_kernel_tunables:1;
bool protect_kernel_modules:1;
};
int setup_namespace(const char *chroot, int setup_namespace(const char *chroot,
const NameSpaceInfo *ns_info,
char **read_write_paths, char **read_write_paths,
char **read_only_paths, char **read_only_paths,
char **inaccessible_paths, char **inaccessible_paths,
const char *tmp_dir, const char *tmp_dir,
const char *var_tmp_dir, const char *var_tmp_dir,
bool private_dev,
bool protect_sysctl,
bool protect_cgroups,
ProtectHome protect_home, ProtectHome protect_home,
ProtectSystem protect_system, ProtectSystem protect_system,
unsigned long mount_flags); unsigned long mount_flags);

View file

@ -45,6 +45,14 @@ int main(int argc, char *argv[]) {
"/home/lennart/projects", "/home/lennart/projects",
NULL NULL
}; };
static const NameSpaceInfo ns_info = {
.private_dev = true,
.protect_control_groups = true,
.protect_kernel_tunables = true,
.protect_kernel_modules = true,
};
char *root_directory; char *root_directory;
char *projects_directory; char *projects_directory;
int r; int r;
@ -69,14 +77,12 @@ int main(int argc, char *argv[]) {
log_info("Not chrooted"); log_info("Not chrooted");
r = setup_namespace(root_directory, r = setup_namespace(root_directory,
&ns_info,
(char **) writable, (char **) writable,
(char **) readonly, (char **) readonly,
(char **) inaccessible, (char **) inaccessible,
tmp_dir, tmp_dir,
var_tmp_dir, var_tmp_dir,
true,
true,
true,
PROTECT_HOME_NO, PROTECT_HOME_NO,
PROTECT_SYSTEM_NO, PROTECT_SYSTEM_NO,
0); 0);