1
0
mirror of https://github.com/systemd/systemd synced 2025-10-03 10:44:44 +02:00

Compare commits

...

22 Commits

Author SHA1 Message Date
Lennart Poettering
407234203b
Merge pull request #18615 from xry111/private-ipc-1
New directives PrivateIPC and IPCNamespacePath
2021-03-04 18:04:28 +01:00
caoxia
370d3c31b4 trans_time sec is int32,it will overflow if local system time is later than 2038. 2021-03-04 18:00:29 +01:00
Lennart Poettering
9706d27cbe
Merge pull request #18840 from yuwata/libudev-monitor-tiny-cleanup
io-util: introduce ppoll_usec()
2021-03-04 17:23:17 +01:00
Lennart Poettering
1b153a82f4 install: include OS headers before our own definition
Doesn't matter much, but matches more our usual coding style where our
definition are done after all headers provided by the OS are included.
2021-03-04 16:20:46 +01:00
Zbigniew Jędrzejewski-Szmek
b4e9c97477
Merge pull request #18773 from yuwata/network-move-several-functions
network: move several functions
2021-03-04 12:25:59 +01:00
Anita Zhang
01584bf9e4 run: update dbus unique names check
Some code in systemd-run checks that a bus's unique name must start with
`:1.`. However the dbus specification on unique connection names only specifies
that it must begin with a colon. And the freedesktop/dbus implementation allows
allows unique names to go up to `:INT_MAX.INT_MAX`. So update the
current check to only look for a colon at the beginning.
2021-03-04 09:52:13 +00:00
Yu Watanabe
d9e2af0ae8 tree-wide: use ppoll_usec() 2021-03-04 05:06:48 +09:00
Yu Watanabe
c4febde9d0 io-util: introduce ppoll_usec() helper function 2021-03-04 05:06:43 +09:00
Yu Watanabe
1d61d70abb libudev: shorten code a bit
fd_wait_for_event() or ppoll() does not return -EAGAIN.
2021-03-04 05:03:44 +09:00
Xℹ Ruoyao
80271a446c
Remount /dev/mqueue in unshared mount namespace for PrivateIPC 2021-03-04 00:08:09 +08:00
Xℹ Ruoyao
a70581ffb5
New directives PrivateIPC and IPCNamespacePath 2021-03-04 00:04:36 +08:00
Xℹ Ruoyao
54c2459d56
Refactor network namespace specific functions in generic helpers 2021-03-04 00:04:36 +08:00
Xℹ Ruoyao
a959cd2812
fuzz: add NetworkNamespacePath= into directives.service 2021-03-04 00:04:35 +08:00
Yu Watanabe
66d2330265 network: do not remove LLDP state file on failure 2021-03-03 16:42:23 +09:00
Yu Watanabe
5288861bf6 network: use conservative_rename() at one more place 2021-03-03 16:34:51 +09:00
Yu Watanabe
a34e58d445 network: remove DHCP lease and LLDP state file on link_free() 2021-03-03 16:31:28 +09:00
Yu Watanabe
ab7153b3f4 dhcp: use unlink_and_freep() in dhcp_lease_save() 2021-03-03 16:26:32 +09:00
Yu Watanabe
3be9d62ad1 network: move manager_{rtnl,udev}_process_link() to networkd-link.[ch] 2021-03-03 16:12:33 +09:00
Yu Watanabe
24e3ed843f network: drop unnecessary {} 2021-03-03 16:12:33 +09:00
Yu Watanabe
44e1f7e3dc network: minor style fixes 2021-03-03 16:12:33 +09:00
Yu Watanabe
d23a66f274 network: use unlink_and_freep() cleanup functions
This also makes state files not removed on failure.
2021-03-03 16:11:45 +09:00
Yu Watanabe
3b5a4fc685 network: move state file related functions to networkd-state-file.[ch] 2021-03-03 16:07:45 +09:00
43 changed files with 1373 additions and 1114 deletions

View File

@ -2693,6 +2693,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b PrivateMounts = ...; readonly b PrivateMounts = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b PrivateIPC = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s ProtectHome = '...'; readonly s ProtectHome = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s ProtectSystem = '...'; readonly s ProtectSystem = '...';
@ -2777,6 +2779,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s NetworkNamespacePath = '...'; readonly s NetworkNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s IPCNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s KillMode = '...'; readonly s KillMode = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly i KillSignal = ...; readonly i KillSignal = ...;
@ -3194,6 +3198,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
<!--property PrivateMounts is not documented!--> <!--property PrivateMounts is not documented!-->
<!--property PrivateIPC is not documented!-->
<!--property ProtectHome is not documented!--> <!--property ProtectHome is not documented!-->
<!--property ProtectSystem 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 NetworkNamespacePath is not documented!-->
<!--property IPCNamespacePath is not documented!-->
<!--property KillMode is not documented!--> <!--property KillMode is not documented!-->
<!--property KillSignal 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="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="ProtectHome"/>
<variablelist class="dbus-property" generated="True" extra-ref="ProtectSystem"/> <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="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="KillMode"/>
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/> <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") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b PrivateMounts = ...; readonly b PrivateMounts = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b PrivateIPC = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s ProtectHome = '...'; readonly s ProtectHome = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s ProtectSystem = '...'; readonly s ProtectSystem = '...';
@ -4538,6 +4552,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s NetworkNamespacePath = '...'; readonly s NetworkNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s IPCNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s KillMode = '...'; readonly s KillMode = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly i KillSignal = ...; readonly i KillSignal = ...;
@ -4983,6 +4999,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
<!--property PrivateMounts is not documented!--> <!--property PrivateMounts is not documented!-->
<!--property PrivateIPC is not documented!-->
<!--property ProtectHome is not documented!--> <!--property ProtectHome is not documented!-->
<!--property ProtectSystem 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 NetworkNamespacePath is not documented!-->
<!--property IPCNamespacePath is not documented!-->
<!--property KillMode is not documented!--> <!--property KillMode is not documented!-->
<!--property KillSignal 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="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="ProtectHome"/>
<variablelist class="dbus-property" generated="True" extra-ref="ProtectSystem"/> <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="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="KillMode"/>
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/> <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") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b PrivateMounts = ...; readonly b PrivateMounts = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b PrivateIPC = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s ProtectHome = '...'; readonly s ProtectHome = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s ProtectSystem = '...'; readonly s ProtectSystem = '...';
@ -6227,6 +6253,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s NetworkNamespacePath = '...'; readonly s NetworkNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s IPCNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s KillMode = '...'; readonly s KillMode = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly i KillSignal = ...; readonly i KillSignal = ...;
@ -6600,6 +6628,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
<!--property PrivateMounts is not documented!--> <!--property PrivateMounts is not documented!-->
<!--property PrivateIPC is not documented!-->
<!--property ProtectHome is not documented!--> <!--property ProtectHome is not documented!-->
<!--property ProtectSystem 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 NetworkNamespacePath is not documented!-->
<!--property IPCNamespacePath is not documented!-->
<!--property KillMode is not documented!--> <!--property KillMode is not documented!-->
<!--property KillSignal 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="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="ProtectHome"/>
<variablelist class="dbus-property" generated="True" extra-ref="ProtectSystem"/> <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="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="KillMode"/>
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/> <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") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b PrivateMounts = ...; readonly b PrivateMounts = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b PrivateIPC = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s ProtectHome = '...'; readonly s ProtectHome = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s ProtectSystem = '...'; readonly s ProtectSystem = '...';
@ -7883,6 +7921,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s NetworkNamespacePath = '...'; readonly s NetworkNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s IPCNamespacePath = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly s KillMode = '...'; readonly s KillMode = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const") @org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly i KillSignal = ...; readonly i KillSignal = ...;
@ -8242,6 +8282,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
<!--property PrivateMounts is not documented!--> <!--property PrivateMounts is not documented!-->
<!--property PrivateIPC is not documented!-->
<!--property ProtectHome is not documented!--> <!--property ProtectHome is not documented!-->
<!--property ProtectSystem 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 NetworkNamespacePath is not documented!-->
<!--property IPCNamespacePath is not documented!-->
<!--property KillMode is not documented!--> <!--property KillMode is not documented!-->
<!--property KillSignal 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="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="ProtectHome"/>
<variablelist class="dbus-property" generated="True" extra-ref="ProtectSystem"/> <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="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="KillMode"/>
<variablelist class="dbus-property" generated="True" extra-ref="KillSignal"/> <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> <xi:include href="system-only.xml" xpointer="singular"/></listitem>
</varlistentry> </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> <varlistentry>
<term><varname>PrivateUsers=</varname></term> <term><varname>PrivateUsers=</varname></term>
@ -3585,7 +3632,7 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
<row> <row>
<entry>226</entry> <entry>226</entry>
<entry><constant>EXIT_NAMESPACE</constant></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>
<row> <row>
<entry>227</entry> <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 <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 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 <varname>PrivateTmp=</varname> directives (see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for <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 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 <filename>/tmp/</filename>, <filename>/var/tmp/</filename>, IPC namespace and network namespace as
that is started. If multiple listed units are already started, it is not defined which namespace is one listed unit that is started. If multiple listed units are already started, it is not defined
joined. Note that this setting only has an effect if which namespace is joined. Note that this setting only has an effect if
<varname>PrivateNetwork=</varname>/<varname>NetworkNamespacePath=</varname> and/or <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 <varname>PrivateTmp=</varname> is enabled for both the unit that joins the namespace and the unit
whose namespace is joined.</para></listitem> whose namespace is joined.</para></listitem>
</varlistentry> </varlistentry>

View File

@ -2,7 +2,6 @@
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <poll.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
@ -159,24 +158,42 @@ int pipe_eof(int fd) {
return !!(r & POLLHUP); return !!(r & POLLHUP);
} }
int fd_wait_for_event(int fd, int event, usec_t t) { int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout) {
struct pollfd pollfd = {
.fd = fd,
.events = event,
};
struct timespec ts; struct timespec ts;
int r; int r;
r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); assert(fds || nfds == 0);
if (nfds == 0)
return 0;
r = ppoll(fds, nfds, timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL);
if (r < 0) if (r < 0)
return -errno; return -errno;
if (r == 0) if (r == 0)
return 0; return 0;
if (pollfd.revents & POLLNVAL) for (size_t i = 0, n = r; i < nfds && n > 0; i++) {
return -EBADF; if (fds[i].revents == 0)
continue;
if (fds[i].revents & POLLNVAL)
return -EBADF;
n--;
}
return r;
}
int fd_wait_for_event(int fd, int event, usec_t timeout) {
struct pollfd pollfd = {
.fd = fd,
.events = event,
};
int r;
r = ppoll_usec(&pollfd, 1, timeout);
if (r <= 0)
return r;
return pollfd.revents; return pollfd.revents;
} }

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include <poll.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@ -18,6 +19,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
int pipe_eof(int fd); int pipe_eof(int fd);
int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout);
int fd_wait_for_event(int fd, int event, usec_t timeout); int fd_wait_for_event(int fd, int event, usec_t timeout);
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length); ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);

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(); return reset_uid_gid();
} }
int fd_is_network_ns(int fd) { int fd_is_ns(int fd, unsigned long nsflag) {
struct statfs s; struct statfs s;
int r; int r;
/* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice /* Checks whether the specified file descriptor refers to a namespace created by specifying nsflag in clone().
* way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle * On old kernels there's no nice way to detect that, hence on those we'll return a recognizable error (EUCLEAN),
* this somewhat nicely. * 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 * 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. */ * 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 -errno;
} }
return r == CLONE_NEWNET; return (unsigned long) r == nsflag;
} }
int detach_mount_namespace(void) { 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_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 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); 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("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("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("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("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("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), 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("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("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("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: */ /* Obsolete/redundant properties: */
SD_BUS_PROPERTY("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), 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")) if (streq(name, "PrivateNetwork"))
return bus_set_transient_bool(u, name, &c->private_network, message, flags, error); 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")) if (streq(name, "PrivateUsers"))
return bus_set_transient_bool(u, name, &c->private_users, message, flags, error); 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")) if (streq(name, "NetworkNamespacePath"))
return bus_set_transient_path(u, name, &c->network_namespace_path, message, flags, error); 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")) { if (streq(name, "SupplementaryGroups")) {
_cleanup_strv_free_ char **l = NULL; _cleanup_strv_free_ char **l = NULL;
char **p; char **p;

View File

@ -2037,7 +2037,9 @@ bool exec_needs_mount_namespace(
context->protect_kernel_logs || context->protect_kernel_logs ||
context->protect_control_groups || context->protect_control_groups ||
context->protect_proc != PROTECT_PROC_DEFAULT || 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; return true;
if (context->root_directory) { if (context->root_directory) {
@ -3178,6 +3180,7 @@ static int apply_mount_namespace(
.protect_system = context->protect_system, .protect_system = context->protect_system,
.protect_proc = context->protect_proc, .protect_proc = context->protect_proc,
.proc_subset = context->proc_subset, .proc_subset = context->proc_subset,
.private_ipc = context->private_ipc || context->ipc_namespace_path,
}; };
} else if (!context->dynamic_user && root_dir) } else if (!context->dynamic_user && root_dir)
/* /*
@ -3476,8 +3479,10 @@ static int close_remaining_fds(
n_dont_close += n_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->netns_storage_socket);
append_socket_pair(dont_close, &n_dont_close, runtime->ipcns_storage_socket);
}
if (dcreds) { if (dcreds) {
if (dcreds->user) if (dcreds->user)
@ -3918,13 +3923,21 @@ static int exec_child(
} }
if (context->network_namespace_path && runtime && runtime->netns_storage_socket[0] >= 0) { 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) { if (r < 0) {
*exit_status = EXIT_NETWORK; *exit_status = EXIT_NETWORK;
return log_unit_error_errno(unit, r, "Failed to open network namespace path %s: %m", context->network_namespace_path); 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); r = setup_input(context, params, socket_fd, named_iofds);
if (r < 0) { if (r < 0) {
*exit_status = EXIT_STDIN; *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 ((context->private_network || context->network_namespace_path) && runtime && runtime->netns_storage_socket[0] >= 0) {
if (ns_type_supported(NAMESPACE_NET)) { 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) if (r == -EPERM)
log_unit_warning_errno(unit, r, log_unit_warning_errno(unit, r,
"PrivateNetwork=yes is configured, but network namespace setup failed, ignoring: %m"); "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."); 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); needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
if (needs_mount_namespace) { if (needs_mount_namespace) {
_cleanup_free_ char *error_path = NULL; _cleanup_free_ char *error_path = NULL;
@ -4314,7 +4346,7 @@ static int exec_child(
#endif #endif
/* We repeat the fd closing here, to make sure that nothing is leaked from the PAM modules. Note that we are /* 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(). */ * 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); 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->tmp_dir = mfree(rt->tmp_dir);
rt->var_tmp_dir = mfree(rt->var_tmp_dir); rt->var_tmp_dir = mfree(rt->var_tmp_dir);
safe_close_pair(rt->netns_storage_socket); safe_close_pair(rt->netns_storage_socket);
safe_close_pair(rt->ipcns_storage_socket);
return mfree(rt); return mfree(rt);
} }
@ -6081,6 +6114,7 @@ static int exec_runtime_allocate(ExecRuntime **ret, const char *id) {
*n = (ExecRuntime) { *n = (ExecRuntime) {
.id = TAKE_PTR(id_copy), .id = TAKE_PTR(id_copy),
.netns_storage_socket = { -1, -1 }, .netns_storage_socket = { -1, -1 },
.ipcns_storage_socket = { -1, -1 },
}; };
*ret = n; *ret = n;
@ -6093,6 +6127,7 @@ static int exec_runtime_add(
char **tmp_dir, char **tmp_dir,
char **var_tmp_dir, char **var_tmp_dir,
int netns_storage_socket[2], int netns_storage_socket[2],
int ipcns_storage_socket[2],
ExecRuntime **ret) { ExecRuntime **ret) {
_cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL; _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL;
@ -6101,7 +6136,7 @@ static int exec_runtime_add(
assert(m); assert(m);
assert(id); 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); r = exec_runtime_allocate(&rt, id);
if (r < 0) if (r < 0)
@ -6120,6 +6155,11 @@ static int exec_runtime_add(
rt->netns_storage_socket[1] = TAKE_FD(netns_storage_socket[1]); 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; rt->manager = m;
if (ret) if (ret)
@ -6136,7 +6176,7 @@ static int exec_runtime_make(
ExecRuntime **ret) { ExecRuntime **ret) {
_cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL; _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; int r;
assert(m); assert(m);
@ -6144,7 +6184,7 @@ static int exec_runtime_make(
assert(id); assert(id);
/* It is not necessary to create ExecRuntime object. */ /* 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; *ret = NULL;
return 0; return 0;
} }
@ -6163,7 +6203,12 @@ static int exec_runtime_make(
return -errno; 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) if (r < 0)
return r; return r;
@ -6254,6 +6299,26 @@ int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) {
fprintf(f, " netns-socket-1=%i", copy); 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); 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]); safe_close(rt->netns_storage_socket[1]);
rt->netns_storage_socket[1] = fdset_remove(fds, fd); 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 } else
return 0; 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) { int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
_cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL; _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
char *id = NULL; char *id = NULL;
int r, fdpair[] = {-1, -1}; int r, netns_fdpair[] = {-1, -1}, ipcns_fdpair[] = {-1, -1};
const char *p, *v = value; const char *p, *v = value;
size_t n; size_t n;
@ -6401,13 +6488,13 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
n = strcspn(v, " "); n = strcspn(v, " ");
buf = strndupa(v, n); buf = strndupa(v, n);
r = safe_atoi(buf, &fdpair[0]); r = safe_atoi(buf, &netns_fdpair[0]);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-0=%s: %m", buf); 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), return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
"exec-runtime specification netns-socket-0= refers to unknown fd %d: %m", fdpair[0]); "exec-runtime specification netns-socket-0= refers to unknown fd %d: %m", netns_fdpair[0]);
fdpair[0] = fdset_remove(fds, fdpair[0]); netns_fdpair[0] = fdset_remove(fds, netns_fdpair[0]);
if (v[n] != ' ') if (v[n] != ' ')
goto finalize; goto finalize;
p = v + n + 1; p = v + n + 1;
@ -6419,17 +6506,56 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) {
n = strcspn(v, " "); n = strcspn(v, " ");
buf = strndupa(v, n); buf = strndupa(v, n);
r = safe_atoi(buf, &fdpair[1]);
r = safe_atoi(buf, &netns_fdpair[1]);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-1=%s: %m", buf); 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), return log_debug_errno(SYNTHETIC_ERRNO(EBADF),
"exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", fdpair[1]); "exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", netns_fdpair[1]);
fdpair[1] = fdset_remove(fds, 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: 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) if (r < 0)
return log_debug_errno(r, "Failed to add exec-runtime: %m"); return log_debug_errno(r, "Failed to add exec-runtime: %m");
return 0; 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 /* An AF_UNIX socket pair, that contains a datagram containing a file descriptor referring to the network
* namespace. */ * namespace. */
int netns_storage_socket[2]; 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 { typedef enum ExecDirectoryType {
@ -280,6 +283,7 @@ struct ExecContext {
bool private_devices; bool private_devices;
bool private_users; bool private_users;
bool private_mounts; bool private_mounts;
bool private_ipc;
bool protect_kernel_tunables; bool protect_kernel_tunables;
bool protect_kernel_modules; bool protect_kernel_modules;
bool protect_kernel_logs; bool protect_kernel_logs;
@ -314,6 +318,7 @@ struct ExecContext {
Set *address_families; Set *address_families;
char *network_namespace_path; char *network_namespace_path;
char *ipc_namespace_path;
ExecDirectory directories[_EXEC_DIRECTORY_TYPE_MAX]; ExecDirectory directories[_EXEC_DIRECTORY_TYPE_MAX];
ExecPreserveMode runtime_directory_preserve_mode; 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.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.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.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.LogNamespace, config_parse_log_namespace, 0, offsetof($1, exec_context)
$1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network) $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.PrivateUsers, config_parse_bool, 0, offsetof($1, exec_context.private_users)
$1.PrivateMounts, config_parse_bool, 0, offsetof($1, exec_context.private_mounts) $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.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.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) $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 "mountpoint-util.h"
#include "namespace-util.h" #include "namespace-util.h"
#include "namespace.h" #include "namespace.h"
#include "nsflags.h"
#include "nulstr-util.h" #include "nulstr-util.h"
#include "os-util.h" #include "os-util.h"
#include "path-util.h" #include "path-util.h"
@ -63,6 +64,7 @@ typedef enum MountMode {
EXEC, EXEC,
TMPFS, TMPFS,
EXTENSION_IMAGES, /* Mounted outside the root directory, and used by subsequent mounts */ EXTENSION_IMAGES, /* Mounted outside the root directory, and used by subsequent mounts */
MQUEUEFS,
READWRITE_IMPLICIT, /* Should have the lowest priority. */ READWRITE_IMPLICIT, /* Should have the lowest priority. */
_MOUNT_MODE_MAX, _MOUNT_MODE_MAX,
} MountMode; } MountMode;
@ -227,6 +229,7 @@ static const char * const mount_mode_table[_MOUNT_MODE_MAX] = {
[READWRITE_IMPLICIT] = "rw-implicit", [READWRITE_IMPLICIT] = "rw-implicit",
[EXEC] = "exec", [EXEC] = "exec",
[NOEXEC] = "noexec", [NOEXEC] = "noexec",
[MQUEUEFS] = "mqueuefs",
}; };
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(mount_mode, MountMode); 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); 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) { 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, _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: case RUN:
return mount_run(m); return mount_run(m);
case MQUEUEFS:
return mount_mqueuefs(m);
case MOUNT_IMAGES: case MOUNT_IMAGES:
return mount_image(m, NULL); return mount_image(m, NULL);
@ -1515,7 +1539,8 @@ static size_t namespace_calculate_mounts(
(creds_path ? 2 : 1) + (creds_path ? 2 : 1) +
!!log_namespace + !!log_namespace +
setup_propagate + /* /run/systemd/incoming */ 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) { 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 (creds_path) {
/* If our service has a credentials store configured, then bind that one in, but hide /* If our service has a credentials store configured, then bind that one in, but hide
* everything else. */ * everything else. */
@ -2508,13 +2541,17 @@ int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) {
return 0; return 0;
} }
int setup_netns(const int netns_storage_socket[static 2]) { int setup_shareable_ns(const int ns_storage_socket[static 2], unsigned long nsflag) {
_cleanup_close_ int netns = -1; _cleanup_close_ int ns = -1;
int r, q; int r, q;
const char *ns_name, *ns_path;
assert(netns_storage_socket); assert(ns_storage_socket);
assert(netns_storage_socket[0] >= 0); assert(ns_storage_socket[0] >= 0);
assert(netns_storage_socket[1] >= 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 /* We use the passed socketpair as a storage buffer for our
* namespace reference fd. Whatever process runs this first * 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! */ * 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; return -errno;
netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT); ns = receive_one_fd(ns_storage_socket[0], MSG_DONTWAIT);
if (netns == -EAGAIN) { if (ns == -EAGAIN) {
/* Nothing stored yet, so let's create a new namespace. */ /* Nothing stored yet, so let's create a new namespace. */
if (unshare(CLONE_NEWNET) < 0) { if (unshare(nsflag) < 0) {
r = -errno; r = -errno;
goto fail; goto fail;
} }
(void) loopback_setup(); (void) loopback_setup();
netns = open("/proc/self/ns/net", O_RDONLY|O_CLOEXEC|O_NOCTTY); ns_path = strjoina("/proc/self/ns/", ns_name);
if (netns < 0) { ns = open(ns_path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (ns < 0) {
r = -errno; r = -errno;
goto fail; goto fail;
} }
r = 1; r = 1;
} else if (netns < 0) { } else if (ns < 0) {
r = netns; r = ns;
goto fail; goto fail;
} else { } else {
/* Yay, found something, so let's join the namespace */ /* Yay, found something, so let's join the namespace */
if (setns(netns, CLONE_NEWNET) < 0) { if (setns(ns, nsflag) < 0) {
r = -errno; r = -errno;
goto fail; goto fail;
} }
@ -2560,45 +2598,45 @@ int setup_netns(const int netns_storage_socket[static 2]) {
r = 0; 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) { if (q < 0) {
r = q; r = q;
goto fail; goto fail;
} }
fail: fail:
(void) lockf(netns_storage_socket[0], F_ULOCK, 0); (void) lockf(ns_storage_socket[0], F_ULOCK, 0);
return r; return r;
} }
int open_netns_path(const int netns_storage_socket[static 2], const char *path) { int open_shareable_ns_path(const int ns_storage_socket[static 2], const char *path, unsigned long nsflag) {
_cleanup_close_ int netns = -1; _cleanup_close_ int ns = -1;
int q, r; int q, r;
assert(netns_storage_socket); assert(ns_storage_socket);
assert(netns_storage_socket[0] >= 0); assert(ns_storage_socket[0] >= 0);
assert(netns_storage_socket[1] >= 0); assert(ns_storage_socket[1] >= 0);
assert(path); assert(path);
/* If the storage socket doesn't contain a netns fd yet, open one via the file system and store it in /* 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_netns() which will allocate a * it. This is supposed to be called ahead of time, i.e. before setup_shareable_ns() which will
* new anonymous netns if needed. */ * 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; return -errno;
netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT); ns = receive_one_fd(ns_storage_socket[0], MSG_DONTWAIT);
if (netns == -EAGAIN) { if (ns == -EAGAIN) {
/* Nothing stored yet. Open the file from the file system. */ /* Nothing stored yet. Open the file from the file system. */
netns = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC); ns = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
if (netns < 0) { if (ns < 0) {
r = -errno; r = -errno;
goto fail; goto fail;
} }
r = fd_is_network_ns(netns); r = fd_is_ns(ns, nsflag);
if (r == 0) { /* Not a netns? Refuse early. */ if (r == 0) { /* Not a ns of our type? Refuse early. */
r = -EINVAL; r = -EINVAL;
goto fail; goto fail;
} }
@ -2607,20 +2645,20 @@ int open_netns_path(const int netns_storage_socket[static 2], const char *path)
r = 1; r = 1;
} else if (netns < 0) { } else if (ns < 0) {
r = netns; r = ns;
goto fail; goto fail;
} else } else
r = 0; /* Already allocated */ 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) { if (q < 0) {
r = q; r = q;
goto fail; goto fail;
} }
fail: fail:
(void) lockf(netns_storage_socket[0], F_ULOCK, 0); (void) lockf(ns_storage_socket[0], F_ULOCK, 0);
return r; return r;
} }

View File

@ -73,6 +73,7 @@ struct NamespaceInfo {
bool protect_kernel_logs; bool protect_kernel_logs;
bool mount_apivfs; bool mount_apivfs;
bool protect_hostname; bool protect_hostname;
bool private_ipc;
ProtectHome protect_home; ProtectHome protect_home;
ProtectSystem protect_system; ProtectSystem protect_system;
ProtectProc protect_proc; ProtectProc protect_proc;
@ -160,8 +161,8 @@ int setup_tmp_dirs(
char **tmp_dir, char **tmp_dir,
char **var_tmp_dir); char **var_tmp_dir);
int setup_netns(const int netns_storage_socket[static 2]); int setup_shareable_ns(const int ns_storage_socket[static 2], unsigned long nsflag);
int open_netns_path(const int netns_storage_socket[static 2], const char *path); 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_; const char* protect_home_to_string(ProtectHome p) _const_;
ProtectHome protect_home_from_string(const char *s) _pure_; 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 && if (s->exec_context.network_namespace_path &&
s->exec_runtime && s->exec_runtime &&
s->exec_runtime->netns_storage_socket[0] >= 0) { 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) 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); 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) 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"); 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) { s->exec_runtime->netns_storage_socket[0] >= 0) {
if (ns_type_supported(NAMESPACE_NET)) { 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) { if (r < 0) {
log_unit_error_errno(UNIT(s), r, "Failed to join network namespace: %m"); log_unit_error_errno(UNIT(s), r, "Failed to join network namespace: %m");
_exit(EXIT_NETWORK); _exit(EXIT_NETWORK);

View File

@ -5,7 +5,6 @@
#include <fnmatch.h> #include <fnmatch.h>
#include <getopt.h> #include <getopt.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <poll.h>
#include <signal.h> #include <signal.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
@ -2095,8 +2094,6 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
{ .fd = poll_fd, .events = POLLIN }, { .fd = poll_fd, .events = POLLIN },
{ .fd = STDOUT_FILENO }, { .fd = STDOUT_FILENO },
}; };
struct timespec ts;
usec_t timeout; usec_t timeout;
int r; int r;
@ -2110,21 +2107,16 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to determine journal waiting time: %m"); return log_error_errno(r, "Failed to determine journal waiting time: %m");
if (ppoll(pollfds, ELEMENTSOF(pollfds), r = ppoll_usec(pollfds, ELEMENTSOF(pollfds), timeout);
timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL) < 0) { if (r == -EINTR)
if (errno == EINTR) return 0;
return 0; if (r < 0)
return log_error_errno(r, "Couldn't wait for journal event: %m");
return log_error_errno(errno, "Couldn't wait for journal event: %m"); if (pollfds[1].revents & (POLLHUP|POLLERR)) /* STDOUT has been closed? */
}
if (pollfds[1].revents & (POLLHUP|POLLERR|POLLNVAL)) /* STDOUT has been closed? */
return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED), return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED),
"Standard output has been closed."); "Standard output has been closed.");
if (pollfds[0].revents & POLLNVAL)
return log_debug_errno(SYNTHETIC_ERRNO(EBADF), "Change fd closed?");
r = sd_journal_process(j); r = sd_journal_process(j);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to process journal events: %m"); return log_error_errno(r, "Failed to process journal events: %m");

View File

@ -869,7 +869,7 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
} }
int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
_cleanup_free_ char *temp_path = NULL; _cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
struct sd_dhcp_raw_option *option; struct sd_dhcp_raw_option *option;
struct in_addr address; struct in_addr address;
@ -889,7 +889,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
r = fopen_temporary(lease_file, &f, &temp_path); r = fopen_temporary(lease_file, &f, &temp_path);
if (r < 0) if (r < 0)
goto fail; return r;
(void) fchmod(fileno(f), 0644); (void) fchmod(fileno(f), 0644);
@ -992,10 +992,8 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
_cleanup_free_ char *client_id_hex = NULL; _cleanup_free_ char *client_id_hex = NULL;
client_id_hex = hexmem(client_id, client_id_len); client_id_hex = hexmem(client_id, client_id_len);
if (!client_id_hex) { if (!client_id_hex)
r = -ENOMEM; return -ENOMEM;
goto fail;
}
fprintf(f, "CLIENTID=%s\n", client_id_hex); fprintf(f, "CLIENTID=%s\n", client_id_hex);
} }
@ -1004,10 +1002,8 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
_cleanup_free_ char *option_hex = NULL; _cleanup_free_ char *option_hex = NULL;
option_hex = hexmem(data, data_len); option_hex = hexmem(data, data_len);
if (!option_hex) { if (!option_hex)
r = -ENOMEM; return -ENOMEM;
goto fail;
}
fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex); fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex);
} }
@ -1017,28 +1013,23 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
xsprintf(key, "OPTION_%" PRIu8, option->tag); xsprintf(key, "OPTION_%" PRIu8, option->tag);
r = serialize_dhcp_option(f, key, option->data, option->length); r = serialize_dhcp_option(f, key, option->data, option->length);
if (r < 0) if (r < 0)
goto fail; return r;
} }
r = fflush_and_check(f); r = fflush_and_check(f);
if (r < 0) if (r < 0)
goto fail; return r;
r = conservative_rename(temp_path, lease_file); r = conservative_rename(temp_path, lease_file);
if (r < 0) if (r < 0)
goto fail; return r;
temp_path = mfree(temp_path);
return 0; return 0;
fail:
if (temp_path)
(void) unlink(temp_path);
return log_error_errno(r, "Failed to save lease data %s: %m", lease_file);
} }
int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
_cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL;
_cleanup_free_ char _cleanup_free_ char
*address = NULL, *address = NULL,

View File

@ -2,7 +2,6 @@
#include <endian.h> #include <endian.h>
#include <netdb.h> #include <netdb.h>
#include <poll.h>
#include <pthread.h> #include <pthread.h>
#include <signal.h> #include <signal.h>
#include <stdlib.h> #include <stdlib.h>
@ -32,6 +31,7 @@
#include "fd-util.h" #include "fd-util.h"
#include "hexdecoct.h" #include "hexdecoct.h"
#include "hostname-util.h" #include "hostname-util.h"
#include "io-util.h"
#include "macro.h" #include "macro.h"
#include "memory-util.h" #include "memory-util.h"
#include "missing_syscall.h" #include "missing_syscall.h"
@ -3255,9 +3255,8 @@ _public_ int sd_bus_process_priority(sd_bus *bus, int64_t priority, sd_bus_messa
static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
struct pollfd p[2] = {}; struct pollfd p[2] = {};
int r, n;
struct timespec ts;
usec_t m = USEC_INFINITY; usec_t m = USEC_INFINITY;
int r, n;
assert(bus); assert(bus);
@ -3312,16 +3311,9 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) {
if (timeout_usec != (uint64_t) -1 && (m == USEC_INFINITY || timeout_usec < m)) if (timeout_usec != (uint64_t) -1 && (m == USEC_INFINITY || timeout_usec < m))
m = timeout_usec; m = timeout_usec;
r = ppoll(p, n, m == USEC_INFINITY ? NULL : timespec_store(&ts, m), NULL); r = ppoll_usec(p, n, m);
if (r < 0) if (r <= 0)
return -errno; return r;
if (r == 0)
return 0;
if (p[0].revents & POLLNVAL)
return -EBADF;
if (n >= 2 && (p[1].revents & POLLNVAL))
return -EBADF;
return 1; return 1;
} }

View File

@ -206,12 +206,10 @@ static int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_
for (;;) { for (;;) {
/* Wait for next message */ /* Wait for next message */
r = fd_wait_for_event(device_monitor_get_fd(udev_monitor->monitor), POLLIN, 0); r = fd_wait_for_event(device_monitor_get_fd(udev_monitor->monitor), POLLIN, 0);
if (r < 0) { if (r == -EINTR)
if (IN_SET(r, -EINTR, -EAGAIN)) continue;
continue; if (r < 0)
return r; return r;
}
if (r == 0) if (r == 0)
return -EAGAIN; return -EAGAIN;

View File

@ -113,6 +113,8 @@ sources = files('''
networkd-speed-meter.h networkd-speed-meter.h
networkd-sriov.c networkd-sriov.c
networkd-sriov.h networkd-sriov.h
networkd-state-file.c
networkd-state-file.h
networkd-sysctl.c networkd-sysctl.c
networkd-sysctl.h networkd-sysctl.h
networkd-util.c networkd-util.c

View File

@ -17,6 +17,7 @@
#include "networkd-link.h" #include "networkd-link.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-network.h" #include "networkd-network.h"
#include "networkd-state-file.h"
#include "string-table.h" #include "string-table.h"
#include "strv.h" #include "strv.h"
#include "sysctl-util.h" #include "sysctl-util.h"

View File

@ -13,6 +13,7 @@
#include "networkd-link-bus.h" #include "networkd-link-bus.h"
#include "networkd-link.h" #include "networkd-link.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-state-file.h"
#include "parse-util.h" #include "parse-util.h"
#include "resolve-util.h" #include "resolve-util.h"
#include "socket-netlink.h" #include "socket-netlink.h"

View File

@ -11,6 +11,8 @@
#include "bond.h" #include "bond.h"
#include "bridge.h" #include "bridge.h"
#include "bus-util.h" #include "bus-util.h"
#include "device-private.h"
#include "device-util.h"
#include "dhcp-identifier.h" #include "dhcp-identifier.h"
#include "dhcp-lease-internal.h" #include "dhcp-lease-internal.h"
#include "env-file.h" #include "env-file.h"
@ -42,6 +44,7 @@
#include "networkd-sysctl.h" #include "networkd-sysctl.h"
#include "networkd-radv.h" #include "networkd-radv.h"
#include "networkd-routing-policy-rule.h" #include "networkd-routing-policy-rule.h"
#include "networkd-state-file.h"
#include "networkd-wifi.h" #include "networkd-wifi.h"
#include "set.h" #include "set.h"
#include "socket-util.h" #include "socket-util.h"
@ -543,8 +546,6 @@ static Link *link_free(Link *link) {
link->ndisc_addresses = set_free(link->ndisc_addresses); link->ndisc_addresses = set_free(link->ndisc_addresses);
link_free_engines(link); link_free_engines(link);
free(link->lease_file);
free(link->lldp_file);
free(link->ifname); free(link->ifname);
strv_free(link->alternative_names); strv_free(link->alternative_names);
@ -552,8 +553,9 @@ static Link *link_free(Link *link) {
free(link->ssid); free(link->ssid);
free(link->driver); free(link->driver);
(void) unlink(link->state_file); unlink_and_free(link->lease_file);
free(link->state_file); unlink_and_free(link->lldp_file);
unlink_and_free(link->state_file);
sd_device_unref(link->sd_device); sd_device_unref(link->sd_device);
@ -1733,7 +1735,7 @@ static void link_detach_from_manager(Link *link) {
link_unref(link); link_unref(link);
} }
void link_drop(Link *link) { static void link_drop(Link *link) {
if (!link || link->state == LINK_STATE_LINGER) if (!link || link->state == LINK_STATE_LINGER)
return; return;
@ -2380,7 +2382,7 @@ static int link_initialized_handler(sd_netlink *rtnl, sd_netlink_message *m, Lin
return 1; return 1;
} }
int link_initialized(Link *link, sd_device *device) { static int link_initialized(Link *link, sd_device *device) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r; int r;
@ -2420,7 +2422,7 @@ int link_initialized(Link *link, sd_device *device) {
return 0; return 0;
} }
int link_add(Manager *m, sd_netlink_message *message, Link **ret) { static int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL; _cleanup_(sd_device_unrefp) sd_device *device = NULL;
char ifindex_str[2 + DECIMAL_STR_MAX(int)]; char ifindex_str[2 + DECIMAL_STR_MAX(int)];
Link *link; Link *link;
@ -2505,6 +2507,57 @@ int link_ipv6ll_gained(Link *link, const struct in6_addr *address) {
return 0; return 0;
} }
int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata) {
sd_device_action_t action;
Manager *m = userdata;
Link *link = NULL;
int r, ifindex;
assert(m);
assert(device);
r = sd_device_get_action(device, &action);
if (r < 0) {
log_device_debug_errno(device, r, "Failed to get udev action, ignoring device: %m");
return 0;
}
/* Ignore the "remove" uevent — let's remove a device only if rtnetlink says so. All other uevents
* are "positive" events in some form, i.e. inform us about a changed or new network interface, that
* still exists and we are interested in that. */
if (action == SD_DEVICE_REMOVE)
return 0;
r = sd_device_get_ifindex(device, &ifindex);
if (r < 0) {
log_device_debug_errno(device, r, "Ignoring udev %s event for device without ifindex or with invalid ifindex: %m",
device_action_to_string(action));
return 0;
}
r = device_is_renaming(device);
if (r < 0) {
log_device_error_errno(device, r, "Failed to determine the device is renamed or not, ignoring '%s' uevent: %m",
device_action_to_string(action));
return 0;
}
if (r > 0) {
log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed.");
return 0;
}
r = link_get(m, ifindex, &link);
if (r < 0) {
if (r != -ENODEV)
log_debug_errno(r, "Failed to get link from ifindex %i, ignoring: %m", ifindex);
return 0;
}
(void) link_initialized(link, device);
return 0;
}
static int link_carrier_gained(Link *link) { static int link_carrier_gained(Link *link) {
int r; int r;
@ -2618,13 +2671,14 @@ int link_carrier_reset(Link *link) {
return 0; return 0;
} }
/* This is called every time an interface admin state changes to up;
* specifically, when IFF_UP flag changes from unset to set */
static int link_admin_state_up(Link *link) { static int link_admin_state_up(Link *link) {
int r; int r;
assert(link); assert(link);
/* This is called every time an interface admin state changes to up;
* specifically, when IFF_UP flag changes from unset to set. */
if (!link->network) if (!link->network)
return 0; return 0;
@ -2648,7 +2702,6 @@ static int link_admin_state_up(Link *link) {
} }
static int link_admin_state_down(Link *link) { static int link_admin_state_down(Link *link) {
assert(link); assert(link);
if (!link->network) if (!link->network)
@ -2662,7 +2715,7 @@ static int link_admin_state_down(Link *link) {
return 0; return 0;
} }
int link_update(Link *link, sd_netlink_message *m) { static int link_update(Link *link, sd_netlink_message *m) {
_cleanup_strv_free_ char **s = NULL; _cleanup_strv_free_ char **s = NULL;
hw_addr_data hw_addr; hw_addr_data hw_addr;
const char *ifname; const char *ifname;
@ -2806,388 +2859,91 @@ int link_update(Link *link, sd_netlink_message *m) {
return 0; return 0;
} }
static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) { int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
bool space = false; Link *link = NULL;
Link *link; NetDev *netdev = NULL;
uint16_t type;
const char *name;
int r, ifindex;
assert(f); assert(rtnl);
assert(prefix); assert(message);
assert(m);
if (hashmap_isempty(h)) if (sd_netlink_message_is_error(message)) {
return; r = sd_netlink_message_get_errno(message);
if (r < 0)
log_message_warning_errno(message, r, "rtnl: Could not receive link message, ignoring");
fputs(prefix, f);
HASHMAP_FOREACH(link, h) {
if (space)
fputc(' ', f);
fprintf(f, "%i", link->ifindex);
space = true;
}
fputc('\n', f);
}
static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) {
for (unsigned j = 0; j < n_dns; j++) {
const char *str;
if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex)
continue;
str = in_addr_full_to_string(dns[j]);
if (!str)
continue;
if (*space)
fputc(' ', f);
fputs(str, f);
*space = true;
}
}
static void serialize_addresses(
FILE *f,
const char *lvalue,
bool *space,
char **addresses,
sd_dhcp_lease *lease,
bool conditional,
sd_dhcp_lease_server_type_t what,
sd_dhcp6_lease *lease6,
bool conditional6,
int (*lease6_get_addr)(sd_dhcp6_lease*, const struct in6_addr**),
int (*lease6_get_fqdn)(sd_dhcp6_lease*, char ***)) {
int r;
bool _space = false;
if (!space)
space = &_space;
if (lvalue)
fprintf(f, "%s=", lvalue);
fputstrv(f, addresses, NULL, space);
if (lease && conditional) {
const struct in_addr *lease_addresses;
r = sd_dhcp_lease_get_servers(lease, what, &lease_addresses);
if (r > 0)
serialize_in_addrs(f, lease_addresses, r, space, in4_addr_is_non_local);
}
if (lease6 && conditional6 && lease6_get_addr) {
const struct in6_addr *in6_addrs;
r = lease6_get_addr(lease6, &in6_addrs);
if (r > 0)
serialize_in6_addrs(f, in6_addrs, r, space);
}
if (lease6 && conditional6 && lease6_get_fqdn) {
char **in6_hosts;
r = lease6_get_fqdn(lease6, &in6_hosts);
if (r > 0)
fputstrv(f, in6_hosts, NULL, space);
}
if (lvalue)
fputc('\n', f);
}
int link_save(Link *link) {
const char *admin_state, *oper_state, *carrier_state, *address_state;
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(link);
assert(link->state_file);
assert(link->lease_file);
assert(link->manager);
if (link->state == LINK_STATE_LINGER) {
(void) unlink(link->state_file);
return 0; return 0;
} }
link_lldp_save(link); r = sd_netlink_message_get_type(message, &type);
if (r < 0) {
admin_state = link_state_to_string(link->state); log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m");
assert(admin_state); return 0;
} else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) {
oper_state = link_operstate_to_string(link->operstate); log_warning("rtnl: Received unexpected message type %u when processing link, ignoring.", type);
assert(oper_state); return 0;
carrier_state = link_carrier_state_to_string(link->carrier_state);
assert(carrier_state);
address_state = link_address_state_to_string(link->address_state);
assert(address_state);
r = fopen_temporary(link->state_file, &f, &temp_path);
if (r < 0)
goto fail;
(void) fchmod(fileno(f), 0644);
fprintf(f,
"# This is private data. Do not parse.\n"
"ADMIN_STATE=%s\n"
"OPER_STATE=%s\n"
"CARRIER_STATE=%s\n"
"ADDRESS_STATE=%s\n",
admin_state, oper_state, carrier_state, address_state);
if (link->network) {
char **dhcp6_domains = NULL, **dhcp_domains = NULL;
const char *dhcp_domainname = NULL, *p;
bool space;
fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
yes_no(link->network->required_for_online));
LinkOperationalStateRange st = link->network->required_operstate_for_online;
fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s%s%s\n",
strempty(link_operstate_to_string(st.min)),
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "",
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : "");
fprintf(f, "ACTIVATION_POLICY=%s\n",
activation_policy_to_string(link->network->activation_policy));
fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
/************************************************************/
fputs("DNS=", f);
space = false;
if (link->n_dns != (unsigned) -1)
link_save_dns(link, f, link->dns, link->n_dns, &space);
else
link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
serialize_addresses(f, NULL, &space,
NULL,
link->dhcp_lease,
link->network->dhcp_use_dns,
SD_DHCP_LEASE_DNS,
link->dhcp6_lease,
link->network->dhcp6_use_dns,
sd_dhcp6_lease_get_dns,
NULL);
/* Make sure to flush out old entries before we use the NDisc data */
ndisc_vacuum(link);
if (link->network->ipv6_accept_ra_use_dns && link->ndisc_rdnss) {
NDiscRDNSS *dd;
SET_FOREACH(dd, link->ndisc_rdnss)
serialize_in6_addrs(f, &dd->address, 1, &space);
}
fputc('\n', f);
/************************************************************/
serialize_addresses(f, "NTP", NULL,
link->ntp ?: link->network->ntp,
link->dhcp_lease,
link->network->dhcp_use_ntp,
SD_DHCP_LEASE_NTP,
link->dhcp6_lease,
link->network->dhcp6_use_ntp,
sd_dhcp6_lease_get_ntp_addrs,
sd_dhcp6_lease_get_ntp_fqdn);
serialize_addresses(f, "SIP", NULL,
NULL,
link->dhcp_lease,
link->network->dhcp_use_sip,
SD_DHCP_LEASE_SIP,
NULL, false, NULL, NULL);
/************************************************************/
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
if (link->dhcp_lease) {
(void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname);
(void) sd_dhcp_lease_get_search_domains(link->dhcp_lease, &dhcp_domains);
}
if (link->dhcp6_lease)
(void) sd_dhcp6_lease_get_domains(link->dhcp6_lease, &dhcp6_domains);
}
fputs("DOMAINS=", f);
space = false;
ORDERED_SET_FOREACH(p, link->search_domains ?: link->network->search_domains)
fputs_with_space(f, p, NULL, &space);
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) {
if (dhcp_domainname)
fputs_with_space(f, dhcp_domainname, NULL, &space);
if (dhcp_domains)
fputstrv(f, dhcp_domains, NULL, &space);
if (dhcp6_domains)
fputstrv(f, dhcp6_domains, NULL, &space);
}
if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_YES) {
NDiscDNSSL *dd;
SET_FOREACH(dd, link->ndisc_dnssl)
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
}
fputc('\n', f);
/************************************************************/
fputs("ROUTE_DOMAINS=", f);
space = false;
ORDERED_SET_FOREACH(p, link->route_domains ?: link->network->route_domains)
fputs_with_space(f, p, NULL, &space);
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) {
if (dhcp_domainname)
fputs_with_space(f, dhcp_domainname, NULL, &space);
if (dhcp_domains)
fputstrv(f, dhcp_domains, NULL, &space);
if (dhcp6_domains)
fputstrv(f, dhcp6_domains, NULL, &space);
}
if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_ROUTE) {
NDiscDNSSL *dd;
SET_FOREACH(dd, link->ndisc_dnssl)
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
}
fputc('\n', f);
/************************************************************/
fprintf(f, "LLMNR=%s\n",
resolve_support_to_string(link->llmnr >= 0 ? link->llmnr : link->network->llmnr));
/************************************************************/
fprintf(f, "MDNS=%s\n",
resolve_support_to_string(link->mdns >= 0 ? link->mdns : link->network->mdns));
/************************************************************/
int dns_default_route =
link->dns_default_route >= 0 ? link->dns_default_route :
link->network->dns_default_route;
if (dns_default_route >= 0)
fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(dns_default_route));
/************************************************************/
DnsOverTlsMode dns_over_tls_mode =
link->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID ? link->dns_over_tls_mode :
link->network->dns_over_tls_mode;
if (dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
fprintf(f, "DNS_OVER_TLS=%s\n", dns_over_tls_mode_to_string(dns_over_tls_mode));
/************************************************************/
DnssecMode dnssec_mode =
link->dnssec_mode != _DNSSEC_MODE_INVALID ? link->dnssec_mode :
link->network->dnssec_mode;
if (dnssec_mode != _DNSSEC_MODE_INVALID)
fprintf(f, "DNSSEC=%s\n", dnssec_mode_to_string(dnssec_mode));
/************************************************************/
Set *nta_anchors = link->dnssec_negative_trust_anchors;
if (set_isempty(nta_anchors))
nta_anchors = link->network->dnssec_negative_trust_anchors;
if (!set_isempty(nta_anchors)) {
const char *n;
fputs("DNSSEC_NTA=", f);
space = false;
SET_FOREACH(n, nta_anchors)
fputs_with_space(f, n, NULL, &space);
fputc('\n', f);
}
} }
print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links); r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links); if (r < 0) {
log_warning_errno(r, "rtnl: Could not get ifindex from link message, ignoring: %m");
return 0;
} else if (ifindex <= 0) {
log_warning("rtnl: received link message with invalid ifindex %d, ignoring.", ifindex);
return 0;
}
if (link->dhcp_lease) { r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
r = dhcp_lease_save(link->dhcp_lease, link->lease_file); if (r < 0) {
if (r < 0) log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m");
goto fail; return 0;
}
fprintf(f, (void) link_get(m, ifindex, &link);
"DHCP_LEASE=%s\n", (void) netdev_get(m, name, &netdev);
link->lease_file);
} else
(void) unlink(link->lease_file);
r = link_serialize_dhcp6_client(link, f); switch (type) {
if (r < 0) case RTM_NEWLINK:
goto fail; if (!link) {
/* link is new, so add it */
r = link_add(m, message, &link);
if (r < 0) {
log_warning_errno(r, "Could not process new link message, ignoring: %m");
return 0;
}
}
r = fflush_and_check(f); if (netdev) {
if (r < 0) /* netdev exists, so make sure the ifindex matches */
goto fail; r = netdev_set_ifindex(netdev, message);
if (r < 0) {
log_warning_errno(r, "Could not process new link message for netdev, ignoring: %m");
return 0;
}
}
r = conservative_rename(temp_path, link->state_file); r = link_update(link, message);
if (r < 0) if (r < 0) {
goto fail; log_warning_errno(r, "Could not process link message, ignoring: %m");
return 0;
}
return 0; break;
fail: case RTM_DELLINK:
(void) unlink(link->state_file); link_drop(link);
if (temp_path) netdev_drop(netdev);
(void) unlink(temp_path);
return log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file); break;
}
/* The serialized state in /run is no longer up-to-date. */ default:
void link_dirty(Link *link) { assert_not_reached("Received link message with invalid RTNL message type.");
int r; }
assert(link); return 1;
/* mark manager dirty as link is dirty */
manager_dirty(link->manager);
r = set_ensure_put(&link->manager->dirty_links, NULL, link);
if (r <= 0)
/* Ignore allocation errors and don't take another ref if the link was already dirty */
return;
link_ref(link);
}
/* The serialized state in /run is up-to-date */
void link_clean(Link *link) {
assert(link);
assert(link->manager);
link_unref(set_remove(link->manager->dirty_links, link));
}
int link_save_and_clean(Link *link) {
int r;
r = link_save(link);
if (r < 0)
return r;
link_clean(link);
return 0;
} }
static const char* const link_state_table[_LINK_STATE_MAX] = { static const char* const link_state_table[_LINK_STATE_MAX] = {

View File

@ -203,24 +203,15 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref);
DEFINE_TRIVIAL_DESTRUCTOR(link_netlink_destroy_callback, Link, link_unref); DEFINE_TRIVIAL_DESTRUCTOR(link_netlink_destroy_callback, Link, link_unref);
int link_get(Manager *m, int ifindex, Link **ret); int link_get(Manager *m, int ifindex, Link **ret);
int link_add(Manager *manager, sd_netlink_message *message, Link **ret);
void link_drop(Link *link);
int link_down(Link *link, link_netlink_message_handler_t callback); int link_down(Link *link, link_netlink_message_handler_t callback);
void link_enter_failed(Link *link); void link_enter_failed(Link *link);
int link_initialized(Link *link, sd_device *device);
void link_set_state(Link *link, LinkState state); void link_set_state(Link *link, LinkState state);
void link_check_ready(Link *link); void link_check_ready(Link *link);
void link_update_operstate(Link *link, bool also_update_bond_master); void link_update_operstate(Link *link, bool also_update_bond_master);
int link_update(Link *link, sd_netlink_message *message);
void link_dirty(Link *link);
void link_clean(Link *link);
int link_save(Link *link);
int link_save_and_clean(Link *link);
int link_carrier_reset(Link *link); int link_carrier_reset(Link *link);
bool link_has_carrier(Link *link); bool link_has_carrier(Link *link);
@ -241,6 +232,9 @@ LinkState link_state_from_string(const char *s) _pure_;
int link_configure(Link *link); int link_configure(Link *link);
int link_reconfigure(Link *link, bool force); int link_reconfigure(Link *link, bool force);
int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata);
int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m);
int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg); int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg);
#define log_link_message_error_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_ERR, err, msg) #define log_link_message_error_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_ERR, err, msg)
#define log_link_message_warning_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_WARNING, err, msg) #define log_link_message_warning_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_WARNING, err, msg)

View File

@ -6,6 +6,7 @@
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "fs-util.h"
#include "networkd-link.h" #include "networkd-link.h"
#include "networkd-lldp-rx.h" #include "networkd-lldp-rx.h"
#include "networkd-lldp-tx.h" #include "networkd-lldp-tx.h"
@ -134,7 +135,7 @@ int link_update_lldp(Link *link) {
} }
int link_lldp_save(Link *link) { int link_lldp_save(Link *link) {
_cleanup_free_ char *temp_path = NULL; _cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
sd_lldp_neighbor **l = NULL; sd_lldp_neighbor **l = NULL;
int n = 0, r, i; int n = 0, r, i;
@ -149,10 +150,10 @@ int link_lldp_save(Link *link) {
r = sd_lldp_get_neighbors(link->lldp, &l); r = sd_lldp_get_neighbors(link->lldp, &l);
if (r < 0) if (r < 0)
goto finish; return r;
if (r == 0) { if (r == 0) {
(void) unlink(link->lldp_file); (void) unlink(link->lldp_file);
goto finish; return 0;
} }
n = r; n = r;
@ -181,19 +182,13 @@ int link_lldp_save(Link *link) {
if (r < 0) if (r < 0)
goto finish; goto finish;
if (rename(temp_path, link->lldp_file) < 0) { r = conservative_rename(temp_path, link->lldp_file);
r = -errno; if (r < 0)
goto finish; goto finish;
}
finish: finish:
if (r < 0) { if (r < 0)
(void) unlink(link->lldp_file);
if (temp_path)
(void) unlink(temp_path);
log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file); log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file);
}
if (l) { if (l) {
for (i = 0; i < n; i++) for (i = 0; i < n; i++)

View File

@ -17,8 +17,6 @@
#include "bus-util.h" #include "bus-util.h"
#include "conf-parser.h" #include "conf-parser.h"
#include "def.h" #include "def.h"
#include "device-private.h"
#include "device-util.h"
#include "dns-domain.h" #include "dns-domain.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
@ -38,6 +36,7 @@
#include "networkd-nexthop.h" #include "networkd-nexthop.h"
#include "networkd-routing-policy-rule.h" #include "networkd-routing-policy-rule.h"
#include "networkd-speed-meter.h" #include "networkd-speed-meter.h"
#include "networkd-state-file.h"
#include "ordered-set.h" #include "ordered-set.h"
#include "path-lookup.h" #include "path-lookup.h"
#include "path-util.h" #include "path-util.h"
@ -48,7 +47,6 @@
#include "strv.h" #include "strv.h"
#include "sysctl-util.h" #include "sysctl-util.h"
#include "tmpfile-util.h" #include "tmpfile-util.h"
#include "udev-util.h"
/* use 128 MB for receive socket kernel queue. */ /* use 128 MB for receive socket kernel queue. */
#define RCVBUF_SIZE (128*1024*1024) #define RCVBUF_SIZE (128*1024*1024)
@ -181,57 +179,6 @@ int manager_connect_bus(Manager *m) {
return 0; return 0;
} }
static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata) {
sd_device_action_t action;
Manager *m = userdata;
Link *link = NULL;
int r, ifindex;
assert(m);
assert(device);
r = sd_device_get_action(device, &action);
if (r < 0) {
log_device_debug_errno(device, r, "Failed to get udev action, ignoring device: %m");
return 0;
}
/* Ignore the "remove" uevent — let's remove a device only if rtnetlink says so. All other uevents
* are "positive" events in some form, i.e. inform us about a changed or new network interface, that
* still exists and we are interested in that. */
if (action == SD_DEVICE_REMOVE)
return 0;
r = sd_device_get_ifindex(device, &ifindex);
if (r < 0) {
log_device_debug_errno(device, r, "Ignoring udev %s event for device without ifindex or with invalid ifindex: %m",
device_action_to_string(action));
return 0;
}
r = device_is_renaming(device);
if (r < 0) {
log_device_error_errno(device, r, "Failed to determine the device is renamed or not, ignoring '%s' uevent: %m",
device_action_to_string(action));
return 0;
}
if (r > 0) {
log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed.");
return 0;
}
r = link_get(m, ifindex, &link);
if (r < 0) {
if (r != -ENODEV)
log_debug_errno(r, "Failed to get link from ifindex %i, ignoring: %m", ifindex);
return 0;
}
(void) link_initialized(link, device);
return 0;
}
static int manager_connect_udev(Manager *m) { static int manager_connect_udev(Manager *m) {
int r; int r;
@ -263,93 +210,6 @@ static int manager_connect_udev(Manager *m) {
return 0; return 0;
} }
static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
Link *link = NULL;
NetDev *netdev = NULL;
uint16_t type;
const char *name;
int r, ifindex;
assert(rtnl);
assert(message);
assert(m);
if (sd_netlink_message_is_error(message)) {
r = sd_netlink_message_get_errno(message);
if (r < 0)
log_message_warning_errno(message, r, "rtnl: Could not receive link message, ignoring");
return 0;
}
r = sd_netlink_message_get_type(message, &type);
if (r < 0) {
log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m");
return 0;
} else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) {
log_warning("rtnl: Received unexpected message type %u when processing link, ignoring.", type);
return 0;
}
r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
if (r < 0) {
log_warning_errno(r, "rtnl: Could not get ifindex from link message, ignoring: %m");
return 0;
} else if (ifindex <= 0) {
log_warning("rtnl: received link message with invalid ifindex %d, ignoring.", ifindex);
return 0;
}
r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
if (r < 0) {
log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m");
return 0;
}
(void) link_get(m, ifindex, &link);
(void) netdev_get(m, name, &netdev);
switch (type) {
case RTM_NEWLINK:
if (!link) {
/* link is new, so add it */
r = link_add(m, message, &link);
if (r < 0) {
log_warning_errno(r, "Could not process new link message, ignoring: %m");
return 0;
}
}
if (netdev) {
/* netdev exists, so make sure the ifindex matches */
r = netdev_set_ifindex(netdev, message);
if (r < 0) {
log_warning_errno(r, "Could not process new link message for netdev, ignoring: %m");
return 0;
}
}
r = link_update(link, message);
if (r < 0) {
log_warning_errno(r, "Could not process link message, ignoring: %m");
return 0;
}
break;
case RTM_DELLINK:
link_drop(link);
netdev_drop(netdev);
break;
default:
assert_not_reached("Received link message with invalid RTNL message type.");
}
return 1;
}
static int systemd_netlink_fd(void) { static int systemd_netlink_fd(void) {
int n, fd, rtnl_fd = -EINVAL; int n, fd, rtnl_fd = -EINVAL;
@ -357,14 +217,13 @@ static int systemd_netlink_fd(void) {
if (n <= 0) if (n <= 0)
return -EINVAL; return -EINVAL;
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++)
if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) { if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
if (rtnl_fd >= 0) if (rtnl_fd >= 0)
return -EINVAL; return -EINVAL;
rtnl_fd = fd; rtnl_fd = fd;
} }
}
return rtnl_fd; return rtnl_fd;
} }
@ -466,300 +325,24 @@ static int manager_connect_rtnl(Manager *m) {
return 0; return 0;
} }
static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr_full *dns) {
const char *p;
int r;
assert(s);
assert(dns);
if (dns->ifindex != 0 && dns->ifindex != ifindex)
return 0;
p = in_addr_full_to_string(dns);
if (!p)
return 0;
r = ordered_set_put_strdup(s, p);
if (r == -EEXIST)
return 0;
return r;
}
static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_addr_full **dns, unsigned n) {
int r, c = 0;
assert(s);
assert(dns || n == 0);
for (unsigned i = 0; i < n; i++) {
r = ordered_set_put_dns_server(s, ifindex, dns[i]);
if (r < 0)
return r;
c += r;
}
return c;
}
static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address) {
char *p;
int r;
assert(s);
assert(address);
r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
if (r < 0)
return r;
r = ordered_set_consume(s, p);
if (r == -EEXIST)
return 0;
return r;
}
static int ordered_set_put_in4_addrv(OrderedSet *s,
const struct in_addr *addresses,
size_t n,
bool (*predicate)(const struct in_addr *addr)) {
int r, c = 0;
assert(s);
assert(n == 0 || addresses);
for (size_t i = 0; i < n; i++) {
if (predicate && !predicate(&addresses[i]))
continue;
r = ordered_set_put_in4_addr(s, addresses+i);
if (r < 0)
return r;
c += r;
}
return c;
}
static int manager_save(Manager *m) {
_cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
const char *operstate_str, *carrier_state_str, *address_state_str;
LinkOperationalState operstate = LINK_OPERSTATE_OFF;
LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
LinkAddressState address_state = LINK_ADDRESS_STATE_OFF;
_cleanup_free_ char *temp_path = NULL;
_cleanup_strv_free_ char **p = NULL;
_cleanup_fclose_ FILE *f = NULL;
Link *link;
int r;
assert(m);
assert(m->state_file);
/* We add all NTP and DNS server to a set, to filter out duplicates */
dns = ordered_set_new(&string_hash_ops);
if (!dns)
return -ENOMEM;
ntp = ordered_set_new(&string_hash_ops);
if (!ntp)
return -ENOMEM;
sip = ordered_set_new(&string_hash_ops);
if (!sip)
return -ENOMEM;
search_domains = ordered_set_new(&dns_name_hash_ops);
if (!search_domains)
return -ENOMEM;
route_domains = ordered_set_new(&dns_name_hash_ops);
if (!route_domains)
return -ENOMEM;
HASHMAP_FOREACH(link, m->links) {
const struct in_addr *addresses;
if (link->flags & IFF_LOOPBACK)
continue;
if (link->operstate > operstate)
operstate = link->operstate;
if (link->carrier_state > carrier_state)
carrier_state = link->carrier_state;
if (link->address_state > address_state)
address_state = link->address_state;
if (!link->network)
continue;
/* First add the static configured entries */
if (link->n_dns != (unsigned) -1)
r = ordered_set_put_dns_servers(dns, link->ifindex, link->dns, link->n_dns);
else
r = ordered_set_put_dns_servers(dns, link->ifindex, link->network->dns, link->network->n_dns);
if (r < 0)
return r;
r = ordered_set_put_strdupv(ntp, link->ntp ?: link->network->ntp);
if (r < 0)
return r;
r = ordered_set_put_string_set(search_domains, link->search_domains ?: link->network->search_domains);
if (r < 0)
return r;
r = ordered_set_put_string_set(route_domains, link->route_domains ?: link->network->route_domains);
if (r < 0)
return r;
if (!link->dhcp_lease)
continue;
/* Secondly, add the entries acquired via DHCP */
if (link->network->dhcp_use_dns) {
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(dns, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
if (link->network->dhcp_use_ntp) {
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(ntp, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
if (link->network->dhcp_use_sip) {
r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(sip, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
const char *domainname;
char **domains = NULL;
OrderedSet *target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? search_domains : route_domains;
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
if (r >= 0) {
r = ordered_set_put_strdup(target_domains, domainname);
if (r < 0)
return r;
} else if (r != -ENODATA)
return r;
r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
if (r >= 0) {
r = ordered_set_put_strdupv(target_domains, domains);
if (r < 0)
return r;
} else if (r != -ENODATA)
return r;
}
}
if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)
carrier_state = LINK_CARRIER_STATE_CARRIER;
operstate_str = link_operstate_to_string(operstate);
assert(operstate_str);
carrier_state_str = link_carrier_state_to_string(carrier_state);
assert(carrier_state_str);
address_state_str = link_address_state_to_string(address_state);
assert(address_state_str);
r = fopen_temporary(m->state_file, &f, &temp_path);
if (r < 0)
return r;
(void) fchmod(fileno(f), 0644);
fprintf(f,
"# This is private data. Do not parse.\n"
"OPER_STATE=%s\n"
"CARRIER_STATE=%s\n"
"ADDRESS_STATE=%s\n",
operstate_str, carrier_state_str, address_state_str);
ordered_set_print(f, "DNS=", dns);
ordered_set_print(f, "NTP=", ntp);
ordered_set_print(f, "SIP=", sip);
ordered_set_print(f, "DOMAINS=", search_domains);
ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
r = fflush_and_check(f);
if (r < 0)
goto fail;
r = conservative_rename(temp_path, m->state_file);
if (r < 0)
goto fail;
if (m->operational_state != operstate) {
m->operational_state = operstate;
if (strv_extend(&p, "OperationalState") < 0)
log_oom();
}
if (m->carrier_state != carrier_state) {
m->carrier_state = carrier_state;
if (strv_extend(&p, "CarrierState") < 0)
log_oom();
}
if (m->address_state != address_state) {
m->address_state = address_state;
if (strv_extend(&p, "AddressState") < 0)
log_oom();
}
if (p) {
r = manager_send_changed_strv(m, p);
if (r < 0)
log_error_errno(r, "Could not emit changed properties: %m");
}
m->dirty = false;
return 0;
fail:
(void) unlink(m->state_file);
(void) unlink(temp_path);
return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
}
static int manager_dirty_handler(sd_event_source *s, void *userdata) { static int manager_dirty_handler(sd_event_source *s, void *userdata) {
Manager *m = userdata; Manager *m = userdata;
Link *link; Link *link;
int r;
assert(m); assert(m);
if (m->dirty) if (m->dirty) {
manager_save(m); r = manager_save(m);
if (r < 0)
log_warning_errno(r, "Failed to update state file %s, ignoring: %m", m->state_file);
}
SET_FOREACH(link, m->dirty_links) SET_FOREACH(link, m->dirty_links) {
(void) link_save_and_clean(link); r = link_save_and_clean(link);
if (r < 0)
log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file);
}
return 1; return 1;
} }
@ -929,10 +512,15 @@ int manager_start(Manager *m) {
/* The dirty handler will deal with future serialization, but the first one /* The dirty handler will deal with future serialization, but the first one
must be done explicitly. */ must be done explicitly. */
manager_save(m); r = manager_save(m);
if (r < 0)
log_warning_errno(r, "Failed to update state file %s, ignoring: %m", m->state_file);
HASHMAP_FOREACH(link, m->links) HASHMAP_FOREACH(link, m->links) {
(void) link_save(link); r = link_save(link);
if (r < 0)
log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file);
}
return 0; return 0;
} }
@ -1155,13 +743,6 @@ Link* manager_find_uplink(Manager *m, Link *exclude) {
return NULL; return NULL;
} }
void manager_dirty(Manager *manager) {
assert(manager);
/* the serialized state in /run is no longer up-to-date */
manager->dirty = true;
}
static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
const sd_bus_error *e; const sd_bus_error *e;
int r; int r;

View File

@ -100,8 +100,6 @@ bool manager_should_reload(Manager *m);
int manager_enumerate(Manager *m); int manager_enumerate(Manager *m);
void manager_dirty(Manager *m);
Link* manager_find_uplink(Manager *m, Link *exclude); Link* manager_find_uplink(Manager *m, Link *exclude);
int manager_set_hostname(Manager *m, const char *hostname); int manager_set_hostname(Manager *m, const char *hostname);

View File

@ -15,6 +15,7 @@
#include "networkd-dhcp6.h" #include "networkd-dhcp6.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-ndisc.h" #include "networkd-ndisc.h"
#include "networkd-state-file.h"
#include "string-table.h" #include "string-table.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"

View File

@ -0,0 +1,682 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <netinet/in.h>
#include <linux/if.h>
#include "alloc-util.h"
#include "dns-domain.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "network-internal.h"
#include "networkd-link.h"
#include "networkd-manager-bus.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-state-file.h"
#include "ordered-set.h"
#include "set.h"
#include "strv.h"
#include "tmpfile-util.h"
static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr_full *dns) {
const char *p;
int r;
assert(s);
assert(dns);
if (dns->ifindex != 0 && dns->ifindex != ifindex)
return 0;
p = in_addr_full_to_string(dns);
if (!p)
return 0;
r = ordered_set_put_strdup(s, p);
if (r == -EEXIST)
return 0;
return r;
}
static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_addr_full **dns, unsigned n) {
int r, c = 0;
assert(s);
assert(dns || n == 0);
for (unsigned i = 0; i < n; i++) {
r = ordered_set_put_dns_server(s, ifindex, dns[i]);
if (r < 0)
return r;
c += r;
}
return c;
}
static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address) {
char *p;
int r;
assert(s);
assert(address);
r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
if (r < 0)
return r;
r = ordered_set_consume(s, p);
if (r == -EEXIST)
return 0;
return r;
}
static int ordered_set_put_in4_addrv(
OrderedSet *s,
const struct in_addr *addresses,
size_t n,
bool (*predicate)(const struct in_addr *addr)) {
int r, c = 0;
assert(s);
assert(n == 0 || addresses);
for (size_t i = 0; i < n; i++) {
if (predicate && !predicate(&addresses[i]))
continue;
r = ordered_set_put_in4_addr(s, addresses+i);
if (r < 0)
return r;
c += r;
}
return c;
}
int manager_save(Manager *m) {
_cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL;
const char *operstate_str, *carrier_state_str, *address_state_str;
LinkOperationalState operstate = LINK_OPERSTATE_OFF;
LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF;
LinkAddressState address_state = LINK_ADDRESS_STATE_OFF;
_cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_strv_free_ char **p = NULL;
_cleanup_fclose_ FILE *f = NULL;
Link *link;
int r;
assert(m);
assert(m->state_file);
/* We add all NTP and DNS server to a set, to filter out duplicates */
dns = ordered_set_new(&string_hash_ops);
if (!dns)
return -ENOMEM;
ntp = ordered_set_new(&string_hash_ops);
if (!ntp)
return -ENOMEM;
sip = ordered_set_new(&string_hash_ops);
if (!sip)
return -ENOMEM;
search_domains = ordered_set_new(&dns_name_hash_ops);
if (!search_domains)
return -ENOMEM;
route_domains = ordered_set_new(&dns_name_hash_ops);
if (!route_domains)
return -ENOMEM;
HASHMAP_FOREACH(link, m->links) {
const struct in_addr *addresses;
if (link->flags & IFF_LOOPBACK)
continue;
if (link->operstate > operstate)
operstate = link->operstate;
if (link->carrier_state > carrier_state)
carrier_state = link->carrier_state;
if (link->address_state > address_state)
address_state = link->address_state;
if (!link->network)
continue;
/* First add the static configured entries */
if (link->n_dns != (unsigned) -1)
r = ordered_set_put_dns_servers(dns, link->ifindex, link->dns, link->n_dns);
else
r = ordered_set_put_dns_servers(dns, link->ifindex, link->network->dns, link->network->n_dns);
if (r < 0)
return r;
r = ordered_set_put_strdupv(ntp, link->ntp ?: link->network->ntp);
if (r < 0)
return r;
r = ordered_set_put_string_set(search_domains, link->search_domains ?: link->network->search_domains);
if (r < 0)
return r;
r = ordered_set_put_string_set(route_domains, link->route_domains ?: link->network->route_domains);
if (r < 0)
return r;
if (!link->dhcp_lease)
continue;
/* Secondly, add the entries acquired via DHCP */
if (link->network->dhcp_use_dns) {
r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(dns, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
if (link->network->dhcp_use_ntp) {
r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(ntp, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
if (link->network->dhcp_use_sip) {
r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses);
if (r > 0) {
r = ordered_set_put_in4_addrv(sip, addresses, r, in4_addr_is_non_local);
if (r < 0)
return r;
} else if (r < 0 && r != -ENODATA)
return r;
}
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
const char *domainname;
char **domains = NULL;
OrderedSet *target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? search_domains : route_domains;
r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
if (r >= 0) {
r = ordered_set_put_strdup(target_domains, domainname);
if (r < 0)
return r;
} else if (r != -ENODATA)
return r;
r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains);
if (r >= 0) {
r = ordered_set_put_strdupv(target_domains, domains);
if (r < 0)
return r;
} else if (r != -ENODATA)
return r;
}
}
if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED)
carrier_state = LINK_CARRIER_STATE_CARRIER;
operstate_str = link_operstate_to_string(operstate);
assert(operstate_str);
carrier_state_str = link_carrier_state_to_string(carrier_state);
assert(carrier_state_str);
address_state_str = link_address_state_to_string(address_state);
assert(address_state_str);
r = fopen_temporary(m->state_file, &f, &temp_path);
if (r < 0)
return r;
(void) fchmod(fileno(f), 0644);
fprintf(f,
"# This is private data. Do not parse.\n"
"OPER_STATE=%s\n"
"CARRIER_STATE=%s\n"
"ADDRESS_STATE=%s\n",
operstate_str, carrier_state_str, address_state_str);
ordered_set_print(f, "DNS=", dns);
ordered_set_print(f, "NTP=", ntp);
ordered_set_print(f, "SIP=", sip);
ordered_set_print(f, "DOMAINS=", search_domains);
ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
r = fflush_and_check(f);
if (r < 0)
return r;
r = conservative_rename(temp_path, m->state_file);
if (r < 0)
return r;
temp_path = mfree(temp_path);
if (m->operational_state != operstate) {
m->operational_state = operstate;
if (strv_extend(&p, "OperationalState") < 0)
log_oom();
}
if (m->carrier_state != carrier_state) {
m->carrier_state = carrier_state;
if (strv_extend(&p, "CarrierState") < 0)
log_oom();
}
if (m->address_state != address_state) {
m->address_state = address_state;
if (strv_extend(&p, "AddressState") < 0)
log_oom();
}
if (p) {
r = manager_send_changed_strv(m, p);
if (r < 0)
log_warning_errno(r, "Could not emit changed properties, ignoring: %m");
}
m->dirty = false;
return 0;
}
static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
bool space = false;
Link *link;
assert(f);
assert(prefix);
if (hashmap_isempty(h))
return;
fputs(prefix, f);
HASHMAP_FOREACH(link, h) {
if (space)
fputc(' ', f);
fprintf(f, "%i", link->ifindex);
space = true;
}
fputc('\n', f);
}
static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) {
for (unsigned j = 0; j < n_dns; j++) {
const char *str;
if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex)
continue;
str = in_addr_full_to_string(dns[j]);
if (!str)
continue;
if (*space)
fputc(' ', f);
fputs(str, f);
*space = true;
}
}
static void serialize_addresses(
FILE *f,
const char *lvalue,
bool *space,
char **addresses,
sd_dhcp_lease *lease,
bool conditional,
sd_dhcp_lease_server_type_t what,
sd_dhcp6_lease *lease6,
bool conditional6,
int (*lease6_get_addr)(sd_dhcp6_lease*, const struct in6_addr**),
int (*lease6_get_fqdn)(sd_dhcp6_lease*, char ***)) {
bool _space = false;
int r;
if (!space)
space = &_space;
if (lvalue)
fprintf(f, "%s=", lvalue);
fputstrv(f, addresses, NULL, space);
if (lease && conditional) {
const struct in_addr *lease_addresses;
r = sd_dhcp_lease_get_servers(lease, what, &lease_addresses);
if (r > 0)
serialize_in_addrs(f, lease_addresses, r, space, in4_addr_is_non_local);
}
if (lease6 && conditional6 && lease6_get_addr) {
const struct in6_addr *in6_addrs;
r = lease6_get_addr(lease6, &in6_addrs);
if (r > 0)
serialize_in6_addrs(f, in6_addrs, r, space);
}
if (lease6 && conditional6 && lease6_get_fqdn) {
char **in6_hosts;
r = lease6_get_fqdn(lease6, &in6_hosts);
if (r > 0)
fputstrv(f, in6_hosts, NULL, space);
}
if (lvalue)
fputc('\n', f);
}
int link_save(Link *link) {
const char *admin_state, *oper_state, *carrier_state, *address_state;
_cleanup_(unlink_and_freep) char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(link);
assert(link->state_file);
assert(link->lease_file);
assert(link->manager);
if (link->state == LINK_STATE_LINGER)
return 0;
link_lldp_save(link);
admin_state = link_state_to_string(link->state);
assert(admin_state);
oper_state = link_operstate_to_string(link->operstate);
assert(oper_state);
carrier_state = link_carrier_state_to_string(link->carrier_state);
assert(carrier_state);
address_state = link_address_state_to_string(link->address_state);
assert(address_state);
r = fopen_temporary(link->state_file, &f, &temp_path);
if (r < 0)
return r;
(void) fchmod(fileno(f), 0644);
fprintf(f,
"# This is private data. Do not parse.\n"
"ADMIN_STATE=%s\n"
"OPER_STATE=%s\n"
"CARRIER_STATE=%s\n"
"ADDRESS_STATE=%s\n",
admin_state, oper_state, carrier_state, address_state);
if (link->network) {
char **dhcp6_domains = NULL, **dhcp_domains = NULL;
const char *dhcp_domainname = NULL, *p;
bool space;
fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
yes_no(link->network->required_for_online));
LinkOperationalStateRange st = link->network->required_operstate_for_online;
fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s%s%s\n",
strempty(link_operstate_to_string(st.min)),
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "",
st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : "");
fprintf(f, "ACTIVATION_POLICY=%s\n",
activation_policy_to_string(link->network->activation_policy));
fprintf(f, "NETWORK_FILE=%s\n", link->network->filename);
/************************************************************/
fputs("DNS=", f);
space = false;
if (link->n_dns != (unsigned) -1)
link_save_dns(link, f, link->dns, link->n_dns, &space);
else
link_save_dns(link, f, link->network->dns, link->network->n_dns, &space);
serialize_addresses(f, NULL, &space,
NULL,
link->dhcp_lease,
link->network->dhcp_use_dns,
SD_DHCP_LEASE_DNS,
link->dhcp6_lease,
link->network->dhcp6_use_dns,
sd_dhcp6_lease_get_dns,
NULL);
/* Make sure to flush out old entries before we use the NDisc data */
ndisc_vacuum(link);
if (link->network->ipv6_accept_ra_use_dns && link->ndisc_rdnss) {
NDiscRDNSS *dd;
SET_FOREACH(dd, link->ndisc_rdnss)
serialize_in6_addrs(f, &dd->address, 1, &space);
}
fputc('\n', f);
/************************************************************/
serialize_addresses(f, "NTP", NULL,
link->ntp ?: link->network->ntp,
link->dhcp_lease,
link->network->dhcp_use_ntp,
SD_DHCP_LEASE_NTP,
link->dhcp6_lease,
link->network->dhcp6_use_ntp,
sd_dhcp6_lease_get_ntp_addrs,
sd_dhcp6_lease_get_ntp_fqdn);
serialize_addresses(f, "SIP", NULL,
NULL,
link->dhcp_lease,
link->network->dhcp_use_sip,
SD_DHCP_LEASE_SIP,
NULL, false, NULL, NULL);
/************************************************************/
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
if (link->dhcp_lease) {
(void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname);
(void) sd_dhcp_lease_get_search_domains(link->dhcp_lease, &dhcp_domains);
}
if (link->dhcp6_lease)
(void) sd_dhcp6_lease_get_domains(link->dhcp6_lease, &dhcp6_domains);
}
fputs("DOMAINS=", f);
space = false;
ORDERED_SET_FOREACH(p, link->search_domains ?: link->network->search_domains)
fputs_with_space(f, p, NULL, &space);
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) {
if (dhcp_domainname)
fputs_with_space(f, dhcp_domainname, NULL, &space);
if (dhcp_domains)
fputstrv(f, dhcp_domains, NULL, &space);
if (dhcp6_domains)
fputstrv(f, dhcp6_domains, NULL, &space);
}
if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_YES) {
NDiscDNSSL *dd;
SET_FOREACH(dd, link->ndisc_dnssl)
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
}
fputc('\n', f);
/************************************************************/
fputs("ROUTE_DOMAINS=", f);
space = false;
ORDERED_SET_FOREACH(p, link->route_domains ?: link->network->route_domains)
fputs_with_space(f, p, NULL, &space);
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) {
if (dhcp_domainname)
fputs_with_space(f, dhcp_domainname, NULL, &space);
if (dhcp_domains)
fputstrv(f, dhcp_domains, NULL, &space);
if (dhcp6_domains)
fputstrv(f, dhcp6_domains, NULL, &space);
}
if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_ROUTE) {
NDiscDNSSL *dd;
SET_FOREACH(dd, link->ndisc_dnssl)
fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space);
}
fputc('\n', f);
/************************************************************/
fprintf(f, "LLMNR=%s\n",
resolve_support_to_string(link->llmnr >= 0 ? link->llmnr : link->network->llmnr));
/************************************************************/
fprintf(f, "MDNS=%s\n",
resolve_support_to_string(link->mdns >= 0 ? link->mdns : link->network->mdns));
/************************************************************/
int dns_default_route =
link->dns_default_route >= 0 ? link->dns_default_route :
link->network->dns_default_route;
if (dns_default_route >= 0)
fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(dns_default_route));
/************************************************************/
DnsOverTlsMode dns_over_tls_mode =
link->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID ? link->dns_over_tls_mode :
link->network->dns_over_tls_mode;
if (dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
fprintf(f, "DNS_OVER_TLS=%s\n", dns_over_tls_mode_to_string(dns_over_tls_mode));
/************************************************************/
DnssecMode dnssec_mode =
link->dnssec_mode != _DNSSEC_MODE_INVALID ? link->dnssec_mode :
link->network->dnssec_mode;
if (dnssec_mode != _DNSSEC_MODE_INVALID)
fprintf(f, "DNSSEC=%s\n", dnssec_mode_to_string(dnssec_mode));
/************************************************************/
Set *nta_anchors = link->dnssec_negative_trust_anchors;
if (set_isempty(nta_anchors))
nta_anchors = link->network->dnssec_negative_trust_anchors;
if (!set_isempty(nta_anchors)) {
const char *n;
fputs("DNSSEC_NTA=", f);
space = false;
SET_FOREACH(n, nta_anchors)
fputs_with_space(f, n, NULL, &space);
fputc('\n', f);
}
}
print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links);
print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links);
if (link->dhcp_lease) {
r = dhcp_lease_save(link->dhcp_lease, link->lease_file);
if (r < 0)
return r;
fprintf(f,
"DHCP_LEASE=%s\n",
link->lease_file);
} else
(void) unlink(link->lease_file);
r = link_serialize_dhcp6_client(link, f);
if (r < 0)
return r;
r = fflush_and_check(f);
if (r < 0)
return r;
r = conservative_rename(temp_path, link->state_file);
if (r < 0)
return r;
temp_path = mfree(temp_path);
return 0;
}
void link_dirty(Link *link) {
int r;
assert(link);
assert(link->manager);
/* The serialized state in /run is no longer up-to-date. */
/* Also mark manager dirty as link is dirty */
link->manager->dirty = true;
r = set_ensure_put(&link->manager->dirty_links, NULL, link);
if (r <= 0)
/* Ignore allocation errors and don't take another ref if the link was already dirty */
return;
link_ref(link);
}
void link_clean(Link *link) {
assert(link);
assert(link->manager);
/* The serialized state in /run is up-to-date */
link_unref(set_remove(link->manager->dirty_links, link));
}
int link_save_and_clean(Link *link) {
int r;
r = link_save(link);
if (r < 0)
return r;
link_clean(link);
return 0;
}

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
typedef struct Link Link;
typedef struct Manager Manager;
void link_dirty(Link *link);
void link_clean(Link *link);
int link_save(Link *link);
int link_save_and_clean(Link *link);
int manager_save(Manager *m);

View File

@ -4563,7 +4563,7 @@ static int run_container(
if (child_netns_fd < 0) if (child_netns_fd < 0)
return log_error_errno(errno, "Cannot open file %s: %m", arg_network_namespace_path); 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) 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); 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) else if (r < 0)

View File

@ -959,7 +959,7 @@ static int make_unit_name(sd_bus *bus, UnitType t, char **ret) {
/* We managed to get the unique name, then let's use that to /* We managed to get the unique name, then let's use that to
* name our transient units. */ * name our transient units. */
id = startswith(unique, ":1."); id = startswith(unique, ":");
if (!id) if (!id)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Unique name %s has unexpected format.", "Unique name %s has unexpected format.",

View File

@ -4,7 +4,6 @@
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h> #include <limits.h>
#include <poll.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
@ -276,44 +275,28 @@ int ask_password_plymouth(
pollfd[POLL_INOTIFY].events = POLLIN; pollfd[POLL_INOTIFY].events = POLLIN;
for (;;) { for (;;) {
int sleep_for = -1, j; usec_t timeout;
if (until > 0) { if (until > 0)
usec_t y; timeout = usec_sub_unsigned(until, now(CLOCK_MONOTONIC));
else
y = now(CLOCK_MONOTONIC); timeout = USEC_INFINITY;
if (y > until) {
r = -ETIME;
goto finish;
}
sleep_for = (int) ((until - y) / USEC_PER_MSEC);
}
if (flag_file && access(flag_file, F_OK) < 0) { if (flag_file && access(flag_file, F_OK) < 0) {
r = -errno; r = -errno;
goto finish; goto finish;
} }
j = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for); r = ppoll_usec(pollfd, notify >= 0 ? 2 : 1, timeout);
if (j < 0) { if (r == -EINTR)
if (errno == EINTR) continue;
continue; if (r < 0)
r = -errno;
goto finish; goto finish;
} else if (j == 0) { if (r == 0) {
r = -ETIME; r = -ETIME;
goto finish; goto finish;
} }
if (pollfd[POLL_SOCKET].revents & POLLNVAL ||
(notify >= 0 && pollfd[POLL_INOTIFY].revents & POLLNVAL)) {
r = -EBADF;
goto finish;
}
if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0) if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0)
(void) flush_fd(notify); (void) flush_fd(notify);
@ -513,21 +496,13 @@ int ask_password_tty(
for (;;) { for (;;) {
_cleanup_(erase_char) char c; _cleanup_(erase_char) char c;
int sleep_for = -1, k; usec_t timeout;
ssize_t n; ssize_t n;
if (until > 0) { if (until > 0)
usec_t y; timeout = usec_sub_unsigned(until, now(CLOCK_MONOTONIC));
else
y = now(CLOCK_MONOTONIC); timeout = USEC_INFINITY;
if (y > until) {
r = -ETIME;
goto finish;
}
sleep_for = (int) DIV_ROUND_UP(until - y, USEC_PER_MSEC);
}
if (flag_file) if (flag_file)
if (access(flag_file, F_OK) < 0) { if (access(flag_file, F_OK) < 0) {
@ -535,24 +510,16 @@ int ask_password_tty(
goto finish; goto finish;
} }
k = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for); r = ppoll_usec(pollfd, notify >= 0 ? 2 : 1, timeout);
if (k < 0) { if (r == -EINTR)
if (errno == EINTR) continue;
continue; if (r < 0)
r = -errno;
goto finish; goto finish;
} else if (k == 0) { if (r == 0) {
r = -ETIME; r = -ETIME;
goto finish; goto finish;
} }
if ((pollfd[POLL_TTY].revents & POLLNVAL) ||
(notify >= 0 && (pollfd[POLL_INOTIFY].revents & POLLNVAL))) {
r = -EBADF;
goto finish;
}
if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyname) { if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyname) {
(void) flush_fd(notify); (void) flush_fd(notify);
@ -875,38 +842,24 @@ int ask_password_agent(
char passphrase[LINE_MAX+1]; char passphrase[LINE_MAX+1];
struct iovec iovec; struct iovec iovec;
struct ucred *ucred; struct ucred *ucred;
usec_t timeout;
ssize_t n; ssize_t n;
int k;
usec_t t;
t = now(CLOCK_MONOTONIC); if (until > 0)
timeout = usec_sub_unsigned(until, now(CLOCK_MONOTONIC));
else
timeout = USEC_INFINITY;
if (until > 0 && until <= t) { r = ppoll_usec(pollfd, notify >= 0 ? _FD_MAX : _FD_MAX - 1, timeout);
if (r == -EINTR)
continue;
if (r < 0)
goto finish;
if (r == 0) {
r = -ETIME; r = -ETIME;
goto finish; goto finish;
} }
k = poll(pollfd, notify >= 0 ? _FD_MAX : _FD_MAX - 1, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1);
if (k < 0) {
if (errno == EINTR)
continue;
r = -errno;
goto finish;
}
if (k <= 0) {
r = -ETIME;
goto finish;
}
if (pollfd[FD_SOCKET].revents & POLLNVAL ||
pollfd[FD_SIGNAL].revents & POLLNVAL ||
(notify >= 0 && pollfd[FD_INOTIFY].revents & POLLNVAL)) {
r = -EBADF;
goto finish;
}
if (pollfd[FD_SIGNAL].revents & POLLIN) { if (pollfd[FD_SIGNAL].revents & POLLIN) {
r = -EINTR; r = -EINTR;
goto finish; goto finish;

View File

@ -2,7 +2,6 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <poll.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
@ -12,6 +11,7 @@
#include "barrier.h" #include "barrier.h"
#include "fd-util.h" #include "fd-util.h"
#include "io-util.h"
#include "macro.h" #include "macro.h"
/** /**
@ -219,14 +219,10 @@ static bool barrier_read(Barrier *b, int64_t comp) {
uint64_t buf; uint64_t buf;
int r; int r;
r = poll(pfd, ELEMENTSOF(pfd), -1); r = ppoll_usec(pfd, ELEMENTSOF(pfd), USEC_INFINITY);
if (r < 0) { if (r == -EINTR)
if (IN_SET(errno, EAGAIN, EINTR)) continue;
continue; if (r < 0)
goto error;
}
if (pfd[0].revents & POLLNVAL ||
pfd[1].revents & POLLNVAL)
goto error; goto error;
if (pfd[1].revents) { if (pfd[1].revents) {

View File

@ -882,6 +882,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
"ProtectProc", "ProtectProc",
"ProcSubset", "ProcSubset",
"NetworkNamespacePath", "NetworkNamespacePath",
"IPCNamespacePath",
"LogNamespace")) "LogNamespace"))
return bus_append_string(m, field, eq); 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", "PrivateNetwork",
"PrivateUsers", "PrivateUsers",
"PrivateMounts", "PrivateMounts",
"PrivateIPC",
"NoNewPrivileges", "NoNewPrivileges",
"SyslogLevelPrefix", "SyslogLevelPrefix",
"MemoryDenyWriteExecute", "MemoryDenyWriteExecute",

View File

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include <stdbool.h>
typedef enum UnitFilePresetMode UnitFilePresetMode; typedef enum UnitFilePresetMode UnitFilePresetMode;
typedef enum UnitFileChangeType UnitFileChangeType; typedef enum UnitFileChangeType UnitFileChangeType;
typedef enum UnitFileFlags UnitFileFlags; typedef enum UnitFileFlags UnitFileFlags;
@ -9,8 +11,6 @@ typedef struct UnitFileChange UnitFileChange;
typedef struct UnitFileList UnitFileList; typedef struct UnitFileList UnitFileList;
typedef struct UnitFileInstallInfo UnitFileInstallInfo; typedef struct UnitFileInstallInfo UnitFileInstallInfo;
#include <stdbool.h>
#include "hashmap.h" #include "hashmap.h"
#include "macro.h" #include "macro.h"
#include "path-lookup.h" #include "path-lookup.h"

View File

@ -69,3 +69,11 @@ int namespace_flags_to_string(unsigned long flags, char **ret) {
return 0; 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_from_string(const char *name, unsigned long *ret);
int namespace_flags_to_string(unsigned long flags, char **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 { struct namespace_flag_map {
unsigned long flag; unsigned long flag;

View File

@ -2,7 +2,6 @@
#include <errno.h> #include <errno.h>
#include <getopt.h> #include <getopt.h>
#include <poll.h>
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@ -15,6 +14,7 @@
#include "bus-internal.h" #include "bus-internal.h"
#include "bus-util.h" #include "bus-util.h"
#include "errno-util.h" #include "errno-util.h"
#include "io-util.h"
#include "log.h" #include "log.h"
#include "main-func.h" #include "main-func.h"
#include "util.h" #include "util.h"
@ -181,8 +181,9 @@ static int run(int argc, char *argv[]) {
for (;;) { for (;;) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
int events_a, events_b, fd; int events_a, events_b, fd;
uint64_t timeout_a, timeout_b, t; usec_t timeout_a, timeout_b, t;
struct timespec _ts, *ts;
assert_cc(sizeof(usec_t) == sizeof(uint64_t));
r = sd_bus_process(a, &m); r = sd_bus_process(a, &m);
if (r < 0) if (r < 0)
@ -235,23 +236,7 @@ static int run(int argc, char *argv[]) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get timeout: %m"); return log_error_errno(r, "Failed to get timeout: %m");
t = timeout_a; t = usec_sub_unsigned(MIN(timeout_a, timeout_b), now(CLOCK_MONOTONIC));
if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a))
t = timeout_b;
if (t == (uint64_t) -1)
ts = NULL;
else {
usec_t nw;
nw = now(CLOCK_MONOTONIC);
if (t > nw)
t -= nw;
else
t = 0;
ts = timespec_store(&_ts, t);
}
struct pollfd p[3] = { struct pollfd p[3] = {
{ .fd = fd, .events = events_a }, { .fd = fd, .events = events_a },
@ -259,13 +244,9 @@ static int run(int argc, char *argv[]) {
{ .fd = STDOUT_FILENO, .events = events_b & POLLOUT }, { .fd = STDOUT_FILENO, .events = events_b & POLLOUT },
}; };
r = ppoll(p, ELEMENTSOF(p), ts, NULL); r = ppoll_usec(p, ELEMENTSOF(p), t);
if (r < 0) if (r < 0)
return log_error_errno(errno, "ppoll() failed: %m"); return log_error_errno(r, "ppoll() failed: %m");
if (p[0].revents & POLLNVAL ||
p[1].revents & POLLNVAL ||
p[2].revents & POLLNVAL)
return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Invalid file descriptor to poll on?");
} }
return 0; return 0;

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 }; _cleanup_close_pair_ int s[2] = { -1, -1 };
pid_t pid1, pid2, pid3; pid_t pid1, pid2, pid3;
int r, n = 0; int r, n = 0;
@ -80,7 +80,7 @@ static void test_netns(void) {
assert_se(pid1 >= 0); assert_se(pid1 >= 0);
if (pid1 == 0) { if (pid1 == 0) {
r = setup_netns(s); r = setup_shareable_ns(s, nsflag);
assert_se(r >= 0); assert_se(r >= 0);
_exit(r); _exit(r);
} }
@ -89,7 +89,7 @@ static void test_netns(void) {
assert_se(pid2 >= 0); assert_se(pid2 >= 0);
if (pid2 == 0) { if (pid2 == 0) {
r = setup_netns(s); r = setup_shareable_ns(s, nsflag);
assert_se(r >= 0); assert_se(r >= 0);
exit(r); exit(r);
} }
@ -98,7 +98,7 @@ static void test_netns(void) {
assert_se(pid3 >= 0); assert_se(pid3 >= 0);
if (pid3 == 0) { if (pid3 == 0) {
r = setup_netns(s); r = setup_shareable_ns(s, nsflag);
assert_se(r >= 0); assert_se(r >= 0);
exit(r); exit(r);
} }
@ -121,6 +121,14 @@ static void test_netns(void) {
assert_se(n == 1); 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) { static void test_protect_kernel_logs(void) {
int r; int r;
pid_t pid; 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_tmpdir("sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device", z, zz);
test_netns(); test_netns();
test_ipcns();
test_protect_kernel_logs(); test_protect_kernel_logs();
return EXIT_SUCCESS; return EXIT_SUCCESS;

View File

@ -2,6 +2,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <sched.h>
#include <unistd.h> #include <unistd.h>
#include "alloc-util.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); 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; _cleanup_close_ int fd = -1;
assert_se(fd_is_network_ns(STDIN_FILENO) == 0); assert_se(fd_is_ns(STDIN_FILENO, CLONE_NEWNET) == 0);
assert_se(fd_is_network_ns(STDERR_FILENO) == 0); assert_se(fd_is_ns(STDERR_FILENO, CLONE_NEWNET) == 0);
assert_se(fd_is_network_ns(STDOUT_FILENO) == 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((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); fd = safe_close(fd);
assert_se((fd = open("/proc/self/ns/net", O_CLOEXEC|O_RDONLY)) >= 0); 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) { static void test_device_major_minor_valid(void) {
@ -159,7 +164,7 @@ int main(int argc, char *argv[]) {
test_is_symlink(); test_is_symlink();
test_path_is_fs_type(); test_path_is_fs_type();
test_path_is_temporary_fs(); test_path_is_temporary_fs();
test_fd_is_network_ns(); test_fd_is_ns();
test_device_major_minor_valid(); test_device_major_minor_valid();
test_device_path_make_canonical(); test_device_path_make_canonical();

View File

@ -72,6 +72,13 @@ static double ts_to_d(const struct timespec *ts) {
return ts->tv_sec + (1.0e-9 * ts->tv_nsec); return ts->tv_sec + (1.0e-9 * ts->tv_nsec);
} }
static uint32_t graceful_add_offset_1900_1970(time_t t) {
/* Adds OFFSET_1900_1970 to t and returns it as 32bit value. This is handles overflows
* gracefully in a deterministic and well-defined way by cutting off the top bits. */
uint64_t a = (uint64_t) t + OFFSET_1900_1970;
return (uint32_t) (a & UINT64_C(0xFFFFFFFF));
}
static int manager_timeout(sd_event_source *source, usec_t usec, void *userdata) { static int manager_timeout(sd_event_source *source, usec_t usec, void *userdata) {
_cleanup_free_ char *pretty = NULL; _cleanup_free_ char *pretty = NULL;
Manager *m = userdata; Manager *m = userdata;
@ -121,7 +128,7 @@ static int manager_send_request(Manager *m) {
*/ */
assert_se(clock_gettime(clock_boottime_or_monotonic(), &m->trans_time_mon) >= 0); assert_se(clock_gettime(clock_boottime_or_monotonic(), &m->trans_time_mon) >= 0);
assert_se(clock_gettime(CLOCK_REALTIME, &m->trans_time) >= 0); assert_se(clock_gettime(CLOCK_REALTIME, &m->trans_time) >= 0);
ntpmsg.trans_time.sec = htobe32(m->trans_time.tv_sec + OFFSET_1900_1970); ntpmsg.trans_time.sec = htobe32(graceful_add_offset_1900_1970(m->trans_time.tv_sec));
ntpmsg.trans_time.frac = htobe32(m->trans_time.tv_nsec); ntpmsg.trans_time.frac = htobe32(m->trans_time.tv_nsec);
server_address_pretty(m->current_server_address, &pretty); server_address_pretty(m->current_server_address, &pretty);
@ -476,7 +483,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re
m->missed_replies = 0; m->missed_replies = 0;
/* check our "time cookie" (we just stored nanoseconds in the fraction field) */ /* check our "time cookie" (we just stored nanoseconds in the fraction field) */
if (be32toh(ntpmsg.origin_time.sec) != m->trans_time.tv_sec + OFFSET_1900_1970 || if (be32toh(ntpmsg.origin_time.sec) != graceful_add_offset_1900_1970(m->trans_time.tv_sec) ||
be32toh(ntpmsg.origin_time.frac) != (unsigned long) m->trans_time.tv_nsec) { be32toh(ntpmsg.origin_time.frac) != (unsigned long) m->trans_time.tv_nsec) {
log_debug("Invalid reply; not our transmit time. Ignoring."); log_debug("Invalid reply; not our transmit time. Ignoring.");
return 0; return 0;

View File

@ -6,7 +6,6 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <getopt.h> #include <getopt.h>
#include <poll.h>
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <sys/prctl.h> #include <sys/prctl.h>
@ -366,7 +365,7 @@ static int process_and_watch_password_files(bool watch) {
} }
for (;;) { for (;;) {
int timeout = -1; usec_t timeout = USEC_INFINITY;
r = process_password_files(); r = process_password_files();
if (r < 0) { if (r < 0) {
@ -385,16 +384,11 @@ static int process_and_watch_password_files(bool watch) {
if (!watch) if (!watch)
break; break;
if (poll(pollfd, _FD_MAX, timeout) < 0) { r = ppoll_usec(pollfd, _FD_MAX, timeout);
if (errno == EINTR) if (r == -EINTR)
continue; continue;
if (r < 0)
return -errno; return r;
}
if (pollfd[FD_SIGNAL].revents & POLLNVAL ||
pollfd[FD_INOTIFY].revents & POLLNVAL)
return -EBADF;
if (pollfd[FD_INOTIFY].revents != 0) if (pollfd[FD_INOTIFY].revents != 0)
(void) flush_fd(notify); (void) flush_fd(notify);

View File

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