]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
New directives PrivateIPC and IPCNamespacePath
authorXℹ Ruoyao <xry111@mengyan1223.wang>
Tue, 16 Feb 2021 15:58:56 +0000 (23:58 +0800)
committerXℹ Ruoyao <xry111@mengyan1223.wang>
Wed, 3 Mar 2021 16:04:36 +0000 (00:04 +0800)
man/org.freedesktop.systemd1.xml
man/systemd.exec.xml
man/systemd.unit.xml
src/core/dbus-execute.c
src/core/execute.c
src/core/execute.h
src/core/load-fragment-gperf.gperf.m4
src/core/socket.c
src/shared/bus-unit-util.c
src/test/test-stat-util.c
test/fuzz/fuzz-unit-file/directives.service

index 21630478962c6ae35b1ebc9dd986a310d85210f8..aff43217e1690703a7bcaeaafd900f3b88651668 100644 (file)
@@ -2693,6 +2693,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly b PrivateMounts = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly b PrivateIPC = ...;
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s ProtectHome = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s ProtectSystem = '...';
@@ -2777,6 +2779,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s NetworkNamespacePath = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly s IPCNamespacePath = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s KillMode = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly i KillSignal = ...;
@@ -3194,6 +3198,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--property PrivateMounts is not documented!-->
 
+    <!--property PrivateIPC is not documented!-->
+
     <!--property ProtectHome is not documented!-->
 
     <!--property ProtectSystem is not documented!-->
@@ -3278,6 +3284,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <!--property NetworkNamespacePath is not documented!-->
 
+    <!--property IPCNamespacePath is not documented!-->
+
     <!--property KillMode is not documented!-->
 
     <!--property KillSignal is not documented!-->
@@ -3772,6 +3780,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="PrivateMounts"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="PrivateIPC"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="ProtectHome"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="ProtectSystem"/>
@@ -3856,6 +3866,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
 
     <variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="IPCNamespacePath"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
@@ -4454,6 +4466,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly b PrivateMounts = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly b PrivateIPC = ...;
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s ProtectHome = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s ProtectSystem = '...';
@@ -4538,6 +4552,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s NetworkNamespacePath = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly s IPCNamespacePath = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s KillMode = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly i KillSignal = ...;
@@ -4983,6 +4999,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <!--property PrivateMounts is not documented!-->
 
+    <!--property PrivateIPC is not documented!-->
+
     <!--property ProtectHome is not documented!-->
 
     <!--property ProtectSystem is not documented!-->
@@ -5067,6 +5085,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <!--property NetworkNamespacePath is not documented!-->
 
+    <!--property IPCNamespacePath is not documented!-->
+
     <!--property KillMode is not documented!-->
 
     <!--property KillSignal is not documented!-->
@@ -5559,6 +5579,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <variablelist class="dbus-property" generated="True" extra-ref="PrivateMounts"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="PrivateIPC"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="ProtectHome"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="ProtectSystem"/>
@@ -5643,6 +5665,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
 
     <variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="IPCNamespacePath"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
@@ -6143,6 +6167,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly b PrivateMounts = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly b PrivateIPC = ...;
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s ProtectHome = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s ProtectSystem = '...';
@@ -6227,6 +6253,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s NetworkNamespacePath = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly s IPCNamespacePath = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s KillMode = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly i KillSignal = ...;
@@ -6600,6 +6628,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <!--property PrivateMounts is not documented!-->
 
+    <!--property PrivateIPC is not documented!-->
+
     <!--property ProtectHome is not documented!-->
 
     <!--property ProtectSystem is not documented!-->
@@ -6684,6 +6714,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <!--property NetworkNamespacePath is not documented!-->
 
+    <!--property IPCNamespacePath is not documented!-->
+
     <!--property KillMode is not documented!-->
 
     <!--property KillSignal is not documented!-->
@@ -7094,6 +7126,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <variablelist class="dbus-property" generated="True" extra-ref="PrivateMounts"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="PrivateIPC"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="ProtectHome"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="ProtectSystem"/>
@@ -7178,6 +7212,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
 
     <variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="IPCNamespacePath"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
@@ -7799,6 +7835,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly b PrivateMounts = ...;
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly b PrivateIPC = ...;
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s ProtectHome = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s ProtectSystem = '...';
@@ -7883,6 +7921,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s NetworkNamespacePath = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
+      readonly s IPCNamespacePath = '...';
+      @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly s KillMode = '...';
       @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
       readonly i KillSignal = ...;
@@ -8242,6 +8282,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <!--property PrivateMounts is not documented!-->
 
+    <!--property PrivateIPC is not documented!-->
+
     <!--property ProtectHome is not documented!-->
 
     <!--property ProtectSystem is not documented!-->
@@ -8326,6 +8368,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <!--property NetworkNamespacePath is not documented!-->
 
+    <!--property IPCNamespacePath is not documented!-->
+
     <!--property KillMode is not documented!-->
 
     <!--property KillSignal is not documented!-->
@@ -8722,6 +8766,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <variablelist class="dbus-property" generated="True" extra-ref="PrivateMounts"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="PrivateIPC"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="ProtectHome"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="ProtectSystem"/>
@@ -8806,6 +8852,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
 
     <variablelist class="dbus-property" generated="True" extra-ref="NetworkNamespacePath"/>
 
+    <variablelist class="dbus-property" generated="True" extra-ref="IPCNamespacePath"/>
+
     <variablelist class="dbus-property" generated="True" extra-ref="KillMode"/>
 
     <variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/>
index 30e64224c3e74ac6d0d8ebe257219aa5e684efbd..51f873f8cd91a734f657cf8ba3d01576e2f49bc4 100644 (file)
@@ -1603,6 +1603,53 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
         <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><varname>PrivateIPC=</varname></term>
+
+        <listitem><para>Takes a boolean argument. If true, sets up a new IPC namespace for the executed processes.
+        Each IPC namespace has its own set of System V IPC identifiers and its own POSIX message queue file system.
+        This is useful to avoid name clash of IPC identifiers. Defaults to false. It is possible to run two or
+        more units within the same private IPC namespace by using the <varname>JoinsNamespaceOf=</varname> directive,
+        see <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+        details.</para>
+
+        <para>Note that IPC namespacing does not have an effect on
+        <constant>AF_UNIX</constant> sockets, which are the most common
+        form of IPC used on Linux. Instead, <constant>AF_UNIX</constant>
+        sockets in the file system are subject to mount namespacing, and
+        those in the abstract namespace are subject to network namespacing.
+        IPC namespacing only has an effect on SysV IPC (which is mostly
+        legacy) as well as POSIX message queues (for which
+        <constant>AF_UNIX</constant>/<constant>SOCK_SEQPACKET</constant>
+        sockets are typically a better replacement). IPC namespacing also
+        has no effect on POSIX shared memory (which is subject to mount
+        namespacing) either. See
+        <citerefentry><refentrytitle>ipc_namespaces</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
+        the details.</para>
+
+        <para>Note that the implementation of this setting might be impossible (for example if IPC namespaces are
+        not available), and the unit should be written in a way that does not solely rely on this setting for
+        security.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>IPCNamespacePath=</varname></term>
+
+        <listitem><para>Takes an absolute file system path refererring to a Linux IPC namespace
+        pseudo-file (i.e. a file like <filename>/proc/$PID/ns/ipc</filename> or a bind mount or symlink to
+        one). When set the invoked processes are added to the network namespace referenced by that path. The
+        path has to point to a valid namespace file at the moment the processes are forked off. If this
+        option is used <varname>PrivateIPC=</varname> has no effect. If this option is used together with
+        <varname>JoinsNamespaceOf=</varname> then it only has an effect if this unit is started before any of
+        the listed units that have <varname>PrivateIPC=</varname> or
+        <varname>IPCNamespacePath=</varname> configured, as otherwise the network namespace of those
+        units is reused.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
+      </varlistentry>
+
       <varlistentry>
         <term><varname>PrivateUsers=</varname></term>
 
@@ -3585,7 +3632,7 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
           <row>
             <entry>226</entry>
             <entry><constant>EXIT_NAMESPACE</constant></entry>
-            <entry>Failed to set up mount namespacing. See <varname>ReadOnlyPaths=</varname> and related settings above.</entry>
+            <entry>Failed to set up mount, UTS, or IPC namespacing. See <varname>ReadOnlyPaths=</varname>, <varname>ProtectHostname=</varname>, <varname>PrivateIPC=</varname>, and related settings above.</entry>
           </row>
           <row>
             <entry>227</entry>
index 6a9d4dc486d51ef3007567525911338b2ae6eb7c..20e52c566423f940cd2ffd6ea0cf78f2dddf6cad 100644 (file)
 
         <listitem><para>For units that start processes (such as service units), lists one or more other units
         whose network and/or temporary file namespace to join. This only applies to unit types which support
-        the <varname>PrivateNetwork=</varname>, <varname>NetworkNamespacePath=</varname> and
+        the <varname>PrivateNetwork=</varname>, <varname>NetworkNamespacePath=</varname>,
+        <varname>PrivateIPC=</varname>, <varname>IPCNamespacePath=</varname>, and
         <varname>PrivateTmp=</varname> directives (see
         <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
         details). If a unit that has this setting set is started, its processes will see the same
-        <filename>/tmp/</filename>, <filename>/var/tmp/</filename> and network namespace as one listed unit
-        that is started. If multiple listed units are already started, it is not defined which namespace is
-        joined. Note that this setting only has an effect if
-        <varname>PrivateNetwork=</varname>/<varname>NetworkNamespacePath=</varname> and/or
+        <filename>/tmp/</filename>, <filename>/var/tmp/</filename>, IPC namespace and network namespace as
+        one listed unit that is started. If multiple listed units are already started, it is not defined
+        which namespace is joined. Note that this setting only has an effect if
+        <varname>PrivateNetwork=</varname>/<varname>NetworkNamespacePath=</varname>,
+        <varname>PrivateIPC=</varname>/<varname>IPCNamespacePath=</varname> and/or
         <varname>PrivateTmp=</varname> is enabled for both the unit that joins the namespace and the unit
         whose namespace is joined.</para></listitem>
       </varlistentry>
index a4817ca6de7baa92dbda9782abe3a662d44f96b3..f474a02b0e27040e8e47726637385c44f2e2bf20 100644 (file)
@@ -1162,6 +1162,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("PrivateUsers", "b", bus_property_get_bool, offsetof(ExecContext, private_users), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("PrivateMounts", "b", bus_property_get_bool, offsetof(ExecContext, private_mounts), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("PrivateIPC", "b", bus_property_get_bool, offsetof(ExecContext, private_ipc), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ProtectHome", "s", property_get_protect_home, offsetof(ExecContext, protect_home), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ProtectSystem", "s", property_get_protect_system, offsetof(ExecContext, protect_system), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1204,6 +1205,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_PROPERTY("ProcSubset", "s", property_get_proc_subset, offsetof(ExecContext, proc_subset), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("ProtectHostname", "b", bus_property_get_bool, offsetof(ExecContext, protect_hostname), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("NetworkNamespacePath", "s", NULL, offsetof(ExecContext, network_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("IPCNamespacePath", "s", NULL, offsetof(ExecContext, ipc_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
 
         /* Obsolete/redundant properties: */
         SD_BUS_PROPERTY("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
@@ -1753,6 +1755,9 @@ int bus_exec_context_set_transient_property(
         if (streq(name, "PrivateNetwork"))
                 return bus_set_transient_bool(u, name, &c->private_network, message, flags, error);
 
+        if (streq(name, "PrivateIPC"))
+                return bus_set_transient_bool(u, name, &c->private_ipc, message, flags, error);
+
         if (streq(name, "PrivateUsers"))
                 return bus_set_transient_bool(u, name, &c->private_users, message, flags, error);
 
@@ -1873,6 +1878,9 @@ int bus_exec_context_set_transient_property(
         if (streq(name, "NetworkNamespacePath"))
                 return bus_set_transient_path(u, name, &c->network_namespace_path, message, flags, error);
 
+        if (streq(name, "IPCNamespacePath"))
+                return bus_set_transient_path(u, name, &c->ipc_namespace_path, message, flags, error);
+
         if (streq(name, "SupplementaryGroups")) {
                 _cleanup_strv_free_ char **l = NULL;
                 char **p;
index 0a2d2e1158519d2054a8dec28d6b8b07eca0e093..684b5a233e7919dc12df7ab2d76f130bb395e494 100644 (file)
@@ -3476,8 +3476,10 @@ static int close_remaining_fds(
                 n_dont_close += n_fds;
         }
 
-        if (runtime)
+        if (runtime) {
                 append_socket_pair(dont_close, &n_dont_close, runtime->netns_storage_socket);
+                append_socket_pair(dont_close, &n_dont_close, runtime->ipcns_storage_socket);
+        }
 
         if (dcreds) {
                 if (dcreds->user)
@@ -3925,6 +3927,14 @@ static int exec_child(
                 }
         }
 
+        if (context->ipc_namespace_path && runtime && runtime->ipcns_storage_socket[0] >= 0) {
+                r = open_shareable_ns_path(runtime->ipcns_storage_socket, context->ipc_namespace_path, CLONE_NEWIPC);
+                if (r < 0) {
+                        *exit_status = EXIT_NAMESPACE;
+                        return log_unit_error_errno(unit, r, "Failed to open IPC namespace path %s: %m", context->ipc_namespace_path);
+                }
+        }
+
         r = setup_input(context, params, socket_fd, named_iofds);
         if (r < 0) {
                 *exit_status = EXIT_STDIN;
@@ -4211,6 +4221,25 @@ static int exec_child(
                         log_unit_warning(unit, "PrivateNetwork=yes is configured, but the kernel does not support network namespaces, ignoring.");
         }
 
+        if ((context->private_ipc || context->ipc_namespace_path) && runtime && runtime->ipcns_storage_socket[0] >= 0) {
+
+                if (ns_type_supported(NAMESPACE_IPC)) {
+                        r = setup_shareable_ns(runtime->ipcns_storage_socket, CLONE_NEWIPC);
+                        if (r == -EPERM)
+                                log_unit_warning_errno(unit, r,
+                                                       "PrivateIPC=yes is configured, but IPC namespace setup failed, ignoring: %m");
+                        else if (r < 0) {
+                                *exit_status = EXIT_NAMESPACE;
+                                return log_unit_error_errno(unit, r, "Failed to set up IPC namespacing: %m");
+                        }
+                } else if (context->ipc_namespace_path) {
+                        *exit_status = EXIT_NAMESPACE;
+                        return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                                    "IPCNamespacePath= is not supported, refusing.");
+                } else
+                        log_unit_warning(unit, "PrivateIPC=yes is configured, but the kernel does not support IPC namespaces, ignoring.");
+        }
+
         needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
         if (needs_mount_namespace) {
                 _cleanup_free_ char *error_path = NULL;
@@ -4314,7 +4343,7 @@ static int exec_child(
 #endif
 
         /* We repeat the fd closing here, to make sure that nothing is leaked from the PAM modules. Note that we are
-         * more aggressive this time since socket_fd and the netns fds we don't need anymore. We do keep the exec_fd
+         * more aggressive this time since socket_fd and the netns and ipcns fds we don't need anymore. We do keep the exec_fd
          * however if we have it as we want to keep it open until the final execve(). */
 
         r = close_all_fds(keep_fds, n_keep_fds);
@@ -6057,6 +6086,7 @@ static ExecRuntime* exec_runtime_free(ExecRuntime *rt, bool destroy) {
         rt->tmp_dir = mfree(rt->tmp_dir);
         rt->var_tmp_dir = mfree(rt->var_tmp_dir);
         safe_close_pair(rt->netns_storage_socket);
+        safe_close_pair(rt->ipcns_storage_socket);
         return mfree(rt);
 }
 
@@ -6081,6 +6111,7 @@ static int exec_runtime_allocate(ExecRuntime **ret, const char *id) {
         *n = (ExecRuntime) {
                 .id = TAKE_PTR(id_copy),
                 .netns_storage_socket = { -1, -1 },
+                .ipcns_storage_socket = { -1, -1 },
         };
 
         *ret = n;
@@ -6093,6 +6124,7 @@ static int exec_runtime_add(
                 char **tmp_dir,
                 char **var_tmp_dir,
                 int netns_storage_socket[2],
+                int ipcns_storage_socket[2],
                 ExecRuntime **ret) {
 
         _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
@@ -6101,7 +6133,7 @@ static int exec_runtime_add(
         assert(m);
         assert(id);
 
-        /* tmp_dir, var_tmp_dir, netns_storage_socket fds are donated on success */
+        /* tmp_dir, var_tmp_dir, {net,ipc}ns_storage_socket fds are donated on success */
 
         r = exec_runtime_allocate(&rt, id);
         if (r < 0)
@@ -6120,6 +6152,11 @@ static int exec_runtime_add(
                 rt->netns_storage_socket[1] = TAKE_FD(netns_storage_socket[1]);
         }
 
+        if (ipcns_storage_socket) {
+                rt->ipcns_storage_socket[0] = TAKE_FD(ipcns_storage_socket[0]);
+                rt->ipcns_storage_socket[1] = TAKE_FD(ipcns_storage_socket[1]);
+        }
+
         rt->manager = m;
 
         if (ret)
@@ -6136,7 +6173,7 @@ static int exec_runtime_make(
                 ExecRuntime **ret) {
 
         _cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL;
-        _cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 };
+        _cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 }, ipcns_storage_socket[2] = { -1, -1 };
         int r;
 
         assert(m);
@@ -6144,7 +6181,7 @@ static int exec_runtime_make(
         assert(id);
 
         /* It is not necessary to create ExecRuntime object. */
-        if (!c->private_network && !c->private_tmp && !c->network_namespace_path) {
+        if (!c->private_network && !c->private_ipc && !c->private_tmp && !c->network_namespace_path) {
                 *ret = NULL;
                 return 0;
         }
@@ -6163,7 +6200,12 @@ static int exec_runtime_make(
                         return -errno;
         }
 
-        r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ret);
+        if (c->private_ipc || c->ipc_namespace_path) {
+                if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ipcns_storage_socket) < 0)
+                        return -errno;
+        }
+
+        r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ipcns_storage_socket, ret);
         if (r < 0)
                 return r;
 
@@ -6254,6 +6296,26 @@ int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
                         fprintf(f, " netns-socket-1=%i", copy);
                 }
 
+                if (rt->ipcns_storage_socket[0] >= 0) {
+                        int copy;
+
+                        copy = fdset_put_dup(fds, rt->ipcns_storage_socket[0]);
+                        if (copy < 0)
+                                return copy;
+
+                        fprintf(f, " ipcns-socket-0=%i", copy);
+                }
+
+                if (rt->ipcns_storage_socket[1] >= 0) {
+                        int copy;
+
+                        copy = fdset_put_dup(fds, rt->ipcns_storage_socket[1]);
+                        if (copy < 0)
+                                return copy;
+
+                        fprintf(f, " ipcns-socket-1=%i", copy);
+                }
+
                 fputc('\n', f);
         }
 
@@ -6335,6 +6397,28 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
 
                 safe_close(rt->netns_storage_socket[1]);
                 rt->netns_storage_socket[1] = fdset_remove(fds, fd);
+
+        } else if (streq(key, "ipcns-socket-0")) {
+                int fd;
+
+                if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
+                        log_unit_debug(u, "Failed to parse ipcns socket value: %s", value);
+                        return 0;
+                }
+
+                safe_close(rt->ipcns_storage_socket[0]);
+                rt->ipcns_storage_socket[0] = fdset_remove(fds, fd);
+
+        } else if (streq(key, "ipcns-socket-1")) {
+                int fd;
+
+                if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) {
+                        log_unit_debug(u, "Failed to parse ipcns socket value: %s", value);
+                        return 0;
+                }
+
+                safe_close(rt->ipcns_storage_socket[1]);
+                rt->ipcns_storage_socket[1] = fdset_remove(fds, fd);
         } else
                 return 0;
 
@@ -6358,7 +6442,7 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value,
 int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
         _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
         char *id = NULL;
-        int r, fdpair[] = {-1, -1};
+        int r, netns_fdpair[] = {-1, -1}, ipcns_fdpair[] = {-1, -1};
         const char *p, *v = value;
         size_t n;
 
@@ -6401,13 +6485,13 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
                 n = strcspn(v, " ");
                 buf = strndupa(v, n);
 
-                r = safe_atoi(buf, &fdpair[0]);
+                r = safe_atoi(buf, &netns_fdpair[0]);
                 if (r < 0)
                         return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-0=%s: %m", buf);
-                if (!fdset_contains(fds, fdpair[0]))
+                if (!fdset_contains(fds, netns_fdpair[0]))
                         return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
-                                               "exec-runtime specification netns-socket-0= refers to unknown fd %d: %m", fdpair[0]);
-                fdpair[0] = fdset_remove(fds, fdpair[0]);
+                                               "exec-runtime specification netns-socket-0= refers to unknown fd %d: %m", netns_fdpair[0]);
+                netns_fdpair[0] = fdset_remove(fds, netns_fdpair[0]);
                 if (v[n] != ' ')
                         goto finalize;
                 p = v + n + 1;
@@ -6419,17 +6503,56 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
 
                 n = strcspn(v, " ");
                 buf = strndupa(v, n);
-                r = safe_atoi(buf, &fdpair[1]);
+
+                r = safe_atoi(buf, &netns_fdpair[1]);
                 if (r < 0)
                         return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-1=%s: %m", buf);
-                if (!fdset_contains(fds, fdpair[1]))
+                if (!fdset_contains(fds, netns_fdpair[1]))
+                        return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
+                                               "exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", netns_fdpair[1]);
+                netns_fdpair[1] = fdset_remove(fds, netns_fdpair[1]);
+                if (v[n] != ' ')
+                        goto finalize;
+                p = v + n + 1;
+        }
+
+        v = startswith(p, "ipcns-socket-0=");
+        if (v) {
+                char *buf;
+
+                n = strcspn(v, " ");
+                buf = strndupa(v, n);
+
+                r = safe_atoi(buf, &ipcns_fdpair[0]);
+                if (r < 0)
+                        return log_debug_errno(r, "Unable to parse exec-runtime specification ipcns-socket-0=%s: %m", buf);
+                if (!fdset_contains(fds, ipcns_fdpair[0]))
+                        return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
+                                               "exec-runtime specification ipcns-socket-0= refers to unknown fd %d: %m", ipcns_fdpair[0]);
+                ipcns_fdpair[0] = fdset_remove(fds, ipcns_fdpair[0]);
+                if (v[n] != ' ')
+                        goto finalize;
+                p = v + n + 1;
+        }
+
+        v = startswith(p, "ipcns-socket-1=");
+        if (v) {
+                char *buf;
+
+                n = strcspn(v, " ");
+                buf = strndupa(v, n);
+
+                r = safe_atoi(buf, &ipcns_fdpair[1]);
+                if (r < 0)
+                        return log_debug_errno(r, "Unable to parse exec-runtime specification ipcns-socket-1=%s: %m", buf);
+                if (!fdset_contains(fds, ipcns_fdpair[1]))
                         return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
-                                               "exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", fdpair[1]);
-                fdpair[1] = fdset_remove(fds, fdpair[1]);
+                                               "exec-runtime specification ipcns-socket-1= refers to unknown fd %d: %m", ipcns_fdpair[1]);
+                ipcns_fdpair[1] = fdset_remove(fds, ipcns_fdpair[1]);
         }
 
 finalize:
-        r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, fdpair, NULL);
+        r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_fdpair, ipcns_fdpair, NULL);
         if (r < 0)
                 return log_debug_errno(r, "Failed to add exec-runtime: %m");
         return 0;
index 20e1799b46a2f126a9feaac6dc34205ae78be20a..4c7a5b874f364ed5dbcfe5f40691f6132a59f5ae 100644 (file)
@@ -117,6 +117,9 @@ struct ExecRuntime {
         /* An AF_UNIX socket pair, that contains a datagram containing a file descriptor referring to the network
          * namespace. */
         int netns_storage_socket[2];
+
+        /* Like netns_storage_socket, but the file descriptor is referring to the IPC namespace. */
+        int ipcns_storage_socket[2];
 };
 
 typedef enum ExecDirectoryType {
@@ -280,6 +283,7 @@ struct ExecContext {
         bool private_devices;
         bool private_users;
         bool private_mounts;
+        bool private_ipc;
         bool protect_kernel_tunables;
         bool protect_kernel_modules;
         bool protect_kernel_logs;
@@ -314,6 +318,7 @@ struct ExecContext {
         Set *address_families;
 
         char *network_namespace_path;
+        char *ipc_namespace_path;
 
         ExecDirectory directories[_EXEC_DIRECTORY_TYPE_MAX];
         ExecPreserveMode runtime_directory_preserve_mode;
index 6a11ef0d9d76923e8d0afcbe3d60e72e96e88ac3..21bbcffe41af6d84ecbcc4f31c287a318b4dc579 100644 (file)
@@ -133,10 +133,12 @@ $1.ProtectKernelLogs,                    config_parse_bool,
 $1.ProtectClock,                         config_parse_bool,                           0,                                  offsetof($1, exec_context.protect_clock)
 $1.ProtectControlGroups,                 config_parse_bool,                           0,                                  offsetof($1, exec_context.protect_control_groups)
 $1.NetworkNamespacePath,                 config_parse_unit_path_printf,               0,                                  offsetof($1, exec_context.network_namespace_path)
+$1.IPCNamespacePath,                     config_parse_unit_path_printf,               0,                                  offsetof($1, exec_context.ipc_namespace_path)
 $1.LogNamespace,                         config_parse_log_namespace,                  0,                                  offsetof($1, exec_context)
 $1.PrivateNetwork,                       config_parse_bool,                           0,                                  offsetof($1, exec_context.private_network)
 $1.PrivateUsers,                         config_parse_bool,                           0,                                  offsetof($1, exec_context.private_users)
 $1.PrivateMounts,                        config_parse_bool,                           0,                                  offsetof($1, exec_context.private_mounts)
+$1.PrivateIPC,                           config_parse_bool,                           0,                                  offsetof($1, exec_context.private_ipc)
 $1.ProtectSystem,                        config_parse_protect_system,                 0,                                  offsetof($1, exec_context.protect_system)
 $1.ProtectHome,                          config_parse_protect_home,                   0,                                  offsetof($1, exec_context.protect_home)
 $1.MountFlags,                           config_parse_exec_mount_flags,               0,                                  offsetof($1, exec_context.mount_flags)
index 4bc77f3018aa4f69cf505737b10fe317de317954..6255e704ced0f1a6a464d99ddeee509672fcc7db 100644 (file)
@@ -1552,6 +1552,14 @@ static int socket_address_listen_in_cgroup(
                         return log_unit_error_errno(UNIT(s), r, "Failed to open network namespace path %s: %m", s->exec_context.network_namespace_path);
         }
 
+        if (s->exec_context.ipc_namespace_path &&
+            s->exec_runtime &&
+            s->exec_runtime->ipcns_storage_socket[0] >= 0) {
+                r = open_shareable_ns_path(s->exec_runtime->netns_storage_socket, s->exec_context.network_namespace_path, CLONE_NEWIPC);
+                if (r < 0)
+                        return log_unit_error_errno(UNIT(s), r, "Failed to open IPC namespace path %s: %m", s->exec_context.ipc_namespace_path);
+        }
+
         if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
                 return log_unit_error_errno(UNIT(s), errno, "Failed to create communication channel: %m");
 
index a58495dbf84b352e99b2f80dd1bf61984189bc65..9ed537879159e089e9c9ccdaa057ec1ac2276965 100644 (file)
@@ -882,6 +882,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
                               "ProtectProc",
                               "ProcSubset",
                               "NetworkNamespacePath",
+                              "IPCNamespacePath",
                               "LogNamespace"))
                 return bus_append_string(m, field, eq);
 
@@ -894,6 +895,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
                               "PrivateNetwork",
                               "PrivateUsers",
                               "PrivateMounts",
+                              "PrivateIPC",
                               "NoNewPrivileges",
                               "SyslogLevelPrefix",
                               "MemoryDenyWriteExecute",
index 7f03db5fa7a3ea96c7b66c2b8a43ea113d3c8f64..4dd18be65cdd805af0251687ed477fd179e62ff7 100644 (file)
@@ -2,8 +2,8 @@
 
 #include <fcntl.h>
 #include <linux/magic.h>
-#include <unistd.h>
 #include <sched.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "fd-util.h"
index bdc4515d626b33d9fc19877558682074ad24c4ab..55204463c8d31f253f9a7e4e6dd8d81ba5124e12 100644 (file)
@@ -111,6 +111,7 @@ IOWriteIOPSMax=
 IPAccounting=
 IPAddressAllow=
 IPAddressDeny=
+IPCNamespacePath=
 IPTOS=
 IPTTL=
 IgnoreOnIsolate=
@@ -857,6 +858,7 @@ PivotRoot=
 Port=
 PowerKeyIgnoreInhibited=
 Private=
+PrivateIPC=
 PrivateDevices=
 PrivateNetwork=
 PrivateTmp=