core/unit: make JoinsNamespaceOf= implies the inverse dependency

Previously, even if a.service has JoinsNamespaceOf=b.service, the
inverse direction of reference was not introduced.
Hence, a.service is started earlier than b.service, the namespace will
not shared with b.service.
Also, even if a.service had the reference to b.service, b.service did not.
If b.service is freed earlier, then unit_clear_dependencies() does not clear
the reference from a to b, and will cause use-after-free on unit_free() for
a.service.

Let's make JoinsNamespaceOf=b.service in a.service implies the inverse
dependency, i.e. JoinsNamespaceOf=a.service for b.service. Then, we can safely
free b.service.
This commit is contained in:
Yu Watanabe 2023-05-23 06:36:44 +09:00
parent 512df9de23
commit a60f96fcf5
5 changed files with 15 additions and 14 deletions

View file

@ -856,16 +856,18 @@
<term><varname>JoinsNamespaceOf=</varname></term>
<listitem><para>For units that start processes (such as service units), lists one or more other units
whose network and/or temporary file namespace to join. This only applies to unit types which support
the <varname>PrivateNetwork=</varname>, <varname>NetworkNamespacePath=</varname>,
whose network and/or temporary file namespace to join. If this is specified on a unit (say, a.service
has <varname>JoinsNamespaceOf=b.service</varname>), then this the inverse dependency
(<varname>JoinsNamespaceOf=a.service</varname> for b.service) is implied. This only applies to unit
types which support the <varname>PrivateNetwork=</varname>, <varname>NetworkNamespacePath=</varname>,
<varname>PrivateIPC=</varname>, <varname>IPCNamespacePath=</varname>, and
<varname>PrivateTmp=</varname> directives (see
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details). If a unit that has this setting set is started, its processes will see the same
<filename>/tmp/</filename>, <filename>/var/tmp/</filename>, IPC namespace and network namespace as
one listed unit that is started. If multiple listed units are already started, it is not defined
which namespace is joined. Note that this setting only has an effect if
<varname>PrivateNetwork=</varname>/<varname>NetworkNamespacePath=</varname>,
one listed unit that is started. If multiple listed units are already started and these do not share
their namespace, then it is not defined which namespace is joined. Note that this setting only has an
effect if <varname>PrivateNetwork=</varname>/<varname>NetworkNamespacePath=</varname>,
<varname>PrivateIPC=</varname>/<varname>IPCNamespacePath=</varname> and/or
<varname>PrivateTmp=</varname> is enabled for both the unit that joins the namespace and the unit
whose namespace is joined.</para></listitem>

View file

@ -3209,12 +3209,11 @@ int unit_add_dependency(
return r;
notify = r > 0;
if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID && inverse_table[d] != d) {
r = unit_add_dependency_hashmap(&other->dependencies, inverse_table[d], u, 0, mask);
if (r < 0)
return r;
notify_other = r > 0;
}
assert(inverse_table[d] >= 0 && inverse_table[d] < _UNIT_DEPENDENCY_MAX);
r = unit_add_dependency_hashmap(&other->dependencies, inverse_table[d], u, 0, mask);
if (r < 0)
return r;
notify_other = r > 0;
if (add_reference) {
r = unit_add_dependency_hashmap(&u->dependencies, UNIT_REFERENCES, other, mask, 0);

View file

@ -3,4 +3,4 @@
Type=oneshot
MountAPIVFS=yes
PrivateTmp=yes
ExecStart=test ! -e /tmp/shared-private-file
ExecStart=test -e /tmp/shared-private-file

View file

@ -4,6 +4,6 @@ Type=notify
NotifyAccess=all
MountAPIVFS=yes
PrivateTmp=yes
ExecStartPre=test ! -e /tmp/shared-private-file-x
ExecStartPre=test -e /tmp/shared-private-file-x
ExecStartPre=test ! -e /tmp/hoge
ExecStart=/bin/bash -c 'touch /tmp/shared-private-file-y && systemd-notify --ready && sleep infinity'

View file

@ -7,5 +7,5 @@ Type=oneshot
MountAPIVFS=yes
PrivateTmp=yes
ExecStart=test ! -e /tmp/shared-private-file-x
ExecStart=test -e /tmp/shared-private-file-y
ExecStart=test ! -e /tmp/shared-private-file-y
ExecStart=test ! -e /tmp/hoge