mirror of
https://github.com/systemd/systemd
synced 2025-10-02 18:24:46 +02:00
Compare commits
9 Commits
fa02711758
...
9c274488a9
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9c274488a9 | ||
![]() |
155d626bc6 | ||
![]() |
d895e10a24 | ||
![]() |
b66789a9b5 | ||
![]() |
a437c5e4da | ||
![]() |
249a967f62 | ||
![]() |
93f597013a | ||
![]() |
82fb2da213 | ||
![]() |
280b3781bd |
@ -2565,6 +2565,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly s RootVerity = '...';
|
readonly s RootVerity = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly a(sba(ss)) ExtensionImages = [...];
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly a(ssba(ss)) MountImages = [...];
|
readonly a(ssba(ss)) MountImages = [...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly i OOMScoreAdjust = ...;
|
readonly i OOMScoreAdjust = ...;
|
||||||
@ -3070,24 +3072,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
|
|
||||||
<!--property WorkingDirectory is not documented!-->
|
<!--property WorkingDirectory is not documented!-->
|
||||||
|
|
||||||
<!--property RootDirectory is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootImage is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootImageOptions is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootHash is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootHashPath is not documented!-->
|
<!--property RootHashPath is not documented!-->
|
||||||
|
|
||||||
<!--property RootHashSignature is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootHashSignaturePath is not documented!-->
|
<!--property RootHashSignaturePath is not documented!-->
|
||||||
|
|
||||||
<!--property RootVerity is not documented!-->
|
|
||||||
|
|
||||||
<!--property MountImages is not documented!-->
|
|
||||||
|
|
||||||
<!--property OOMScoreAdjust is not documented!-->
|
<!--property OOMScoreAdjust is not documented!-->
|
||||||
|
|
||||||
<!--property CoredumpFilter is not documented!-->
|
<!--property CoredumpFilter is not documented!-->
|
||||||
@ -3656,6 +3644,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="RootVerity"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="RootVerity"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImages"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MountImages"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MountImages"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="OOMScoreAdjust"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="OOMScoreAdjust"/>
|
||||||
@ -3978,6 +3968,17 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
|
|
||||||
<para><varname>ControlGroup</varname> indicates the control group path the processes of this service
|
<para><varname>ControlGroup</varname> indicates the control group path the processes of this service
|
||||||
unit are placed in.</para>
|
unit are placed in.</para>
|
||||||
|
|
||||||
|
<para>The following properties map 1:1 to corresponding settings in the unit file:
|
||||||
|
<varname>RootDirectory</varname>
|
||||||
|
<varname>RootImage</varname>
|
||||||
|
<varname>RootImageOptions</varname>
|
||||||
|
<varname>RootVerity</varname>
|
||||||
|
<varname>RootHash</varname>
|
||||||
|
<varname>RootHashSignature</varname>
|
||||||
|
<varname>MountImages</varname>
|
||||||
|
<varname>ExtensionImages</varname>
|
||||||
|
see systemd.exec(5) for their meaning.</para>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
@ -4325,6 +4326,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly s RootVerity = '...';
|
readonly s RootVerity = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly a(sba(ss)) ExtensionImages = [...];
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly a(ssba(ss)) MountImages = [...];
|
readonly a(ssba(ss)) MountImages = [...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly i OOMScoreAdjust = ...;
|
readonly i OOMScoreAdjust = ...;
|
||||||
@ -4858,24 +4861,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
|
|
||||||
<!--property WorkingDirectory is not documented!-->
|
<!--property WorkingDirectory is not documented!-->
|
||||||
|
|
||||||
<!--property RootDirectory is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootImage is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootImageOptions is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootHash is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootHashPath is not documented!-->
|
<!--property RootHashPath is not documented!-->
|
||||||
|
|
||||||
<!--property RootHashSignature is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootHashSignaturePath is not documented!-->
|
<!--property RootHashSignaturePath is not documented!-->
|
||||||
|
|
||||||
<!--property RootVerity is not documented!-->
|
|
||||||
|
|
||||||
<!--property MountImages is not documented!-->
|
|
||||||
|
|
||||||
<!--property OOMScoreAdjust is not documented!-->
|
<!--property OOMScoreAdjust is not documented!-->
|
||||||
|
|
||||||
<!--property CoredumpFilter is not documented!-->
|
<!--property CoredumpFilter is not documented!-->
|
||||||
@ -5442,6 +5431,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="RootVerity"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="RootVerity"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImages"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MountImages"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MountImages"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="OOMScoreAdjust"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="OOMScoreAdjust"/>
|
||||||
@ -6024,6 +6015,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly s RootVerity = '...';
|
readonly s RootVerity = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly a(sba(ss)) ExtensionImages = [...];
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly a(ssba(ss)) MountImages = [...];
|
readonly a(ssba(ss)) MountImages = [...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly i OOMScoreAdjust = ...;
|
readonly i OOMScoreAdjust = ...;
|
||||||
@ -6485,24 +6478,10 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
|
|
||||||
<!--property WorkingDirectory is not documented!-->
|
<!--property WorkingDirectory is not documented!-->
|
||||||
|
|
||||||
<!--property RootDirectory is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootImage is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootImageOptions is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootHash is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootHashPath is not documented!-->
|
<!--property RootHashPath is not documented!-->
|
||||||
|
|
||||||
<!--property RootHashSignature is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootHashSignaturePath is not documented!-->
|
<!--property RootHashSignaturePath is not documented!-->
|
||||||
|
|
||||||
<!--property RootVerity is not documented!-->
|
|
||||||
|
|
||||||
<!--property MountImages is not documented!-->
|
|
||||||
|
|
||||||
<!--property OOMScoreAdjust is not documented!-->
|
<!--property OOMScoreAdjust is not documented!-->
|
||||||
|
|
||||||
<!--property CoredumpFilter is not documented!-->
|
<!--property CoredumpFilter is not documented!-->
|
||||||
@ -6987,6 +6966,8 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="RootVerity"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="RootVerity"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImages"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MountImages"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MountImages"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="OOMScoreAdjust"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="OOMScoreAdjust"/>
|
||||||
@ -7690,6 +7671,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly s RootVerity = '...';
|
readonly s RootVerity = '...';
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
|
readonly a(sba(ss)) ExtensionImages = [...];
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly a(ssba(ss)) MountImages = [...];
|
readonly a(ssba(ss)) MountImages = [...];
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
|
||||||
readonly i OOMScoreAdjust = ...;
|
readonly i OOMScoreAdjust = ...;
|
||||||
@ -8137,24 +8120,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
|
|
||||||
<!--property WorkingDirectory is not documented!-->
|
<!--property WorkingDirectory is not documented!-->
|
||||||
|
|
||||||
<!--property RootDirectory is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootImage is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootImageOptions is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootHash is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootHashPath is not documented!-->
|
<!--property RootHashPath is not documented!-->
|
||||||
|
|
||||||
<!--property RootHashSignature is not documented!-->
|
|
||||||
|
|
||||||
<!--property RootHashSignaturePath is not documented!-->
|
<!--property RootHashSignaturePath is not documented!-->
|
||||||
|
|
||||||
<!--property RootVerity is not documented!-->
|
|
||||||
|
|
||||||
<!--property MountImages is not documented!-->
|
|
||||||
|
|
||||||
<!--property OOMScoreAdjust is not documented!-->
|
<!--property OOMScoreAdjust is not documented!-->
|
||||||
|
|
||||||
<!--property CoredumpFilter is not documented!-->
|
<!--property CoredumpFilter is not documented!-->
|
||||||
@ -8625,6 +8594,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="RootVerity"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="RootVerity"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="ExtensionImages"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MountImages"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MountImages"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="OOMScoreAdjust"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="OOMScoreAdjust"/>
|
||||||
|
@ -433,6 +433,48 @@
|
|||||||
|
|
||||||
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>ExtensionImages=</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>This setting is similar to <varname>MountImages=</varname> in that it mounts a file
|
||||||
|
system hierarchy from a block device node or loopback file, but instead of providing a destination path,
|
||||||
|
an overlay will be set up. This option expects a whitespace separated list of mount definitions. Each
|
||||||
|
definition consists of a source path, optionally followed by a colon and a list of mount options.</para>
|
||||||
|
|
||||||
|
<para>A read-only OverlayFS will be set up on top of <filename>/usr/</filename> and
|
||||||
|
<filename>/opt/</filename> hierarchies from the root. The order in which the images are listed
|
||||||
|
will determine the order in which the overlay is laid down: images specified first to last will result
|
||||||
|
in overlayfs layers bottom to top.</para>
|
||||||
|
|
||||||
|
<para>Mount options may be defined as a single comma-separated list of options, in which case they
|
||||||
|
will be implicitly applied to the root partition on the image, or a series of colon-separated tuples
|
||||||
|
of partition name and mount options. Valid partition names and mount options are the same as for
|
||||||
|
<varname>RootImageOptions=</varname> setting described above.</para>
|
||||||
|
|
||||||
|
<para>Each mount definition may be prefixed with <literal>-</literal>, in which case it will be
|
||||||
|
ignored when its source path does not exist. The source argument is a path to a block device node or
|
||||||
|
regular file. If the source path contains a <literal>:</literal>, it needs to be escaped as
|
||||||
|
<literal>\:</literal>. The device node or file system image file needs to follow the same rules as
|
||||||
|
specified for <varname>RootImage=</varname>. Any mounts created with this option are specific to the
|
||||||
|
unit, and are not visible in the host's mount table.</para>
|
||||||
|
|
||||||
|
<para>These settings may be used more than once, each usage appends to the unit's list of image
|
||||||
|
paths. If the empty string is assigned, the entire list of mount paths defined prior to this is
|
||||||
|
reset.</para>
|
||||||
|
|
||||||
|
<para>When <varname>DevicePolicy=</varname> is set to <literal>closed</literal> or
|
||||||
|
<literal>strict</literal>, or set to <literal>auto</literal> and <varname>DeviceAllow=</varname> is
|
||||||
|
set, then this setting adds <filename>/dev/loop-control</filename> with <constant>rw</constant> mode,
|
||||||
|
<literal>block-loop</literal> and <literal>block-blkext</literal> with <constant>rwm</constant> mode
|
||||||
|
to <varname>DeviceAllow=</varname>. See
|
||||||
|
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||||
|
for the details about <varname>DevicePolicy=</varname> or <varname>DeviceAllow=</varname>. Also, see
|
||||||
|
<varname>PrivateDevices=</varname> below, as it may change the setting of
|
||||||
|
<varname>DevicePolicy=</varname>.</para>
|
||||||
|
|
||||||
|
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
@ -115,6 +115,11 @@ prefixdir = get_option('prefix')
|
|||||||
if not prefixdir.startswith('/')
|
if not prefixdir.startswith('/')
|
||||||
error('Prefix is not absolute: "@0@"'.format(prefixdir))
|
error('Prefix is not absolute: "@0@"'.format(prefixdir))
|
||||||
endif
|
endif
|
||||||
|
if prefixdir != rootprefixdir and not prefixdir.startswith(rootprefixdir.strip('/') + '/')
|
||||||
|
error('Prefix is not below root prefix (now rootprefix=@0@ prefix=@1@)'.format(
|
||||||
|
rootprefixdir, prefixdir))
|
||||||
|
endif
|
||||||
|
|
||||||
bindir = join_paths(prefixdir, get_option('bindir'))
|
bindir = join_paths(prefixdir, get_option('bindir'))
|
||||||
libdir = join_paths(prefixdir, get_option('libdir'))
|
libdir = join_paths(prefixdir, get_option('libdir'))
|
||||||
sysconfdir = join_paths(prefixdir, get_option('sysconfdir'))
|
sysconfdir = join_paths(prefixdir, get_option('sysconfdir'))
|
||||||
|
@ -45,11 +45,14 @@ int reset_signal_mask(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) {
|
int sigaction_many_internal(const struct sigaction *sa, ...) {
|
||||||
int r = 0;
|
int sig, r = 0;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, sa);
|
||||||
|
|
||||||
/* negative signal ends the list. 0 signal is skipped. */
|
/* negative signal ends the list. 0 signal is skipped. */
|
||||||
for (; sig >= 0; sig = va_arg(ap, int)) {
|
while ((sig = va_arg(ap, int)) >= 0) {
|
||||||
|
|
||||||
if (sig == 0)
|
if (sig == 0)
|
||||||
continue;
|
continue;
|
||||||
@ -60,49 +63,6 @@ static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sigaction_many(const struct sigaction *sa, ...) {
|
|
||||||
va_list ap;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
va_start(ap, sa);
|
|
||||||
r = sigaction_many_ap(sa, 0, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ignore_signals(int sig, ...) {
|
|
||||||
|
|
||||||
static const struct sigaction sa = {
|
|
||||||
.sa_handler = SIG_IGN,
|
|
||||||
.sa_flags = SA_RESTART,
|
|
||||||
};
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
va_start(ap, sig);
|
|
||||||
r = sigaction_many_ap(&sa, sig, ap);
|
|
||||||
va_end(ap);
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
int default_signals(int sig, ...) {
|
|
||||||
|
|
||||||
static const struct sigaction sa = {
|
|
||||||
.sa_handler = SIG_DFL,
|
|
||||||
.sa_flags = SA_RESTART,
|
|
||||||
};
|
|
||||||
|
|
||||||
va_list ap;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
va_start(ap, sig);
|
|
||||||
r = sigaction_many_ap(&sa, sig, ap);
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
@ -8,9 +8,28 @@
|
|||||||
int reset_all_signal_handlers(void);
|
int reset_all_signal_handlers(void);
|
||||||
int reset_signal_mask(void);
|
int reset_signal_mask(void);
|
||||||
|
|
||||||
int ignore_signals(int sig, ...);
|
int sigaction_many_internal(const struct sigaction *sa, ...);
|
||||||
int default_signals(int sig, ...);
|
|
||||||
int sigaction_many(const struct sigaction *sa, ...);
|
#define ignore_signals(...) \
|
||||||
|
sigaction_many_internal( \
|
||||||
|
&(const struct sigaction) { \
|
||||||
|
.sa_handler = SIG_IGN, \
|
||||||
|
.sa_flags = SA_RESTART \
|
||||||
|
}, \
|
||||||
|
__VA_ARGS__, \
|
||||||
|
-1)
|
||||||
|
|
||||||
|
#define default_signals(...) \
|
||||||
|
sigaction_many_internal( \
|
||||||
|
&(const struct sigaction) { \
|
||||||
|
.sa_handler = SIG_DFL, \
|
||||||
|
.sa_flags = SA_RESTART \
|
||||||
|
}, \
|
||||||
|
__VA_ARGS__, \
|
||||||
|
-1)
|
||||||
|
|
||||||
|
#define sigaction_many(sa, ...) \
|
||||||
|
sigaction_many_internal(sa, __VA_ARGS__, -1)
|
||||||
|
|
||||||
int sigset_add_many(sigset_t *ss, ...);
|
int sigset_add_many(sigset_t *ss, ...);
|
||||||
int sigprocmask_many(int how, sigset_t *old, ...);
|
int sigprocmask_many(int how, sigset_t *old, ...);
|
||||||
|
@ -1623,20 +1623,20 @@ CGroupMask unit_get_ancestor_disable_mask(Unit *u) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CGroupMask unit_get_target_mask(Unit *u) {
|
CGroupMask unit_get_target_mask(Unit *u) {
|
||||||
CGroupMask mask;
|
CGroupMask own_mask, mask;
|
||||||
|
|
||||||
/* This returns the cgroup mask of all controllers to enable
|
/* This returns the cgroup mask of all controllers to enable for a specific cgroup, i.e. everything
|
||||||
* for a specific cgroup, i.e. everything it needs itself,
|
* it needs itself, plus all that its children need, plus all that its siblings need. This is
|
||||||
* plus all that its children need, plus all that its siblings
|
* primarily useful on the legacy cgroup hierarchy, where we need to duplicate each cgroup in each
|
||||||
* need. This is primarily useful on the legacy cgroup
|
|
||||||
* hierarchy, where we need to duplicate each cgroup in each
|
|
||||||
* hierarchy that shall be enabled for it. */
|
* hierarchy that shall be enabled for it. */
|
||||||
|
|
||||||
mask = unit_get_own_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u);
|
own_mask = unit_get_own_mask(u);
|
||||||
|
|
||||||
if (mask & CGROUP_MASK_BPF_FIREWALL & ~u->manager->cgroup_supported)
|
if (own_mask & CGROUP_MASK_BPF_FIREWALL & ~u->manager->cgroup_supported)
|
||||||
emit_bpf_firewall_warning(u);
|
emit_bpf_firewall_warning(u);
|
||||||
|
|
||||||
|
mask = own_mask | unit_get_members_mask(u) | unit_get_siblings_mask(u);
|
||||||
|
|
||||||
mask &= u->manager->cgroup_supported;
|
mask &= u->manager->cgroup_supported;
|
||||||
mask &= ~unit_get_ancestor_disable_mask(u);
|
mask &= ~unit_get_ancestor_disable_mask(u);
|
||||||
|
|
||||||
|
@ -996,6 +996,60 @@ static int property_get_mount_images(
|
|||||||
return sd_bus_message_close_container(reply);
|
return sd_bus_message_close_container(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int property_get_extension_images(
|
||||||
|
sd_bus *bus,
|
||||||
|
const char *path,
|
||||||
|
const char *interface,
|
||||||
|
const char *property,
|
||||||
|
sd_bus_message *reply,
|
||||||
|
void *userdata,
|
||||||
|
sd_bus_error *error) {
|
||||||
|
|
||||||
|
ExecContext *c = userdata;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(bus);
|
||||||
|
assert(c);
|
||||||
|
assert(property);
|
||||||
|
assert(reply);
|
||||||
|
|
||||||
|
r = sd_bus_message_open_container(reply, 'a', "(sba(ss))");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < c->n_extension_images; i++) {
|
||||||
|
MountOptions *m;
|
||||||
|
|
||||||
|
r = sd_bus_message_open_container(reply, SD_BUS_TYPE_STRUCT, "sba(ss)");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
r = sd_bus_message_append(
|
||||||
|
reply, "sb",
|
||||||
|
c->extension_images[i].source,
|
||||||
|
c->extension_images[i].ignore_enoent);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
r = sd_bus_message_open_container(reply, 'a', "(ss)");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
LIST_FOREACH(mount_options, m, c->extension_images[i].mount_options) {
|
||||||
|
r = sd_bus_message_append(reply, "(ss)",
|
||||||
|
partition_designator_to_string(m->partition_designator),
|
||||||
|
m->options);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
r = sd_bus_message_close_container(reply);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
r = sd_bus_message_close_container(reply);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sd_bus_message_close_container(reply);
|
||||||
|
}
|
||||||
|
|
||||||
const sd_bus_vtable bus_exec_vtable[] = {
|
const sd_bus_vtable bus_exec_vtable[] = {
|
||||||
SD_BUS_VTABLE_START(0),
|
SD_BUS_VTABLE_START(0),
|
||||||
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
@ -1044,6 +1098,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
|||||||
SD_BUS_PROPERTY("RootHashSignature", "ay", property_get_root_hash_sig, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootHashSignature", "ay", property_get_root_hash_sig, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootHashSignaturePath", "s", NULL, offsetof(ExecContext, root_hash_sig_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootHashSignaturePath", "s", NULL, offsetof(ExecContext, root_hash_sig_path), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
|
SD_BUS_PROPERTY("ExtensionImages", "a(sba(ss))", property_get_extension_images, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("MountImages", "a(ssba(ss))", property_get_mount_images, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("MountImages", "a(ssba(ss))", property_get_mount_images, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
SD_BUS_PROPERTY("CoredumpFilter", "t", property_get_coredump_filter, 0, SD_BUS_VTABLE_PROPERTY_CONST),
|
||||||
@ -3356,6 +3411,7 @@ int bus_exec_context_set_transient_property(
|
|||||||
.destination = destination,
|
.destination = destination,
|
||||||
.mount_options = options,
|
.mount_options = options,
|
||||||
.ignore_enoent = permissive,
|
.ignore_enoent = permissive,
|
||||||
|
.type = MOUNT_IMAGE_DISCRETE,
|
||||||
});
|
});
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -3389,6 +3445,95 @@ int bus_exec_context_set_transient_property(
|
|||||||
|
|
||||||
mount_images = mount_image_free_many(mount_images, &n_mount_images);
|
mount_images = mount_image_free_many(mount_images, &n_mount_images);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
} else if (streq(name, "ExtensionImages")) {
|
||||||
|
_cleanup_free_ char *format_str = NULL;
|
||||||
|
MountImage *extension_images = NULL;
|
||||||
|
size_t n_extension_images = 0;
|
||||||
|
|
||||||
|
r = sd_bus_message_enter_container(message, 'a', "(sba(ss))");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
|
||||||
|
_cleanup_free_ char *source_escaped = NULL;
|
||||||
|
char *source, *tuple;
|
||||||
|
int permissive;
|
||||||
|
|
||||||
|
r = sd_bus_message_enter_container(message, 'r', "sba(ss)");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_bus_message_read(message, "sb", &source, &permissive);
|
||||||
|
if (r <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!path_is_absolute(source))
|
||||||
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not absolute.", source);
|
||||||
|
if (!path_is_normalized(source))
|
||||||
|
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not normalized.", source);
|
||||||
|
|
||||||
|
/* Need to store them in the unit with the escapes, so that they can be parsed again */
|
||||||
|
source_escaped = shell_escape(source, ":");
|
||||||
|
if (!source_escaped)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
tuple = strjoin(format_str,
|
||||||
|
format_str ? " " : "",
|
||||||
|
permissive ? "-" : "",
|
||||||
|
source_escaped);
|
||||||
|
if (!tuple)
|
||||||
|
return -ENOMEM;
|
||||||
|
free_and_replace(format_str, tuple);
|
||||||
|
|
||||||
|
r = bus_read_mount_options(message, error, &options, &format_str, ":");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_bus_message_exit_container(message);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = mount_image_add(&extension_images, &n_extension_images,
|
||||||
|
&(MountImage) {
|
||||||
|
.source = source,
|
||||||
|
.mount_options = options,
|
||||||
|
.ignore_enoent = permissive,
|
||||||
|
.type = MOUNT_IMAGE_EXTENSION,
|
||||||
|
});
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = sd_bus_message_exit_container(message);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||||
|
if (n_extension_images == 0) {
|
||||||
|
c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
|
||||||
|
|
||||||
|
unit_write_settingf(u, flags, name, "%s=", name);
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < n_extension_images; ++i) {
|
||||||
|
r = mount_image_add(&c->extension_images, &c->n_extension_images, &extension_images[i]);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
unit_write_settingf(u, flags|UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS,
|
||||||
|
name,
|
||||||
|
"%s=%s",
|
||||||
|
name,
|
||||||
|
format_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension_images = mount_image_free_many(extension_images, &n_extension_images);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1268,7 +1268,7 @@ static int setup_pam(
|
|||||||
if (setresuid(uid, uid, uid) < 0)
|
if (setresuid(uid, uid, uid) < 0)
|
||||||
log_warning_errno(errno, "Failed to setresuid() in sd-pam: %m");
|
log_warning_errno(errno, "Failed to setresuid() in sd-pam: %m");
|
||||||
|
|
||||||
(void) ignore_signals(SIGPIPE, -1);
|
(void) ignore_signals(SIGPIPE);
|
||||||
|
|
||||||
/* Wait until our parent died. This will only work if
|
/* Wait until our parent died. This will only work if
|
||||||
* the above setresuid() succeeds, otherwise the kernel
|
* the above setresuid() succeeds, otherwise the kernel
|
||||||
@ -2018,6 +2018,9 @@ bool exec_needs_mount_namespace(
|
|||||||
if (context->n_mount_images > 0)
|
if (context->n_mount_images > 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (context->n_extension_images > 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (!IN_SET(context->mount_flags, 0, MS_SHARED))
|
if (!IN_SET(context->mount_flags, 0, MS_SHARED))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -3235,6 +3238,8 @@ static int apply_mount_namespace(
|
|||||||
context->root_hash, context->root_hash_size, context->root_hash_path,
|
context->root_hash, context->root_hash_size, context->root_hash_path,
|
||||||
context->root_hash_sig, context->root_hash_sig_size, context->root_hash_sig_path,
|
context->root_hash_sig, context->root_hash_sig_size, context->root_hash_sig_path,
|
||||||
context->root_verity,
|
context->root_verity,
|
||||||
|
context->extension_images,
|
||||||
|
context->n_extension_images,
|
||||||
propagate_dir,
|
propagate_dir,
|
||||||
incoming_dir,
|
incoming_dir,
|
||||||
root_dir || root_image ? params->notify_socket : NULL,
|
root_dir || root_image ? params->notify_socket : NULL,
|
||||||
@ -3728,16 +3733,14 @@ static int exec_child(
|
|||||||
|
|
||||||
rename_process_from_path(command->path);
|
rename_process_from_path(command->path);
|
||||||
|
|
||||||
/* We reset exactly these signals, since they are the
|
/* We reset exactly these signals, since they are the only ones we set to SIG_IGN in the main
|
||||||
* only ones we set to SIG_IGN in the main daemon. All
|
* daemon. All others we leave untouched because we set them to SIG_DFL or a valid handler initially,
|
||||||
* others we leave untouched because we set them to
|
* both of which will be demoted to SIG_DFL. */
|
||||||
* SIG_DFL or a valid handler initially, both of which
|
|
||||||
* will be demoted to SIG_DFL. */
|
|
||||||
(void) default_signals(SIGNALS_CRASH_HANDLER,
|
(void) default_signals(SIGNALS_CRASH_HANDLER,
|
||||||
SIGNALS_IGNORE, -1);
|
SIGNALS_IGNORE);
|
||||||
|
|
||||||
if (context->ignore_sigpipe)
|
if (context->ignore_sigpipe)
|
||||||
(void) ignore_signals(SIGPIPE, -1);
|
(void) ignore_signals(SIGPIPE);
|
||||||
|
|
||||||
r = reset_signal_mask();
|
r = reset_signal_mask();
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@ -4821,6 +4824,7 @@ void exec_context_done(ExecContext *c) {
|
|||||||
c->root_hash_sig_size = 0;
|
c->root_hash_sig_size = 0;
|
||||||
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
c->root_hash_sig_path = mfree(c->root_hash_sig_path);
|
||||||
c->root_verity = mfree(c->root_verity);
|
c->root_verity = mfree(c->root_verity);
|
||||||
|
c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
|
||||||
c->tty_path = mfree(c->tty_path);
|
c->tty_path = mfree(c->tty_path);
|
||||||
c->syslog_identifier = mfree(c->syslog_identifier);
|
c->syslog_identifier = mfree(c->syslog_identifier);
|
||||||
c->user = mfree(c->user);
|
c->user = mfree(c->user);
|
||||||
@ -5663,6 +5667,19 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
|
|||||||
strempty(o->options));
|
strempty(o->options));
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < c->n_extension_images; i++) {
|
||||||
|
MountOptions *o;
|
||||||
|
|
||||||
|
fprintf(f, "%sExtensionImages: %s%s", prefix,
|
||||||
|
c->extension_images[i].ignore_enoent ? "-": "",
|
||||||
|
c->extension_images[i].source);
|
||||||
|
LIST_FOREACH(mount_options, o, c->extension_images[i].mount_options)
|
||||||
|
fprintf(f, ":%s:%s",
|
||||||
|
partition_designator_to_string(o->partition_designator),
|
||||||
|
strempty(o->options));
|
||||||
|
fprintf(f, "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool exec_context_maintains_privileges(const ExecContext *c) {
|
bool exec_context_maintains_privileges(const ExecContext *c) {
|
||||||
|
@ -251,6 +251,8 @@ struct ExecContext {
|
|||||||
size_t n_temporary_filesystems;
|
size_t n_temporary_filesystems;
|
||||||
MountImage *mount_images;
|
MountImage *mount_images;
|
||||||
size_t n_mount_images;
|
size_t n_mount_images;
|
||||||
|
MountImage *extension_images;
|
||||||
|
size_t n_extension_images;
|
||||||
|
|
||||||
uint64_t capability_bounding_set;
|
uint64_t capability_bounding_set;
|
||||||
uint64_t capability_ambient_set;
|
uint64_t capability_ambient_set;
|
||||||
|
@ -28,6 +28,7 @@ $1.RootImageOptions, config_parse_root_image_options,
|
|||||||
$1.RootHash, config_parse_exec_root_hash, 0, offsetof($1, exec_context)
|
$1.RootHash, config_parse_exec_root_hash, 0, offsetof($1, exec_context)
|
||||||
$1.RootHashSignature, config_parse_exec_root_hash_sig, 0, offsetof($1, exec_context)
|
$1.RootHashSignature, config_parse_exec_root_hash_sig, 0, offsetof($1, exec_context)
|
||||||
$1.RootVerity, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_verity)
|
$1.RootVerity, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_verity)
|
||||||
|
$1.ExtensionImages, config_parse_extension_images, 0, offsetof($1, exec_context)
|
||||||
$1.MountImages, config_parse_mount_images, 0, offsetof($1, exec_context)
|
$1.MountImages, config_parse_mount_images, 0, offsetof($1, exec_context)
|
||||||
$1.User, config_parse_user_group_compat, 0, offsetof($1, exec_context.user)
|
$1.User, config_parse_user_group_compat, 0, offsetof($1, exec_context.user)
|
||||||
$1.Group, config_parse_user_group_compat, 0, offsetof($1, exec_context.group)
|
$1.Group, config_parse_user_group_compat, 0, offsetof($1, exec_context.group)
|
||||||
|
@ -5117,6 +5117,148 @@ int config_parse_mount_images(
|
|||||||
.destination = dresolved,
|
.destination = dresolved,
|
||||||
.mount_options = options,
|
.mount_options = options,
|
||||||
.ignore_enoent = permissive,
|
.ignore_enoent = permissive,
|
||||||
|
.type = MOUNT_IMAGE_DISCRETE,
|
||||||
|
});
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_parse_extension_images(
|
||||||
|
const char *unit,
|
||||||
|
const char *filename,
|
||||||
|
unsigned line,
|
||||||
|
const char *section,
|
||||||
|
unsigned section_line,
|
||||||
|
const char *lvalue,
|
||||||
|
int ltype,
|
||||||
|
const char *rvalue,
|
||||||
|
void *data,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
ExecContext *c = data;
|
||||||
|
const Unit *u = userdata;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(filename);
|
||||||
|
assert(lvalue);
|
||||||
|
assert(rvalue);
|
||||||
|
assert(data);
|
||||||
|
|
||||||
|
if (isempty(rvalue)) {
|
||||||
|
/* Empty assignment resets the list */
|
||||||
|
c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const char *p = rvalue;;) {
|
||||||
|
_cleanup_free_ char *source = NULL, *tuple = NULL, *sresolved = NULL;
|
||||||
|
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
|
||||||
|
bool permissive = false;
|
||||||
|
const char *q = NULL;
|
||||||
|
char *s = NULL;
|
||||||
|
|
||||||
|
r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
|
||||||
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||||
|
"Invalid syntax %s=%s, ignoring: %m", lvalue, rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (r == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
q = tuple;
|
||||||
|
r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
|
||||||
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||||
|
"Invalid syntax in %s=, ignoring: %s", lvalue, tuple);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (r == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
s = source;
|
||||||
|
if (s[0] == '-') {
|
||||||
|
permissive = true;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = unit_full_printf(u, s, &sresolved);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||||
|
"Failed to resolve unit specifiers in \"%s\", ignoring: %m", s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = path_simplify_and_warn(sresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue);
|
||||||
|
if (r < 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *partition = NULL, *mount_options = NULL, *mount_options_resolved = NULL;
|
||||||
|
MountOptions *o = NULL;
|
||||||
|
PartitionDesignator partition_designator;
|
||||||
|
|
||||||
|
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
|
||||||
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", q);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
/* Single set of options, applying to the root partition/single filesystem */
|
||||||
|
if (r == 1) {
|
||||||
|
r = unit_full_printf(u, partition, &mount_options_resolved);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", partition);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
o = new(MountOptions, 1);
|
||||||
|
if (!o)
|
||||||
|
return log_oom();
|
||||||
|
*o = (MountOptions) {
|
||||||
|
.partition_designator = PARTITION_ROOT,
|
||||||
|
.options = TAKE_PTR(mount_options_resolved),
|
||||||
|
};
|
||||||
|
LIST_APPEND(mount_options, options, o);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
partition_designator = partition_designator_from_string(partition);
|
||||||
|
if (partition_designator < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid partition name %s, ignoring", partition);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
r = unit_full_printf(u, mount_options, &mount_options_resolved);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", mount_options);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
o = new(MountOptions, 1);
|
||||||
|
if (!o)
|
||||||
|
return log_oom();
|
||||||
|
*o = (MountOptions) {
|
||||||
|
.partition_designator = partition_designator,
|
||||||
|
.options = TAKE_PTR(mount_options_resolved),
|
||||||
|
};
|
||||||
|
LIST_APPEND(mount_options, options, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = mount_image_add(&c->extension_images, &c->n_extension_images,
|
||||||
|
&(MountImage) {
|
||||||
|
.source = sresolved,
|
||||||
|
.mount_options = options,
|
||||||
|
.ignore_enoent = permissive,
|
||||||
|
.type = MOUNT_IMAGE_EXTENSION,
|
||||||
});
|
});
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
@ -138,6 +138,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_timeout_abort);
|
|||||||
CONFIG_PARSER_PROTOTYPE(config_parse_swap_priority);
|
CONFIG_PARSER_PROTOTYPE(config_parse_swap_priority);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_mount_images);
|
CONFIG_PARSER_PROTOTYPE(config_parse_mount_images);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_socket_timestamping);
|
CONFIG_PARSER_PROTOTYPE(config_parse_socket_timestamping);
|
||||||
|
CONFIG_PARSER_PROTOTYPE(config_parse_extension_images);
|
||||||
|
|
||||||
/* gperf prototypes */
|
/* gperf prototypes */
|
||||||
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
|
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
|
||||||
|
@ -323,9 +323,8 @@ static void install_crash_handler(void) {
|
|||||||
};
|
};
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
/* We ignore the return value here, since, we don't mind if we
|
/* We ignore the return value here, since, we don't mind if we cannot set up a crash handler */
|
||||||
* cannot set up a crash handler */
|
r = sigaction_many(&sa, SIGNALS_CRASH_HANDLER);
|
||||||
r = sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_debug_errno(r, "I had trouble setting up the crash handler, ignoring: %m");
|
log_debug_errno(r, "I had trouble setting up the crash handler, ignoring: %m");
|
||||||
}
|
}
|
||||||
@ -2756,7 +2755,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
/* Reset all signal handlers. */
|
/* Reset all signal handlers. */
|
||||||
(void) reset_all_signal_handlers();
|
(void) reset_all_signal_handlers();
|
||||||
(void) ignore_signals(SIGNALS_IGNORE, -1);
|
(void) ignore_signals(SIGNALS_IGNORE);
|
||||||
|
|
||||||
(void) parse_configuration(&saved_rlimit_nofile, &saved_rlimit_memlock);
|
(void) parse_configuration(&saved_rlimit_nofile, &saved_rlimit_memlock);
|
||||||
|
|
||||||
|
@ -11,6 +11,9 @@
|
|||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "base-filesystem.h"
|
#include "base-filesystem.h"
|
||||||
#include "dev-setup.h"
|
#include "dev-setup.h"
|
||||||
|
#include "env-util.h"
|
||||||
|
#include "escape.h"
|
||||||
|
#include "extension-release.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
@ -24,6 +27,7 @@
|
|||||||
#include "namespace-util.h"
|
#include "namespace-util.h"
|
||||||
#include "namespace.h"
|
#include "namespace.h"
|
||||||
#include "nulstr-util.h"
|
#include "nulstr-util.h"
|
||||||
|
#include "os-util.h"
|
||||||
#include "path-util.h"
|
#include "path-util.h"
|
||||||
#include "selinux-util.h"
|
#include "selinux-util.h"
|
||||||
#include "socket-util.h"
|
#include "socket-util.h"
|
||||||
@ -41,6 +45,7 @@
|
|||||||
typedef enum MountMode {
|
typedef enum MountMode {
|
||||||
/* This is ordered by priority! */
|
/* This is ordered by priority! */
|
||||||
INACCESSIBLE,
|
INACCESSIBLE,
|
||||||
|
OVERLAY_MOUNT,
|
||||||
MOUNT_IMAGES,
|
MOUNT_IMAGES,
|
||||||
BIND_MOUNT,
|
BIND_MOUNT,
|
||||||
BIND_MOUNT_RECURSIVE,
|
BIND_MOUNT_RECURSIVE,
|
||||||
@ -57,6 +62,7 @@ typedef enum MountMode {
|
|||||||
NOEXEC,
|
NOEXEC,
|
||||||
EXEC,
|
EXEC,
|
||||||
TMPFS,
|
TMPFS,
|
||||||
|
EXTENSION_IMAGES, /* Mounted outside the root directory, and used by subsequent mounts */
|
||||||
READWRITE_IMPLICIT, /* Should have the lowest priority. */
|
READWRITE_IMPLICIT, /* Should have the lowest priority. */
|
||||||
_MOUNT_MODE_MAX,
|
_MOUNT_MODE_MAX,
|
||||||
} MountMode;
|
} MountMode;
|
||||||
@ -205,6 +211,7 @@ static const MountEntry protect_system_strict_table[] = {
|
|||||||
|
|
||||||
static const char * const mount_mode_table[_MOUNT_MODE_MAX] = {
|
static const char * const mount_mode_table[_MOUNT_MODE_MAX] = {
|
||||||
[INACCESSIBLE] = "inaccessible",
|
[INACCESSIBLE] = "inaccessible",
|
||||||
|
[OVERLAY_MOUNT] = "overlay",
|
||||||
[BIND_MOUNT] = "bind",
|
[BIND_MOUNT] = "bind",
|
||||||
[BIND_MOUNT_RECURSIVE] = "rbind",
|
[BIND_MOUNT_RECURSIVE] = "rbind",
|
||||||
[PRIVATE_TMP] = "private-tmp",
|
[PRIVATE_TMP] = "private-tmp",
|
||||||
@ -392,6 +399,101 @@ static int append_mount_images(MountEntry **p, const MountImage *mount_images, s
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int append_extension_images(
|
||||||
|
MountEntry **p,
|
||||||
|
const char *root,
|
||||||
|
const char *extension_dir,
|
||||||
|
char **hierarchies,
|
||||||
|
const MountImage *mount_images,
|
||||||
|
size_t n) {
|
||||||
|
|
||||||
|
_cleanup_strv_free_ char **overlays = NULL;
|
||||||
|
char **hierarchy;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(p);
|
||||||
|
assert(extension_dir);
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Prepare a list of overlays, that will have as each element a string suitable for being
|
||||||
|
* passed as a lowerdir= parameter, so start with the hierachy on the root.
|
||||||
|
* The overlays vector will have the same number of elements and will correspond to the
|
||||||
|
* hierarchies vector, so they can be iterated upon together. */
|
||||||
|
STRV_FOREACH(hierarchy, hierarchies) {
|
||||||
|
_cleanup_free_ char *prefixed_hierarchy = NULL;
|
||||||
|
|
||||||
|
prefixed_hierarchy = path_join(root, *hierarchy);
|
||||||
|
if (!prefixed_hierarchy)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
r = strv_consume(&overlays, TAKE_PTR(prefixed_hierarchy));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First, prepare a mount for each image, but these won't be visible to the unit, instead
|
||||||
|
* they will be mounted in our propagate directory, and used as a source for the overlay. */
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
_cleanup_free_ char *mount_point = NULL;
|
||||||
|
const MountImage *m = mount_images + i;
|
||||||
|
|
||||||
|
r = asprintf(&mount_point, "%s/%zu", extension_dir, i);
|
||||||
|
if (r < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (size_t j = 0; hierarchies && hierarchies[j]; ++j) {
|
||||||
|
_cleanup_free_ char *prefixed_hierarchy = NULL, *escaped = NULL, *lowerdir = NULL;
|
||||||
|
|
||||||
|
prefixed_hierarchy = path_join(mount_point, hierarchies[j]);
|
||||||
|
if (!prefixed_hierarchy)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
escaped = shell_escape(prefixed_hierarchy, ",:");
|
||||||
|
if (!escaped)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* Note that lowerdir= parameters are in 'reverse' order, so the
|
||||||
|
* top-most directory in the overlay comes first in the list. */
|
||||||
|
lowerdir = strjoin(escaped, ":", overlays[j]);
|
||||||
|
if (!lowerdir)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
free_and_replace(overlays[j], lowerdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
*((*p)++) = (MountEntry) {
|
||||||
|
.path_malloc = TAKE_PTR(mount_point),
|
||||||
|
.image_options = m->mount_options,
|
||||||
|
.ignore = m->ignore_enoent,
|
||||||
|
.source_const = m->source,
|
||||||
|
.mode = EXTENSION_IMAGES,
|
||||||
|
.has_prefix = true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Then, for each hierarchy, prepare an overlay with the list of lowerdir= strings
|
||||||
|
* set up earlier. */
|
||||||
|
for (size_t i = 0; hierarchies && hierarchies[i]; ++i) {
|
||||||
|
_cleanup_free_ char *prefixed_hierarchy = NULL;
|
||||||
|
|
||||||
|
prefixed_hierarchy = path_join(root, hierarchies[i]);
|
||||||
|
if (!prefixed_hierarchy)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*((*p)++) = (MountEntry) {
|
||||||
|
.path_malloc = TAKE_PTR(prefixed_hierarchy),
|
||||||
|
.options_malloc = TAKE_PTR(overlays[i]),
|
||||||
|
.mode = OVERLAY_MOUNT,
|
||||||
|
.has_prefix = true,
|
||||||
|
.ignore = true, /* If the source image doesn't set the ignore bit it will fail earlier. */
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int append_tmpfs_mounts(MountEntry **p, const TemporaryFileSystem *tmpfs, size_t n) {
|
static int append_tmpfs_mounts(MountEntry **p, const TemporaryFileSystem *tmpfs, size_t n) {
|
||||||
assert(p);
|
assert(p);
|
||||||
|
|
||||||
@ -494,6 +596,12 @@ static int append_protect_system(MountEntry **p, ProtectSystem protect_system, b
|
|||||||
static int mount_path_compare(const MountEntry *a, const MountEntry *b) {
|
static int mount_path_compare(const MountEntry *a, const MountEntry *b) {
|
||||||
int d;
|
int d;
|
||||||
|
|
||||||
|
/* EXTENSION_IMAGES will be used by other mounts as a base, so sort them first
|
||||||
|
* regardless of the prefix - they are set up in the propagate directory anyway */
|
||||||
|
d = -CMP(a->mode == EXTENSION_IMAGES, b->mode == EXTENSION_IMAGES);
|
||||||
|
if (d != 0)
|
||||||
|
return d;
|
||||||
|
|
||||||
/* If the paths are not equal, then order prefixes first */
|
/* If the paths are not equal, then order prefixes first */
|
||||||
d = path_compare(mount_entry_path(a), mount_entry_path(b));
|
d = path_compare(mount_entry_path(a), mount_entry_path(b));
|
||||||
if (d != 0)
|
if (d != 0)
|
||||||
@ -640,7 +748,8 @@ static void drop_outside_root(const char *root_directory, MountEntry *m, size_t
|
|||||||
|
|
||||||
for (f = m, t = m; f < m + *n; f++) {
|
for (f = m, t = m; f < m + *n; f++) {
|
||||||
|
|
||||||
if (!path_startswith(mount_entry_path(f), root_directory)) {
|
/* ExtensionImages bases are opened in /run/systemd/unit-extensions on the host */
|
||||||
|
if (f->mode != EXTENSION_IMAGES && !path_startswith(mount_entry_path(f), root_directory)) {
|
||||||
log_debug("%s is outside of root directory.", mount_entry_path(f));
|
log_debug("%s is outside of root directory.", mount_entry_path(f));
|
||||||
mount_entry_done(f);
|
mount_entry_done(f);
|
||||||
continue;
|
continue;
|
||||||
@ -1003,12 +1112,28 @@ static int mount_run(const MountEntry *m) {
|
|||||||
return mount_tmpfs(m);
|
return mount_tmpfs(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mount_images(const MountEntry *m) {
|
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,
|
||||||
|
*host_os_release_sysext_level = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
|
|
||||||
r = verity_dissect_and_mount(mount_entry_source(m), mount_entry_path(m), m->image_options);
|
if (m->mode == EXTENSION_IMAGES) {
|
||||||
|
r = parse_os_release(
|
||||||
|
empty_to_root(root_directory),
|
||||||
|
"ID", &host_os_release_id,
|
||||||
|
"VERSION_ID", &host_os_release_version_id,
|
||||||
|
"SYSEXT_LEVEL", &host_os_release_sysext_level,
|
||||||
|
NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to acquire 'os-release' data of OS tree '%s': %m", empty_to_root(root_directory));
|
||||||
|
}
|
||||||
|
|
||||||
|
r = verity_dissect_and_mount(
|
||||||
|
mount_entry_source(m), mount_entry_path(m), m->image_options,
|
||||||
|
host_os_release_id, host_os_release_version_id, host_os_release_sysext_level);
|
||||||
if (r == -ENOENT && m->ignore)
|
if (r == -ENOENT && m->ignore)
|
||||||
return 0;
|
return 0;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1017,6 +1142,25 @@ static int mount_images(const MountEntry *m) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mount_overlay(const MountEntry *m) {
|
||||||
|
const char *options;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(m);
|
||||||
|
|
||||||
|
options = strjoina("lowerdir=", mount_entry_options(m));
|
||||||
|
|
||||||
|
(void) mkdir_p_label(mount_entry_path(m), 0755);
|
||||||
|
|
||||||
|
r = mount_nofollow_verbose(LOG_DEBUG, "overlay", mount_entry_path(m), "overlay", MS_RDONLY, options);
|
||||||
|
if (r == -ENOENT && m->ignore)
|
||||||
|
return 0;
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int follow_symlink(
|
static int follow_symlink(
|
||||||
const char *root_directory,
|
const char *root_directory,
|
||||||
MountEntry *m) {
|
MountEntry *m) {
|
||||||
@ -1049,7 +1193,7 @@ static int follow_symlink(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apply_mount(
|
static int apply_one_mount(
|
||||||
const char *root_directory,
|
const char *root_directory,
|
||||||
MountEntry *m,
|
MountEntry *m,
|
||||||
const NamespaceInfo *ns_info) {
|
const NamespaceInfo *ns_info) {
|
||||||
@ -1173,7 +1317,13 @@ static int apply_mount(
|
|||||||
return mount_run(m);
|
return mount_run(m);
|
||||||
|
|
||||||
case MOUNT_IMAGES:
|
case MOUNT_IMAGES:
|
||||||
return mount_images(m);
|
return mount_image(m, NULL);
|
||||||
|
|
||||||
|
case EXTENSION_IMAGES:
|
||||||
|
return mount_image(m, root_directory);
|
||||||
|
|
||||||
|
case OVERLAY_MOUNT:
|
||||||
|
return mount_overlay(m);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert_not_reached("Unknown mode");
|
assert_not_reached("Unknown mode");
|
||||||
@ -1317,6 +1467,8 @@ static size_t namespace_calculate_mounts(
|
|||||||
size_t n_bind_mounts,
|
size_t n_bind_mounts,
|
||||||
size_t n_temporary_filesystems,
|
size_t n_temporary_filesystems,
|
||||||
size_t n_mount_images,
|
size_t n_mount_images,
|
||||||
|
size_t n_extension_images,
|
||||||
|
size_t n_hierarchies,
|
||||||
const char* tmp_dir,
|
const char* tmp_dir,
|
||||||
const char* var_tmp_dir,
|
const char* var_tmp_dir,
|
||||||
const char *creds_path,
|
const char *creds_path,
|
||||||
@ -1350,6 +1502,7 @@ static size_t namespace_calculate_mounts(
|
|||||||
strv_length(empty_directories) +
|
strv_length(empty_directories) +
|
||||||
n_bind_mounts +
|
n_bind_mounts +
|
||||||
n_mount_images +
|
n_mount_images +
|
||||||
|
(n_extension_images > 0 ? n_hierarchies + n_extension_images : 0) + /* Mount each image plus an overlay per hierarchy */
|
||||||
n_temporary_filesystems +
|
n_temporary_filesystems +
|
||||||
ns_info->private_dev +
|
ns_info->private_dev +
|
||||||
(ns_info->protect_kernel_tunables ? ELEMENTSOF(protect_kernel_tunables_table) : 0) +
|
(ns_info->protect_kernel_tunables ? ELEMENTSOF(protect_kernel_tunables_table) : 0) +
|
||||||
@ -1378,6 +1531,111 @@ static void normalize_mounts(const char *root_directory, MountEntry *mounts, siz
|
|||||||
drop_nop(mounts, n_mounts);
|
drop_nop(mounts, n_mounts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int apply_mounts(
|
||||||
|
const char *root,
|
||||||
|
const NamespaceInfo *ns_info,
|
||||||
|
MountEntry *mounts,
|
||||||
|
size_t *n_mounts,
|
||||||
|
char **error_path) {
|
||||||
|
|
||||||
|
_cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
|
||||||
|
_cleanup_free_ char **deny_list = NULL;
|
||||||
|
size_t j;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (n_mounts == 0) /* Shortcut: nothing to do */
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
assert(root);
|
||||||
|
assert(mounts);
|
||||||
|
assert(n_mounts);
|
||||||
|
|
||||||
|
/* Open /proc/self/mountinfo now as it may become unavailable if we mount anything on top of
|
||||||
|
* /proc. For example, this is the case with the option: 'InaccessiblePaths=/proc'. */
|
||||||
|
proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
|
||||||
|
if (!proc_self_mountinfo) {
|
||||||
|
if (error_path)
|
||||||
|
*error_path = strdup("/proc/self/mountinfo");
|
||||||
|
return log_debug_errno(errno, "Failed to open /proc/self/mountinfo: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* First round, establish all mounts we need */
|
||||||
|
for (;;) {
|
||||||
|
bool again = false;
|
||||||
|
|
||||||
|
for (MountEntry *m = mounts; m < mounts + *n_mounts; ++m) {
|
||||||
|
|
||||||
|
if (m->applied)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* ExtensionImages are first opened in the propagate directory, not in the root_directory */
|
||||||
|
r = follow_symlink(m->mode != EXTENSION_IMAGES ? root : NULL, m);
|
||||||
|
if (r < 0) {
|
||||||
|
if (error_path && mount_entry_path(m))
|
||||||
|
*error_path = strdup(mount_entry_path(m));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
if (r == 0) {
|
||||||
|
/* We hit a symlinked mount point. The entry got rewritten and might
|
||||||
|
* point to a very different place now. Let's normalize the changed
|
||||||
|
* list, and start from the beginning. After all to mount the entry
|
||||||
|
* at the new location we might need some other mounts first */
|
||||||
|
again = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = apply_one_mount(root, m, ns_info);
|
||||||
|
if (r < 0) {
|
||||||
|
if (error_path && mount_entry_path(m))
|
||||||
|
*error_path = strdup(mount_entry_path(m));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
m->applied = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!again)
|
||||||
|
break;
|
||||||
|
|
||||||
|
normalize_mounts(root, mounts, n_mounts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a deny list we can pass to bind_mount_recursive() */
|
||||||
|
deny_list = new(char*, (*n_mounts)+1);
|
||||||
|
if (!deny_list)
|
||||||
|
return -ENOMEM;
|
||||||
|
for (j = 0; j < *n_mounts; j++)
|
||||||
|
deny_list[j] = (char*) mount_entry_path(mounts+j);
|
||||||
|
deny_list[j] = NULL;
|
||||||
|
|
||||||
|
/* Second round, flip the ro bits if necessary. */
|
||||||
|
for (MountEntry *m = mounts; m < mounts + *n_mounts; ++m) {
|
||||||
|
r = make_read_only(m, deny_list, proc_self_mountinfo);
|
||||||
|
if (r < 0) {
|
||||||
|
if (error_path && mount_entry_path(m))
|
||||||
|
*error_path = strdup(mount_entry_path(m));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Third round, flip the noexec bits with a simplified deny list. */
|
||||||
|
for (j = 0; j < *n_mounts; j++)
|
||||||
|
if (IN_SET((mounts+j)->mode, EXEC, NOEXEC))
|
||||||
|
deny_list[j] = (char*) mount_entry_path(mounts+j);
|
||||||
|
deny_list[j] = NULL;
|
||||||
|
|
||||||
|
for (MountEntry *m = mounts; m < mounts + *n_mounts; ++m) {
|
||||||
|
r = make_noexec(m, deny_list, proc_self_mountinfo);
|
||||||
|
if (r < 0) {
|
||||||
|
if (error_path && mount_entry_path(m))
|
||||||
|
*error_path = strdup(mount_entry_path(m));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static bool root_read_only(
|
static bool root_read_only(
|
||||||
char **read_only_paths,
|
char **read_only_paths,
|
||||||
ProtectSystem protect_system) {
|
ProtectSystem protect_system) {
|
||||||
@ -1514,6 +1772,8 @@ int setup_namespace(
|
|||||||
size_t root_hash_sig_size,
|
size_t root_hash_sig_size,
|
||||||
const char *root_hash_sig_path,
|
const char *root_hash_sig_path,
|
||||||
const char *verity_data_path,
|
const char *verity_data_path,
|
||||||
|
const MountImage *extension_images,
|
||||||
|
size_t n_extension_images,
|
||||||
const char *propagate_dir,
|
const char *propagate_dir,
|
||||||
const char *incoming_dir,
|
const char *incoming_dir,
|
||||||
const char *notify_socket,
|
const char *notify_socket,
|
||||||
@ -1524,9 +1784,10 @@ int setup_namespace(
|
|||||||
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
||||||
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
||||||
_cleanup_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT;
|
_cleanup_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT;
|
||||||
|
_cleanup_strv_free_ char **hierarchies = NULL;
|
||||||
MountEntry *m = NULL, *mounts = NULL;
|
MountEntry *m = NULL, *mounts = NULL;
|
||||||
bool require_prefix = false, setup_propagate = false;
|
bool require_prefix = false, setup_propagate = false;
|
||||||
const char *root;
|
const char *root, *extension_dir = "/run/systemd/unit-extensions";
|
||||||
size_t n_mounts;
|
size_t n_mounts;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -1607,6 +1868,12 @@ int setup_namespace(
|
|||||||
require_prefix = true;
|
require_prefix = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (n_extension_images > 0) {
|
||||||
|
r = parse_env_extension_hierarchies(&hierarchies);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
n_mounts = namespace_calculate_mounts(
|
n_mounts = namespace_calculate_mounts(
|
||||||
ns_info,
|
ns_info,
|
||||||
read_write_paths,
|
read_write_paths,
|
||||||
@ -1618,6 +1885,8 @@ int setup_namespace(
|
|||||||
n_bind_mounts,
|
n_bind_mounts,
|
||||||
n_temporary_filesystems,
|
n_temporary_filesystems,
|
||||||
n_mount_images,
|
n_mount_images,
|
||||||
|
n_extension_images,
|
||||||
|
strv_length(hierarchies),
|
||||||
tmp_dir, var_tmp_dir,
|
tmp_dir, var_tmp_dir,
|
||||||
creds_path,
|
creds_path,
|
||||||
log_namespace,
|
log_namespace,
|
||||||
@ -1685,6 +1954,10 @@ int setup_namespace(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
|
r = append_extension_images(&m, root, extension_dir, hierarchies, extension_images, n_extension_images);
|
||||||
|
if (r < 0)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
if (ns_info->private_dev)
|
if (ns_info->private_dev)
|
||||||
*(m++) = (MountEntry) {
|
*(m++) = (MountEntry) {
|
||||||
.path_const = "/dev",
|
.path_const = "/dev",
|
||||||
@ -1844,6 +2117,12 @@ int setup_namespace(
|
|||||||
if (setup_propagate)
|
if (setup_propagate)
|
||||||
(void) mkdir_p(propagate_dir, 0600);
|
(void) mkdir_p(propagate_dir, 0600);
|
||||||
|
|
||||||
|
if (n_extension_images > 0) {
|
||||||
|
/* ExtensionImages mountpoint directories will be created
|
||||||
|
* while parsing the mounts to create, so have the parent ready */
|
||||||
|
(void) mkdir_p(extension_dir, 0600);
|
||||||
|
}
|
||||||
|
|
||||||
/* Remount / as SLAVE so that nothing now mounted in the namespace
|
/* Remount / as SLAVE so that nothing now mounted in the namespace
|
||||||
* shows up in the parent */
|
* shows up in the parent */
|
||||||
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
|
if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) {
|
||||||
@ -1894,96 +2173,10 @@ int setup_namespace(
|
|||||||
if (root_image || root_directory)
|
if (root_image || root_directory)
|
||||||
(void) base_filesystem_create(root, UID_INVALID, GID_INVALID);
|
(void) base_filesystem_create(root, UID_INVALID, GID_INVALID);
|
||||||
|
|
||||||
if (n_mounts > 0) {
|
/* Now make the magic happen */
|
||||||
_cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
|
r = apply_mounts(root, ns_info, mounts, &n_mounts, error_path);
|
||||||
_cleanup_free_ char **deny_list = NULL;
|
if (r < 0)
|
||||||
size_t j;
|
goto finish;
|
||||||
|
|
||||||
/* Open /proc/self/mountinfo now as it may become unavailable if we mount anything on top of
|
|
||||||
* /proc. For example, this is the case with the option: 'InaccessiblePaths=/proc'. */
|
|
||||||
proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
|
|
||||||
if (!proc_self_mountinfo) {
|
|
||||||
r = log_debug_errno(errno, "Failed to open /proc/self/mountinfo: %m");
|
|
||||||
if (error_path)
|
|
||||||
*error_path = strdup("/proc/self/mountinfo");
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* First round, establish all mounts we need */
|
|
||||||
for (;;) {
|
|
||||||
bool again = false;
|
|
||||||
|
|
||||||
for (m = mounts; m < mounts + n_mounts; ++m) {
|
|
||||||
|
|
||||||
if (m->applied)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
r = follow_symlink(root, m);
|
|
||||||
if (r < 0) {
|
|
||||||
if (error_path && mount_entry_path(m))
|
|
||||||
*error_path = strdup(mount_entry_path(m));
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
if (r == 0) {
|
|
||||||
/* We hit a symlinked mount point. The entry got rewritten and might
|
|
||||||
* point to a very different place now. Let's normalize the changed
|
|
||||||
* list, and start from the beginning. After all to mount the entry
|
|
||||||
* at the new location we might need some other mounts first */
|
|
||||||
again = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = apply_mount(root, m, ns_info);
|
|
||||||
if (r < 0) {
|
|
||||||
if (error_path && mount_entry_path(m))
|
|
||||||
*error_path = strdup(mount_entry_path(m));
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
m->applied = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!again)
|
|
||||||
break;
|
|
||||||
|
|
||||||
normalize_mounts(root, mounts, &n_mounts);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Create a deny list we can pass to bind_mount_recursive() */
|
|
||||||
deny_list = new(char*, n_mounts+1);
|
|
||||||
if (!deny_list) {
|
|
||||||
r = -ENOMEM;
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
for (j = 0; j < n_mounts; j++)
|
|
||||||
deny_list[j] = (char*) mount_entry_path(mounts+j);
|
|
||||||
deny_list[j] = NULL;
|
|
||||||
|
|
||||||
/* Second round, flip the ro bits if necessary. */
|
|
||||||
for (m = mounts; m < mounts + n_mounts; ++m) {
|
|
||||||
r = make_read_only(m, deny_list, proc_self_mountinfo);
|
|
||||||
if (r < 0) {
|
|
||||||
if (error_path && mount_entry_path(m))
|
|
||||||
*error_path = strdup(mount_entry_path(m));
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Third round, flip the noexec bits with a simplified deny list. */
|
|
||||||
for (m = mounts, j = 0; m < mounts + n_mounts; ++m)
|
|
||||||
if (IN_SET(m->mode, EXEC, NOEXEC))
|
|
||||||
deny_list[j++] = (char*) mount_entry_path(m);
|
|
||||||
deny_list[j] = NULL;
|
|
||||||
|
|
||||||
for (m = mounts; m < mounts + n_mounts; ++m) {
|
|
||||||
r = make_noexec(m, deny_list, proc_self_mountinfo);
|
|
||||||
if (r < 0) {
|
|
||||||
if (error_path && mount_entry_path(m))
|
|
||||||
*error_path = strdup(mount_entry_path(m));
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
|
/* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
|
||||||
r = mount_move_root(root);
|
r = mount_move_root(root);
|
||||||
@ -2096,9 +2289,11 @@ int mount_image_add(MountImage **m, size_t *n, const MountImage *item) {
|
|||||||
if (!s)
|
if (!s)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
d = strdup(item->destination);
|
if (item->destination) {
|
||||||
if (!d)
|
d = strdup(item->destination);
|
||||||
return -ENOMEM;
|
if (!d)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
LIST_FOREACH(mount_options, i, item->mount_options) {
|
LIST_FOREACH(mount_options, i, item->mount_options) {
|
||||||
_cleanup_(mount_options_free_allp) MountOptions *o;
|
_cleanup_(mount_options_free_allp) MountOptions *o;
|
||||||
@ -2128,6 +2323,7 @@ int mount_image_add(MountImage **m, size_t *n, const MountImage *item) {
|
|||||||
.destination = TAKE_PTR(d),
|
.destination = TAKE_PTR(d),
|
||||||
.mount_options = TAKE_PTR(options),
|
.mount_options = TAKE_PTR(options),
|
||||||
.ignore_enoent = item->ignore_enoent,
|
.ignore_enoent = item->ignore_enoent,
|
||||||
|
.type = item->type,
|
||||||
};
|
};
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -93,11 +93,19 @@ struct TemporaryFileSystem {
|
|||||||
char *options;
|
char *options;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum MountImageType {
|
||||||
|
MOUNT_IMAGE_DISCRETE,
|
||||||
|
MOUNT_IMAGE_EXTENSION,
|
||||||
|
_MOUNT_IMAGE_TYPE_MAX,
|
||||||
|
_MOUNT_IMAGE_TYPE_INVALID = -EINVAL,
|
||||||
|
} MountImageType;
|
||||||
|
|
||||||
struct MountImage {
|
struct MountImage {
|
||||||
char *source;
|
char *source;
|
||||||
char *destination;
|
char *destination; /* Unused if MountImageType == MOUNT_IMAGE_EXTENSION */
|
||||||
LIST_HEAD(MountOptions, mount_options);
|
LIST_HEAD(MountOptions, mount_options);
|
||||||
bool ignore_enoent;
|
bool ignore_enoent;
|
||||||
|
MountImageType type;
|
||||||
};
|
};
|
||||||
|
|
||||||
int setup_namespace(
|
int setup_namespace(
|
||||||
@ -129,6 +137,8 @@ int setup_namespace(
|
|||||||
size_t root_hash_sig_size,
|
size_t root_hash_sig_size,
|
||||||
const char *root_hash_sig_path,
|
const char *root_hash_sig_path,
|
||||||
const char *root_verity,
|
const char *root_verity,
|
||||||
|
const MountImage *extension_images,
|
||||||
|
size_t n_extension_images,
|
||||||
const char *propagate_dir,
|
const char *propagate_dir,
|
||||||
const char *incoming_dir,
|
const char *incoming_dir,
|
||||||
const char *notify_socket,
|
const char *notify_socket,
|
||||||
|
@ -4756,8 +4756,8 @@ int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret) {
|
|||||||
if (r != 0)
|
if (r != 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
(void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1);
|
(void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE);
|
||||||
(void) ignore_signals(SIGPIPE, -1);
|
(void) ignore_signals(SIGPIPE);
|
||||||
|
|
||||||
(void) prctl(PR_SET_PDEATHSIG, SIGTERM);
|
(void) prctl(PR_SET_PDEATHSIG, SIGTERM);
|
||||||
|
|
||||||
|
@ -1110,7 +1110,7 @@ static int run_debug(int argc, char **argv, void *userdata) {
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
/* Don't interfere with gdb and its handling of SIGINT. */
|
/* Don't interfere with gdb and its handling of SIGINT. */
|
||||||
(void) ignore_signals(SIGINT, -1);
|
(void) ignore_signals(SIGINT);
|
||||||
|
|
||||||
fork_name = strjoina("(", debugger_call[0], ")");
|
fork_name = strjoina("(", debugger_call[0], ")");
|
||||||
|
|
||||||
@ -1127,7 +1127,7 @@ static int run_debug(int argc, char **argv, void *userdata) {
|
|||||||
r = wait_for_terminate_and_check(debugger_call[0], pid, WAIT_LOG_ABNORMAL);
|
r = wait_for_terminate_and_check(debugger_call[0], pid, WAIT_LOG_ABNORMAL);
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
(void) default_signals(SIGINT, -1);
|
(void) default_signals(SIGINT);
|
||||||
|
|
||||||
if (unlink_path) {
|
if (unlink_path) {
|
||||||
log_debug("Removed temporary file %s", path);
|
log_debug("Removed temporary file %s", path);
|
||||||
|
@ -289,7 +289,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
(void) ignore_signals(SIGPIPE, -1);
|
(void) ignore_signals(SIGPIPE);
|
||||||
|
|
||||||
return export_main(argc, argv);
|
return export_main(argc, argv);
|
||||||
}
|
}
|
||||||
|
@ -306,7 +306,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
(void) ignore_signals(SIGPIPE, -1);
|
(void) ignore_signals(SIGPIPE);
|
||||||
|
|
||||||
return import_main(argc, argv);
|
return import_main(argc, argv);
|
||||||
}
|
}
|
||||||
|
@ -349,7 +349,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
if (r <= 0)
|
if (r <= 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
(void) ignore_signals(SIGPIPE, -1);
|
(void) ignore_signals(SIGPIPE);
|
||||||
|
|
||||||
return pull_main(argc, argv);
|
return pull_main(argc, argv);
|
||||||
}
|
}
|
||||||
|
@ -295,7 +295,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
/* Ignore SIGINT and allow the forked process to receive it */
|
/* Ignore SIGINT and allow the forked process to receive it */
|
||||||
(void) ignore_signals(SIGINT, -1);
|
(void) ignore_signals(SIGINT);
|
||||||
|
|
||||||
if (!arg_who) {
|
if (!arg_who) {
|
||||||
w = strv_join(argv + optind, " ");
|
w = strv_join(argv + optind, " ");
|
||||||
|
@ -788,7 +788,7 @@ static int manager_connect_console(Manager *m) {
|
|||||||
"Not enough real-time signals available: %u-%u",
|
"Not enough real-time signals available: %u-%u",
|
||||||
SIGRTMIN, SIGRTMAX);
|
SIGRTMIN, SIGRTMAX);
|
||||||
|
|
||||||
assert_se(ignore_signals(SIGRTMIN + 1, -1) >= 0);
|
assert_se(ignore_signals(SIGRTMIN + 1) >= 0);
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN, -1) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN, -1) >= 0);
|
||||||
|
|
||||||
r = sd_event_add_signal(m->event, NULL, SIGRTMIN, manager_vt_switch, m);
|
r = sd_event_add_signal(m->event, NULL, SIGRTMIN, manager_vt_switch, m);
|
||||||
|
@ -4850,7 +4850,7 @@ static int run_container(
|
|||||||
assert_se(sigprocmask(SIG_BLOCK, &mask_chld, NULL) >= 0);
|
assert_se(sigprocmask(SIG_BLOCK, &mask_chld, NULL) >= 0);
|
||||||
|
|
||||||
/* Reset signal to default */
|
/* Reset signal to default */
|
||||||
r = default_signals(SIGCHLD, -1);
|
r = default_signals(SIGCHLD);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to reset SIGCHLD: %m");
|
return log_error_errno(r, "Failed to reset SIGCHLD: %m");
|
||||||
|
|
||||||
@ -5219,7 +5219,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
/* Ignore SIGPIPE here, because we use splice() on the ptyfwd stuff and that will generate SIGPIPE if
|
/* Ignore SIGPIPE here, because we use splice() on the ptyfwd stuff and that will generate SIGPIPE if
|
||||||
* the result is closed. Note that the container payload child will reset signal mask+handler anyway,
|
* the result is closed. Note that the container payload child will reset signal mask+handler anyway,
|
||||||
* so just turning this off here means we only turn it off in nspawn itself, not any children. */
|
* so just turning this off here means we only turn it off in nspawn itself, not any children. */
|
||||||
(void) ignore_signals(SIGPIPE, -1);
|
(void) ignore_signals(SIGPIPE);
|
||||||
|
|
||||||
n_fd_passed = sd_listen_fds(false);
|
n_fd_passed = sd_listen_fds(false);
|
||||||
if (n_fd_passed > 0) {
|
if (n_fd_passed > 0) {
|
||||||
|
@ -1766,6 +1766,110 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (streq(field, "ExtensionImages")) {
|
||||||
|
const char *p = eq;
|
||||||
|
|
||||||
|
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *source = NULL, *tuple = NULL;
|
||||||
|
const char *q = NULL, *s = NULL;
|
||||||
|
bool permissive = false;
|
||||||
|
|
||||||
|
r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
q = tuple;
|
||||||
|
r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
s = source;
|
||||||
|
if (s[0] == '-') {
|
||||||
|
permissive = true;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_bus_message_open_container(m, 'r', "sba(ss)");
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
r = sd_bus_message_append(m, "sb", s, permissive);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
r = sd_bus_message_open_container(m, 'a', "(ss)");
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *partition = NULL, *mount_options = NULL;
|
||||||
|
|
||||||
|
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
/* Single set of options, applying to the root partition/single filesystem */
|
||||||
|
if (r == 1) {
|
||||||
|
r = sd_bus_message_append(m, "(ss)", "root", partition);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (partition_designator_from_string(partition) < 0)
|
||||||
|
return bus_log_create_error(-EINVAL);
|
||||||
|
|
||||||
|
r = sd_bus_message_append(m, "(ss)", partition, mount_options);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_bus_message_close_container(m);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
r = sd_bus_message_close_container(m);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
r = sd_bus_message_close_container(m);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
r = sd_bus_message_close_container(m);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
r = sd_bus_message_close_container(m);
|
||||||
|
if (r < 0)
|
||||||
|
return bus_log_create_error(r);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "dissect-image.h"
|
#include "dissect-image.h"
|
||||||
#include "dm-util.h"
|
#include "dm-util.h"
|
||||||
#include "env-file.h"
|
#include "env-file.h"
|
||||||
|
#include "extension-release.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
@ -2621,7 +2622,14 @@ static const char *const partition_designator_table[] = {
|
|||||||
[PARTITION_VAR] = "var",
|
[PARTITION_VAR] = "var",
|
||||||
};
|
};
|
||||||
|
|
||||||
int verity_dissect_and_mount(const char *src, const char *dest, const MountOptions *options) {
|
int verity_dissect_and_mount(
|
||||||
|
const char *src,
|
||||||
|
const char *dest,
|
||||||
|
const MountOptions *options,
|
||||||
|
const char *required_host_os_release_id,
|
||||||
|
const char *required_host_os_release_version_id,
|
||||||
|
const char *required_host_os_release_sysext_level) {
|
||||||
|
|
||||||
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
|
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
|
||||||
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
||||||
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
||||||
@ -2683,6 +2691,30 @@ int verity_dissect_and_mount(const char *src, const char *dest, const MountOptio
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to mount image: %m");
|
return log_debug_errno(r, "Failed to mount image: %m");
|
||||||
|
|
||||||
|
/* If we got os-release values from the caller, then we need to match them with the image's
|
||||||
|
* extension-release.d/ content. Return -EINVAL if there's any mismatch.
|
||||||
|
* First, check the distro ID. If that matches, then check the new SYSEXT_LEVEL value if
|
||||||
|
* available, or else fallback to VERSION_ID. */
|
||||||
|
if (required_host_os_release_id &&
|
||||||
|
(required_host_os_release_version_id || required_host_os_release_sysext_level)) {
|
||||||
|
_cleanup_strv_free_ char **extension_release = NULL;
|
||||||
|
|
||||||
|
r = load_extension_release_pairs(dest, dissected_image->image_name, &extension_release);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to parse image %s extension-release metadata: %m", dissected_image->image_name);
|
||||||
|
|
||||||
|
r = extension_release_validate(
|
||||||
|
dissected_image->image_name,
|
||||||
|
required_host_os_release_id,
|
||||||
|
required_host_os_release_version_id,
|
||||||
|
required_host_os_release_sysext_level,
|
||||||
|
extension_release);
|
||||||
|
if (r == 0)
|
||||||
|
return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "Image %s extension-release metadata does not match the root's", dissected_image->image_name);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to compare image %s extension-release metadata with the root's os-release: %m", dissected_image->image_name);
|
||||||
|
}
|
||||||
|
|
||||||
if (decrypted_image) {
|
if (decrypted_image) {
|
||||||
r = decrypted_image_relinquish(decrypted_image);
|
r = decrypted_image_relinquish(decrypted_image);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -164,4 +164,4 @@ bool dissected_image_has_verity(const DissectedImage *image, PartitionDesignator
|
|||||||
|
|
||||||
int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image);
|
int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image);
|
||||||
|
|
||||||
int verity_dissect_and_mount(const char *src, const char *dest, const MountOptions *options);
|
int verity_dissect_and_mount(const char *src, const char *dest, const MountOptions *options, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level);
|
||||||
|
@ -77,3 +77,18 @@ int extension_release_validate(
|
|||||||
log_debug("Version info of extension '%s' matches host.", name);
|
log_debug("Version info of extension '%s' matches host.", name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int parse_env_extension_hierarchies(char ***ret_hierarchies) {
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = getenv_path_list("SYSTEMD_SYSEXT_HIERARCHIES", ret_hierarchies);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to parse SYSTEMD_SYSEXT_HIERARCHIES environment variable : %m");
|
||||||
|
if (!*ret_hierarchies) {
|
||||||
|
*ret_hierarchies = strv_new("/usr", "/opt");
|
||||||
|
if (!*ret_hierarchies)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -10,3 +10,6 @@ int extension_release_validate(
|
|||||||
const char *host_os_release_version_id,
|
const char *host_os_release_version_id,
|
||||||
const char *host_os_release_sysext_level,
|
const char *host_os_release_sysext_level,
|
||||||
char **extension_release);
|
char **extension_release);
|
||||||
|
|
||||||
|
/* Parse SYSTEMD_SYSEXT_HIERARCHIES and if not set, return "/usr /opt" */
|
||||||
|
int parse_env_extension_hierarchies(char ***ret_hierarchies);
|
||||||
|
@ -2260,7 +2260,7 @@ int table_print(Table *t, FILE *f) {
|
|||||||
|
|
||||||
/* Drop trailing white spaces of last column when no cosmetics is set. */
|
/* Drop trailing white spaces of last column when no cosmetics is set. */
|
||||||
if (j == display_columns - 1 &&
|
if (j == display_columns - 1 &&
|
||||||
(!colors_enabled() || !table_data_color(d)) &&
|
(!colors_enabled() || (!table_data_color(d) && row != t->data)) &&
|
||||||
(!urlify_enabled() || !d->url))
|
(!urlify_enabled() || !d->url))
|
||||||
delete_trailing_chars(aligned, NULL);
|
delete_trailing_chars(aligned, NULL);
|
||||||
|
|
||||||
|
@ -855,7 +855,7 @@ static int mount_in_namespace(
|
|||||||
mount_tmp_created = true;
|
mount_tmp_created = true;
|
||||||
|
|
||||||
if (is_image)
|
if (is_image)
|
||||||
r = verity_dissect_and_mount(chased_src, mount_tmp, options);
|
r = verity_dissect_and_mount(chased_src, mount_tmp, options, NULL, NULL, NULL);
|
||||||
else
|
else
|
||||||
r = mount_follow_verbose(LOG_DEBUG, chased_src, mount_tmp, NULL, MS_BIND, NULL);
|
r = mount_follow_verbose(LOG_DEBUG, chased_src, mount_tmp, NULL, MS_BIND, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -262,7 +262,7 @@ int pager_open(PagerFlags flags) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r > 0)
|
if (r > 0)
|
||||||
(void) ignore_signals(SIGINT, -1);
|
(void) ignore_signals(SIGINT);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -982,16 +982,10 @@ static int run(int argc, char *argv[]) {
|
|||||||
/* For debugging purposes it might make sense to do this for other hierarchies than /usr/ and
|
/* For debugging purposes it might make sense to do this for other hierarchies than /usr/ and
|
||||||
* /opt/, but let's make that a hacker/debugging feature, i.e. env var instead of cmdline
|
* /opt/, but let's make that a hacker/debugging feature, i.e. env var instead of cmdline
|
||||||
* switch. */
|
* switch. */
|
||||||
r = getenv_path_list("SYSTEMD_SYSEXT_HIERARCHIES", &arg_hierarchies);
|
r = parse_env_extension_hierarchies(&arg_hierarchies);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse $SYSTEMD_SYSEXT_HIERARCHIES environment variable: %m");
|
return log_error_errno(r, "Failed to parse $SYSTEMD_SYSEXT_HIERARCHIES environment variable: %m");
|
||||||
|
|
||||||
if (!arg_hierarchies) {
|
|
||||||
arg_hierarchies = strv_new("/usr", "/opt");
|
|
||||||
if (!arg_hierarchies)
|
|
||||||
return log_oom();
|
|
||||||
}
|
|
||||||
|
|
||||||
return sysext_main(argc, argv);
|
return sysext_main(argc, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ int switch_root(int argc, char *argv[], void *userdata) {
|
|||||||
|
|
||||||
/* If we are slow to exit after the root switch, the new systemd instance will send us a signal to
|
/* If we are slow to exit after the root switch, the new systemd instance will send us a signal to
|
||||||
* terminate. Just ignore it and exit normally. This way the unit does not end up as failed. */
|
* terminate. Just ignore it and exit normally. This way the unit does not end up as failed. */
|
||||||
r = ignore_signals(SIGTERM, -1);
|
r = ignore_signals(SIGTERM);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_warning_errno(r, "Failed to change disposition of SIGTERM to ignore: %m");
|
log_warning_errno(r, "Failed to change disposition of SIGTERM to ignore: %m");
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ int switch_root(int argc, char *argv[], void *userdata) {
|
|||||||
|
|
||||||
r = bus_call_method(bus, bus_systemd_mgr, "SwitchRoot", &error, NULL, "ss", root, init);
|
r = bus_call_method(bus, bus_systemd_mgr, "SwitchRoot", &error, NULL, "ss", root, init);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
(void) default_signals(SIGTERM, -1);
|
(void) default_signals(SIGTERM);
|
||||||
|
|
||||||
return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r));
|
return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r));
|
||||||
}
|
}
|
||||||
|
@ -338,7 +338,7 @@ static void test_cg_tests(void) {
|
|||||||
|
|
||||||
r = cg_unified();
|
r = cg_unified();
|
||||||
if (r == -ENOMEDIUM) {
|
if (r == -ENOMEDIUM) {
|
||||||
log_notice_errno(r, "Skipping cg hierarchy tests: %m");
|
log_tests_skipped("cgroup not mounted");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert_se(r >= 0);
|
assert_se(r >= 0);
|
||||||
|
@ -47,10 +47,11 @@ static void test_cg_create(void) {
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = cg_unified_cached(false);
|
r = cg_unified_cached(false);
|
||||||
if (r < 0) {
|
if (r == -ENOMEDIUM) {
|
||||||
log_info_errno(r, "Skipping %s: %m", __func__);
|
log_tests_skipped("cgroup not mounted");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
assert_se(r >= 0);
|
||||||
|
|
||||||
_cleanup_free_ char *here = NULL;
|
_cleanup_free_ char *here = NULL;
|
||||||
assert_se(cg_pid_get_path_shifted(0, NULL, &here) >= 0);
|
assert_se(cg_pid_get_path_shifted(0, NULL, &here) >= 0);
|
||||||
|
@ -129,6 +129,11 @@ static void test_condition_test_control_group_hierarchy(void) {
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = cg_unified();
|
r = cg_unified();
|
||||||
|
if (r == -ENOMEDIUM) {
|
||||||
|
log_tests_skipped("cgroup not mounted");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert_se(r >= 0);
|
||||||
|
|
||||||
condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, "v1", false, false);
|
condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, "v1", false, false);
|
||||||
assert_se(condition);
|
assert_se(condition);
|
||||||
@ -148,10 +153,11 @@ static void test_condition_test_control_group_controller(void) {
|
|||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = cg_unified();
|
r = cg_unified();
|
||||||
if (r < 0) {
|
if (r == -ENOMEDIUM) {
|
||||||
log_notice_errno(r, "Skipping ConditionControlGroupController tests: %m");
|
log_tests_skipped("cgroup not mounted");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
assert_se(r >= 0);
|
||||||
|
|
||||||
/* Invalid controllers are ignored */
|
/* Invalid controllers are ignored */
|
||||||
condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, "thisisnotarealcontroller", false, false);
|
condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, "thisisnotarealcontroller", false, false);
|
||||||
|
@ -175,6 +175,8 @@ static void test_protect_kernel_logs(void) {
|
|||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
0,
|
0,
|
||||||
|
@ -103,6 +103,8 @@ int main(int argc, char *argv[]) {
|
|||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
0,
|
0,
|
||||||
|
@ -130,14 +130,14 @@ static void test_block_signals(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void test_ignore_signals(void) {
|
static void test_ignore_signals(void) {
|
||||||
assert_se(ignore_signals(SIGINT, -1) >= 0);
|
assert_se(ignore_signals(SIGINT) >= 0);
|
||||||
assert_se(kill(getpid_cached(), SIGINT) >= 0);
|
assert_se(kill(getpid_cached(), SIGINT) >= 0);
|
||||||
assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0);
|
assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE) >= 0);
|
||||||
assert_se(kill(getpid_cached(), SIGUSR1) >= 0);
|
assert_se(kill(getpid_cached(), SIGUSR1) >= 0);
|
||||||
assert_se(kill(getpid_cached(), SIGUSR2) >= 0);
|
assert_se(kill(getpid_cached(), SIGUSR2) >= 0);
|
||||||
assert_se(kill(getpid_cached(), SIGTERM) >= 0);
|
assert_se(kill(getpid_cached(), SIGTERM) >= 0);
|
||||||
assert_se(kill(getpid_cached(), SIGPIPE) >= 0);
|
assert_se(kill(getpid_cached(), SIGPIPE) >= 0);
|
||||||
assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0);
|
assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE) >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
@ -9,6 +9,8 @@ TEST_INSTALL_VERITY_MINIMAL=1
|
|||||||
|
|
||||||
. $TEST_BASE_DIR/test-functions
|
. $TEST_BASE_DIR/test-functions
|
||||||
|
|
||||||
|
command -v mksquashfs >/dev/null 2>&1 || exit 0
|
||||||
|
command -v veritysetup >/dev/null 2>&1 || exit 0
|
||||||
command -v sfdisk >/dev/null 2>&1 || exit 0
|
command -v sfdisk >/dev/null 2>&1 || exit 0
|
||||||
|
|
||||||
# Need loop devices for systemd-dissect
|
# Need loop devices for systemd-dissect
|
||||||
@ -17,6 +19,7 @@ test_append_files() {
|
|||||||
instmods loop =block
|
instmods loop =block
|
||||||
instmods squashfs =squashfs
|
instmods squashfs =squashfs
|
||||||
instmods dm_verity =md
|
instmods dm_verity =md
|
||||||
|
instmods overlay =overlayfs
|
||||||
install_dmevent
|
install_dmevent
|
||||||
generate_module_dependencies
|
generate_module_dependencies
|
||||||
inst_binary losetup
|
inst_binary losetup
|
||||||
|
@ -206,6 +206,7 @@ RootImage=
|
|||||||
RootHash=
|
RootHash=
|
||||||
RootHashSignature=
|
RootHashSignature=
|
||||||
RootVerity=
|
RootVerity=
|
||||||
|
ExtensionImages=
|
||||||
RuntimeMaxSec=
|
RuntimeMaxSec=
|
||||||
SELinuxContextFromNet=
|
SELinuxContextFromNet=
|
||||||
SecureBits=
|
SecureBits=
|
||||||
|
@ -480,18 +480,20 @@ install_verity_minimal() {
|
|||||||
BASICTOOLS=(
|
BASICTOOLS=(
|
||||||
bash
|
bash
|
||||||
cat
|
cat
|
||||||
|
grep
|
||||||
mount
|
mount
|
||||||
sleep
|
sleep
|
||||||
)
|
)
|
||||||
oldinitdir=$initdir
|
oldinitdir=$initdir
|
||||||
rm -rfv $TESTDIR/minimal
|
rm -rfv $TESTDIR/minimal
|
||||||
export initdir=$TESTDIR/minimal
|
export initdir=$TESTDIR/minimal
|
||||||
mkdir -p $initdir/usr/lib/systemd/system $initdir/etc
|
mkdir -p $initdir/usr/lib/systemd/system $initdir/usr/lib/extension-release.d $initdir/etc $initdir/var/tmp $initdir/opt
|
||||||
setup_basic_dirs
|
setup_basic_dirs
|
||||||
install_basic_tools
|
install_basic_tools
|
||||||
cp $os_release $initdir/usr/lib/os-release
|
cp $os_release $initdir/usr/lib/os-release
|
||||||
ln -s ../usr/lib/os-release $initdir/etc/os-release
|
ln -s ../usr/lib/os-release $initdir/etc/os-release
|
||||||
touch $initdir/etc/machine-id $initdir/etc/resolv.conf
|
touch $initdir/etc/machine-id $initdir/etc/resolv.conf
|
||||||
|
touch $initdir/opt/some_file
|
||||||
echo MARKER=1 >> $initdir/usr/lib/os-release
|
echo MARKER=1 >> $initdir/usr/lib/os-release
|
||||||
echo -e "[Service]\nExecStartPre=cat /usr/lib/os-release\nExecStart=sleep 120" > $initdir/usr/lib/systemd/system/app0.service
|
echo -e "[Service]\nExecStartPre=cat /usr/lib/os-release\nExecStart=sleep 120" > $initdir/usr/lib/systemd/system/app0.service
|
||||||
cp $initdir/usr/lib/systemd/system/app0.service $initdir/usr/lib/systemd/system/app0-foo.service
|
cp $initdir/usr/lib/systemd/system/app0.service $initdir/usr/lib/systemd/system/app0-foo.service
|
||||||
@ -507,6 +509,52 @@ install_verity_minimal() {
|
|||||||
mksquashfs $initdir $oldinitdir/usr/share/minimal_1.raw
|
mksquashfs $initdir $oldinitdir/usr/share/minimal_1.raw
|
||||||
veritysetup format $oldinitdir/usr/share/minimal_1.raw $oldinitdir/usr/share/minimal_1.verity | \
|
veritysetup format $oldinitdir/usr/share/minimal_1.raw $oldinitdir/usr/share/minimal_1.verity | \
|
||||||
grep '^Root hash:' | cut -f2 | tr -d '\n' > $oldinitdir/usr/share/minimal_1.roothash
|
grep '^Root hash:' | cut -f2 | tr -d '\n' > $oldinitdir/usr/share/minimal_1.roothash
|
||||||
|
|
||||||
|
# Rolling distros like Arch do not set VERSION_ID
|
||||||
|
local version_id=""
|
||||||
|
if grep -q "^VERSION_ID=" $os_release; then
|
||||||
|
version_id="$(grep "^VERSION_ID=" $os_release)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
export initdir=$TESTDIR/app0
|
||||||
|
mkdir -p $initdir/usr/lib/extension-release.d $initdir/usr/lib/systemd/system $initdir/opt
|
||||||
|
grep "^ID=" $os_release > $initdir/usr/lib/extension-release.d/extension-release.app0
|
||||||
|
echo "${version_id}" >> $initdir/usr/lib/extension-release.d/extension-release.app0
|
||||||
|
cat <<EOF > $initdir/usr/lib/systemd/system/app0.service
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
RemainAfterExit=yes
|
||||||
|
ExecStart=/opt/script0.sh
|
||||||
|
EOF
|
||||||
|
cat <<EOF > $initdir/opt/script0.sh
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
test -e /usr/lib/os-release
|
||||||
|
cat /usr/lib/extension-release.d/extension-release.app0
|
||||||
|
EOF
|
||||||
|
chmod +x $initdir/opt/script0.sh
|
||||||
|
echo MARKER=1 > $initdir/usr/lib/systemd/system/some_file
|
||||||
|
mksquashfs $initdir $oldinitdir/usr/share/app0.raw
|
||||||
|
|
||||||
|
export initdir=$TESTDIR/app1
|
||||||
|
mkdir -p $initdir/usr/lib/extension-release.d $initdir/usr/lib/systemd/system $initdir/opt
|
||||||
|
grep "^ID=" $os_release > $initdir/usr/lib/extension-release.d/extension-release.app1
|
||||||
|
echo "${version_id}" >> $initdir/usr/lib/extension-release.d/extension-release.app1
|
||||||
|
cat <<EOF > $initdir/usr/lib/systemd/system/app1.service
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
RemainAfterExit=yes
|
||||||
|
ExecStart=/opt/script1.sh
|
||||||
|
EOF
|
||||||
|
cat <<EOF > $initdir/opt/script1.sh
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
test -e /usr/lib/os-release
|
||||||
|
cat /usr/lib/extension-release.d/extension-release.app1
|
||||||
|
EOF
|
||||||
|
chmod +x $initdir/opt/script1.sh
|
||||||
|
echo MARKER=1 > $initdir/usr/lib/systemd/system/other_file
|
||||||
|
mksquashfs $initdir $oldinitdir/usr/share/app1.raw
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -227,6 +227,27 @@ done
|
|||||||
|
|
||||||
systemctl is-active testservice-50d.service
|
systemctl is-active testservice-50d.service
|
||||||
|
|
||||||
|
# ExtensionImages will set up an overlay
|
||||||
|
systemd-run -t --property ExtensionImages=/usr/share/app0.raw --property RootImage=${image}.raw cat /opt/script0.sh | grep -q -F "extension-release.app0"
|
||||||
|
systemd-run -t --property ExtensionImages=/usr/share/app0.raw --property RootImage=${image}.raw cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
|
||||||
|
systemd-run -t --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage=${image}.raw cat /opt/script0.sh | grep -q -F "extension-release.app0"
|
||||||
|
systemd-run -t --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage=${image}.raw cat /usr/lib/systemd/system/some_file | grep -q -F "MARKER=1"
|
||||||
|
systemd-run -t --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage=${image}.raw cat /opt/script1.sh | grep -q -F "extension-release.app1"
|
||||||
|
systemd-run -t --property ExtensionImages="/usr/share/app0.raw /usr/share/app1.raw" --property RootImage=${image}.raw cat /usr/lib/systemd/system/other_file | grep -q -F "MARKER=1"
|
||||||
|
cat >/run/systemd/system/testservice-50e.service <<EOF
|
||||||
|
[Service]
|
||||||
|
MountAPIVFS=yes
|
||||||
|
TemporaryFileSystem=/run
|
||||||
|
RootImage=${image}.raw
|
||||||
|
ExtensionImages=/usr/share/app0.raw /usr/share/app1.raw:nosuid
|
||||||
|
ExecStart=/bin/bash -c '/opt/script0.sh | grep ID'
|
||||||
|
ExecStart=/bin/bash -c '/opt/script1.sh | grep ID'
|
||||||
|
Type=oneshot
|
||||||
|
RemainAfterExit=yes
|
||||||
|
EOF
|
||||||
|
systemctl start testservice-50e.service
|
||||||
|
systemctl is-active testservice-50e.service
|
||||||
|
|
||||||
echo OK >/testok
|
echo OK >/testok
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user