Merge pull request #4658 from endocode/djalal/sandbox-various-fixes-v1
core: improve the logic that implies no new privileges and documentation fixes
This commit is contained in:
@@ -1684,6 +1684,10 @@ EXTRA_DIST += \
|
||||
test/test-execute/exec-runtimedirectory-mode.service \
|
||||
test/test-execute/exec-runtimedirectory-owner.service \
|
||||
test/test-execute/exec-runtimedirectory-owner-nfsnobody.service \
|
||||
test/test-execute/exec-restrict-namespaces-no.service \
|
||||
test/test-execute/exec-restrict-namespaces-yes.service \
|
||||
test/test-execute/exec-restrict-namespaces-mnt.service \
|
||||
test/test-execute/exec-restrict-namespaces-mnt-blacklist.service \
|
||||
test/bus-policy/hello.conf \
|
||||
test/bus-policy/methods.conf \
|
||||
test/bus-policy/ownerships.conf \
|
||||
|
||||
+47
-27
@@ -999,7 +999,11 @@
|
||||
using <citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry> of
|
||||
<filename>/dev/zero</filename> instead of using <constant>MAP_ANON</constant>. This setting is implied if
|
||||
<varname>DynamicUser=</varname> is set. For this setting the same restrictions regarding mount propagation and
|
||||
privileges apply as for <varname>ReadOnlyPaths=</varname> and related calls, see above.</para></listitem>
|
||||
privileges apply as for <varname>ReadOnlyPaths=</varname> and related calls, see above.
|
||||
If turned on and if running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant>
|
||||
capability (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname>
|
||||
is implied.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@@ -1090,9 +1094,35 @@
|
||||
mechanism. Almost no services need to write to these at runtime; it is hence recommended to turn this on for
|
||||
most services. For this setting the same restrictions regarding mount propagation and privileges apply as for
|
||||
<varname>ReadOnlyPaths=</varname> and related calls, see above. Defaults to off.
|
||||
Note that this option does not prevent kernel tuning through IPC interfaces and external programs. However
|
||||
<varname>InaccessiblePaths=</varname> can be used to make some IPC file system objects
|
||||
inaccessible.</para></listitem>
|
||||
If turned on and if running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant>
|
||||
capability (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname>
|
||||
is implied. Note that this option does not prevent kernel tuning through IPC interfaces
|
||||
and external programs. However <varname>InaccessiblePaths=</varname> can be used to
|
||||
make some IPC file system objects inaccessible.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ProtectKernelModules=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument. If true, explicit module loading will
|
||||
be denied. This allows to turn off module load and unload operations on modular
|
||||
kernels. It is recommended 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
|
||||
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,
|
||||
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
|
||||
mapping tables might still happen as side effect of requested user operations,
|
||||
both privileged and unprivileged. To disable module auto-load feature please see
|
||||
<citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
<constant>kernel.modules_disabled</constant> mechanism and
|
||||
<filename>/proc/sys/kernel/modules_disabled</filename> documentation.
|
||||
If turned on and if running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant>
|
||||
capability (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname>
|
||||
is implied.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@@ -1237,7 +1267,7 @@
|
||||
<listitem><para>Takes a boolean argument. If true, ensures that the service process and all its children can
|
||||
never gain new privileges through <function>execve()</function> (e.g. via setuid or setgid bits, or filesystem
|
||||
capabilities). This is the simplest and most effective way to ensure that a process and its children can never
|
||||
elevate privileges again. Defaults to false, but in the user manager instance certain settings force
|
||||
elevate privileges again. Defaults to false, but certain settings force
|
||||
<varname>NoNewPrivileges=yes</varname>, ignoring the value of this setting. This is the case when
|
||||
<varname>SystemCallFilter=</varname>, <varname>SystemCallArchitectures=</varname>,
|
||||
<varname>RestrictAddressFamilies=</varname>, <varname>RestrictNamespaces=</varname>,
|
||||
@@ -1482,27 +1512,11 @@
|
||||
<citerefentry><refentrytitle>setns</refentrytitle><manvolnum>2</manvolnum></citerefentry> system calls, taking
|
||||
the specified flags parameters into account. Note that — if this option is used — in addition to restricting
|
||||
creation and switching of the specified types of namespaces (or all of them, if true) access to the
|
||||
<function>setns()</function> system call with a zero flags parameter is prohibited.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ProtectKernelModules=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument. If true, explicit module loading will
|
||||
be denied. This allows to turn off module load and unload operations on modular
|
||||
kernels. It is recommended 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
|
||||
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,
|
||||
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
|
||||
mapping tables might still happen as side effect of requested user operations,
|
||||
both privileged and unprivileged. To disable module auto-load feature please see
|
||||
<citerefentry><refentrytitle>sysctl.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
<constant>kernel.modules_disabled</constant> mechanism and
|
||||
<filename>/proc/sys/kernel/modules_disabled</filename> documentation.</para></listitem>
|
||||
<function>setns()</function> system call with a zero flags parameter is prohibited.
|
||||
If running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant>
|
||||
capability (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname>
|
||||
is implied.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@@ -1563,6 +1577,9 @@
|
||||
that generate program code dynamically at runtime, such as JIT execution engines, or programs compiled making
|
||||
use of the code "trampoline" feature of various C compilers. This option improves service security, as it makes
|
||||
harder for software exploits to change running code dynamically.
|
||||
If running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant>
|
||||
capability (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname>
|
||||
is implied.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
@@ -1573,7 +1590,10 @@
|
||||
the unit are refused. This restricts access to realtime task scheduling policies such as
|
||||
<constant>SCHED_FIFO</constant>, <constant>SCHED_RR</constant> or <constant>SCHED_DEADLINE</constant>. See
|
||||
<citerefentry project='man-pages'><refentrytitle>sched</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details about
|
||||
these scheduling policies. Realtime scheduling policies may be used to monopolize CPU time for longer periods
|
||||
these scheduling policies. If running in user mode, or in system mode, but
|
||||
without the <constant>CAP_SYS_ADMIN</constant> capability
|
||||
(e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname>
|
||||
is implied. Realtime scheduling policies may be used to monopolize CPU time for longer periods
|
||||
of time, and may hence be used to lock up or otherwise trigger Denial-of-Service situations on the system. It
|
||||
is hence recommended to restrict access to realtime scheduling to the few programs that actually require
|
||||
them. Defaults to off.</para></listitem>
|
||||
|
||||
@@ -781,7 +781,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||
SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RestrictNamespace", "t", bus_property_get_ulong, offsetof(ExecContext, restrict_namespaces), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("RestrictNamespaces", "t", bus_property_get_ulong, offsetof(ExecContext, restrict_namespaces), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
|
||||
+2
-1
@@ -2201,7 +2201,8 @@ static bool context_has_no_new_privileges(const ExecContext *c) {
|
||||
if (have_effective_cap(CAP_SYS_ADMIN)) /* if we are privileged, we don't need NNP */
|
||||
return false;
|
||||
|
||||
return context_has_address_families(c) || /* we need NNP if we have any form of seccomp and are unprivileged */
|
||||
/* We need NNP if we have any form of seccomp and are unprivileged */
|
||||
return context_has_address_families(c) ||
|
||||
c->memory_deny_write_execute ||
|
||||
c->restrict_realtime ||
|
||||
exec_context_restrict_namespaces_set(c) ||
|
||||
|
||||
@@ -216,7 +216,6 @@ struct ExecContext {
|
||||
bool nice_set:1;
|
||||
bool ioprio_set:1;
|
||||
bool cpu_sched_set:1;
|
||||
bool no_new_privileges_set:1;
|
||||
};
|
||||
|
||||
static inline bool exec_context_restrict_namespaces_set(const ExecContext *c) {
|
||||
|
||||
@@ -57,7 +57,7 @@ m4_ifdef(`HAVE_SECCOMP',
|
||||
$1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs)
|
||||
$1.SystemCallErrorNumber, config_parse_syscall_errno, 0, offsetof($1, exec_context)
|
||||
$1.MemoryDenyWriteExecute, config_parse_bool, 0, offsetof($1, exec_context.memory_deny_write_execute)
|
||||
$1.RestrictNamespaces, config_parse_restrict_namespaces, 0, offsetof($1, exec_context.restrict_namespaces)
|
||||
$1.RestrictNamespaces, config_parse_restrict_namespaces, 0, offsetof($1, exec_context)
|
||||
$1.RestrictRealtime, config_parse_bool, 0, offsetof($1, exec_context.restrict_realtime)
|
||||
$1.RestrictAddressFamilies, config_parse_address_families, 0, offsetof($1, exec_context)',
|
||||
`$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
|
||||
|
||||
@@ -3896,7 +3896,6 @@ int config_parse_no_new_privileges(
|
||||
}
|
||||
|
||||
c->no_new_privileges = k;
|
||||
c->no_new_privileges_set = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3429,14 +3429,6 @@ int unit_patch_contexts(Unit *u) {
|
||||
ec->working_directory_missing_ok = true;
|
||||
}
|
||||
|
||||
if (MANAGER_IS_USER(u->manager) &&
|
||||
(ec->syscall_whitelist ||
|
||||
!set_isempty(ec->syscall_filter) ||
|
||||
!set_isempty(ec->syscall_archs) ||
|
||||
ec->address_families_whitelist ||
|
||||
!set_isempty(ec->address_families)))
|
||||
ec->no_new_privileges = true;
|
||||
|
||||
if (ec->private_devices)
|
||||
ec->capability_bounding_set &= ~((UINT64_C(1) << CAP_MKNOD) | (UINT64_C(1) << CAP_SYS_RAWIO));
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "missing.h"
|
||||
#include "nsflags.h"
|
||||
#include "parse-util.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "rlimit-util.h"
|
||||
@@ -769,6 +770,23 @@ int bus_print_property(const char *name, sd_bus_message *property, bool value, b
|
||||
char timespan[FORMAT_TIMESPAN_MAX];
|
||||
|
||||
print_property(name, "%s", format_timespan(timespan, sizeof(timespan), u, 0));
|
||||
} else if (streq(name, "RestrictNamespaces")) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
const char *result = NULL;
|
||||
|
||||
if ((u & NAMESPACE_FLAGS_ALL) == 0)
|
||||
result = "yes";
|
||||
else if ((u & NAMESPACE_FLAGS_ALL) == NAMESPACE_FLAGS_ALL)
|
||||
result = "no";
|
||||
else {
|
||||
r = namespace_flag_to_string_many(u, &s);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
result = s;
|
||||
}
|
||||
|
||||
print_property(name, "%s", result);
|
||||
} else
|
||||
print_property(name, "%"PRIu64, u);
|
||||
|
||||
|
||||
@@ -219,6 +219,18 @@ static void test_exec_systemcallerrornumber(Manager *m) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_exec_restrict_namespaces(Manager *m) {
|
||||
#ifdef HAVE_SECCOMP
|
||||
if (!is_seccomp_available())
|
||||
return;
|
||||
|
||||
test(m, "exec-restrict-namespaces-no.service", 0, CLD_EXITED);
|
||||
test(m, "exec-restrict-namespaces-yes.service", 1, CLD_EXITED);
|
||||
test(m, "exec-restrict-namespaces-mnt.service", 0, CLD_EXITED);
|
||||
test(m, "exec-restrict-namespaces-mnt-blacklist.service", 1, CLD_EXITED);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_exec_systemcall_system_mode_with_user(Manager *m) {
|
||||
#ifdef HAVE_SECCOMP
|
||||
if (!is_seccomp_available())
|
||||
@@ -435,6 +447,7 @@ int main(int argc, char *argv[]) {
|
||||
test_exec_privatenetwork,
|
||||
test_exec_systemcallfilter,
|
||||
test_exec_systemcallerrornumber,
|
||||
test_exec_restrict_namespaces,
|
||||
test_exec_user,
|
||||
test_exec_group,
|
||||
test_exec_supplementary_groups,
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=Test RestrictNamespaces=~mnt
|
||||
|
||||
[Service]
|
||||
RestrictNamespaces=~mnt
|
||||
ExecStart=/bin/sh -x -c 'unshare -m'
|
||||
Type=oneshot
|
||||
@@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=Test RestrictNamespaces=mnt
|
||||
|
||||
[Service]
|
||||
RestrictNamespaces=mnt
|
||||
ExecStart=/bin/sh -x -c 'unshare -m'
|
||||
Type=oneshot
|
||||
@@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=Test RestrictNamespaces=no
|
||||
|
||||
[Service]
|
||||
RestrictNamespaces=no
|
||||
ExecStart=/bin/sh -x -c 'unshare -m -u -i -n -p -f'
|
||||
Type=oneshot
|
||||
@@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=Test RestrictNamespaces=yes
|
||||
|
||||
[Service]
|
||||
RestrictNamespaces=yes
|
||||
ExecStart=/bin/sh -x -c 'unshare -m'
|
||||
Type=oneshot
|
||||
Reference in New Issue
Block a user