Zbigniew Jędrzejewski-Szmek 5d6eed
From d262fb5809de27d51e9d6b97c6b114804c2b95c5 Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek 03e93e
From: Lennart Poettering <lennart@poettering.net>
Zbigniew Jędrzejewski-Szmek 03e93e
Date: Tue, 1 Nov 2016 20:25:19 -0600
Zbigniew Jędrzejewski-Szmek 03e93e
Subject: [PATCH] core: add new RestrictNamespaces= unit file setting
Zbigniew Jędrzejewski-Szmek 03e93e
Zbigniew Jędrzejewski-Szmek 03e93e
This new setting permits restricting whether namespaces may be created and
Zbigniew Jędrzejewski-Szmek 03e93e
managed by processes started by a unit. It installs a seccomp filter blocking
Zbigniew Jędrzejewski-Szmek 03e93e
certain invocations of unshare(), clone() and setns().
Zbigniew Jędrzejewski-Szmek 03e93e
Zbigniew Jędrzejewski-Szmek 03e93e
RestrictNamespaces=no is the default, and does not restrict namespaces in any
Zbigniew Jędrzejewski-Szmek 03e93e
way. RestrictNamespaces=yes takes away the ability to create or manage any kind
Zbigniew Jędrzejewski-Szmek 03e93e
of namspace. "RestrictNamespaces=mnt ipc" restricts the creation of namespaces
Zbigniew Jędrzejewski-Szmek 03e93e
so that only mount and IPC namespaces may be created/managed, but no other
Zbigniew Jędrzejewski-Szmek 03e93e
kind of namespaces.
Zbigniew Jędrzejewski-Szmek 03e93e
Zbigniew Jędrzejewski-Szmek 03e93e
This setting should be improve security quite a bit as in particular user
Zbigniew Jędrzejewski-Szmek 03e93e
namespacing was a major source of CVEs in the kernel in the past, and is
Zbigniew Jędrzejewski-Szmek 03e93e
accessible to unprivileged processes. With this setting the entire attack
Zbigniew Jędrzejewski-Szmek 03e93e
surface may be removed for system services that do not make use of namespaces.
Zbigniew Jędrzejewski-Szmek 03e93e
Zbigniew Jędrzejewski-Szmek 03e93e
(cherry picked from commit add005357d535681c7075ced8eec2b6e61b43728)
Zbigniew Jędrzejewski-Szmek 03e93e
---
Zbigniew Jędrzejewski-Szmek 03e93e
 Makefile.am                           |   4 +-
Zbigniew Jędrzejewski-Szmek 03e93e
 TODO                                  |   6 --
Zbigniew Jędrzejewski-Szmek 03e93e
 man/systemd.exec.xml                  |  50 +++++++++-----
Zbigniew Jędrzejewski-Szmek 03e93e
 src/core/dbus-execute.c               |  21 ++++++
Zbigniew Jędrzejewski-Szmek 03e93e
 src/core/execute.c                    |  30 ++++++++
Zbigniew Jędrzejewski-Szmek 03e93e
 src/core/execute.h                    |   9 +++
Zbigniew Jędrzejewski-Szmek 03e93e
 src/core/load-fragment-gperf.gperf.m4 |   2 +
Zbigniew Jędrzejewski-Szmek 03e93e
 src/core/load-fragment.c              |  49 +++++++++++++
Zbigniew Jędrzejewski-Szmek 03e93e
 src/core/load-fragment.h              |   1 +
Zbigniew Jędrzejewski-Szmek 03e93e
 src/shared/bus-unit-util.c            |  25 +++++++
Zbigniew Jędrzejewski-Szmek 03e93e
 src/shared/nsflags.c                  | 126 ++++++++++++++++++++++++++++++++++
Zbigniew Jędrzejewski-Szmek 03e93e
 src/shared/nsflags.h                  |  49 +++++++++++++
Zbigniew Jędrzejewski-Szmek 03e93e
 src/shared/seccomp-util.c             |  89 ++++++++++++++++++++++++
Zbigniew Jędrzejewski-Szmek 03e93e
 src/shared/seccomp-util.h             |   2 +
Zbigniew Jędrzejewski-Szmek 03e93e
 src/test/test-seccomp.c               |  94 +++++++++++++++++++++++++
Zbigniew Jędrzejewski-Szmek 03e93e
 15 files changed, 534 insertions(+), 23 deletions(-)
Zbigniew Jędrzejewski-Szmek 03e93e
 create mode 100644 src/shared/nsflags.c
Zbigniew Jędrzejewski-Szmek 03e93e
 create mode 100644 src/shared/nsflags.h
Zbigniew Jędrzejewski-Szmek 03e93e
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/Makefile.am b/Makefile.am
Zbigniew Jędrzejewski-Szmek 03e93e
index f2d8bf57f7..1031e797b3 100644
Zbigniew Jędrzejewski-Szmek 03e93e
--- a/Makefile.am
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/Makefile.am
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -1046,7 +1046,9 @@ libshared_la_SOURCES = \
Zbigniew Jędrzejewski-Szmek 03e93e
 	src/shared/tests.h \
Zbigniew Jędrzejewski-Szmek 03e93e
 	src/shared/tests.c \
Zbigniew Jędrzejewski-Szmek 03e93e
 	src/shared/fdset.c \
Zbigniew Jędrzejewski-Szmek 03e93e
-	src/shared/fdset.h
Zbigniew Jędrzejewski-Szmek 03e93e
+	src/shared/fdset.h \
Zbigniew Jędrzejewski-Szmek 03e93e
+	src/shared/nsflags.h \
Zbigniew Jędrzejewski-Szmek 03e93e
+	src/shared/nsflags.c
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
 if HAVE_UTMP
Zbigniew Jędrzejewski-Szmek 03e93e
 libshared_la_SOURCES += \
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/TODO b/TODO
Zbigniew Jędrzejewski-Szmek 03e93e
index c8266a549d..164e33708e 100644
Zbigniew Jędrzejewski-Szmek 03e93e
--- a/TODO
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/TODO
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -59,14 +59,10 @@ Features:
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
 * define gpt header bits to select volatility mode
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
-* nspawn: mount loopback filesystems with "discard"
Zbigniew Jędrzejewski-Szmek 03e93e
-
Zbigniew Jędrzejewski-Szmek 03e93e
 * ProtectKernelLogs= (drops CAP_SYSLOG, add seccomp for syslog() syscall, and DeviceAllow to /dev/kmsg) in service files
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
 * ProtectClock= (drops CAP_SYS_TIMES, adds seecomp filters for settimeofday, adjtimex), sets DeviceAllow o /dev/rtc
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
-* ProtectKernelModules= (drops CAP_SYS_MODULE and filters the kmod syscalls)
Zbigniew Jędrzejewski-Szmek 03e93e
-
Zbigniew Jędrzejewski-Szmek 03e93e
 * ProtectTracing= (drops CAP_SYS_PTRACE, blocks ptrace syscall, makes /sys/kernel/tracing go away)
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
 * ProtectMount= (drop mount/umount/pivot_root from seccomp, disallow fuse via DeviceAllow, imply Mountflags=slave)
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -88,8 +84,6 @@ Features:
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
 * Add RootImage= for mounting a disk image or file as root directory
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
-* RestrictNamespaces= or so in services (taking away the ability to create namespaces, with setns, unshare, clone)
Zbigniew Jędrzejewski-Szmek 03e93e
-
Zbigniew Jędrzejewski-Szmek 03e93e
 * make sure the ratelimit object can deal with USEC_INFINITY as way to turn off things
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
 * journalctl: make sure -f ends when the container indicated by -M terminates
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
Zbigniew Jędrzejewski-Szmek 03e93e
index 3c350df11f..33bca1bfb0 100644
Zbigniew Jędrzejewski-Szmek 03e93e
--- a/man/systemd.exec.xml
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/man/systemd.exec.xml
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -1234,22 +1234,16 @@
Zbigniew Jędrzejewski-Szmek 03e93e
       <varlistentry>
Zbigniew Jędrzejewski-Szmek 03e93e
         <term><varname>NoNewPrivileges=</varname></term>
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
-        <listitem><para>Takes a boolean argument. If true, ensures that the service
Zbigniew Jędrzejewski-Szmek 03e93e
-        process and all its children can never gain new privileges. This option is more
Zbigniew Jędrzejewski-Szmek 03e93e
-        powerful than the respective secure bits flags (see above), as it also prohibits
Zbigniew Jędrzejewski-Szmek 03e93e
-        UID changes of any kind. This is the simplest and most effective way to ensure that
Zbigniew Jędrzejewski-Szmek 03e93e
-        a process and its children can never elevate privileges again. Defaults to false,
Zbigniew Jędrzejewski-Szmek 03e93e
-        but in the user manager instance certain settings force
Zbigniew Jędrzejewski-Szmek 03e93e
-        <varname>NoNewPrivileges=yes</varname>, ignoring the value of this setting.
Zbigniew Jędrzejewski-Szmek 03e93e
-        Those is the case when <varname>SystemCallFilter=</varname>,
Zbigniew Jędrzejewski-Szmek 03e93e
-        <varname>SystemCallArchitectures=</varname>,
Zbigniew Jędrzejewski-Szmek 03e93e
-        <varname>RestrictAddressFamilies=</varname>,
Zbigniew Jędrzejewski-Szmek 03e93e
-        <varname>PrivateDevices=</varname>,
Zbigniew Jędrzejewski-Szmek 03e93e
-        <varname>ProtectKernelTunables=</varname>,
Zbigniew Jędrzejewski-Szmek 03e93e
-        <varname>ProtectKernelModules=</varname>,
Zbigniew Jędrzejewski-Szmek 03e93e
-        <varname>MemoryDenyWriteExecute=</varname>, or
Zbigniew Jędrzejewski-Szmek 03e93e
-        <varname>RestrictRealtime=</varname> are specified.
Zbigniew Jędrzejewski-Szmek 03e93e
-        </para></listitem>
Zbigniew Jędrzejewski-Szmek 03e93e
+        <listitem><para>Takes a boolean argument. If true, ensures that the service process and all its children can
Zbigniew Jędrzejewski-Szmek 03e93e
+        never gain new privileges through <function>execve()</function> (e.g. via setuid or setgid bits, or filesystem
Zbigniew Jędrzejewski-Szmek 03e93e
+        capabilities). This is the simplest and most effective way to ensure that a process and its children can never
Zbigniew Jędrzejewski-Szmek 03e93e
+        elevate privileges again. Defaults to false, but in the user manager instance certain settings force
Zbigniew Jędrzejewski-Szmek 03e93e
+        <varname>NoNewPrivileges=yes</varname>, ignoring the value of this setting.  This is the case when
Zbigniew Jędrzejewski-Szmek 03e93e
+        <varname>SystemCallFilter=</varname>, <varname>SystemCallArchitectures=</varname>,
Zbigniew Jędrzejewski-Szmek 03e93e
+        <varname>RestrictAddressFamilies=</varname>, <varname>RestrictNamespaces=</varname>,
Zbigniew Jędrzejewski-Szmek 03e93e
+        <varname>PrivateDevices=</varname>, <varname>ProtectKernelTunables=</varname>,
Zbigniew Jędrzejewski-Szmek 03e93e
+        <varname>ProtectKernelModules=</varname>, <varname>MemoryDenyWriteExecute=</varname>, or
Zbigniew Jędrzejewski-Szmek 03e93e
+        <varname>RestrictRealtime=</varname> are specified.</para></listitem>
Zbigniew Jędrzejewski-Szmek 03e93e
       </varlistentry>
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
       <varlistentry>
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -1462,6 +1456,30 @@
Zbigniew Jędrzejewski-Szmek 03e93e
         logging. This does not affect commands prefixed with <literal>+</literal>.</para></listitem>
Zbigniew Jędrzejewski-Szmek 03e93e
       </varlistentry>
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+      <varlistentry>
Zbigniew Jędrzejewski-Szmek 03e93e
+        <term><varname>RestrictNamespaces=</varname></term>
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        <listitem><para>Restricts access to Linux namespace functionality for the processes of this unit. For details
Zbigniew Jędrzejewski-Szmek 03e93e
+        about Linux namespaces, see
Zbigniew Jędrzejewski-Szmek 03e93e
+        <citerefentry><refentrytitle>namespaces</refentrytitle><manvolnum>7</manvolnum></citerefentry>. Either takes a
Zbigniew Jędrzejewski-Szmek 03e93e
+        boolean argument, or a space-separated list of namespace type identifiers. If false (the default), no
Zbigniew Jędrzejewski-Szmek 03e93e
+        restrictions on namespace creation and switching are made. If true, access to any kind of namespacing is
Zbigniew Jędrzejewski-Szmek 03e93e
+        prohibited. Otherwise, a space-separated list of namespace type identifiers must be specified, consisting of
Zbigniew Jędrzejewski-Szmek 03e93e
+        any combination of: <constant>cgroup</constant>, <constant>ipc</constant>, <constant>net</constant>,
Zbigniew Jędrzejewski-Szmek 03e93e
+        <constant>mnt</constant>, <constant>pid</constant>, <constant>user</constant> and <constant>uts</constant>. Any
Zbigniew Jędrzejewski-Szmek 03e93e
+        namespace type listed is made accessible to the unit's processes, access to namespace types not listed is
Zbigniew Jędrzejewski-Szmek 03e93e
+        prohibited (whitelisting). By prepending the list with a single tilda character (<literal>~</literal>) the
Zbigniew Jędrzejewski-Szmek 03e93e
+        effect may be inverted: only the listed namespace types will be made inaccessible, all unlisted ones are
Zbigniew Jędrzejewski-Szmek 03e93e
+        permitted (blacklisting). If the empty string is assigned, the default namespace restrictions are applied,
Zbigniew Jędrzejewski-Szmek 03e93e
+        which is equivalent to false. Internally, this setting limits access to the
Zbigniew Jędrzejewski-Szmek 03e93e
+        <citerefentry><refentrytitle>unshare</refentrytitle><manvolnum>2</manvolnum></citerefentry>,
Zbigniew Jędrzejewski-Szmek 03e93e
+        <citerefentry><refentrytitle>clone</refentrytitle><manvolnum>2</manvolnum></citerefentry> and
Zbigniew Jędrzejewski-Szmek 03e93e
+        <citerefentry><refentrytitle>setns</refentrytitle><manvolnum>2</manvolnum></citerefentry> system calls, taking
Zbigniew Jędrzejewski-Szmek 03e93e
+        the specified flags parameters into account. Note that — if this option is used — in addition to restricting
Zbigniew Jędrzejewski-Szmek 03e93e
+        creation and switching of the specified types of namespaces (or all of them, if true) access to the
Zbigniew Jędrzejewski-Szmek 03e93e
+        <function>setns()</function> system call with a zero flags parameter is prohibited.</para></listitem>
Zbigniew Jędrzejewski-Szmek 03e93e
+      </varlistentry>
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
       <varlistentry>
Zbigniew Jędrzejewski-Szmek 03e93e
         <term><varname>ProtectKernelModules=</varname></term>
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
Zbigniew Jędrzejewski-Szmek 03e93e
index 03f23780c1..d7bb0496a0 100644
Zbigniew Jędrzejewski-Szmek 03e93e
--- a/src/core/dbus-execute.c
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/src/core/dbus-execute.c
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -781,6 +781,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
Zbigniew Jędrzejewski-Szmek 03e93e
         SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST),
Zbigniew Jędrzejewski-Szmek 03e93e
         SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST),
Zbigniew Jędrzejewski-Szmek 03e93e
         SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST),
Zbigniew Jędrzejewski-Szmek 03e93e
+        SD_BUS_PROPERTY("RestrictNamespace", "t", bus_property_get_ulong, offsetof(ExecContext, restrict_namespaces), SD_BUS_VTABLE_PROPERTY_CONST),
Zbigniew Jędrzejewski-Szmek 03e93e
         SD_BUS_VTABLE_END
Zbigniew Jędrzejewski-Szmek 03e93e
 };
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -1591,7 +1592,27 @@ int bus_exec_context_set_transient_property(
Zbigniew Jędrzejewski-Szmek 03e93e
                 }
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
                 return 1;
Zbigniew Jędrzejewski-Szmek 03e93e
+        } else if (streq(name, "RestrictNamespaces")) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                uint64_t flags;
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+                r = sd_bus_message_read(message, "t", &flags);
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (r < 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        return r;
Zbigniew Jędrzejewski-Szmek 03e93e
+                if ((flags & NAMESPACE_FLAGS_ALL) != flags)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown namespace types");
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (mode != UNIT_CHECK) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                        _cleanup_free_ char *s = NULL;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                        r = namespace_flag_to_string_many(flags, &s);
Zbigniew Jędrzejewski-Szmek 03e93e
+                        if (r < 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                                return r;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                        c->restrict_namespaces = flags;
Zbigniew Jędrzejewski-Szmek 03e93e
+                        unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s);
Zbigniew Jędrzejewski-Szmek 03e93e
+                }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                return 1;
Zbigniew Jędrzejewski-Szmek 03e93e
         }
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
         ri = rlimit_from_string(name);
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/src/core/execute.c b/src/core/execute.c
Zbigniew Jędrzejewski-Szmek 03e93e
index 224382b581..59ce0774c4 100644
Zbigniew Jędrzejewski-Szmek 03e93e
--- a/src/core/execute.c
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/src/core/execute.c
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -1534,6 +1534,18 @@ static int apply_private_devices(const Unit *u, const ExecContext *c) {
Zbigniew Jędrzejewski-Szmek 03e93e
         return seccomp_load_filter_set(SCMP_ACT_ALLOW, syscall_filter_sets + SYSCALL_FILTER_SET_RAW_IO, SCMP_ACT_ERRNO(EPERM));
Zbigniew Jędrzejewski-Szmek 03e93e
 }
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+static int apply_restrict_namespaces(Unit *u, const ExecContext *c) {
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert(c);
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (!exec_context_restrict_namespaces_set(c))
Zbigniew Jędrzejewski-Szmek 03e93e
+                return 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (skip_seccomp_unavailable(u, "RestrictNamespaces="))
Zbigniew Jędrzejewski-Szmek 03e93e
+                return 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        return seccomp_restrict_namespaces(c->restrict_namespaces);
Zbigniew Jędrzejewski-Szmek 03e93e
+}
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
 #endif
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
 static void do_idle_pipe_dance(int idle_pipe[4]) {
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -2183,6 +2195,7 @@ static bool context_has_no_new_privileges(const ExecContext *c) {
Zbigniew Jędrzejewski-Szmek 03e93e
         return context_has_address_families(c) || /* we need NNP if we have any form of seccomp and are unprivileged */
Zbigniew Jędrzejewski-Szmek 03e93e
                 c->memory_deny_write_execute ||
Zbigniew Jędrzejewski-Szmek 03e93e
                 c->restrict_realtime ||
Zbigniew Jędrzejewski-Szmek 03e93e
+                exec_context_restrict_namespaces_set(c) ||
Zbigniew Jędrzejewski-Szmek 03e93e
                 c->protect_kernel_tunables ||
Zbigniew Jędrzejewski-Szmek 03e93e
                 c->protect_kernel_modules ||
Zbigniew Jędrzejewski-Szmek 03e93e
                 c->private_devices ||
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -2764,6 +2777,12 @@ static int exec_child(
Zbigniew Jędrzejewski-Szmek 03e93e
                         }
Zbigniew Jędrzejewski-Szmek 03e93e
                 }
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+                r = apply_restrict_namespaces(unit, context);
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (r < 0) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                        *exit_status = EXIT_SECCOMP;
Zbigniew Jędrzejewski-Szmek 03e93e
+                        return r;
Zbigniew Jędrzejewski-Szmek 03e93e
+                }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
                 if (context->protect_kernel_tunables) {
Zbigniew Jędrzejewski-Szmek 03e93e
                         r = apply_protect_sysctl(unit, context);
Zbigniew Jędrzejewski-Szmek 03e93e
                         if (r < 0) {
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -2947,6 +2966,7 @@ void exec_context_init(ExecContext *c) {
Zbigniew Jędrzejewski-Szmek 03e93e
         c->personality = PERSONALITY_INVALID;
Zbigniew Jędrzejewski-Szmek 03e93e
         c->runtime_directory_mode = 0755;
Zbigniew Jędrzejewski-Szmek 03e93e
         c->capability_bounding_set = CAP_ALL;
Zbigniew Jędrzejewski-Szmek 03e93e
+        c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
Zbigniew Jędrzejewski-Szmek 03e93e
 }
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
 void exec_context_done(ExecContext *c) {
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -3244,6 +3264,7 @@ static void strv_fprintf(FILE *f, char **l) {
Zbigniew Jędrzejewski-Szmek 03e93e
 void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
Zbigniew Jędrzejewski-Szmek 03e93e
         char **e, **d;
Zbigniew Jędrzejewski-Szmek 03e93e
         unsigned i;
Zbigniew Jędrzejewski-Szmek 03e93e
+        int r;
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
         assert(c);
Zbigniew Jędrzejewski-Szmek 03e93e
         assert(f);
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -3524,6 +3545,15 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
Zbigniew Jędrzejewski-Szmek 03e93e
                 fputc('\n', f);
Zbigniew Jędrzejewski-Szmek 03e93e
         }
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (exec_context_restrict_namespaces_set(c)) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                _cleanup_free_ char *s = NULL;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                r = namespace_flag_to_string_many(c->restrict_namespaces, &s);
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (r >= 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        fprintf(f, "%sRestrictNamespaces: %s\n",
Zbigniew Jędrzejewski-Szmek 03e93e
+                                prefix, s);
Zbigniew Jędrzejewski-Szmek 03e93e
+        }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
         if (c->syscall_errno > 0)
Zbigniew Jędrzejewski-Szmek 03e93e
                 fprintf(f,
Zbigniew Jędrzejewski-Szmek 03e93e
                         "%sSystemCallErrorNumber: %s\n",
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/src/core/execute.h b/src/core/execute.h
Zbigniew Jędrzejewski-Szmek 03e93e
index c7d0f7761e..56f880cffe 100644
Zbigniew Jędrzejewski-Szmek 03e93e
--- a/src/core/execute.h
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/src/core/execute.h
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -35,6 +35,7 @@ typedef struct ExecParameters ExecParameters;
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "list.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "missing.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "namespace.h"
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "nsflags.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
 typedef enum ExecUtmpMode {
Zbigniew Jędrzejewski-Szmek 03e93e
         EXEC_UTMP_INIT,
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -195,6 +196,8 @@ struct ExecContext {
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
         unsigned long personality;
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+        unsigned long restrict_namespaces; /* The CLONE_NEWxyz flags permitted to the unit's processes */
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
         Set *syscall_filter;
Zbigniew Jędrzejewski-Szmek 03e93e
         Set *syscall_archs;
Zbigniew Jędrzejewski-Szmek 03e93e
         int syscall_errno;
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -216,6 +219,12 @@ struct ExecContext {
Zbigniew Jędrzejewski-Szmek 03e93e
         bool no_new_privileges_set:1;
Zbigniew Jędrzejewski-Szmek 03e93e
 };
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+static inline bool exec_context_restrict_namespaces_set(const ExecContext *c) {
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert(c);
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        return (c->restrict_namespaces & NAMESPACE_FLAGS_ALL) != NAMESPACE_FLAGS_ALL;
Zbigniew Jędrzejewski-Szmek 03e93e
+}
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
 typedef enum ExecFlags {
Zbigniew Jędrzejewski-Szmek 03e93e
         EXEC_CONFIRM_SPAWN     = 1U << 0,
Zbigniew Jędrzejewski-Szmek 03e93e
         EXEC_APPLY_PERMISSIONS = 1U << 1,
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
Zbigniew Jędrzejewski-Szmek 03e93e
index af2f9d960b..cb2f384f47 100644
Zbigniew Jędrzejewski-Szmek 03e93e
--- a/src/core/load-fragment-gperf.gperf.m4
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/src/core/load-fragment-gperf.gperf.m4
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -57,12 +57,14 @@ m4_ifdef(`HAVE_SECCOMP',
Zbigniew Jędrzejewski-Szmek 03e93e
 $1.SystemCallArchitectures,      config_parse_syscall_archs,         0,                             offsetof($1, exec_context.syscall_archs)
Zbigniew Jędrzejewski-Szmek 03e93e
 $1.SystemCallErrorNumber,        config_parse_syscall_errno,         0,                             offsetof($1, exec_context)
Zbigniew Jędrzejewski-Szmek 03e93e
 $1.MemoryDenyWriteExecute,       config_parse_bool,                  0,                             offsetof($1, exec_context.memory_deny_write_execute)
Zbigniew Jędrzejewski-Szmek 03e93e
+$1.RestrictNamespaces,           config_parse_restrict_namespaces,   0,                             offsetof($1, exec_context.restrict_namespaces)
Zbigniew Jędrzejewski-Szmek 03e93e
 $1.RestrictRealtime,             config_parse_bool,                  0,                             offsetof($1, exec_context.restrict_realtime)
Zbigniew Jędrzejewski-Szmek 03e93e
 $1.RestrictAddressFamilies,      config_parse_address_families,      0,                             offsetof($1, exec_context)',
Zbigniew Jędrzejewski-Szmek 03e93e
 `$1.SystemCallFilter,            config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
Zbigniew Jędrzejewski-Szmek 03e93e
 $1.SystemCallArchitectures,      config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
Zbigniew Jędrzejewski-Szmek 03e93e
 $1.SystemCallErrorNumber,        config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
Zbigniew Jędrzejewski-Szmek 03e93e
 $1.MemoryDenyWriteExecute,       config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
Zbigniew Jędrzejewski-Szmek 03e93e
+$1.RestrictNamespaces,           config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
Zbigniew Jędrzejewski-Szmek 03e93e
 $1.RestrictRealtime,             config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
Zbigniew Jędrzejewski-Szmek 03e93e
 $1.RestrictAddressFamilies,      config_parse_warn_compat,           DISABLED_CONFIGURATION,        0')
Zbigniew Jędrzejewski-Szmek 03e93e
 $1.LimitCPU,                     config_parse_limit,                 RLIMIT_CPU,                    offsetof($1, exec_context.rlimit)
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
Zbigniew Jędrzejewski-Szmek 03e93e
index cbc826809e..e0fa484c1e 100644
Zbigniew Jędrzejewski-Szmek 03e93e
--- a/src/core/load-fragment.c
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/src/core/load-fragment.c
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -2905,6 +2905,54 @@ int config_parse_address_families(
Zbigniew Jędrzejewski-Szmek 03e93e
         if (!isempty(state))
Zbigniew Jędrzejewski-Szmek 03e93e
                 log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+        return 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+}
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+int config_parse_restrict_namespaces(
Zbigniew Jędrzejewski-Szmek 03e93e
+                const char *unit,
Zbigniew Jędrzejewski-Szmek 03e93e
+                const char *filename,
Zbigniew Jędrzejewski-Szmek 03e93e
+                unsigned line,
Zbigniew Jędrzejewski-Szmek 03e93e
+                const char *section,
Zbigniew Jędrzejewski-Szmek 03e93e
+                unsigned section_line,
Zbigniew Jędrzejewski-Szmek 03e93e
+                const char *lvalue,
Zbigniew Jędrzejewski-Szmek 03e93e
+                int ltype,
Zbigniew Jędrzejewski-Szmek 03e93e
+                const char *rvalue,
Zbigniew Jędrzejewski-Szmek 03e93e
+                void *data,
Zbigniew Jędrzejewski-Szmek 03e93e
+                void *userdata) {
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        ExecContext *c = data;
Zbigniew Jędrzejewski-Szmek 03e93e
+        bool invert = false;
Zbigniew Jędrzejewski-Szmek 03e93e
+        int r;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (isempty(rvalue)) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                /* Reset to the default. */
Zbigniew Jędrzejewski-Szmek 03e93e
+                c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
Zbigniew Jędrzejewski-Szmek 03e93e
+                return 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+        }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (rvalue[0] == '~') {
Zbigniew Jędrzejewski-Szmek 03e93e
+                invert = true;
Zbigniew Jędrzejewski-Szmek 03e93e
+                rvalue++;
Zbigniew Jędrzejewski-Szmek 03e93e
+        }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        r = parse_boolean(rvalue);
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (r > 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                c->restrict_namespaces = 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+        else if (r == 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                c->restrict_namespaces = NAMESPACE_FLAGS_ALL;
Zbigniew Jędrzejewski-Szmek 03e93e
+        else {
Zbigniew Jędrzejewski-Szmek 03e93e
+                /* Not a boolean argument, in this case it's a list of namespace types. */
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                r = namespace_flag_from_string_many(rvalue, &c->restrict_namespaces);
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (r < 0) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse namespace type string, ignoring: %s", rvalue);
Zbigniew Jędrzejewski-Szmek 03e93e
+                        return 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+                }
Zbigniew Jędrzejewski-Szmek 03e93e
+        }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (invert)
Zbigniew Jędrzejewski-Szmek 03e93e
+                c->restrict_namespaces = (~c->restrict_namespaces) & NAMESPACE_FLAGS_ALL;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
         return 0;
Zbigniew Jędrzejewski-Szmek 03e93e
 }
Zbigniew Jędrzejewski-Szmek 03e93e
 #endif
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -4327,6 +4375,7 @@ void unit_dump_config_items(FILE *f) {
Zbigniew Jędrzejewski-Szmek 03e93e
                 { config_parse_syscall_archs,         "ARCHS" },
Zbigniew Jędrzejewski-Szmek 03e93e
                 { config_parse_syscall_errno,         "ERRNO" },
Zbigniew Jędrzejewski-Szmek 03e93e
                 { config_parse_address_families,      "FAMILIES" },
Zbigniew Jędrzejewski-Szmek 03e93e
+                { config_parse_restrict_namespaces,   "NAMESPACES"  },
Zbigniew Jędrzejewski-Szmek 03e93e
 #endif
Zbigniew Jędrzejewski-Szmek 03e93e
                 { config_parse_cpu_shares,            "SHARES" },
Zbigniew Jędrzejewski-Szmek 03e93e
                 { config_parse_cpu_weight,            "WEIGHT" },
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
Zbigniew Jędrzejewski-Szmek 03e93e
index c05f205c37..1cff815a50 100644
Zbigniew Jędrzejewski-Szmek 03e93e
--- a/src/core/load-fragment.h
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/src/core/load-fragment.h
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -116,6 +116,7 @@ int config_parse_fdname(const char *unit, const char *filename, unsigned line, c
Zbigniew Jędrzejewski-Szmek 03e93e
 int config_parse_sec_fix_0(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
Zbigniew Jędrzejewski-Szmek 03e93e
 int config_parse_user_group(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
Zbigniew Jędrzejewski-Szmek 03e93e
 int config_parse_user_group_strv(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
Zbigniew Jędrzejewski-Szmek 03e93e
+int config_parse_restrict_namespaces(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
 /* gperf prototypes */
Zbigniew Jędrzejewski-Szmek 03e93e
 const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
Zbigniew Jędrzejewski-Szmek 03e93e
index f639e0e832..35e2c8f18e 100644
Zbigniew Jędrzejewski-Szmek 03e93e
--- a/src/shared/bus-unit-util.c
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/src/shared/bus-unit-util.c
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -27,6 +27,7 @@
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "hashmap.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "list.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "locale-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "nsflags.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "parse-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "path-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "process-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -553,6 +554,30 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
                 r = sd_bus_message_close_container(m);
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+        } else if (streq(field, "RestrictNamespaces")) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                bool invert = false;
Zbigniew Jędrzejewski-Szmek 03e93e
+                uint64_t flags = 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (eq[0] == '~') {
Zbigniew Jędrzejewski-Szmek 03e93e
+                        invert = true;
Zbigniew Jędrzejewski-Szmek 03e93e
+                        eq++;
Zbigniew Jędrzejewski-Szmek 03e93e
+                }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                r = parse_boolean(eq);
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (r > 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        flags = 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+                else if (r == 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        flags = NAMESPACE_FLAGS_ALL;
Zbigniew Jędrzejewski-Szmek 03e93e
+                else {
Zbigniew Jędrzejewski-Szmek 03e93e
+                        r = namespace_flag_from_string_many(eq, &flags);
Zbigniew Jędrzejewski-Szmek 03e93e
+                        if (r < 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                                return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
Zbigniew Jędrzejewski-Szmek 03e93e
+                }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (invert)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        flags = (~flags) & NAMESPACE_FLAGS_ALL;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                r = sd_bus_message_append(m, "v", "t", flags);
Zbigniew Jędrzejewski-Szmek 03e93e
         } else {
Zbigniew Jędrzejewski-Szmek 03e93e
                 log_error("Unknown assignment %s.", assignment);
Zbigniew Jędrzejewski-Szmek 03e93e
                 return -EINVAL;
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/src/shared/nsflags.c b/src/shared/nsflags.c
Zbigniew Jędrzejewski-Szmek 03e93e
new file mode 100644
Zbigniew Jędrzejewski-Szmek 03e93e
index 0000000000..8fcbe97ba7
Zbigniew Jędrzejewski-Szmek 03e93e
--- /dev/null
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/src/shared/nsflags.c
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -0,0 +1,126 @@
Zbigniew Jędrzejewski-Szmek 03e93e
+/***
Zbigniew Jędrzejewski-Szmek 03e93e
+  This file is part of systemd.
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+  Copyright 2016 Lennart Poettering
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+  systemd is free software; you can redistribute it and/or modify it
Zbigniew Jędrzejewski-Szmek 03e93e
+  under the terms of the GNU Lesser General Public License as published by
Zbigniew Jędrzejewski-Szmek 03e93e
+  the Free Software Foundation; either version 2.1 of the License, or
Zbigniew Jędrzejewski-Szmek 03e93e
+  (at your option) any later version.
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+  systemd is distributed in the hope that it will be useful, but
Zbigniew Jędrzejewski-Szmek 03e93e
+  WITHOUT ANY WARRANTY; without even the implied warranty of
Zbigniew Jędrzejewski-Szmek 03e93e
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Zbigniew Jędrzejewski-Szmek 03e93e
+  Lesser General Public License for more details.
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+  You should have received a copy of the GNU Lesser General Public License
Zbigniew Jędrzejewski-Szmek 03e93e
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
Zbigniew Jędrzejewski-Szmek 03e93e
+***/
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+#include <sched.h>
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "alloc-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "extract-word.h"
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "nsflags.h"
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "seccomp-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "string-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+const struct namespace_flag_map namespace_flag_map[] = {
Zbigniew Jędrzejewski-Szmek 03e93e
+        { CLONE_NEWCGROUP, "cgroup" },
Zbigniew Jędrzejewski-Szmek 03e93e
+        { CLONE_NEWIPC,    "ipc"    },
Zbigniew Jędrzejewski-Szmek 03e93e
+        { CLONE_NEWNET,    "net"    },
Zbigniew Jędrzejewski-Szmek 03e93e
+        /* So, the mount namespace flag is called CLONE_NEWNS for historical reasons. Let's expose it here under a more
Zbigniew Jędrzejewski-Szmek 03e93e
+         * explanatory name: "mnt". This is in-line with how the kernel exposes namespaces in /proc/$PID/ns. */
Zbigniew Jędrzejewski-Szmek 03e93e
+        { CLONE_NEWNS,     "mnt"    },
Zbigniew Jędrzejewski-Szmek 03e93e
+        { CLONE_NEWPID,    "pid"    },
Zbigniew Jędrzejewski-Szmek 03e93e
+        { CLONE_NEWUSER,   "user"   },
Zbigniew Jędrzejewski-Szmek 03e93e
+        { CLONE_NEWUTS,    "uts"    },
Zbigniew Jędrzejewski-Szmek 03e93e
+        {}
Zbigniew Jędrzejewski-Szmek 03e93e
+};
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+const char* namespace_flag_to_string(unsigned long flag) {
Zbigniew Jędrzejewski-Szmek 03e93e
+        unsigned i;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        flag &= NAMESPACE_FLAGS_ALL;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        for (i = 0; namespace_flag_map[i].name; i++)
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (flag == namespace_flag_map[i].flag)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        return namespace_flag_map[i].name;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        return NULL; /* either unknown namespace flag, or a combination of many. This call supports neither. */
Zbigniew Jędrzejewski-Szmek 03e93e
+}
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+unsigned long namespace_flag_from_string(const char *name) {
Zbigniew Jędrzejewski-Szmek 03e93e
+        unsigned i;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (isempty(name))
Zbigniew Jędrzejewski-Szmek 03e93e
+                return 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        for (i = 0; namespace_flag_map[i].name; i++)
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (streq(name, namespace_flag_map[i].name))
Zbigniew Jędrzejewski-Szmek 03e93e
+                        return namespace_flag_map[i].flag;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        return 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+}
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+int namespace_flag_from_string_many(const char *name, unsigned long *ret) {
Zbigniew Jędrzejewski-Szmek 03e93e
+        unsigned long flags = 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+        int r;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(ret);
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (!name) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                *ret = 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+                return 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+        }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        for (;;) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                _cleanup_free_ char *word = NULL;
Zbigniew Jędrzejewski-Szmek 03e93e
+                unsigned long f;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                r = extract_first_word(&name, &word, NULL, 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (r < 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        return r;
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (r == 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        break;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                f = namespace_flag_from_string(word);
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (f == 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        return -EINVAL;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                flags |= f;
Zbigniew Jędrzejewski-Szmek 03e93e
+        }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        *ret = flags;
Zbigniew Jędrzejewski-Szmek 03e93e
+        return 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+}
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+int namespace_flag_to_string_many(unsigned long flags, char **ret) {
Zbigniew Jędrzejewski-Szmek 03e93e
+        _cleanup_free_ char *s = NULL;
Zbigniew Jędrzejewski-Szmek 03e93e
+        unsigned i;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        for (i = 0; namespace_flag_map[i].name; i++) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                if ((flags & namespace_flag_map[i].flag) != namespace_flag_map[i].flag)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        continue;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (!s) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                        s = strdup(namespace_flag_map[i].name);
Zbigniew Jędrzejewski-Szmek 03e93e
+                        if (!s)
Zbigniew Jędrzejewski-Szmek 03e93e
+                                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 03e93e
+                } else {
Zbigniew Jędrzejewski-Szmek 03e93e
+                        if (!strextend(&s, " ", namespace_flag_map[i].name, NULL))
Zbigniew Jędrzejewski-Szmek 03e93e
+                                return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 03e93e
+                }
Zbigniew Jędrzejewski-Szmek 03e93e
+        }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (!s) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                s = strdup("");
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (!s)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 03e93e
+        }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        *ret = s;
Zbigniew Jędrzejewski-Szmek 03e93e
+        s = NULL;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        return 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+}
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/src/shared/nsflags.h b/src/shared/nsflags.h
Zbigniew Jędrzejewski-Szmek 03e93e
new file mode 100644
Zbigniew Jędrzejewski-Szmek 03e93e
index 0000000000..152ab8b936
Zbigniew Jędrzejewski-Szmek 03e93e
--- /dev/null
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/src/shared/nsflags.h
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -0,0 +1,49 @@
Zbigniew Jędrzejewski-Szmek 03e93e
+#pragma once
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+/***
Zbigniew Jędrzejewski-Szmek 03e93e
+  This file is part of systemd.
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+  Copyright 2016 Lennart Poettering
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+  systemd is free software; you can redistribute it and/or modify it
Zbigniew Jędrzejewski-Szmek 03e93e
+  under the terms of the GNU Lesser General Public License as published by
Zbigniew Jędrzejewski-Szmek 03e93e
+  the Free Software Foundation; either version 2.1 of the License, or
Zbigniew Jędrzejewski-Szmek 03e93e
+  (at your option) any later version.
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+  systemd is distributed in the hope that it will be useful, but
Zbigniew Jędrzejewski-Szmek 03e93e
+  WITHOUT ANY WARRANTY; without even the implied warranty of
Zbigniew Jędrzejewski-Szmek 03e93e
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Zbigniew Jędrzejewski-Szmek 03e93e
+  Lesser General Public License for more details.
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+  You should have received a copy of the GNU Lesser General Public License
Zbigniew Jędrzejewski-Szmek 03e93e
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
Zbigniew Jędrzejewski-Szmek 03e93e
+***/
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+#include <sched.h>
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "missing.h"
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+/* The combination of all namespace flags defined by the kernel. The right type for this isn't clear. setns() and
Zbigniew Jędrzejewski-Szmek 03e93e
+ * unshare() expect these flags to be passed as (signed) "int", while clone() wants them as "unsigned long". The latter
Zbigniew Jędrzejewski-Szmek 03e93e
+ * is definitely more appropriate for a flags parameter, and also the larger type of the two, hence let's stick to that
Zbigniew Jędrzejewski-Szmek 03e93e
+ * here. */
Zbigniew Jędrzejewski-Szmek 03e93e
+#define NAMESPACE_FLAGS_ALL                                             \
Zbigniew Jędrzejewski-Szmek 03e93e
+        ((unsigned long) (CLONE_NEWCGROUP|                              \
Zbigniew Jędrzejewski-Szmek 03e93e
+                          CLONE_NEWIPC|                                 \
Zbigniew Jędrzejewski-Szmek 03e93e
+                          CLONE_NEWNET|                                 \
Zbigniew Jędrzejewski-Szmek 03e93e
+                          CLONE_NEWNS|                                  \
Zbigniew Jędrzejewski-Szmek 03e93e
+                          CLONE_NEWPID|                                 \
Zbigniew Jędrzejewski-Szmek 03e93e
+                          CLONE_NEWUSER|                                \
Zbigniew Jędrzejewski-Szmek 03e93e
+                          CLONE_NEWUTS))
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+const char* namespace_flag_to_string(unsigned long flag);
Zbigniew Jędrzejewski-Szmek 03e93e
+unsigned long namespace_flag_from_string(const char *name);
Zbigniew Jędrzejewski-Szmek 03e93e
+int namespace_flag_from_string_many(const char *name, unsigned long *ret);
Zbigniew Jędrzejewski-Szmek 03e93e
+int namespace_flag_to_string_many(unsigned long flags, char **ret);
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+struct namespace_flag_map {
Zbigniew Jędrzejewski-Szmek 03e93e
+        unsigned long flag;
Zbigniew Jędrzejewski-Szmek 03e93e
+        const char *name;
Zbigniew Jędrzejewski-Szmek 03e93e
+};
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+extern const struct namespace_flag_map namespace_flag_map[];
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
Zbigniew Jędrzejewski-Szmek 03e93e
index c9b24f1065..55b97e1efb 100644
Zbigniew Jędrzejewski-Szmek 03e93e
--- a/src/shared/seccomp-util.c
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/src/shared/seccomp-util.c
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -23,7 +23,9 @@
Zbigniew Jędrzejewski-Szmek 03e93e
 #include <sys/prctl.h>
Zbigniew Jędrzejewski-Szmek 03e93e
 #include <linux/seccomp.h>
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "alloc-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "macro.h"
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "nsflags.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "seccomp-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "string-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -574,5 +576,92 @@ int seccomp_load_filter_set(uint32_t default_action, const SyscallFilterSet *set
Zbigniew Jędrzejewski-Szmek 03e93e
 finish:
Zbigniew Jędrzejewski-Szmek 03e93e
         seccomp_release(seccomp);
Zbigniew Jędrzejewski-Szmek 03e93e
         return r;
Zbigniew Jędrzejewski-Szmek 03e93e
+}
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+int seccomp_restrict_namespaces(unsigned long retain) {
Zbigniew Jędrzejewski-Szmek 03e93e
+        scmp_filter_ctx seccomp;
Zbigniew Jędrzejewski-Szmek 03e93e
+        unsigned i;
Zbigniew Jędrzejewski-Szmek 03e93e
+        int r;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (log_get_max_level() >= LOG_DEBUG) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                _cleanup_free_ char *s = NULL;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                (void) namespace_flag_to_string_many(retain, &s);
Zbigniew Jędrzejewski-Szmek 03e93e
+                log_debug("Restricting namespace to: %s.", strna(s));
Zbigniew Jędrzejewski-Szmek 03e93e
+        }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        /* NOOP? */
Zbigniew Jędrzejewski-Szmek 03e93e
+        if ((retain & NAMESPACE_FLAGS_ALL) == NAMESPACE_FLAGS_ALL)
Zbigniew Jędrzejewski-Szmek 03e93e
+                return 0;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        r = seccomp_init_conservative(&seccomp, SCMP_ACT_ALLOW);
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                return r;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        if ((retain & NAMESPACE_FLAGS_ALL) == 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                /* If every single kind of namespace shall be prohibited, then let's block the whole setns() syscall
Zbigniew Jędrzejewski-Szmek 03e93e
+                 * altogether. */
Zbigniew Jędrzejewski-Szmek 03e93e
+                r = seccomp_rule_add(
Zbigniew Jędrzejewski-Szmek 03e93e
+                                seccomp,
Zbigniew Jędrzejewski-Szmek 03e93e
+                                SCMP_ACT_ERRNO(EPERM),
Zbigniew Jędrzejewski-Szmek 03e93e
+                                SCMP_SYS(setns),
Zbigniew Jędrzejewski-Szmek 03e93e
+                                0);
Zbigniew Jędrzejewski-Szmek 03e93e
+        else
Zbigniew Jędrzejewski-Szmek 03e93e
+                /* Otherwise, block only the invocations with the appropriate flags in the loop below, but also the
Zbigniew Jędrzejewski-Szmek 03e93e
+                 * special invocation with a zero flags argument, right here. */
Zbigniew Jędrzejewski-Szmek 03e93e
+                r = seccomp_rule_add(
Zbigniew Jędrzejewski-Szmek 03e93e
+                                seccomp,
Zbigniew Jędrzejewski-Szmek 03e93e
+                                SCMP_ACT_ERRNO(EPERM),
Zbigniew Jędrzejewski-Szmek 03e93e
+                                SCMP_SYS(setns),
Zbigniew Jędrzejewski-Szmek 03e93e
+                                1,
Zbigniew Jędrzejewski-Szmek 03e93e
+                                SCMP_A1(SCMP_CMP_EQ, 0));
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (r < 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                goto finish;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        for (i = 0; namespace_flag_map[i].name; i++) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                unsigned long f;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                f = namespace_flag_map[i].flag;
Zbigniew Jędrzejewski-Szmek 03e93e
+                if ((retain & f) == f) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                        log_debug("Permitting %s.", namespace_flag_map[i].name);
Zbigniew Jędrzejewski-Szmek 03e93e
+                        continue;
Zbigniew Jędrzejewski-Szmek 03e93e
+                }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                log_debug("Blocking %s.", namespace_flag_map[i].name);
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                r = seccomp_rule_add(
Zbigniew Jędrzejewski-Szmek 03e93e
+                                seccomp,
Zbigniew Jędrzejewski-Szmek 03e93e
+                                SCMP_ACT_ERRNO(EPERM),
Zbigniew Jędrzejewski-Szmek 03e93e
+                                SCMP_SYS(unshare),
Zbigniew Jędrzejewski-Szmek 03e93e
+                                1,
Zbigniew Jędrzejewski-Szmek 03e93e
+                                SCMP_A0(SCMP_CMP_MASKED_EQ, f, f));
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (r < 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        goto finish;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                r = seccomp_rule_add(
Zbigniew Jędrzejewski-Szmek 03e93e
+                                seccomp,
Zbigniew Jędrzejewski-Szmek 03e93e
+                                SCMP_ACT_ERRNO(EPERM),
Zbigniew Jędrzejewski-Szmek 03e93e
+                                SCMP_SYS(clone),
Zbigniew Jędrzejewski-Szmek 03e93e
+                                1,
Zbigniew Jędrzejewski-Szmek 03e93e
+                                SCMP_A0(SCMP_CMP_MASKED_EQ, f, f));
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (r < 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        goto finish;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                if ((retain & NAMESPACE_FLAGS_ALL) != 0) {
Zbigniew Jędrzejewski-Szmek 03e93e
+                        r = seccomp_rule_add(
Zbigniew Jędrzejewski-Szmek 03e93e
+                                        seccomp,
Zbigniew Jędrzejewski-Szmek 03e93e
+                                        SCMP_ACT_ERRNO(EPERM),
Zbigniew Jędrzejewski-Szmek 03e93e
+                                        SCMP_SYS(setns),
Zbigniew Jędrzejewski-Szmek 03e93e
+                                        1,
Zbigniew Jędrzejewski-Szmek 03e93e
+                                        SCMP_A1(SCMP_CMP_MASKED_EQ, f, f));
Zbigniew Jędrzejewski-Szmek 03e93e
+                        if (r < 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                                goto finish;
Zbigniew Jędrzejewski-Szmek 03e93e
+                }
Zbigniew Jędrzejewski-Szmek 03e93e
+        }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        r = seccomp_load(seccomp);
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+finish:
Zbigniew Jędrzejewski-Szmek 03e93e
+        seccomp_release(seccomp);
Zbigniew Jędrzejewski-Szmek 03e93e
+        return r;
Zbigniew Jędrzejewski-Szmek 03e93e
 }
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h
Zbigniew Jędrzejewski-Szmek 03e93e
index 8e209efef2..e325dab628 100644
Zbigniew Jędrzejewski-Szmek 03e93e
--- a/src/shared/seccomp-util.h
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/src/shared/seccomp-util.h
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -64,3 +64,5 @@ const SyscallFilterSet *syscall_filter_set_find(const char *name);
Zbigniew Jędrzejewski-Szmek 03e93e
 int seccomp_add_syscall_filter_set(scmp_filter_ctx seccomp, const SyscallFilterSet *set, uint32_t action);
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
 int seccomp_load_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action);
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+int seccomp_restrict_namespaces(unsigned long retain);
Zbigniew Jędrzejewski-Szmek 03e93e
diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c
Zbigniew Jędrzejewski-Szmek 03e93e
index 43d1567288..beb6a7f422 100644
Zbigniew Jędrzejewski-Szmek 03e93e
--- a/src/test/test-seccomp.c
Zbigniew Jędrzejewski-Szmek 03e93e
+++ b/src/test/test-seccomp.c
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -20,10 +20,15 @@
Zbigniew Jędrzejewski-Szmek 03e93e
 #include <stdlib.h>
Zbigniew Jędrzejewski-Szmek 03e93e
 #include <sys/eventfd.h>
Zbigniew Jędrzejewski-Szmek 03e93e
 #include <unistd.h>
Zbigniew Jędrzejewski-Szmek 03e93e
+#include <sched.h>
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "alloc-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "fd-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "macro.h"
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "missing.h"
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "nsflags.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "process-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
+#include "raw-clone.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "seccomp-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "string-util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
 #include "util.h"
Zbigniew Jędrzejewski-Szmek 03e93e
@@ -125,12 +130,101 @@ static void test_filter_sets(void) {
Zbigniew Jędrzejewski-Szmek 03e93e
         }
Zbigniew Jędrzejewski-Szmek 03e93e
 }
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+static void test_restrict_namespace(void) {
Zbigniew Jędrzejewski-Szmek 03e93e
+        _cleanup_free_ char *s = NULL;
Zbigniew Jędrzejewski-Szmek 03e93e
+        pid_t pid;
Zbigniew Jędrzejewski-Szmek 03e93e
+        unsigned long ul;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(namespace_flag_to_string(0) == NULL);
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(streq(namespace_flag_to_string(CLONE_NEWNS), "mnt"));
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(namespace_flag_to_string(CLONE_NEWNS|CLONE_NEWIPC) == NULL);
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(streq(namespace_flag_to_string(CLONE_NEWCGROUP), "cgroup"));
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(namespace_flag_from_string("mnt") == CLONE_NEWNS);
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(namespace_flag_from_string(NULL) == 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(namespace_flag_from_string("") == 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(namespace_flag_from_string("uts") == CLONE_NEWUTS);
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(namespace_flag_from_string(namespace_flag_to_string(CLONE_NEWUTS)) == CLONE_NEWUTS);
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(streq(namespace_flag_to_string(namespace_flag_from_string("ipc")), "ipc"));
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(namespace_flag_from_string_many(NULL, &ul) == 0 && ul == 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(namespace_flag_from_string_many("", &ul) == 0 && ul == 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(namespace_flag_from_string_many("mnt uts ipc", &ul) == 0 && ul == (CLONE_NEWNS|CLONE_NEWUTS|CLONE_NEWIPC));
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(namespace_flag_to_string_many(NAMESPACE_FLAGS_ALL, &s) == 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(streq(s, "cgroup ipc net mnt pid user uts"));
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(namespace_flag_from_string_many(s, &ul) == 0 && ul == NAMESPACE_FLAGS_ALL);
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (!is_seccomp_available())
Zbigniew Jędrzejewski-Szmek 03e93e
+                return;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (geteuid() != 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                return;
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        pid = fork();
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(pid >= 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        if (pid == 0) {
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(seccomp_restrict_namespaces(CLONE_NEWNS|CLONE_NEWNET) >= 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(unshare(CLONE_NEWNS) == 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(unshare(CLONE_NEWNET) == 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(unshare(CLONE_NEWUTS) == -1);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(errno == EPERM);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(unshare(CLONE_NEWIPC) == -1);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(errno == EPERM);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(unshare(CLONE_NEWNET|CLONE_NEWUTS) == -1);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(errno == EPERM);
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                /* We use fd 0 (stdin) here, which of course will fail with EINVAL on setns(). Except of course our
Zbigniew Jędrzejewski-Szmek 03e93e
+                 * seccomp filter worked, and hits first and makes it return EPERM */
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(setns(0, CLONE_NEWNS) == -1);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(errno == EINVAL);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(setns(0, CLONE_NEWNET) == -1);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(errno == EINVAL);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(setns(0, CLONE_NEWUTS) == -1);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(errno == EPERM);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(setns(0, CLONE_NEWIPC) == -1);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(errno == EPERM);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(setns(0, CLONE_NEWNET|CLONE_NEWUTS) == -1);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(errno == EPERM);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(setns(0, 0) == -1);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(errno == EPERM);
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                pid = raw_clone(CLONE_NEWNS);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(pid >= 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (pid == 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        _exit(EXIT_SUCCESS);
Zbigniew Jędrzejewski-Szmek 03e93e
+                pid = raw_clone(CLONE_NEWNET);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(pid >= 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+                if (pid == 0)
Zbigniew Jędrzejewski-Szmek 03e93e
+                        _exit(EXIT_SUCCESS);
Zbigniew Jędrzejewski-Szmek 03e93e
+                pid = raw_clone(CLONE_NEWUTS);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(pid < 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(errno == EPERM);
Zbigniew Jędrzejewski-Szmek 03e93e
+                pid = raw_clone(CLONE_NEWIPC);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(pid < 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(errno == EPERM);
Zbigniew Jędrzejewski-Szmek 03e93e
+                pid = raw_clone(CLONE_NEWNET|CLONE_NEWUTS);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(pid < 0);
Zbigniew Jędrzejewski-Szmek 03e93e
+                assert_se(errno == EPERM);
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+                _exit(EXIT_SUCCESS);
Zbigniew Jędrzejewski-Szmek 03e93e
+        }
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
+        assert_se(wait_for_terminate_and_warn("nsseccomp", pid, true) == EXIT_SUCCESS);
Zbigniew Jędrzejewski-Szmek 03e93e
+}
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
 int main(int argc, char *argv[]) {
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
+        log_set_max_level(LOG_DEBUG);
Zbigniew Jędrzejewski-Szmek 03e93e
+
Zbigniew Jędrzejewski-Szmek 03e93e
         test_seccomp_arch_to_string();
Zbigniew Jędrzejewski-Szmek 03e93e
         test_architecture_table();
Zbigniew Jędrzejewski-Szmek 03e93e
         test_syscall_filter_set_find();
Zbigniew Jędrzejewski-Szmek 03e93e
         test_filter_sets();
Zbigniew Jędrzejewski-Szmek 03e93e
+        test_restrict_namespace();
Zbigniew Jędrzejewski-Szmek 03e93e
 
Zbigniew Jędrzejewski-Szmek 03e93e
         return 0;
Zbigniew Jędrzejewski-Szmek 03e93e
 }