1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-08-25 13:50:12 +03:00

Merge pull request #18615 from xry111/private-ipc-1

New directives PrivateIPC and IPCNamespacePath
This commit is contained in:
Lennart Poettering
2021-03-04 18:04:28 +01:00
committed by GitHub
19 changed files with 396 additions and 83 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

@ -125,13 +125,13 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int
return reset_uid_gid();
}
int fd_is_network_ns(int fd) {
int fd_is_ns(int fd, unsigned long nsflag) {
struct statfs s;
int r;
/* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
* way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
* this somewhat nicely.
/* Checks whether the specified file descriptor refers to a namespace created by specifying nsflag in clone().
* On old kernels there's no nice way to detect that, hence on those we'll return a recognizable error (EUCLEAN),
* so that callers can handle this somewhat nicely.
*
* This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not
* refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */
@ -168,7 +168,7 @@ int fd_is_network_ns(int fd) {
return -errno;
}
return r == CLONE_NEWNET;
return (unsigned long) r == nsflag;
}
int detach_mount_namespace(void) {

View File

@ -6,6 +6,6 @@
int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
int fd_is_network_ns(int fd);
int fd_is_ns(int fd, unsigned long nsflag);
int detach_mount_namespace(void);

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

@ -2037,7 +2037,9 @@ bool exec_needs_mount_namespace(
context->protect_kernel_logs ||
context->protect_control_groups ||
context->protect_proc != PROTECT_PROC_DEFAULT ||
context->proc_subset != PROC_SUBSET_ALL)
context->proc_subset != PROC_SUBSET_ALL ||
context->private_ipc ||
context->ipc_namespace_path)
return true;
if (context->root_directory) {
@ -3178,6 +3180,7 @@ static int apply_mount_namespace(
.protect_system = context->protect_system,
.protect_proc = context->protect_proc,
.proc_subset = context->proc_subset,
.private_ipc = context->private_ipc || context->ipc_namespace_path,
};
} else if (!context->dynamic_user && root_dir)
/*
@ -3476,8 +3479,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)
@ -3918,13 +3923,21 @@ static int exec_child(
}
if (context->network_namespace_path && runtime && runtime->netns_storage_socket[0] >= 0) {
r = open_netns_path(runtime->netns_storage_socket, context->network_namespace_path);
r = open_shareable_ns_path(runtime->netns_storage_socket, context->network_namespace_path, CLONE_NEWNET);
if (r < 0) {
*exit_status = EXIT_NETWORK;
return log_unit_error_errno(unit, r, "Failed to open network namespace path %s: %m", context->network_namespace_path);
}
}
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;
@ -4195,7 +4208,7 @@ static int exec_child(
if ((context->private_network || context->network_namespace_path) && runtime && runtime->netns_storage_socket[0] >= 0) {
if (ns_type_supported(NAMESPACE_NET)) {
r = setup_netns(runtime->netns_storage_socket);
r = setup_shareable_ns(runtime->netns_storage_socket, CLONE_NEWNET);
if (r == -EPERM)
log_unit_warning_errno(unit, r,
"PrivateNetwork=yes is configured, but network namespace setup failed, ignoring: %m");
@ -4211,6 +4224,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 +4346,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 +6089,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 +6114,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 +6127,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 +6136,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 +6155,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 +6176,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 +6184,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 +6203,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 +6299,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 +6400,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 +6445,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 +6488,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 +6506,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

@ -26,6 +26,7 @@
#include "mountpoint-util.h"
#include "namespace-util.h"
#include "namespace.h"
#include "nsflags.h"
#include "nulstr-util.h"
#include "os-util.h"
#include "path-util.h"
@ -63,6 +64,7 @@ typedef enum MountMode {
EXEC,
TMPFS,
EXTENSION_IMAGES, /* Mounted outside the root directory, and used by subsequent mounts */
MQUEUEFS,
READWRITE_IMPLICIT, /* Should have the lowest priority. */
_MOUNT_MODE_MAX,
} MountMode;
@ -227,6 +229,7 @@ static const char * const mount_mode_table[_MOUNT_MODE_MAX] = {
[READWRITE_IMPLICIT] = "rw-implicit",
[EXEC] = "exec",
[NOEXEC] = "noexec",
[MQUEUEFS] = "mqueuefs",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(mount_mode, MountMode);
@ -1112,6 +1115,24 @@ static int mount_run(const MountEntry *m) {
return mount_tmpfs(m);
}
static int mount_mqueuefs(const MountEntry *m) {
int r;
const char *entry_path;
assert(m);
entry_path = mount_entry_path(m);
(void) mkdir_p_label(entry_path, 0755);
(void) umount_recursive(entry_path, 0);
r = mount_nofollow_verbose(LOG_DEBUG, "mqueue", entry_path, "mqueue", m->flags, mount_entry_options(m));
if (r < 0)
return r;
return 0;
}
static int mount_image(const MountEntry *m, const char *root_directory) {
_cleanup_free_ char *host_os_release_id = NULL, *host_os_release_version_id = NULL,
@ -1316,6 +1337,9 @@ static int apply_one_mount(
case RUN:
return mount_run(m);
case MQUEUEFS:
return mount_mqueuefs(m);
case MOUNT_IMAGES:
return mount_image(m, NULL);
@ -1515,7 +1539,8 @@ static size_t namespace_calculate_mounts(
(creds_path ? 2 : 1) +
!!log_namespace +
setup_propagate + /* /run/systemd/incoming */
!!notify_socket;
!!notify_socket +
ns_info->private_ipc; /* /dev/mqueue */
}
static void normalize_mounts(const char *root_directory, MountEntry *mounts, size_t *n_mounts) {
@ -2026,6 +2051,14 @@ int setup_namespace(
};
}
if (ns_info->private_ipc) {
*(m++) = (MountEntry) {
.path_const = "/dev/mqueue",
.mode = MQUEUEFS,
.flags = MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME,
};
}
if (creds_path) {
/* If our service has a credentials store configured, then bind that one in, but hide
* everything else. */
@ -2508,13 +2541,17 @@ int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) {
return 0;
}
int setup_netns(const int netns_storage_socket[static 2]) {
_cleanup_close_ int netns = -1;
int setup_shareable_ns(const int ns_storage_socket[static 2], unsigned long nsflag) {
_cleanup_close_ int ns = -1;
int r, q;
const char *ns_name, *ns_path;
assert(netns_storage_socket);
assert(netns_storage_socket[0] >= 0);
assert(netns_storage_socket[1] >= 0);
assert(ns_storage_socket);
assert(ns_storage_socket[0] >= 0);
assert(ns_storage_socket[1] >= 0);
ns_name = namespace_single_flag_to_string(nsflag);
assert(ns_name);
/* We use the passed socketpair as a storage buffer for our
* namespace reference fd. Whatever process runs this first
@ -2524,35 +2561,36 @@ int setup_netns(const int netns_storage_socket[static 2]) {
*
* It's a bit crazy, but hey, works great! */
if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
if (lockf(ns_storage_socket[0], F_LOCK, 0) < 0)
return -errno;
netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
if (netns == -EAGAIN) {
ns = receive_one_fd(ns_storage_socket[0], MSG_DONTWAIT);
if (ns == -EAGAIN) {
/* Nothing stored yet, so let's create a new namespace. */
if (unshare(CLONE_NEWNET) < 0) {
if (unshare(nsflag) < 0) {
r = -errno;
goto fail;
}
(void) loopback_setup();
netns = open("/proc/self/ns/net", O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (netns < 0) {
ns_path = strjoina("/proc/self/ns/", ns_name);
ns = open(ns_path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (ns < 0) {
r = -errno;
goto fail;
}
r = 1;
} else if (netns < 0) {
r = netns;
} else if (ns < 0) {
r = ns;
goto fail;
} else {
/* Yay, found something, so let's join the namespace */
if (setns(netns, CLONE_NEWNET) < 0) {
if (setns(ns, nsflag) < 0) {
r = -errno;
goto fail;
}
@ -2560,45 +2598,45 @@ int setup_netns(const int netns_storage_socket[static 2]) {
r = 0;
}
q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT);
q = send_one_fd(ns_storage_socket[1], ns, MSG_DONTWAIT);
if (q < 0) {
r = q;
goto fail;
}
fail:
(void) lockf(netns_storage_socket[0], F_ULOCK, 0);
(void) lockf(ns_storage_socket[0], F_ULOCK, 0);
return r;
}
int open_netns_path(const int netns_storage_socket[static 2], const char *path) {
_cleanup_close_ int netns = -1;
int open_shareable_ns_path(const int ns_storage_socket[static 2], const char *path, unsigned long nsflag) {
_cleanup_close_ int ns = -1;
int q, r;
assert(netns_storage_socket);
assert(netns_storage_socket[0] >= 0);
assert(netns_storage_socket[1] >= 0);
assert(ns_storage_socket);
assert(ns_storage_socket[0] >= 0);
assert(ns_storage_socket[1] >= 0);
assert(path);
/* If the storage socket doesn't contain a netns fd yet, open one via the file system and store it in
* it. This is supposed to be called ahead of time, i.e. before setup_netns() which will allocate a
* new anonymous netns if needed. */
/* If the storage socket doesn't contain a ns fd yet, open one via the file system and store it in
* it. This is supposed to be called ahead of time, i.e. before setup_shareable_ns() which will
* allocate a new anonymous ns if needed. */
if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
if (lockf(ns_storage_socket[0], F_LOCK, 0) < 0)
return -errno;
netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
if (netns == -EAGAIN) {
ns = receive_one_fd(ns_storage_socket[0], MSG_DONTWAIT);
if (ns == -EAGAIN) {
/* Nothing stored yet. Open the file from the file system. */
netns = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
if (netns < 0) {
ns = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
if (ns < 0) {
r = -errno;
goto fail;
}
r = fd_is_network_ns(netns);
if (r == 0) { /* Not a netns? Refuse early. */
r = fd_is_ns(ns, nsflag);
if (r == 0) { /* Not a ns of our type? Refuse early. */
r = -EINVAL;
goto fail;
}
@ -2607,20 +2645,20 @@ int open_netns_path(const int netns_storage_socket[static 2], const char *path)
r = 1;
} else if (netns < 0) {
r = netns;
} else if (ns < 0) {
r = ns;
goto fail;
} else
r = 0; /* Already allocated */
q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT);
q = send_one_fd(ns_storage_socket[1], ns, MSG_DONTWAIT);
if (q < 0) {
r = q;
goto fail;
}
fail:
(void) lockf(netns_storage_socket[0], F_ULOCK, 0);
(void) lockf(ns_storage_socket[0], F_ULOCK, 0);
return r;
}

View File

@ -73,6 +73,7 @@ struct NamespaceInfo {
bool protect_kernel_logs;
bool mount_apivfs;
bool protect_hostname;
bool private_ipc;
ProtectHome protect_home;
ProtectSystem protect_system;
ProtectProc protect_proc;
@ -160,8 +161,8 @@ int setup_tmp_dirs(
char **tmp_dir,
char **var_tmp_dir);
int setup_netns(const int netns_storage_socket[static 2]);
int open_netns_path(const int netns_storage_socket[static 2], const char *path);
int setup_shareable_ns(const int ns_storage_socket[static 2], unsigned long nsflag);
int open_shareable_ns_path(const int netns_storage_socket[static 2], const char *path, unsigned long nsflag);
const char* protect_home_to_string(ProtectHome p) _const_;
ProtectHome protect_home_from_string(const char *s) _pure_;

View File

@ -1547,11 +1547,19 @@ static int socket_address_listen_in_cgroup(
if (s->exec_context.network_namespace_path &&
s->exec_runtime &&
s->exec_runtime->netns_storage_socket[0] >= 0) {
r = open_netns_path(s->exec_runtime->netns_storage_socket, s->exec_context.network_namespace_path);
r = open_shareable_ns_path(s->exec_runtime->netns_storage_socket, s->exec_context.network_namespace_path, CLONE_NEWNET);
if (r < 0)
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");
@ -1568,7 +1576,7 @@ static int socket_address_listen_in_cgroup(
s->exec_runtime->netns_storage_socket[0] >= 0) {
if (ns_type_supported(NAMESPACE_NET)) {
r = setup_netns(s->exec_runtime->netns_storage_socket);
r = setup_shareable_ns(s->exec_runtime->netns_storage_socket, CLONE_NEWNET);
if (r < 0) {
log_unit_error_errno(UNIT(s), r, "Failed to join network namespace: %m");
_exit(EXIT_NETWORK);

View File

@ -4563,7 +4563,7 @@ static int run_container(
if (child_netns_fd < 0)
return log_error_errno(errno, "Cannot open file %s: %m", arg_network_namespace_path);
r = fd_is_network_ns(child_netns_fd);
r = fd_is_ns(child_netns_fd, CLONE_NEWNET);
if (r == -EUCLEAN)
log_debug_errno(r, "Cannot determine if passed network namespace path '%s' really refers to a network namespace, assuming it does.", arg_network_namespace_path);
else if (r < 0)

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

@ -69,3 +69,11 @@ int namespace_flags_to_string(unsigned long flags, char **ret) {
return 0;
}
const char *namespace_single_flag_to_string(unsigned long flag) {
for (unsigned i = 0; namespace_flag_map[i].name; i++)
if (namespace_flag_map[i].flag == flag)
return namespace_flag_map[i].name;
return NULL;
}

View File

@ -20,6 +20,7 @@
int namespace_flags_from_string(const char *name, unsigned long *ret);
int namespace_flags_to_string(unsigned long flags, char **ret);
const char *namespace_single_flag_to_string(unsigned long flag);
struct namespace_flag_map {
unsigned long flag;

View File

@ -63,7 +63,7 @@ static void test_tmpdir(const char *id, const char *A, const char *B) {
}
}
static void test_netns(void) {
static void test_shareable_ns(unsigned long nsflag) {
_cleanup_close_pair_ int s[2] = { -1, -1 };
pid_t pid1, pid2, pid3;
int r, n = 0;
@ -80,7 +80,7 @@ static void test_netns(void) {
assert_se(pid1 >= 0);
if (pid1 == 0) {
r = setup_netns(s);
r = setup_shareable_ns(s, nsflag);
assert_se(r >= 0);
_exit(r);
}
@ -89,7 +89,7 @@ static void test_netns(void) {
assert_se(pid2 >= 0);
if (pid2 == 0) {
r = setup_netns(s);
r = setup_shareable_ns(s, nsflag);
assert_se(r >= 0);
exit(r);
}
@ -98,7 +98,7 @@ static void test_netns(void) {
assert_se(pid3 >= 0);
if (pid3 == 0) {
r = setup_netns(s);
r = setup_shareable_ns(s, nsflag);
assert_se(r >= 0);
exit(r);
}
@ -121,6 +121,14 @@ static void test_netns(void) {
assert_se(n == 1);
}
static void test_netns(void) {
test_shareable_ns(CLONE_NEWNET);
}
static void test_ipcns(void) {
test_shareable_ns(CLONE_NEWIPC);
}
static void test_protect_kernel_logs(void) {
int r;
pid_t pid;
@ -224,6 +232,7 @@ int main(int argc, char *argv[]) {
test_tmpdir("sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device", z, zz);
test_netns();
test_ipcns();
test_protect_kernel_logs();
return EXIT_SUCCESS;

View File

@ -2,6 +2,7 @@
#include <fcntl.h>
#include <linux/magic.h>
#include <sched.h>
#include <unistd.h>
#include "alloc-util.h"
@ -67,18 +68,22 @@ static void test_path_is_temporary_fs(void) {
assert_se(path_is_temporary_fs("/i-dont-exist") == -ENOENT);
}
static void test_fd_is_network_ns(void) {
static void test_fd_is_ns(void) {
_cleanup_close_ int fd = -1;
assert_se(fd_is_network_ns(STDIN_FILENO) == 0);
assert_se(fd_is_network_ns(STDERR_FILENO) == 0);
assert_se(fd_is_network_ns(STDOUT_FILENO) == 0);
assert_se(fd_is_ns(STDIN_FILENO, CLONE_NEWNET) == 0);
assert_se(fd_is_ns(STDERR_FILENO, CLONE_NEWNET) == 0);
assert_se(fd_is_ns(STDOUT_FILENO, CLONE_NEWNET) == 0);
assert_se((fd = open("/proc/self/ns/mnt", O_CLOEXEC|O_RDONLY)) >= 0);
assert_se(IN_SET(fd_is_network_ns(fd), 0, -EUCLEAN));
assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 0, -EUCLEAN));
fd = safe_close(fd);
assert_se((fd = open("/proc/self/ns/ipc", O_CLOEXEC|O_RDONLY)) >= 0);
assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWIPC), 1, -EUCLEAN));
fd = safe_close(fd);
assert_se((fd = open("/proc/self/ns/net", O_CLOEXEC|O_RDONLY)) >= 0);
assert_se(IN_SET(fd_is_network_ns(fd), 1, -EUCLEAN));
assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 1, -EUCLEAN));
}
static void test_device_major_minor_valid(void) {
@ -159,7 +164,7 @@ int main(int argc, char *argv[]) {
test_is_symlink();
test_path_is_fs_type();
test_path_is_temporary_fs();
test_fd_is_network_ns();
test_fd_is_ns();
test_device_major_minor_valid();
test_device_path_make_canonical();

View File

@ -111,6 +111,7 @@ IOWriteIOPSMax=
IPAccounting=
IPAddressAllow=
IPAddressDeny=
IPCNamespacePath=
IPTOS=
IPTTL=
IgnoreOnIsolate=
@ -151,6 +152,7 @@ MemorySwapMax=
MessageQueueMaxMessages=
MessageQueueMessageSize=
MountAPIVFS=
NetworkNamespacePath=
NoDelay=
NoExecPaths=
NoNewPrivileges=
@ -856,6 +858,7 @@ PivotRoot=
Port=
PowerKeyIgnoreInhibited=
Private=
PrivateIPC=
PrivateDevices=
PrivateNetwork=
PrivateTmp=