New directives PrivateIPC and IPCNamespacePath

This commit is contained in:
Xℹ Ruoyao 2021-02-16 23:58:56 +08:00
parent 54c2459d56
commit a70581ffb5
No known key found for this signature in database
GPG key ID: D95E4716CCBB34DC
11 changed files with 270 additions and 23 deletions

View 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"/>

View 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>

View file

@ -799,14 +799,16 @@
<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>

View 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;

View 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", fdpair[1]);
fdpair[1] = fdset_remove(fds, fdpair[1]);
"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 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;

View 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;

View 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)

View 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");

View 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",

View 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"

View 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=