mirror of
https://github.com/systemd/systemd
synced 2026-03-16 18:14:46 +01:00
Compare commits
No commits in common. "331fef07d8b2909a84a88cc3d18911853b413f8f" and "985a6fa44b58c307030e43950ff2affa3f32546a" have entirely different histories.
331fef07d8
...
985a6fa44b
23
README
23
README
@ -50,10 +50,9 @@ REQUIREMENTS:
|
|||||||
≥ 5.6 for getrandom() GRND_INSECURE
|
≥ 5.6 for getrandom() GRND_INSECURE
|
||||||
≥ 5.7 for CLONE_INTO_CGROUP, cgroup2fs memory_recursiveprot option,
|
≥ 5.7 for CLONE_INTO_CGROUP, cgroup2fs memory_recursiveprot option,
|
||||||
BPF links and the BPF LSM hook
|
BPF links and the BPF LSM hook
|
||||||
≥ 5.8 for LOOP_CONFIGURE, STATX_ATTR_MOUNT_ROOT, and procfs
|
≥ 5.8 for LOOP_CONFIGURE and STATX_ATTR_MOUNT_ROOT
|
||||||
per-instance hidepid=/subset= options
|
|
||||||
≥ 5.9 for close_range()
|
≥ 5.9 for close_range()
|
||||||
≥ 5.10 for STATX_MNT_ID and MS_NOSYMFOLLOW mount option
|
≥ 5.10 for STATX_MNT_ID
|
||||||
|
|
||||||
⛔ Kernel versions below 5.10 ("minimum baseline") are not supported at all,
|
⛔ Kernel versions below 5.10 ("minimum baseline") are not supported at all,
|
||||||
and are missing required functionality as listed above.
|
and are missing required functionality as listed above.
|
||||||
@ -125,8 +124,7 @@ REQUIREMENTS:
|
|||||||
CONFIG_SECCOMP
|
CONFIG_SECCOMP
|
||||||
CONFIG_SECCOMP_FILTER (required for seccomp support)
|
CONFIG_SECCOMP_FILTER (required for seccomp support)
|
||||||
CONFIG_KCMP (for the kcmp() syscall, used to be under
|
CONFIG_KCMP (for the kcmp() syscall, used to be under
|
||||||
CONFIG_CHECKPOINT_RESTORE before ~5.12;
|
CONFIG_CHECKPOINT_RESTORE before ~5.12)
|
||||||
not needed after 6.10)
|
|
||||||
CONFIG_NET_SCHED
|
CONFIG_NET_SCHED
|
||||||
CONFIG_NET_SCH_FQ_CODEL
|
CONFIG_NET_SCH_FQ_CODEL
|
||||||
|
|
||||||
@ -194,12 +192,25 @@ REQUIREMENTS:
|
|||||||
This is shipped by default, see modprobe.d/systemd.conf.
|
This is shipped by default, see modprobe.d/systemd.conf.
|
||||||
|
|
||||||
Required for systemd-nspawn:
|
Required for systemd-nspawn:
|
||||||
CONFIG_DEVPTS_MULTIPLE_INSTANCES (removed and unneeded since 4.7)
|
CONFIG_DEVPTS_MULTIPLE_INSTANCES or Linux kernel >= 4.7
|
||||||
|
|
||||||
Required for systemd-oomd:
|
Required for systemd-oomd:
|
||||||
CONFIG_PSI
|
CONFIG_PSI
|
||||||
CONFIG_MEMCG
|
CONFIG_MEMCG
|
||||||
|
|
||||||
|
Note that kernel auditing is broken when used with systemd's container
|
||||||
|
code. When using systemd in conjunction with containers, please make
|
||||||
|
sure to either turn off auditing at runtime using the kernel command
|
||||||
|
line option "audit=0", or turn it off at kernel compile time using:
|
||||||
|
CONFIG_AUDIT=n
|
||||||
|
|
||||||
|
If systemd is compiled with libseccomp support on architectures which do
|
||||||
|
not use socketcall() and where seccomp is supported (this effectively
|
||||||
|
means x86-64 and ARM, but excludes 32-bit x86!), then nspawn will now
|
||||||
|
install a work-around seccomp filter that makes containers boot even
|
||||||
|
with audit being enabled. This works correctly only on kernels 3.14 and
|
||||||
|
newer though. TL;DR: turn audit off, still.
|
||||||
|
|
||||||
glibc >= 2.31
|
glibc >= 2.31
|
||||||
libxcrypt >= 4.4.0 (optional)
|
libxcrypt >= 4.4.0 (optional)
|
||||||
libmount >= 2.30 (from util-linux)
|
libmount >= 2.30 (from util-linux)
|
||||||
|
|||||||
6
TODO
6
TODO
@ -107,6 +107,8 @@ Deprecations and removals:
|
|||||||
* drop support for LOOP_CONFIGURE-less loopback block devices, once kernel
|
* drop support for LOOP_CONFIGURE-less loopback block devices, once kernel
|
||||||
baseline is 5.8.
|
baseline is 5.8.
|
||||||
|
|
||||||
|
* Once baseline is 5.10, remove support or MS_NOSYMFOLLOW-less kernels
|
||||||
|
|
||||||
* Remove /dev/mem ACPI FPDT parsing when /sys/firmware/acpi/fpdt is ubiquitous.
|
* Remove /dev/mem ACPI FPDT parsing when /sys/firmware/acpi/fpdt is ubiquitous.
|
||||||
That requires distros to enable CONFIG_ACPI_FPDT, and have kernels v5.12 for
|
That requires distros to enable CONFIG_ACPI_FPDT, and have kernels v5.12 for
|
||||||
x86 and v6.2 for arm.
|
x86 and v6.2 for arm.
|
||||||
@ -120,6 +122,10 @@ Deprecations and removals:
|
|||||||
https://github.com/util-linux/util-linux/commit/508fb0e7ac103b68531a59db2a4473897853ab52
|
https://github.com/util-linux/util-linux/commit/508fb0e7ac103b68531a59db2a4473897853ab52
|
||||||
has hit the prominent distributions, revert --issue-file= hack in units/*getty*service.in
|
has hit the prominent distributions, revert --issue-file= hack in units/*getty*service.in
|
||||||
|
|
||||||
|
* Once kernel baseline is 5.7, obsolete DefaultMemoryMin/Low= and DefaultStartupMemoryLow=
|
||||||
|
since we can systematically enable memory_recursiveprot on cgroupfs and have those
|
||||||
|
enforced by the kernel
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
* systemd-sysupdate: add support a "best before" in manifests (ie. SHA256SUMS)
|
* systemd-sysupdate: add support a "best before" in manifests (ie. SHA256SUMS)
|
||||||
|
|||||||
@ -1012,26 +1012,6 @@
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
|
||||||
<term><option>fixate-volume-key=</option></term>
|
|
||||||
|
|
||||||
<listitem><para>Pin the expected hash of the volume key.</para>
|
|
||||||
|
|
||||||
<para>In certain cases, e.g. for LUKS volumes where the key is sealed to the TPM2, this may be required
|
|
||||||
to provide a guarantee that the volume being attached is the volume which was previously created.
|
|
||||||
<option>fixate-volume-key=</option> can be used to set the expected volume key hash and refuse to attach the volume
|
|
||||||
if it has a different one. The expected hash matches the digest which is measured to the sha256 PCR bank of the
|
|
||||||
TPM2 when <option>tpm2-measure-pcr=</option> is used.</para>
|
|
||||||
|
|
||||||
<para>For newly created LUKS volumes, the expected hash can be generated by
|
|
||||||
<citerefentry><refentrytitle>systemd-repart</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
|
|
||||||
For additional details, see the <option>EncryptedVolume=</option> description at
|
|
||||||
<citerefentry><refentrytitle>repart.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
|
||||||
|
|
||||||
<xi:include href="version-info.xml" xpointer="v260"/>
|
|
||||||
</listitem>
|
|
||||||
</varlistentry>
|
|
||||||
|
|
||||||
</variablelist>
|
</variablelist>
|
||||||
|
|
||||||
<para>At early boot and when the system manager configuration is
|
<para>At early boot and when the system manager configuration is
|
||||||
@ -1141,8 +1121,6 @@ external /dev/sda3 keyfile:LABEL=keydev keyfile-timeout=10s,cipher=xchac
|
|||||||
<member><citerefentry><refentrytitle>systemd-cryptsetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
<member><citerefentry><refentrytitle>systemd-cryptsetup@.service</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||||
<member><citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
<member><citerefentry><refentrytitle>systemd-cryptsetup-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||||
<member><citerefentry><refentrytitle>systemd-cryptenroll</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
<member><citerefentry><refentrytitle>systemd-cryptenroll</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||||
<member><citerefentry><refentrytitle>systemd-repart</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
|
||||||
<member><citerefentry><refentrytitle>repart.d</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
|
|
||||||
<member><citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
|
<member><citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
|
||||||
<member><citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
<member><citerefentry project='die-net'><refentrytitle>cryptsetup</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||||
<member><citerefentry project='man-pages'><refentrytitle>mkswap</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
<member><citerefentry project='man-pages'><refentrytitle>mkswap</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||||
|
|||||||
@ -2969,6 +2969,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly b MemoryAccounting = ...;
|
readonly b MemoryAccounting = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultMemoryLow = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultStartupMemoryLow = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultMemoryMin = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly t MemoryMin = ...;
|
readonly t MemoryMin = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly t MemoryLow = ...;
|
readonly t MemoryLow = ...;
|
||||||
@ -3636,6 +3642,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
|
|
||||||
<!--property MemoryAccounting is not documented!-->
|
<!--property MemoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultMemoryLow is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultStartupMemoryLow is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultMemoryMin is not documented!-->
|
||||||
|
|
||||||
<!--property MemoryMin is not documented!-->
|
<!--property MemoryMin is not documented!-->
|
||||||
|
|
||||||
<!--property MemoryLow is not documented!-->
|
<!--property MemoryLow is not documented!-->
|
||||||
@ -4324,6 +4336,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAccounting"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryLow"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultStartupMemoryLow"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryMin"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryMin"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryMin"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryLow"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryLow"/>
|
||||||
@ -5220,6 +5238,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly b MemoryAccounting = ...;
|
readonly b MemoryAccounting = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultMemoryLow = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultStartupMemoryLow = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultMemoryMin = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly t MemoryMin = ...;
|
readonly t MemoryMin = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly t MemoryLow = ...;
|
readonly t MemoryLow = ...;
|
||||||
@ -5905,6 +5929,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
|
|
||||||
<!--property MemoryAccounting is not documented!-->
|
<!--property MemoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultMemoryLow is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultStartupMemoryLow is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultMemoryMin is not documented!-->
|
||||||
|
|
||||||
<!--property MemoryMin is not documented!-->
|
<!--property MemoryMin is not documented!-->
|
||||||
|
|
||||||
<!--property MemoryLow is not documented!-->
|
<!--property MemoryLow is not documented!-->
|
||||||
@ -6569,6 +6599,12 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAccounting"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryLow"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultStartupMemoryLow"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryMin"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryMin"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryMin"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryLow"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryLow"/>
|
||||||
@ -7289,6 +7325,12 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly b MemoryAccounting = ...;
|
readonly b MemoryAccounting = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultMemoryLow = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultStartupMemoryLow = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultMemoryMin = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly t MemoryMin = ...;
|
readonly t MemoryMin = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly t MemoryLow = ...;
|
readonly t MemoryLow = ...;
|
||||||
@ -7898,6 +7940,12 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
|
|
||||||
<!--property MemoryAccounting is not documented!-->
|
<!--property MemoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultMemoryLow is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultStartupMemoryLow is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultMemoryMin is not documented!-->
|
||||||
|
|
||||||
<!--property MemoryMin is not documented!-->
|
<!--property MemoryMin is not documented!-->
|
||||||
|
|
||||||
<!--property MemoryLow is not documented!-->
|
<!--property MemoryLow is not documented!-->
|
||||||
@ -8470,6 +8518,12 @@ node /org/freedesktop/systemd1/unit/home_2emount {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAccounting"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryLow"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultStartupMemoryLow"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryMin"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryMin"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryMin"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryLow"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryLow"/>
|
||||||
@ -9323,6 +9377,12 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly b MemoryAccounting = ...;
|
readonly b MemoryAccounting = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultMemoryLow = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultStartupMemoryLow = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultMemoryMin = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly t MemoryMin = ...;
|
readonly t MemoryMin = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly t MemoryLow = ...;
|
readonly t MemoryLow = ...;
|
||||||
@ -9914,6 +9974,12 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
|
|
||||||
<!--property MemoryAccounting is not documented!-->
|
<!--property MemoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultMemoryLow is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultStartupMemoryLow is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultMemoryMin is not documented!-->
|
||||||
|
|
||||||
<!--property MemoryMin is not documented!-->
|
<!--property MemoryMin is not documented!-->
|
||||||
|
|
||||||
<!--property MemoryLow is not documented!-->
|
<!--property MemoryLow is not documented!-->
|
||||||
@ -10468,6 +10534,12 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAccounting"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryLow"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultStartupMemoryLow"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryMin"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryMin"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryMin"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryLow"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryLow"/>
|
||||||
@ -11174,6 +11246,12 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly b MemoryAccounting = ...;
|
readonly b MemoryAccounting = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultMemoryLow = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultStartupMemoryLow = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultMemoryMin = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly t MemoryMin = ...;
|
readonly t MemoryMin = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly t MemoryLow = ...;
|
readonly t MemoryLow = ...;
|
||||||
@ -11349,6 +11427,12 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
|
|||||||
|
|
||||||
<!--property MemoryAccounting is not documented!-->
|
<!--property MemoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultMemoryLow is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultStartupMemoryLow is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultMemoryMin is not documented!-->
|
||||||
|
|
||||||
<!--property MemoryMin is not documented!-->
|
<!--property MemoryMin is not documented!-->
|
||||||
|
|
||||||
<!--property MemoryLow is not documented!-->
|
<!--property MemoryLow is not documented!-->
|
||||||
@ -11535,6 +11619,12 @@ node /org/freedesktop/systemd1/unit/system_2eslice {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAccounting"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryLow"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultStartupMemoryLow"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryMin"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryMin"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryMin"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryLow"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryLow"/>
|
||||||
@ -11746,6 +11836,12 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
|
|||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly b MemoryAccounting = ...;
|
readonly b MemoryAccounting = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultMemoryLow = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultStartupMemoryLow = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
|
readonly t DefaultMemoryMin = ...;
|
||||||
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly t MemoryMin = ...;
|
readonly t MemoryMin = ...;
|
||||||
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
|
||||||
readonly t MemoryLow = ...;
|
readonly t MemoryLow = ...;
|
||||||
@ -11935,6 +12031,12 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
|
|||||||
|
|
||||||
<!--property MemoryAccounting is not documented!-->
|
<!--property MemoryAccounting is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultMemoryLow is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultStartupMemoryLow is not documented!-->
|
||||||
|
|
||||||
|
<!--property DefaultMemoryMin is not documented!-->
|
||||||
|
|
||||||
<!--property MemoryMin is not documented!-->
|
<!--property MemoryMin is not documented!-->
|
||||||
|
|
||||||
<!--property MemoryLow is not documented!-->
|
<!--property MemoryLow is not documented!-->
|
||||||
@ -12145,6 +12247,12 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope {
|
|||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAccounting"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryAccounting"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryLow"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultStartupMemoryLow"/>
|
||||||
|
|
||||||
|
<variablelist class="dbus-property" generated="True" extra-ref="DefaultMemoryMin"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryMin"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryMin"/>
|
||||||
|
|
||||||
<variablelist class="dbus-property" generated="True" extra-ref="MemoryLow"/>
|
<variablelist class="dbus-property" generated="True" extra-ref="MemoryLow"/>
|
||||||
|
|||||||
@ -141,11 +141,6 @@
|
|||||||
immediately started (blocking operation unless <option>--no-block</option> is passed) and/or enabled after
|
immediately started (blocking operation unless <option>--no-block</option> is passed) and/or enabled after
|
||||||
attaching the image.</para>
|
attaching the image.</para>
|
||||||
|
|
||||||
<para>When images are attached, an image policy will be generated that pins the attached image by
|
|
||||||
the exact content that was found while attaching, so that it cannot be swapped downgrading security
|
|
||||||
(e.g.: removing dm-verity protection) without a full reinstallation. For more details on policies, see
|
|
||||||
<citerefentry><refentrytitle>systemd.image-policy</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
|
|
||||||
|
|
||||||
<xi:include href="vpick.xml" xpointer="image"/>
|
<xi:include href="vpick.xml" xpointer="image"/>
|
||||||
<xi:include href="vpick.xml" xpointer="directory"/>
|
<xi:include href="vpick.xml" xpointer="directory"/>
|
||||||
<xi:include href="version-info.xml" xpointer="v239"/>
|
<xi:include href="version-info.xml" xpointer="v239"/>
|
||||||
|
|||||||
@ -869,18 +869,13 @@
|
|||||||
<term><varname>EncryptedVolume=</varname></term>
|
<term><varname>EncryptedVolume=</varname></term>
|
||||||
|
|
||||||
<listitem><para>Specifies how the encrypted partition should be set up. Takes at least one and at most
|
<listitem><para>Specifies how the encrypted partition should be set up. Takes at least one and at most
|
||||||
four fields separated with a colon (<literal>:</literal>). The first field specifies the encrypted
|
three fields separated with a colon (<literal>:</literal>). The first field specifies the encrypted
|
||||||
volume name under <filename>/dev/mapper/</filename>. If not specified, <literal>luks-UUID</literal>
|
volume name under <filename>/dev/mapper/</filename>. If not specified, <literal>luks-UUID</literal>
|
||||||
will be used where <literal>UUID</literal> is the LUKS UUID. The second field specifies the keyfile
|
will be used where <literal>UUID</literal> is the LUKS UUID. The second field specifies the keyfile
|
||||||
to use following the same format as specified in crypttab. The third field specifies a
|
to use following the same format as specified in crypttab. The third field specifies a
|
||||||
comma-delimited list of crypttab options. These three fields correspond to the first, third and fourth
|
comma-delimited list of crypttab options. These fields correspond to the first, third and fourth
|
||||||
column of the
|
column of the
|
||||||
<citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>5</manvolnum></citerefentry> format.
|
<citerefentry><refentrytitle>crypttab</refentrytitle><manvolnum>5</manvolnum></citerefentry> format.
|
||||||
The fourth field contains extra options, which are not directly reflected to crypttab options. Currently,
|
|
||||||
the only supported extra option is <varname>fixate-volume-key</varname>. When specified, the volume key
|
|
||||||
hash will be taken upon LUKS volume formatting and the result will be added to the list of crypttab options,
|
|
||||||
i.e. <varname>fixate-volume-key=expected-hash</varname> will be added to the fourth column of the generated
|
|
||||||
crypttab.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>Note that this setting is only taken into account when <option>--generate-crypttab=</option>
|
<para>Note that this setting is only taken into account when <option>--generate-crypttab=</option>
|
||||||
|
|||||||
@ -326,7 +326,7 @@ CPUWeight=20 DisableControllers=cpu / \
|
|||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>MemoryMin=<replaceable>bytes</replaceable></varname>, <varname>MemoryLow=<replaceable>bytes</replaceable></varname></term>
|
<term><varname>MemoryMin=<replaceable>bytes</replaceable></varname>, <varname>MemoryLow=<replaceable>bytes</replaceable></varname></term>
|
||||||
<term><varname>StartupMemoryLow=<replaceable>bytes</replaceable></varname></term>
|
<term><varname>StartupMemoryLow=<replaceable>bytes</replaceable></varname>, <varname>DefaultStartupMemoryLow=<replaceable>bytes</replaceable></varname></term>
|
||||||
|
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>These settings control the <option>memory</option> controller in the unified hierarchy.</para>
|
<para>These settings control the <option>memory</option> controller in the unified hierarchy.</para>
|
||||||
@ -353,6 +353,16 @@ CPUWeight=20 DisableControllers=cpu / \
|
|||||||
For details about this control group attribute, see <ulink
|
For details about this control group attribute, see <ulink
|
||||||
url="https://docs.kernel.org/admin-guide/cgroup-v2.html#memory-interface-files">Memory Interface Files</ulink>.</para>
|
url="https://docs.kernel.org/admin-guide/cgroup-v2.html#memory-interface-files">Memory Interface Files</ulink>.</para>
|
||||||
|
|
||||||
|
<para>Units may have their children use a default <literal>memory.min</literal> or
|
||||||
|
<literal>memory.low</literal> value by specifying <varname>DefaultMemoryMin=</varname> or
|
||||||
|
<varname>DefaultMemoryLow=</varname>, which has the same semantics as
|
||||||
|
<varname>MemoryMin=</varname> and <varname>MemoryLow=</varname>, or <varname>DefaultStartupMemoryLow=</varname>
|
||||||
|
which has the same semantics as <varname>StartupMemoryLow=</varname>.
|
||||||
|
This setting does not affect <literal>memory.min</literal> or <literal>memory.low</literal>
|
||||||
|
in the unit itself.
|
||||||
|
Using it to set a default child allocation is only useful on kernels older than 5.7,
|
||||||
|
which do not support the <literal>memory_recursiveprot</literal> cgroup2 mount option.</para>
|
||||||
|
|
||||||
<para>While <varname>StartupMemoryLow=</varname> applies to the startup and shutdown phases of the system,
|
<para>While <varname>StartupMemoryLow=</varname> applies to the startup and shutdown phases of the system,
|
||||||
<varname>MemoryMin=</varname> applies to normal runtime of the system, and if the former is not set also to
|
<varname>MemoryMin=</varname> applies to normal runtime of the system, and if the former is not set also to
|
||||||
the startup and shutdown phases. Using <varname>StartupMemoryLow=</varname> allows prioritizing specific services at
|
the startup and shutdown phases. Using <varname>StartupMemoryLow=</varname> allows prioritizing specific services at
|
||||||
|
|||||||
@ -18,6 +18,9 @@ TS="${SOURCE_DATE_EPOCH:-$(date +%s)}"
|
|||||||
# The openSUSE filelists hardcode the manpage compression extension. This causes rpmbuild errors since we
|
# The openSUSE filelists hardcode the manpage compression extension. This causes rpmbuild errors since we
|
||||||
# disable manpage compression as the files cannot be found. Fix the issue by removing the compression
|
# disable manpage compression as the files cannot be found. Fix the issue by removing the compression
|
||||||
# extension.
|
# extension.
|
||||||
|
#
|
||||||
|
# TODO: remove patches for removal of cgroups-agent, renaming pubring file, and removal of sysv files
|
||||||
|
# when the upstream spec is updated
|
||||||
while read -r filelist; do
|
while read -r filelist; do
|
||||||
sed -E \
|
sed -E \
|
||||||
-e 's/\.gz$//' \
|
-e 's/\.gz$//' \
|
||||||
|
|||||||
@ -321,7 +321,22 @@ int futimens_opath(int fd, const struct timespec ts[2]) {
|
|||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
|
|
||||||
return RET_NERRNO(utimensat(fd, "", ts, AT_EMPTY_PATH));
|
if (utimensat(fd, "", ts, AT_EMPTY_PATH) >= 0)
|
||||||
|
return 0;
|
||||||
|
if (errno != EINVAL)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
/* Support for AT_EMPTY_PATH is added rather late (kernel 5.8), so fall back to going through /proc/
|
||||||
|
* if unavailable. */
|
||||||
|
|
||||||
|
if (utimensat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), ts, /* flags= */ 0) < 0) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
return proc_fd_enoent_errno();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int stat_warn_permissions(const char *path, const struct stat *st) {
|
int stat_warn_permissions(const char *path, const struct stat *st) {
|
||||||
@ -360,19 +375,6 @@ int access_nofollow(const char *path, int mode) {
|
|||||||
return RET_NERRNO(faccessat(AT_FDCWD, path, mode, AT_SYMLINK_NOFOLLOW));
|
return RET_NERRNO(faccessat(AT_FDCWD, path, mode, AT_SYMLINK_NOFOLLOW));
|
||||||
}
|
}
|
||||||
|
|
||||||
int access_fd(int fd, int mode) {
|
|
||||||
/* Like access() but operates on an already open fd */
|
|
||||||
|
|
||||||
if (fd == AT_FDCWD)
|
|
||||||
return RET_NERRNO(access(".", mode));
|
|
||||||
if (fd == XAT_FDROOT)
|
|
||||||
return RET_NERRNO(access("/", mode));
|
|
||||||
|
|
||||||
assert(fd >= 0);
|
|
||||||
|
|
||||||
return RET_NERRNO(faccessat(fd, "", mode, AT_EMPTY_PATH));
|
|
||||||
}
|
|
||||||
|
|
||||||
int touch_fd(int fd, usec_t stamp) {
|
int touch_fd(int fd, usec_t stamp) {
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
|
|
||||||
@ -710,6 +712,34 @@ char* unlink_and_free(char *p) {
|
|||||||
return mfree(p);
|
return mfree(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int access_fd(int fd, int mode) {
|
||||||
|
/* Like access() but operates on an already open fd */
|
||||||
|
|
||||||
|
if (fd == AT_FDCWD)
|
||||||
|
return RET_NERRNO(access(".", mode));
|
||||||
|
if (fd == XAT_FDROOT)
|
||||||
|
return RET_NERRNO(access("/", mode));
|
||||||
|
|
||||||
|
assert(fd >= 0);
|
||||||
|
|
||||||
|
if (faccessat(fd, "", mode, AT_EMPTY_PATH) >= 0)
|
||||||
|
return 0;
|
||||||
|
if (errno != EINVAL)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
/* Support for AT_EMPTY_PATH is added rather late (kernel 5.8), so fall back to going through /proc/
|
||||||
|
* if unavailable. */
|
||||||
|
|
||||||
|
if (access(FORMAT_PROC_FD_PATH(fd), mode) < 0) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
return proc_fd_enoent_errno();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
|
int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) {
|
||||||
_cleanup_close_ int truncate_fd = -EBADF;
|
_cleanup_close_ int truncate_fd = -EBADF;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@ -1158,6 +1188,19 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
|
|||||||
* • The dir fd can be passed as XAT_FDROOT, in which case any relative paths will be taken relative to the root fs.
|
* • The dir fd can be passed as XAT_FDROOT, in which case any relative paths will be taken relative to the root fs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
_cleanup_close_ int _dir_fd = -EBADF;
|
||||||
|
if (dir_fd == XAT_FDROOT) {
|
||||||
|
if (path_is_absolute(path))
|
||||||
|
dir_fd = AT_FDCWD;
|
||||||
|
else {
|
||||||
|
_dir_fd = open("/", O_CLOEXEC|O_DIRECTORY|O_RDONLY);
|
||||||
|
if (_dir_fd < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
|
dir_fd = _dir_fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == MODE_INVALID)
|
if (mode == MODE_INVALID)
|
||||||
mode = (open_flags & O_DIRECTORY) ? 0755 : 0644;
|
mode = (open_flags & O_DIRECTORY) ? 0755 : 0644;
|
||||||
|
|
||||||
@ -1173,19 +1216,6 @@ int xopenat_full(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_
|
|||||||
return fd_reopen(dir_fd, open_flags & ~O_NOFOLLOW);
|
return fd_reopen(dir_fd, open_flags & ~O_NOFOLLOW);
|
||||||
}
|
}
|
||||||
|
|
||||||
_cleanup_close_ int _dir_fd = -EBADF;
|
|
||||||
if (dir_fd == XAT_FDROOT) {
|
|
||||||
if (path_is_absolute(path))
|
|
||||||
dir_fd = AT_FDCWD;
|
|
||||||
else {
|
|
||||||
_dir_fd = open("/", O_CLOEXEC|O_DIRECTORY|O_PATH);
|
|
||||||
if (_dir_fd < 0)
|
|
||||||
return -errno;
|
|
||||||
|
|
||||||
dir_fd = _dir_fd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool call_label_ops_post = false;
|
bool call_label_ops_post = false;
|
||||||
|
|
||||||
if (FLAGS_SET(open_flags, O_CREAT) && FLAGS_SET(xopen_flags, XO_LABEL)) {
|
if (FLAGS_SET(open_flags, O_CREAT) && FLAGS_SET(xopen_flags, XO_LABEL)) {
|
||||||
|
|||||||
@ -42,7 +42,6 @@ int fd_warn_permissions(const char *path, int fd);
|
|||||||
int stat_warn_permissions(const char *path, const struct stat *st);
|
int stat_warn_permissions(const char *path, const struct stat *st);
|
||||||
|
|
||||||
int access_nofollow(const char *path, int mode);
|
int access_nofollow(const char *path, int mode);
|
||||||
int access_fd(int fd, int mode);
|
|
||||||
|
|
||||||
int touch_fd(int fd, usec_t stamp);
|
int touch_fd(int fd, usec_t stamp);
|
||||||
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
|
int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode);
|
||||||
@ -87,6 +86,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rmdir_and_free);
|
|||||||
char* unlink_and_free(char *p);
|
char* unlink_and_free(char *p);
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free);
|
||||||
|
|
||||||
|
int access_fd(int fd, int mode);
|
||||||
|
|
||||||
typedef enum UnlinkDeallocateFlags {
|
typedef enum UnlinkDeallocateFlags {
|
||||||
UNLINK_REMOVEDIR = 1 << 0,
|
UNLINK_REMOVEDIR = 1 << 0,
|
||||||
UNLINK_ERASE = 1 << 1,
|
UNLINK_ERASE = 1 << 1,
|
||||||
|
|||||||
@ -529,6 +529,66 @@ bool mount_new_api_supported(void) {
|
|||||||
return (cache = true);
|
return (cache = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long ms_nosymfollow_supported(void) {
|
||||||
|
_cleanup_close_ int fsfd = -EBADF, mntfd = -EBADF;
|
||||||
|
static int cache = -1;
|
||||||
|
|
||||||
|
/* Returns MS_NOSYMFOLLOW if it is supported, zero otherwise. */
|
||||||
|
|
||||||
|
if (cache >= 0)
|
||||||
|
return cache ? MS_NOSYMFOLLOW : 0;
|
||||||
|
|
||||||
|
if (!mount_new_api_supported())
|
||||||
|
goto not_supported;
|
||||||
|
|
||||||
|
/* Checks if MS_NOSYMFOLLOW is supported (which was added in 5.10). We use the new mount API's
|
||||||
|
* mount_setattr() call for that, which was added in 5.12, which is close enough. */
|
||||||
|
|
||||||
|
fsfd = fsopen("tmpfs", FSOPEN_CLOEXEC);
|
||||||
|
if (fsfd < 0) {
|
||||||
|
if (ERRNO_IS_NOT_SUPPORTED(errno))
|
||||||
|
goto not_supported;
|
||||||
|
|
||||||
|
log_debug_errno(errno, "Failed to open superblock context for tmpfs: %m");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fsconfig(fsfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0) < 0) {
|
||||||
|
if (ERRNO_IS_NOT_SUPPORTED(errno))
|
||||||
|
goto not_supported;
|
||||||
|
|
||||||
|
log_debug_errno(errno, "Failed to create tmpfs superblock: %m");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mntfd = fsmount(fsfd, FSMOUNT_CLOEXEC, 0);
|
||||||
|
if (mntfd < 0) {
|
||||||
|
if (ERRNO_IS_NOT_SUPPORTED(errno))
|
||||||
|
goto not_supported;
|
||||||
|
|
||||||
|
log_debug_errno(errno, "Failed to turn superblock fd into mount fd: %m");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mount_setattr(mntfd, "", AT_EMPTY_PATH|AT_RECURSIVE,
|
||||||
|
&(struct mount_attr) {
|
||||||
|
.attr_set = MOUNT_ATTR_NOSYMFOLLOW,
|
||||||
|
}, sizeof(struct mount_attr)) < 0) {
|
||||||
|
if (ERRNO_IS_NOT_SUPPORTED(errno))
|
||||||
|
goto not_supported;
|
||||||
|
|
||||||
|
log_debug_errno(errno, "Failed to set MOUNT_ATTR_NOSYMFOLLOW mount attribute: %m");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache = true;
|
||||||
|
return MS_NOSYMFOLLOW;
|
||||||
|
|
||||||
|
not_supported:
|
||||||
|
cache = false;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int mount_option_supported(const char *fstype, const char *key, const char *value) {
|
int mount_option_supported(const char *fstype, const char *key, const char *value) {
|
||||||
_cleanup_close_ int fd = -EBADF;
|
_cleanup_close_ int fd = -EBADF;
|
||||||
int r;
|
int r;
|
||||||
|
|||||||
@ -75,6 +75,7 @@ int mount_propagation_flag_from_string(const char *name, unsigned long *ret);
|
|||||||
bool mount_propagation_flag_is_valid(unsigned long flag);
|
bool mount_propagation_flag_is_valid(unsigned long flag);
|
||||||
|
|
||||||
bool mount_new_api_supported(void);
|
bool mount_new_api_supported(void);
|
||||||
|
unsigned long ms_nosymfollow_supported(void);
|
||||||
|
|
||||||
int mount_option_supported(const char *fstype, const char *key, const char *value);
|
int mount_option_supported(const char *fstype, const char *key, const char *value);
|
||||||
|
|
||||||
|
|||||||
@ -1804,7 +1804,7 @@ int namespace_fork_full(
|
|||||||
|
|
||||||
r = pidref_safe_fork_full(
|
r = pidref_safe_fork_full(
|
||||||
outer_name,
|
outer_name,
|
||||||
/* stdio_fds= */ NULL, /* except_fds= */ NULL, /* n_except_fds= */ 0,
|
/* stdio_fds = */ NULL, /* except_fds = */ NULL, /* n_except_fds = */ 0,
|
||||||
(flags|FORK_DEATHSIG_SIGKILL) & ~(FORK_DEATHSIG_SIGTERM|FORK_DEATHSIG_SIGINT|FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_NEW_USERNS|FORK_NEW_NETNS|FORK_NEW_PIDNS|FORK_CLOSE_ALL_FDS|FORK_PACK_FDS|FORK_CLOEXEC_OFF|FORK_RLIMIT_NOFILE_SAFE),
|
(flags|FORK_DEATHSIG_SIGKILL) & ~(FORK_DEATHSIG_SIGTERM|FORK_DEATHSIG_SIGINT|FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_NEW_USERNS|FORK_NEW_NETNS|FORK_NEW_PIDNS|FORK_CLOSE_ALL_FDS|FORK_PACK_FDS|FORK_CLOEXEC_OFF|FORK_RLIMIT_NOFILE_SAFE),
|
||||||
&pidref_outer);
|
&pidref_outer);
|
||||||
if (r == -EPROTO && FLAGS_SET(flags, FORK_WAIT)) {
|
if (r == -EPROTO && FLAGS_SET(flags, FORK_WAIT)) {
|
||||||
|
|||||||
@ -36,7 +36,8 @@ int readdir_all(int dir_fd, RecurseDirFlags flags, DirectoryEntries **ret) {
|
|||||||
|
|
||||||
assert(dir_fd >= 0);
|
assert(dir_fd >= 0);
|
||||||
|
|
||||||
/* Returns an array with pointers to "struct dirent" directory entries, optionally sorted.
|
/* Returns an array with pointers to "struct dirent" directory entries, optionally sorted. Free the
|
||||||
|
* array with readdir_all_freep().
|
||||||
*
|
*
|
||||||
* Start with space for up to 8 directory entries. We expect at least 2 ("." + ".."), hence hopefully
|
* Start with space for up to 8 directory entries. We expect at least 2 ("." + ".."), hence hopefully
|
||||||
* 8 will cover most cases comprehensively. (Note that most likely a lot more entries will actually
|
* 8 will cover most cases comprehensively. (Note that most likely a lot more entries will actually
|
||||||
|
|||||||
@ -257,22 +257,6 @@ static int xfstatfs(int fd, struct statfs *ret) {
|
|||||||
return RET_NERRNO(fstatfs(fd, ret));
|
return RET_NERRNO(fstatfs(fd, ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
|
|
||||||
_cleanup_close_ int fd = -EBADF;
|
|
||||||
|
|
||||||
assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT));
|
|
||||||
assert(ret);
|
|
||||||
|
|
||||||
if (!isempty(path)) {
|
|
||||||
fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC);
|
|
||||||
if (fd < 0)
|
|
||||||
return fd;
|
|
||||||
dir_fd = fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
return xfstatfs(dir_fd, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
int fd_is_read_only_fs(int fd) {
|
int fd_is_read_only_fs(int fd) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -538,6 +522,22 @@ bool statx_mount_same(const struct statx *a, const struct statx *b) {
|
|||||||
return a->stx_mnt_id == b->stx_mnt_id;
|
return a->stx_mnt_id == b->stx_mnt_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int xstatfsat(int dir_fd, const char *path, struct statfs *ret) {
|
||||||
|
_cleanup_close_ int fd = -EBADF;
|
||||||
|
|
||||||
|
assert(dir_fd >= 0 || IN_SET(dir_fd, AT_FDCWD, XAT_FDROOT));
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
if (!isempty(path)) {
|
||||||
|
fd = xopenat(dir_fd, path, O_PATH|O_CLOEXEC|O_NOCTTY);
|
||||||
|
if (fd < 0)
|
||||||
|
return fd;
|
||||||
|
dir_fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RET_NERRNO(xfstatfs(dir_fd, ret));
|
||||||
|
}
|
||||||
|
|
||||||
usec_t statx_timestamp_load(const struct statx_timestamp *ts) {
|
usec_t statx_timestamp_load(const struct statx_timestamp *ts) {
|
||||||
return timespec_load(&(const struct timespec) { .tv_sec = ts->tv_sec, .tv_nsec = ts->tv_nsec });
|
return timespec_load(&(const struct timespec) { .tv_sec = ts->tv_sec, .tv_nsec = ts->tv_nsec });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,7 +65,7 @@ static int bind_network_interface_install_impl(Unit *u, CGroupRuntime *crt) {
|
|||||||
if (isempty(cc->bind_network_interface))
|
if (isempty(cc->bind_network_interface))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = cg_get_path(crt->cgroup_path, /* suffix= */ NULL, &cgroup_path);
|
r = cg_get_path(crt->cgroup_path, /* suffix = */ NULL, &cgroup_path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_unit_error_errno(u, r, "bind-interface: Failed to get cgroup path: %m");
|
return log_unit_error_errno(u, r, "bind-interface: Failed to get cgroup path: %m");
|
||||||
|
|
||||||
|
|||||||
@ -330,13 +330,13 @@ static int unit_compare_memory_limit(Unit *u, const char *property_name, uint64_
|
|||||||
bool startup = u->manager && IN_SET(manager_state(u->manager), MANAGER_STARTING, MANAGER_INITIALIZING, MANAGER_STOPPING);
|
bool startup = u->manager && IN_SET(manager_state(u->manager), MANAGER_STARTING, MANAGER_INITIALIZING, MANAGER_STOPPING);
|
||||||
|
|
||||||
if (streq(property_name, "MemoryLow")) {
|
if (streq(property_name, "MemoryLow")) {
|
||||||
unit_value = c->memory_low;
|
unit_value = unit_get_ancestor_memory_low(u);
|
||||||
file = "memory.low";
|
file = "memory.low";
|
||||||
} else if (startup && streq(property_name, "StartupMemoryLow")) {
|
} else if (startup && streq(property_name, "StartupMemoryLow")) {
|
||||||
unit_value = c->startup_memory_low;
|
unit_value = unit_get_ancestor_startup_memory_low(u);
|
||||||
file = "memory.low";
|
file = "memory.low";
|
||||||
} else if (streq(property_name, "MemoryMin")) {
|
} else if (streq(property_name, "MemoryMin")) {
|
||||||
unit_value = c->memory_min;
|
unit_value = unit_get_ancestor_memory_min(u);
|
||||||
file = "memory.min";
|
file = "memory.min";
|
||||||
} else if (streq(property_name, "MemoryHigh")) {
|
} else if (streq(property_name, "MemoryHigh")) {
|
||||||
unit_value = c->memory_high;
|
unit_value = c->memory_high;
|
||||||
@ -504,6 +504,8 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
|
|||||||
"%sStartupAllowedMemoryNodes: %s\n"
|
"%sStartupAllowedMemoryNodes: %s\n"
|
||||||
"%sIOWeight: %" PRIu64 "\n"
|
"%sIOWeight: %" PRIu64 "\n"
|
||||||
"%sStartupIOWeight: %" PRIu64 "\n"
|
"%sStartupIOWeight: %" PRIu64 "\n"
|
||||||
|
"%sDefaultMemoryMin: %" PRIu64 "\n"
|
||||||
|
"%sDefaultMemoryLow: %" PRIu64 "\n"
|
||||||
"%sMemoryMin: %" PRIu64 "%s\n"
|
"%sMemoryMin: %" PRIu64 "%s\n"
|
||||||
"%sMemoryLow: %" PRIu64 "%s\n"
|
"%sMemoryLow: %" PRIu64 "%s\n"
|
||||||
"%sStartupMemoryLow: %" PRIu64 "%s\n"
|
"%sStartupMemoryLow: %" PRIu64 "%s\n"
|
||||||
@ -540,6 +542,8 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
|
|||||||
prefix, strempty(startup_cpuset_mems),
|
prefix, strempty(startup_cpuset_mems),
|
||||||
prefix, c->io_weight,
|
prefix, c->io_weight,
|
||||||
prefix, c->startup_io_weight,
|
prefix, c->startup_io_weight,
|
||||||
|
prefix, c->default_memory_min,
|
||||||
|
prefix, c->default_memory_low,
|
||||||
prefix, c->memory_min, format_cgroup_memory_limit_comparison(u, "MemoryMin", cda, sizeof(cda)),
|
prefix, c->memory_min, format_cgroup_memory_limit_comparison(u, "MemoryMin", cda, sizeof(cda)),
|
||||||
prefix, c->memory_low, format_cgroup_memory_limit_comparison(u, "MemoryLow", cdb, sizeof(cdb)),
|
prefix, c->memory_low, format_cgroup_memory_limit_comparison(u, "MemoryLow", cdb, sizeof(cdb)),
|
||||||
prefix, c->startup_memory_low, format_cgroup_memory_limit_comparison(u, "StartupMemoryLow", cdc, sizeof(cdc)),
|
prefix, c->startup_memory_low, format_cgroup_memory_limit_comparison(u, "StartupMemoryLow", cdc, sizeof(cdc)),
|
||||||
@ -760,6 +764,36 @@ int cgroup_context_add_bpf_foreign_program(CGroupContext *c, uint32_t attach_typ
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define UNIT_DEFINE_ANCESTOR_MEMORY_LOOKUP(entry) \
|
||||||
|
uint64_t unit_get_ancestor_##entry(Unit *u) { \
|
||||||
|
CGroupContext *c; \
|
||||||
|
\
|
||||||
|
/* 1. Is entry set in this unit? If so, use that. \
|
||||||
|
* 2. Is the default for this entry set in any \
|
||||||
|
* ancestor? If so, use that. \
|
||||||
|
* 3. Otherwise, return CGROUP_LIMIT_MIN. */ \
|
||||||
|
\
|
||||||
|
assert(u); \
|
||||||
|
\
|
||||||
|
c = unit_get_cgroup_context(u); \
|
||||||
|
if (c && c->entry##_set) \
|
||||||
|
return c->entry; \
|
||||||
|
\
|
||||||
|
while ((u = UNIT_GET_SLICE(u))) { \
|
||||||
|
c = unit_get_cgroup_context(u); \
|
||||||
|
if (c && c->default_##entry##_set) \
|
||||||
|
return c->default_##entry; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* We've reached the root, but nobody had default for \
|
||||||
|
* this entry set, so set it to the kernel default. */ \
|
||||||
|
return CGROUP_LIMIT_MIN; \
|
||||||
|
}
|
||||||
|
|
||||||
|
UNIT_DEFINE_ANCESTOR_MEMORY_LOOKUP(memory_low);
|
||||||
|
UNIT_DEFINE_ANCESTOR_MEMORY_LOOKUP(startup_memory_low);
|
||||||
|
UNIT_DEFINE_ANCESTOR_MEMORY_LOOKUP(memory_min);
|
||||||
|
|
||||||
static void unit_set_xattr_graceful(Unit *u, const char *name, const void *data, size_t size) {
|
static void unit_set_xattr_graceful(Unit *u, const char *name, const void *data, size_t size) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -910,12 +944,39 @@ static void cgroup_delegate_xattr_apply(Unit *u) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void cgroup_survive_xattr_apply(Unit *u) {
|
static void cgroup_survive_xattr_apply(Unit *u) {
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(u);
|
assert(u);
|
||||||
|
|
||||||
if (u->survive_final_kill_signal)
|
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
|
||||||
unit_set_xattr_graceful(u, "user.survive_final_kill_signal", "1", 1);
|
if (!crt)
|
||||||
else
|
return;
|
||||||
|
|
||||||
|
if (u->survive_final_kill_signal) {
|
||||||
|
r = cg_set_xattr(
|
||||||
|
crt->cgroup_path,
|
||||||
|
"user.survive_final_kill_signal",
|
||||||
|
"1",
|
||||||
|
1,
|
||||||
|
/* flags= */ 0);
|
||||||
|
/* user xattr support was added in kernel v5.7 */
|
||||||
|
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
|
||||||
|
r = cg_set_xattr(
|
||||||
|
crt->cgroup_path,
|
||||||
|
"trusted.survive_final_kill_signal",
|
||||||
|
"1",
|
||||||
|
1,
|
||||||
|
/* flags= */ 0);
|
||||||
|
if (r < 0)
|
||||||
|
log_unit_debug_errno(u,
|
||||||
|
r,
|
||||||
|
"Failed to set 'survive_final_kill_signal' xattr on control "
|
||||||
|
"group %s, ignoring: %m",
|
||||||
|
empty_to_root(crt->cgroup_path));
|
||||||
|
} else {
|
||||||
unit_remove_xattr_graceful(u, "user.survive_final_kill_signal");
|
unit_remove_xattr_graceful(u, "user.survive_final_kill_signal");
|
||||||
|
unit_remove_xattr_graceful(u, "trusted.survive_final_kill_signal");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cgroup_xattr_apply(Unit *u) {
|
static void cgroup_xattr_apply(Unit *u) {
|
||||||
@ -1116,9 +1177,8 @@ static void cgroup_apply_cpuset(Unit *u, const CPUSet *cpus, const char *name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static bool cgroup_context_has_io_config(CGroupContext *c) {
|
static bool cgroup_context_has_io_config(CGroupContext *c) {
|
||||||
assert(c);
|
return c->io_accounting ||
|
||||||
|
c->io_weight != CGROUP_WEIGHT_INVALID ||
|
||||||
return c->io_weight != CGROUP_WEIGHT_INVALID ||
|
|
||||||
c->startup_io_weight != CGROUP_WEIGHT_INVALID ||
|
c->startup_io_weight != CGROUP_WEIGHT_INVALID ||
|
||||||
c->io_device_weights ||
|
c->io_device_weights ||
|
||||||
c->io_device_latencies ||
|
c->io_device_latencies ||
|
||||||
@ -1229,11 +1289,15 @@ static void cgroup_apply_io_device_limit(Unit *u, const char *dev_path, uint64_t
|
|||||||
(void) set_attribute_and_warn(u, "io.max", buf);
|
(void) set_attribute_and_warn(u, "io.max", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cgroup_context_has_memory_config(CGroupContext *c) {
|
static bool unit_has_memory_config(Unit *u) {
|
||||||
assert(c);
|
CGroupContext *c;
|
||||||
|
|
||||||
return c->memory_min > 0 ||
|
assert(u);
|
||||||
c->memory_low > 0 || c->startup_memory_low_set ||
|
|
||||||
|
assert_se(c = unit_get_cgroup_context(u));
|
||||||
|
|
||||||
|
return unit_get_ancestor_memory_min(u) > 0 ||
|
||||||
|
unit_get_ancestor_memory_low(u) > 0 || unit_get_ancestor_startup_memory_low(u) > 0 ||
|
||||||
c->memory_high != CGROUP_LIMIT_MAX || c->startup_memory_high_set ||
|
c->memory_high != CGROUP_LIMIT_MAX || c->startup_memory_high_set ||
|
||||||
c->memory_max != CGROUP_LIMIT_MAX || c->startup_memory_max_set ||
|
c->memory_max != CGROUP_LIMIT_MAX || c->startup_memory_max_set ||
|
||||||
c->memory_swap_max != CGROUP_LIMIT_MAX || c->startup_memory_swap_max_set ||
|
c->memory_swap_max != CGROUP_LIMIT_MAX || c->startup_memory_swap_max_set ||
|
||||||
@ -1479,20 +1543,19 @@ static void cgroup_context_apply(
|
|||||||
|
|
||||||
/* 'memory' attributes do not exist on the root cgroup. */
|
/* 'memory' attributes do not exist on the root cgroup. */
|
||||||
if ((apply_mask & CGROUP_MASK_MEMORY) && !is_local_root) {
|
if ((apply_mask & CGROUP_MASK_MEMORY) && !is_local_root) {
|
||||||
uint64_t low = CGROUP_LIMIT_MIN, max = CGROUP_LIMIT_MAX, swap_max = CGROUP_LIMIT_MAX, zswap_max = CGROUP_LIMIT_MAX, high = CGROUP_LIMIT_MAX;
|
uint64_t max = CGROUP_LIMIT_MAX, swap_max = CGROUP_LIMIT_MAX, zswap_max = CGROUP_LIMIT_MAX, high = CGROUP_LIMIT_MAX;
|
||||||
|
|
||||||
if (cgroup_context_has_memory_config(c)) {
|
if (unit_has_memory_config(u)) {
|
||||||
bool startup = IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING, MANAGER_STOPPING);
|
bool startup = IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING, MANAGER_STOPPING);
|
||||||
|
|
||||||
low = startup && c->startup_memory_low_set ? c->startup_memory_low : c->memory_low;
|
|
||||||
high = startup && c->startup_memory_high_set ? c->startup_memory_high : c->memory_high;
|
high = startup && c->startup_memory_high_set ? c->startup_memory_high : c->memory_high;
|
||||||
max = startup && c->startup_memory_max_set ? c->startup_memory_max : c->memory_max;
|
max = startup && c->startup_memory_max_set ? c->startup_memory_max : c->memory_max;
|
||||||
swap_max = startup && c->startup_memory_swap_max_set ? c->startup_memory_swap_max : c->memory_swap_max;
|
swap_max = startup && c->startup_memory_swap_max_set ? c->startup_memory_swap_max : c->memory_swap_max;
|
||||||
zswap_max = startup && c->startup_memory_zswap_max_set ? c->startup_memory_zswap_max : c->memory_zswap_max;
|
zswap_max = startup && c->startup_memory_zswap_max_set ? c->startup_memory_zswap_max : c->memory_zswap_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
cgroup_apply_memory_limit(u, "memory.min", c->memory_min);
|
cgroup_apply_memory_limit(u, "memory.min", unit_get_ancestor_memory_min(u));
|
||||||
cgroup_apply_memory_limit(u, "memory.low", low);
|
cgroup_apply_memory_limit(u, "memory.low", unit_get_ancestor_memory_low(u));
|
||||||
cgroup_apply_memory_limit(u, "memory.high", high);
|
cgroup_apply_memory_limit(u, "memory.high", high);
|
||||||
cgroup_apply_memory_limit(u, "memory.max", max);
|
cgroup_apply_memory_limit(u, "memory.max", max);
|
||||||
cgroup_apply_memory_limit(u, "memory.swap.max", swap_max);
|
cgroup_apply_memory_limit(u, "memory.swap.max", swap_max);
|
||||||
@ -1655,12 +1718,11 @@ static CGroupMask unit_get_cgroup_mask(Unit *u) {
|
|||||||
if (cgroup_context_has_allowed_cpus(c) || cgroup_context_has_allowed_mems(c))
|
if (cgroup_context_has_allowed_cpus(c) || cgroup_context_has_allowed_mems(c))
|
||||||
mask |= CGROUP_MASK_CPUSET;
|
mask |= CGROUP_MASK_CPUSET;
|
||||||
|
|
||||||
if (c->io_accounting ||
|
if (cgroup_context_has_io_config(c))
|
||||||
cgroup_context_has_io_config(c))
|
|
||||||
mask |= CGROUP_MASK_IO;
|
mask |= CGROUP_MASK_IO;
|
||||||
|
|
||||||
if (c->memory_accounting ||
|
if (c->memory_accounting ||
|
||||||
cgroup_context_has_memory_config(c))
|
unit_has_memory_config(u))
|
||||||
mask |= CGROUP_MASK_MEMORY;
|
mask |= CGROUP_MASK_MEMORY;
|
||||||
|
|
||||||
if (cgroup_context_has_device_policy(c))
|
if (cgroup_context_has_device_policy(c))
|
||||||
|
|||||||
@ -137,6 +137,9 @@ typedef struct CGroupContext {
|
|||||||
LIST_HEAD(CGroupIODeviceLimit, io_device_limits);
|
LIST_HEAD(CGroupIODeviceLimit, io_device_limits);
|
||||||
LIST_HEAD(CGroupIODeviceLatency, io_device_latencies);
|
LIST_HEAD(CGroupIODeviceLatency, io_device_latencies);
|
||||||
|
|
||||||
|
uint64_t default_memory_min;
|
||||||
|
uint64_t default_memory_low;
|
||||||
|
uint64_t default_startup_memory_low;
|
||||||
uint64_t memory_min;
|
uint64_t memory_min;
|
||||||
uint64_t memory_low;
|
uint64_t memory_low;
|
||||||
uint64_t startup_memory_low;
|
uint64_t startup_memory_low;
|
||||||
@ -149,6 +152,11 @@ typedef struct CGroupContext {
|
|||||||
uint64_t memory_zswap_max;
|
uint64_t memory_zswap_max;
|
||||||
uint64_t startup_memory_zswap_max;
|
uint64_t startup_memory_zswap_max;
|
||||||
|
|
||||||
|
bool default_memory_min_set:1;
|
||||||
|
bool default_memory_low_set:1;
|
||||||
|
bool default_startup_memory_low_set:1;
|
||||||
|
bool memory_min_set:1;
|
||||||
|
bool memory_low_set:1;
|
||||||
bool startup_memory_low_set:1;
|
bool startup_memory_low_set:1;
|
||||||
bool startup_memory_high_set:1;
|
bool startup_memory_high_set:1;
|
||||||
bool startup_memory_max_set:1;
|
bool startup_memory_max_set:1;
|
||||||
@ -408,6 +416,10 @@ Unit* manager_get_unit_by_pidref_cgroup(Manager *m, const PidRef *pid);
|
|||||||
Unit* manager_get_unit_by_pidref_watching(Manager *m, const PidRef *pid);
|
Unit* manager_get_unit_by_pidref_watching(Manager *m, const PidRef *pid);
|
||||||
Unit* manager_get_unit_by_pidref(Manager *m, PidRef *pid);
|
Unit* manager_get_unit_by_pidref(Manager *m, PidRef *pid);
|
||||||
|
|
||||||
|
uint64_t unit_get_ancestor_memory_min(Unit *u);
|
||||||
|
uint64_t unit_get_ancestor_memory_low(Unit *u);
|
||||||
|
uint64_t unit_get_ancestor_startup_memory_low(Unit *u);
|
||||||
|
|
||||||
int unit_search_main_pid(Unit *u, PidRef *ret);
|
int unit_search_main_pid(Unit *u, PidRef *ret);
|
||||||
|
|
||||||
int unit_get_memory_available(Unit *u, uint64_t *ret);
|
int unit_get_memory_available(Unit *u, uint64_t *ret);
|
||||||
|
|||||||
@ -395,6 +395,9 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
|
|||||||
SD_BUS_PROPERTY("IOWriteIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
|
SD_BUS_PROPERTY("IOWriteIOPSMax", "a(st)", property_get_io_device_limits, 0, 0),
|
||||||
SD_BUS_PROPERTY("IODeviceLatencyTargetUSec", "a(st)", property_get_io_device_latency, 0, 0),
|
SD_BUS_PROPERTY("IODeviceLatencyTargetUSec", "a(st)", property_get_io_device_latency, 0, 0),
|
||||||
SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
|
SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
|
||||||
|
SD_BUS_PROPERTY("DefaultMemoryLow", "t", NULL, offsetof(CGroupContext, default_memory_low), 0),
|
||||||
|
SD_BUS_PROPERTY("DefaultStartupMemoryLow", "t", NULL, offsetof(CGroupContext, default_startup_memory_low), 0),
|
||||||
|
SD_BUS_PROPERTY("DefaultMemoryMin", "t", NULL, offsetof(CGroupContext, default_memory_min), 0),
|
||||||
SD_BUS_PROPERTY("MemoryMin", "t", NULL, offsetof(CGroupContext, memory_min), 0),
|
SD_BUS_PROPERTY("MemoryMin", "t", NULL, offsetof(CGroupContext, memory_min), 0),
|
||||||
SD_BUS_PROPERTY("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0),
|
SD_BUS_PROPERTY("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0),
|
||||||
SD_BUS_PROPERTY("StartupMemoryLow", "t", NULL, offsetof(CGroupContext, startup_memory_low), 0),
|
SD_BUS_PROPERTY("StartupMemoryLow", "t", NULL, offsetof(CGroupContext, startup_memory_low), 0),
|
||||||
@ -444,10 +447,6 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
|
|||||||
SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_ast, 0, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_HIDDEN),
|
SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_ast, 0, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_HIDDEN),
|
||||||
/* since kernel v4.15 CPU accounting requires no controller, i.e. is available everywhere */
|
/* since kernel v4.15 CPU accounting requires no controller, i.e. is available everywhere */
|
||||||
SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool_true, 0, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_HIDDEN),
|
SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool_true, 0, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_HIDDEN),
|
||||||
/* since kernel v5.7 kernel would take care of these when cgroup is mounted with memory_recursiveprot */
|
|
||||||
SD_BUS_PROPERTY("DefaultMemoryMin", "t", bus_property_get_uint64_0, 0, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_HIDDEN),
|
|
||||||
SD_BUS_PROPERTY("DefaultMemoryLow", "t", bus_property_get_uint64_0, 0, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_HIDDEN),
|
|
||||||
SD_BUS_PROPERTY("DefaultStartupMemoryLow", "t", bus_property_get_uint64_0, 0, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_HIDDEN),
|
|
||||||
|
|
||||||
SD_BUS_VTABLE_END
|
SD_BUS_VTABLE_END
|
||||||
};
|
};
|
||||||
@ -1054,11 +1053,19 @@ int bus_cgroup_set_property(
|
|||||||
if (streq(name, "MemoryAccounting"))
|
if (streq(name, "MemoryAccounting"))
|
||||||
return bus_cgroup_set_boolean(u, name, &c->memory_accounting, CGROUP_MASK_MEMORY, message, flags, reterr_error);
|
return bus_cgroup_set_boolean(u, name, &c->memory_accounting, CGROUP_MASK_MEMORY, message, flags, reterr_error);
|
||||||
|
|
||||||
if (streq(name, "MemoryMin"))
|
if (streq(name, "MemoryMin")) {
|
||||||
return bus_cgroup_set_memory_protection(u, name, &c->memory_min, message, flags, reterr_error);
|
r = bus_cgroup_set_memory_protection(u, name, &c->memory_min, message, flags, reterr_error);
|
||||||
|
if (r > 0)
|
||||||
|
c->memory_min_set = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (streq(name, "MemoryLow"))
|
if (streq(name, "MemoryLow")) {
|
||||||
return bus_cgroup_set_memory_protection(u, name, &c->memory_low, message, flags, reterr_error);
|
r = bus_cgroup_set_memory_protection(u, name, &c->memory_low, message, flags, reterr_error);
|
||||||
|
if (r > 0)
|
||||||
|
c->memory_low_set = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (streq(name, "StartupMemoryLow")) {
|
if (streq(name, "StartupMemoryLow")) {
|
||||||
r = bus_cgroup_set_memory_protection(u, name, &c->startup_memory_low, message, flags, reterr_error);
|
r = bus_cgroup_set_memory_protection(u, name, &c->startup_memory_low, message, flags, reterr_error);
|
||||||
@ -1067,6 +1074,27 @@ int bus_cgroup_set_property(
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (streq(name, "DefaultMemoryMin")) {
|
||||||
|
r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_min, message, flags, reterr_error);
|
||||||
|
if (r > 0)
|
||||||
|
c->default_memory_min_set = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(name, "DefaultMemoryLow")) {
|
||||||
|
r = bus_cgroup_set_memory_protection(u, name, &c->default_memory_low, message, flags, reterr_error);
|
||||||
|
if (r > 0)
|
||||||
|
c->default_memory_low_set = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(name, "DefaultStartupMemoryLow")) {
|
||||||
|
r = bus_cgroup_set_memory_protection(u, name, &c->default_startup_memory_low, message, flags, reterr_error);
|
||||||
|
if (r > 0)
|
||||||
|
c->default_startup_memory_low_set = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (streq(name, "MemoryHigh"))
|
if (streq(name, "MemoryHigh"))
|
||||||
return bus_cgroup_set_memory(u, name, &c->memory_high, message, flags, reterr_error);
|
return bus_cgroup_set_memory(u, name, &c->memory_high, message, flags, reterr_error);
|
||||||
|
|
||||||
@ -1107,11 +1135,33 @@ int bus_cgroup_set_property(
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streq(name, "MemoryMinScale"))
|
if (streq(name, "MemoryMinScale")) {
|
||||||
return bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, message, flags, reterr_error);
|
r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_min, message, flags, reterr_error);
|
||||||
|
if (r > 0)
|
||||||
|
c->memory_min_set = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (streq(name, "MemoryLowScale"))
|
if (streq(name, "MemoryLowScale")) {
|
||||||
return bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, message, flags, reterr_error);
|
r = bus_cgroup_set_memory_protection_scale(u, name, &c->memory_low, message, flags, reterr_error);
|
||||||
|
if (r > 0)
|
||||||
|
c->memory_low_set = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(name, "DefaultMemoryMinScale")) {
|
||||||
|
r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_min, message, flags, reterr_error);
|
||||||
|
if (r > 0)
|
||||||
|
c->default_memory_min_set = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (streq(name, "DefaultMemoryLowScale")) {
|
||||||
|
r = bus_cgroup_set_memory_protection_scale(u, name, &c->default_memory_low, message, flags, reterr_error);
|
||||||
|
if (r > 0)
|
||||||
|
c->default_memory_low_set = true;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (streq(name, "MemoryHighScale"))
|
if (streq(name, "MemoryHighScale"))
|
||||||
return bus_cgroup_set_memory_scale(u, name, &c->memory_high, message, flags, reterr_error);
|
return bus_cgroup_set_memory_scale(u, name, &c->memory_high, message, flags, reterr_error);
|
||||||
@ -1991,8 +2041,8 @@ int bus_cgroup_set_property(
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* deprecated CGroup v1 properties */
|
||||||
if (STR_IN_SET(name,
|
if (STR_IN_SET(name,
|
||||||
/* deprecated CGroup v1 properties */
|
|
||||||
"MemoryLimit",
|
"MemoryLimit",
|
||||||
"MemoryLimitScale",
|
"MemoryLimitScale",
|
||||||
"CPUShares",
|
"CPUShares",
|
||||||
@ -2003,13 +2053,7 @@ int bus_cgroup_set_property(
|
|||||||
"BlockIODeviceWeight",
|
"BlockIODeviceWeight",
|
||||||
"BlockIOReadBandwidth",
|
"BlockIOReadBandwidth",
|
||||||
"BlockIOWriteBandwidth",
|
"BlockIOWriteBandwidth",
|
||||||
/* see comments in bus_cgroup_vtable */
|
"CPUAccounting")) { /* see comment in bus_cgroup_vtable */
|
||||||
"CPUAccounting",
|
|
||||||
"DefaultMemoryMin",
|
|
||||||
"DefaultMemoryMinScale",
|
|
||||||
"DefaultMemoryLow",
|
|
||||||
"DefaultMemoryLowScale",
|
|
||||||
"DefaultStartupMemoryLow")) {
|
|
||||||
|
|
||||||
r = sd_bus_message_skip(message, NULL);
|
r = sd_bus_message_skip(message, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|||||||
@ -796,7 +796,7 @@ static int property_get_root_hash_sig(
|
|||||||
|
|
||||||
static int bus_append_mount_options(
|
static int bus_append_mount_options(
|
||||||
sd_bus_message *reply,
|
sd_bus_message *reply,
|
||||||
const MountOptions *options) {
|
MountOptions *options) {
|
||||||
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
|||||||
@ -194,8 +194,7 @@ static int bus_service_method_mount(sd_bus_message *message, void *userdata, sd_
|
|||||||
return sd_bus_error_set(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized");
|
return sd_bus_error_set(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized");
|
||||||
|
|
||||||
if (is_image) {
|
if (is_image) {
|
||||||
r = bus_read_mount_options(message, reterr_error, &options,
|
r = bus_read_mount_options(message, reterr_error, &options, NULL, "");
|
||||||
/* in_out_format_str = */ NULL, /* separator = */ NULL);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -267,50 +267,49 @@ int bus_read_mount_options(
|
|||||||
|
|
||||||
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
|
_cleanup_(mount_options_free_allp) MountOptions *options = NULL;
|
||||||
_cleanup_free_ char *format_str = NULL;
|
_cleanup_free_ char *format_str = NULL;
|
||||||
|
const char *mount_options, *partition;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(message);
|
assert(message);
|
||||||
assert(ret_options);
|
assert(ret_options);
|
||||||
assert(!in_out_format_str == !separator);
|
assert(separator);
|
||||||
|
|
||||||
r = sd_bus_message_enter_container(message, 'a', "(ss)");
|
r = sd_bus_message_enter_container(message, 'a', "(ss)");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
const char *partition, *mount_options;
|
|
||||||
while ((r = sd_bus_message_read(message, "(ss)", &partition, &mount_options)) > 0) {
|
while ((r = sd_bus_message_read(message, "(ss)", &partition, &mount_options)) > 0) {
|
||||||
|
_cleanup_free_ char *escaped = NULL;
|
||||||
PartitionDesignator partition_designator;
|
PartitionDesignator partition_designator;
|
||||||
|
|
||||||
if (chars_intersect(mount_options, WHITESPACE))
|
if (chars_intersect(mount_options, WHITESPACE))
|
||||||
return sd_bus_error_setf(reterr_error, SD_BUS_ERROR_INVALID_ARGS,
|
return sd_bus_error_setf(reterr_error, SD_BUS_ERROR_INVALID_ARGS,
|
||||||
"Invalid mount options string, contains whitespace character(s): %s", mount_options);
|
"Invalid mount options string, contains whitespace character(s): %s", mount_options);
|
||||||
|
|
||||||
partition_designator = partition_designator_from_string(partition);
|
partition_designator = partition_designator_from_string(partition);
|
||||||
if (partition_designator < 0)
|
if (partition_designator < 0)
|
||||||
return sd_bus_error_setf(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Invalid partition name %s", partition);
|
return sd_bus_error_setf(reterr_error, SD_BUS_ERROR_INVALID_ARGS, "Invalid partition name %s", partition);
|
||||||
|
|
||||||
if (!options) {
|
/* Need to store the options with the escapes, so that they can be parsed again */
|
||||||
options = new0(MountOptions, 1);
|
escaped = shell_escape(mount_options, ":");
|
||||||
if (!options)
|
if (!escaped)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
|
||||||
|
|
||||||
r = free_and_strdup(&options->options[partition_designator], mount_options);
|
if (!isempty(escaped)) {
|
||||||
if (r < 0)
|
if (!strextend_with_separator(&format_str, separator, partition, ":", escaped))
|
||||||
return r;
|
|
||||||
|
|
||||||
if (in_out_format_str && !isempty(mount_options)) {
|
|
||||||
/* Need to store the options with the escapes, so that they can be parsed again */
|
|
||||||
_cleanup_free_ char *escaped = NULL;
|
|
||||||
|
|
||||||
escaped = shell_escape(mount_options, ":");
|
|
||||||
if (!escaped)
|
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = strextendf_with_separator(&format_str, separator, "%s:%s", partition, escaped);
|
if (!options) {
|
||||||
|
options = new0(MountOptions, 1);
|
||||||
|
if (!options)
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = free_and_strdup(&options->options[partition_designator], mount_options);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
} else if (options)
|
||||||
|
options->options[partition_designator] = mfree(options->options[partition_designator]);
|
||||||
}
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -319,10 +318,11 @@ int bus_read_mount_options(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (in_out_format_str && !strextend_with_separator(in_out_format_str, separator, format_str))
|
if (options) {
|
||||||
return -ENOMEM;
|
if (in_out_format_str && !strextend_with_separator(in_out_format_str, separator, format_str))
|
||||||
|
return -ENOMEM;
|
||||||
*ret_options = TAKE_PTR(options);
|
*ret_options = TAKE_PTR(options);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -132,6 +132,18 @@ static int exec_cgroup_context_serialize(const CGroupContext *c, FILE *f) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (c->default_memory_min > 0) {
|
||||||
|
r = serialize_item_format(f, "exec-cgroup-context-default-memory-min", "%" PRIu64, c->default_memory_min);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->default_memory_low > 0) {
|
||||||
|
r = serialize_item_format(f, "exec-cgroup-context-default-memory-low", "%" PRIu64, c->default_memory_low);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
if (c->memory_min > 0) {
|
if (c->memory_min > 0) {
|
||||||
r = serialize_item_format(f, "exec-cgroup-context-memory-min", "%" PRIu64, c->memory_min);
|
r = serialize_item_format(f, "exec-cgroup-context-memory-min", "%" PRIu64, c->memory_min);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -214,6 +226,26 @@ static int exec_cgroup_context_serialize(const CGroupContext *c, FILE *f) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = serialize_bool_elide(f, "exec-cgroup-context-default-memory-min-set", c->default_memory_min_set);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = serialize_bool_elide(f, "exec-cgroup-context-default-memory-low-set", c->default_memory_low_set);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = serialize_bool_elide(f, "exec-cgroup-context-default-startup-memory-low-set", c->default_startup_memory_low_set);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = serialize_bool_elide(f, "exec-cgroup-context-memory-min-set", c->memory_min_set);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = serialize_bool_elide(f, "exec-cgroup-context-memory-low-set", c->memory_low_set);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
r = serialize_bool_elide(f, "exec-cgroup-context-startup-memory-low-set", c->startup_memory_low_set);
|
r = serialize_bool_elide(f, "exec-cgroup-context-startup-memory-low-set", c->startup_memory_low_set);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -500,6 +532,14 @@ static int exec_cgroup_context_deserialize(CGroupContext *c, FILE *f) {
|
|||||||
r = safe_atou64(val, &c->startup_io_weight);
|
r = safe_atou64(val, &c->startup_io_weight);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
} else if ((val = startswith(l, "exec-cgroup-context-default-memory-min="))) {
|
||||||
|
r = safe_atou64(val, &c->default_memory_min);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
} else if ((val = startswith(l, "exec-cgroup-context-default-memory-low="))) {
|
||||||
|
r = safe_atou64(val, &c->default_memory_low);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
} else if ((val = startswith(l, "exec-cgroup-context-memory-min="))) {
|
} else if ((val = startswith(l, "exec-cgroup-context-memory-min="))) {
|
||||||
r = safe_atou64(val, &c->memory_min);
|
r = safe_atou64(val, &c->memory_min);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -557,6 +597,31 @@ static int exec_cgroup_context_deserialize(CGroupContext *c, FILE *f) {
|
|||||||
r = safe_atou64(val, &c->tasks_max.scale);
|
r = safe_atou64(val, &c->tasks_max.scale);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
} else if ((val = startswith(l, "exec-cgroup-context-default-memory-min-set="))) {
|
||||||
|
r = parse_boolean(val);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
c->default_memory_min_set = r;
|
||||||
|
} else if ((val = startswith(l, "exec-cgroup-context-default-memory-low-set="))) {
|
||||||
|
r = parse_boolean(val);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
c->default_memory_low_set = r;
|
||||||
|
} else if ((val = startswith(l, "exec-cgroup-context-default-startup-memory-low-set="))) {
|
||||||
|
r = parse_boolean(val);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
c->default_startup_memory_low_set = r;
|
||||||
|
} else if ((val = startswith(l, "exec-cgroup-context-memory-min-set="))) {
|
||||||
|
r = parse_boolean(val);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
c->memory_min_set = r;
|
||||||
|
} else if ((val = startswith(l, "exec-cgroup-context-memory-low-set="))) {
|
||||||
|
r = parse_boolean(val);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
c->memory_low_set = r;
|
||||||
} else if ((val = startswith(l, "exec-cgroup-context-startup-memory-low-set="))) {
|
} else if ((val = startswith(l, "exec-cgroup-context-startup-memory-low-set="))) {
|
||||||
r = parse_boolean(val);
|
r = parse_boolean(val);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|||||||
@ -223,11 +223,11 @@
|
|||||||
{{type}}.CPUQuotaPeriodSec, config_parse_sec_def_infinity, 0, offsetof({{type}}, cgroup_context.cpu_quota_period_usec)
|
{{type}}.CPUQuotaPeriodSec, config_parse_sec_def_infinity, 0, offsetof({{type}}, cgroup_context.cpu_quota_period_usec)
|
||||||
{{type}}.MemoryAccounting, config_parse_bool, 0, offsetof({{type}}, cgroup_context.memory_accounting)
|
{{type}}.MemoryAccounting, config_parse_bool, 0, offsetof({{type}}, cgroup_context.memory_accounting)
|
||||||
{{type}}.MemoryMin, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
{{type}}.MemoryMin, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
||||||
|
{{type}}.DefaultMemoryMin, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
||||||
|
{{type}}.DefaultMemoryLow, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
||||||
|
{{type}}.DefaultStartupMemoryLow, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
||||||
{{type}}.MemoryLow, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
{{type}}.MemoryLow, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
||||||
{{type}}.StartupMemoryLow, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
{{type}}.StartupMemoryLow, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
||||||
{{type}}.DefaultMemoryMin, config_parse_warn_compat, DISABLED_LEGACY, 0
|
|
||||||
{{type}}.DefaultMemoryLow, config_parse_warn_compat, DISABLED_LEGACY, 0
|
|
||||||
{{type}}.DefaultStartupMemoryLow, config_parse_warn_compat, DISABLED_LEGACY, 0
|
|
||||||
{{type}}.MemoryHigh, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
{{type}}.MemoryHigh, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
||||||
{{type}}.StartupMemoryHigh, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
{{type}}.StartupMemoryHigh, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
||||||
{{type}}.MemoryMax, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
{{type}}.MemoryMax, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
|
||||||
|
|||||||
@ -3790,7 +3790,9 @@ int config_parse_memory_limit(
|
|||||||
uint64_t bytes = CGROUP_LIMIT_MAX;
|
uint64_t bytes = CGROUP_LIMIT_MAX;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (isempty(rvalue) && STR_IN_SET(lvalue, "MemoryLow",
|
if (isempty(rvalue) && STR_IN_SET(lvalue, "DefaultMemoryLow",
|
||||||
|
"DefaultMemoryMin",
|
||||||
|
"MemoryLow",
|
||||||
"StartupMemoryLow",
|
"StartupMemoryLow",
|
||||||
"MemoryMin"))
|
"MemoryMin"))
|
||||||
bytes = CGROUP_LIMIT_MIN;
|
bytes = CGROUP_LIMIT_MIN;
|
||||||
@ -3814,17 +3816,31 @@ int config_parse_memory_limit(
|
|||||||
"StartupMemoryZSwapMax",
|
"StartupMemoryZSwapMax",
|
||||||
"MemoryLow",
|
"MemoryLow",
|
||||||
"StartupMemoryLow",
|
"StartupMemoryLow",
|
||||||
"MemoryMin"))) {
|
"MemoryMin",
|
||||||
|
"DefaultMemoryLow",
|
||||||
|
"DefaultstartupMemoryLow",
|
||||||
|
"DefaultMemoryMin"))) {
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Memory limit '%s' out of range, ignoring.", rvalue);
|
log_syntax(unit, LOG_WARNING, filename, line, 0, "Memory limit '%s' out of range, ignoring.", rvalue);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (streq(lvalue, "MemoryMin"))
|
if (streq(lvalue, "DefaultMemoryLow")) {
|
||||||
|
c->default_memory_low = bytes;
|
||||||
|
c->default_memory_low_set = true;
|
||||||
|
} else if (streq(lvalue, "DefaultStartupMemoryLow")) {
|
||||||
|
c->default_startup_memory_low = bytes;
|
||||||
|
c->default_startup_memory_low_set = true;
|
||||||
|
} else if (streq(lvalue, "DefaultMemoryMin")) {
|
||||||
|
c->default_memory_min = bytes;
|
||||||
|
c->default_memory_min_set = true;
|
||||||
|
} else if (streq(lvalue, "MemoryMin")) {
|
||||||
c->memory_min = bytes;
|
c->memory_min = bytes;
|
||||||
else if (streq(lvalue, "MemoryLow"))
|
c->memory_min_set = true;
|
||||||
|
} else if (streq(lvalue, "MemoryLow")) {
|
||||||
c->memory_low = bytes;
|
c->memory_low = bytes;
|
||||||
else if (streq(lvalue, "StartupMemoryLow")) {
|
c->memory_low_set = true;
|
||||||
|
} else if (streq(lvalue, "StartupMemoryLow")) {
|
||||||
c->startup_memory_low = bytes;
|
c->startup_memory_low = bytes;
|
||||||
c->startup_memory_low_set = true;
|
c->startup_memory_low_set = true;
|
||||||
} else if (streq(lvalue, "MemoryHigh"))
|
} else if (streq(lvalue, "MemoryHigh"))
|
||||||
|
|||||||
@ -1515,7 +1515,6 @@ static int mount_private_cgroup2fs(const MountEntry *m, const NamespaceParameter
|
|||||||
|
|
||||||
static int mount_procfs(const MountEntry *m, const NamespaceParameters *p) {
|
static int mount_procfs(const MountEntry *m, const NamespaceParameters *p) {
|
||||||
_cleanup_free_ char *opts = NULL;
|
_cleanup_free_ char *opts = NULL;
|
||||||
int r;
|
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
assert(p);
|
assert(p);
|
||||||
@ -1523,16 +1522,32 @@ static int mount_procfs(const MountEntry *m, const NamespaceParameters *p) {
|
|||||||
if (p->protect_proc != PROTECT_PROC_DEFAULT ||
|
if (p->protect_proc != PROTECT_PROC_DEFAULT ||
|
||||||
p->proc_subset != PROC_SUBSET_ALL) {
|
p->proc_subset != PROC_SUBSET_ALL) {
|
||||||
|
|
||||||
opts = strjoin("hidepid=",
|
/* Starting with kernel 5.8 procfs' hidepid= logic is truly per-instance (previously it
|
||||||
p->protect_proc == PROTECT_PROC_DEFAULT ? "off" : protect_proc_to_string(p->protect_proc));
|
* pretended to be per-instance but actually was per-namespace), hence let's make use of it
|
||||||
if (!opts)
|
* if requested. To make sure this logic succeeds only on kernels where hidepid= is
|
||||||
return -ENOMEM;
|
* per-instance, we'll exclusively use the textual value for hidepid=, since support was
|
||||||
|
* added in the same commit: if it's supported it is thus also per-instance. */
|
||||||
|
|
||||||
if (p->proc_subset != PROC_SUBSET_ALL) {
|
const char *hpv = p->protect_proc == PROTECT_PROC_DEFAULT ?
|
||||||
r = strextendf_with_separator(&opts, ",", "subset=%s", proc_subset_to_string(p->proc_subset));
|
"off" :
|
||||||
if (r < 0)
|
protect_proc_to_string(p->protect_proc);
|
||||||
return r;
|
|
||||||
|
/* hidepid= support was added in 5.8, so we can use fsconfig()/fsopen() (which were added in
|
||||||
|
* 5.2) to check if hidepid= is supported. This avoids a noisy dmesg log by the kernel when
|
||||||
|
* trying to use hidepid= on systems where it isn't supported. The same applies for subset=.
|
||||||
|
* fsopen()/fsconfig() was also backported on some distros which allows us to detect
|
||||||
|
* hidepid=/subset= support in even more scenarios. */
|
||||||
|
|
||||||
|
if (mount_option_supported("proc", "hidepid", hpv) > 0) {
|
||||||
|
opts = strjoin("hidepid=", hpv);
|
||||||
|
if (!opts)
|
||||||
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (p->proc_subset == PROC_SUBSET_PID &&
|
||||||
|
mount_option_supported("proc", "subset", "pid") > 0)
|
||||||
|
if (!strextend_with_separator(&opts, ",", "subset=pid"))
|
||||||
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mount a new instance, so that we get the one that matches our user namespace, if we are running in
|
/* Mount a new instance, so that we get the one that matches our user namespace, if we are running in
|
||||||
|
|||||||
@ -5582,7 +5582,7 @@ int unit_fork_helper_process_full(Unit *u, const char *name, bool into_cgroup, F
|
|||||||
}
|
}
|
||||||
|
|
||||||
int unit_fork_helper_process(Unit *u, const char *name, bool into_cgroup, PidRef *ret) {
|
int unit_fork_helper_process(Unit *u, const char *name, bool into_cgroup, PidRef *ret) {
|
||||||
return unit_fork_helper_process_full(u, name, into_cgroup, /* flags= */ 0, ret);
|
return unit_fork_helper_process_full(u, name, into_cgroup, /* flags = */ 0, ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int unit_fork_and_watch_rm_rf(Unit *u, char **paths, PidRef *ret_pid) {
|
int unit_fork_and_watch_rm_rf(Unit *u, char **paths, PidRef *ret_pid) {
|
||||||
|
|||||||
@ -259,9 +259,12 @@ int unit_cgroup_context_build_json(sd_json_variant **ret, const char *name, void
|
|||||||
|
|
||||||
/* Memory Accounting and Control */
|
/* Memory Accounting and Control */
|
||||||
SD_JSON_BUILD_PAIR_BOOLEAN("MemoryAccounting", c->memory_accounting),
|
SD_JSON_BUILD_PAIR_BOOLEAN("MemoryAccounting", c->memory_accounting),
|
||||||
JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("MemoryMin", c->memory_min, CGROUP_LIMIT_MIN),
|
JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->memory_min_set, "MemoryMin", c->memory_min),
|
||||||
JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("MemoryLow", c->memory_low, CGROUP_LIMIT_MIN),
|
JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->default_memory_min_set, "DefaultMemoryMin", c->default_memory_min),
|
||||||
|
JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->memory_low_set, "MemoryLow", c->memory_low),
|
||||||
|
JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->default_memory_low_set, "DefaultMemoryLow", c->default_memory_low),
|
||||||
JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->startup_memory_low_set, "StartupMemoryLow", c->startup_memory_low),
|
JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->startup_memory_low_set, "StartupMemoryLow", c->startup_memory_low),
|
||||||
|
JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->default_startup_memory_low_set, "DefaultStartupMemoryLow", c->default_startup_memory_low),
|
||||||
JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("MemoryHigh", c->memory_high, CGROUP_LIMIT_MAX),
|
JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("MemoryHigh", c->memory_high, CGROUP_LIMIT_MAX),
|
||||||
JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->startup_memory_high_set, "StartupMemoryHigh", c->startup_memory_high),
|
JSON_BUILD_PAIR_CONDITION_UNSIGNED(c->startup_memory_high_set, "StartupMemoryHigh", c->startup_memory_high),
|
||||||
JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("MemoryMax", c->memory_max, CGROUP_LIMIT_MAX),
|
JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("MemoryMax", c->memory_max, CGROUP_LIMIT_MAX),
|
||||||
|
|||||||
@ -54,7 +54,7 @@ static int json_append_mount_options(sd_json_variant **v, MountOptions *options)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (PartitionDesignator j = 0; j < _PARTITION_DESIGNATOR_MAX; j++) {
|
for (PartitionDesignator j = 0; j < _PARTITION_DESIGNATOR_MAX; j++) {
|
||||||
if (isempty(options->options[j]))
|
if (!options->options[j])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = sd_json_variant_append_arraybo(
|
r = sd_json_variant_append_arraybo(
|
||||||
|
|||||||
@ -126,7 +126,6 @@ static char *arg_tpm2_measure_keyslot_nvpcr = NULL;
|
|||||||
static char *arg_link_keyring = NULL;
|
static char *arg_link_keyring = NULL;
|
||||||
static char *arg_link_key_type = NULL;
|
static char *arg_link_key_type = NULL;
|
||||||
static char *arg_link_key_description = NULL;
|
static char *arg_link_key_description = NULL;
|
||||||
static char *arg_fixate_volume_key = NULL;
|
|
||||||
|
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_cipher, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_cipher, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_hash, freep);
|
||||||
@ -144,7 +143,6 @@ STATIC_DESTRUCTOR_REGISTER(arg_tpm2_pcrlock, freep);
|
|||||||
STATIC_DESTRUCTOR_REGISTER(arg_link_keyring, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_link_keyring, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_link_key_type, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_link_key_type, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_link_key_description, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_link_key_description, freep);
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_fixate_volume_key, freep);
|
|
||||||
|
|
||||||
static const char* const passphrase_type_table[_PASSPHRASE_TYPE_MAX] = {
|
static const char* const passphrase_type_table[_PASSPHRASE_TYPE_MAX] = {
|
||||||
[PASSPHRASE_REGULAR] = "passphrase",
|
[PASSPHRASE_REGULAR] = "passphrase",
|
||||||
@ -653,11 +651,6 @@ static int parse_one_option(const char *option) {
|
|||||||
#else
|
#else
|
||||||
log_error("Build lacks libcryptsetup support for linking volume keys in user specified kernel keyrings upon device activation, ignoring: %s", option);
|
log_error("Build lacks libcryptsetup support for linking volume keys in user specified kernel keyrings upon device activation, ignoring: %s", option);
|
||||||
#endif
|
#endif
|
||||||
} else if ((val = startswith(option, "fixate-volume-key="))) {
|
|
||||||
r = free_and_strdup(&arg_fixate_volume_key, val);
|
|
||||||
if (r < 0)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
} else if (!streq(option, "x-initrd.attach"))
|
} else if (!streq(option, "x-initrd.attach"))
|
||||||
log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
|
log_warning("Encountered unknown /etc/crypttab option '%s', ignoring.", option);
|
||||||
|
|
||||||
@ -1057,29 +1050,24 @@ static int measure_volume_key(
|
|||||||
* unprotected direct hash of the secret volume key over the wire to the TPM. Hence let's instead
|
* unprotected direct hash of the secret volume key over the wire to the TPM. Hence let's instead
|
||||||
* send a HMAC signature instead. */
|
* send a HMAC signature instead. */
|
||||||
|
|
||||||
_cleanup_free_ char *prefix = NULL;
|
_cleanup_free_ char *escaped = NULL;
|
||||||
|
escaped = xescape(name, ":"); /* avoid ambiguity around ":" once we join things below */
|
||||||
|
if (!escaped)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
/* Note: what is extended to the SHA256 bank here must match the expected hash of 'fixate-volume-key='
|
_cleanup_free_ char *s = NULL;
|
||||||
* calculated by cryptsetup_get_volume_key_id(). */
|
s = strjoin("cryptsetup:", escaped, ":", strempty(crypt_get_uuid(cd)));
|
||||||
r = cryptsetup_get_volume_key_prefix(cd, name, &prefix);
|
if (!s)
|
||||||
if (r)
|
return log_oom();
|
||||||
return log_error_errno(r, "Could not verify pcr banks: %m");
|
|
||||||
|
|
||||||
r = tpm2_pcr_extend_bytes(
|
r = tpm2_pcr_extend_bytes(c, l ?: arg_tpm2_measure_banks, arg_tpm2_measure_pcr, &IOVEC_MAKE_STRING(s), &IOVEC_MAKE(volume_key, volume_key_size), TPM2_EVENT_VOLUME_KEY, s);
|
||||||
c,
|
|
||||||
/* banks= */ l ?: arg_tpm2_measure_banks,
|
|
||||||
/* pcr_index = */ arg_tpm2_measure_pcr,
|
|
||||||
/* data = */ &IOVEC_MAKE_STRING(prefix),
|
|
||||||
/* secret = */ &IOVEC_MAKE(volume_key, volume_key_size),
|
|
||||||
/* event_type = */ TPM2_EVENT_VOLUME_KEY,
|
|
||||||
/* description = */ prefix);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Could not extend PCR: %m");
|
return log_error_errno(r, "Could not extend PCR: %m");
|
||||||
|
|
||||||
log_struct(LOG_INFO,
|
log_struct(LOG_INFO,
|
||||||
LOG_MESSAGE_ID(SD_MESSAGE_TPM_PCR_EXTEND_STR),
|
LOG_MESSAGE_ID(SD_MESSAGE_TPM_PCR_EXTEND_STR),
|
||||||
LOG_MESSAGE("Successfully extended PCR index %u with '%s' and volume key (banks %s).", arg_tpm2_measure_pcr, prefix, joined),
|
LOG_MESSAGE("Successfully extended PCR index %u with '%s' and volume key (banks %s).", arg_tpm2_measure_pcr, s, joined),
|
||||||
LOG_ITEM("MEASURING=%s", prefix),
|
LOG_ITEM("MEASURING=%s", s),
|
||||||
LOG_ITEM("PCR=%u", arg_tpm2_measure_pcr),
|
LOG_ITEM("PCR=%u", arg_tpm2_measure_pcr),
|
||||||
LOG_ITEM("BANKS=%s", joined));
|
LOG_ITEM("BANKS=%s", joined));
|
||||||
|
|
||||||
@ -1185,36 +1173,12 @@ static int measured_crypt_activate_by_volume_key(
|
|||||||
|
|
||||||
/* A wrapper around crypt_activate_by_volume_key() which also measures to a PCR if that's requested. */
|
/* A wrapper around crypt_activate_by_volume_key() which also measures to a PCR if that's requested. */
|
||||||
|
|
||||||
/* First, check if volume key digest matches the expectation. */
|
|
||||||
if (arg_fixate_volume_key) {
|
|
||||||
_cleanup_free_ char *key_id = NULL;
|
|
||||||
|
|
||||||
r = cryptsetup_get_volume_key_id(
|
|
||||||
cd,
|
|
||||||
/* volume_name= */ name,
|
|
||||||
/* volume_key= */ volume_key,
|
|
||||||
/* volume_key_size= */ volume_key_size,
|
|
||||||
/* ret= */ &key_id);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to get volume key id.");
|
|
||||||
|
|
||||||
if (!streq(arg_fixate_volume_key, key_id))
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
||||||
"Volume key id: '%s' does not match the expectation: '%s'.",
|
|
||||||
key_id, arg_fixate_volume_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
r = crypt_activate_by_volume_key(cd, name, volume_key, volume_key_size, flags);
|
r = crypt_activate_by_volume_key(cd, name, volume_key, volume_key_size, flags);
|
||||||
if (r == -EEXIST) /* volume is already active */
|
if (r == -EEXIST) /* volume is already active */
|
||||||
return log_external_activation(r, name);
|
return log_external_activation(r, name);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (arg_tpm2_measure_pcr == UINT_MAX) {
|
|
||||||
log_debug("Not measuring volume key, deactivated.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (volume_key_size > 0)
|
if (volume_key_size > 0)
|
||||||
(void) measure_volume_key(cd, name, volume_key, volume_key_size); /* OK if fails */
|
(void) measure_volume_key(cd, name, volume_key, volume_key_size); /* OK if fails */
|
||||||
else
|
else
|
||||||
@ -1240,12 +1204,14 @@ static int measured_crypt_activate_by_passphrase(
|
|||||||
assert(cd);
|
assert(cd);
|
||||||
|
|
||||||
/* A wrapper around crypt_activate_by_passphrase() which also measures to a PCR if that's
|
/* A wrapper around crypt_activate_by_passphrase() which also measures to a PCR if that's
|
||||||
* requested. Note that we may need the volume key for the measurement and/or for the comparison, and
|
* requested. Note that we need the volume key for the measurement, and
|
||||||
* crypt_activate_by_passphrase() doesn't give us access to this. Hence, we operate indirectly, and
|
* crypt_activate_by_passphrase() doesn't give us access to this. Hence, we operate indirectly, and
|
||||||
* retrieve the volume key first, and then activate through that. */
|
* retrieve the volume key first, and then activate through that. */
|
||||||
|
|
||||||
if (arg_tpm2_measure_pcr == UINT_MAX && !arg_fixate_volume_key)
|
if (arg_tpm2_measure_pcr == UINT_MAX) {
|
||||||
|
log_debug("Not measuring volume key, deactivated.");
|
||||||
goto shortcut;
|
goto shortcut;
|
||||||
|
}
|
||||||
|
|
||||||
r = crypt_get_volume_key_size(cd);
|
r = crypt_get_volume_key_size(cd);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1487,9 +1453,6 @@ static bool use_token_plugins(void) {
|
|||||||
return false;
|
return false;
|
||||||
if (arg_tpm2_measure_keyslot_nvpcr)
|
if (arg_tpm2_measure_keyslot_nvpcr)
|
||||||
return false;
|
return false;
|
||||||
/* Volume key is also needed if the expected key id is set */
|
|
||||||
if (arg_fixate_volume_key)
|
|
||||||
return false;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Disable tokens if we're in FIDO2 mode with manual parameters. */
|
/* Disable tokens if we're in FIDO2 mode with manual parameters. */
|
||||||
|
|||||||
@ -340,10 +340,11 @@ static int map_all_fields(
|
|||||||
void process_audit_string(Manager *m, int type, const char *data, size_t size) {
|
void process_audit_string(Manager *m, int type, const char *data, size_t size) {
|
||||||
size_t n = 0, z;
|
size_t n = 0, z;
|
||||||
uint64_t seconds, msec, id;
|
uint64_t seconds, msec, id;
|
||||||
const char *p, *type_name, *type_field_name, *mm;
|
const char *p, *type_name;
|
||||||
char id_field[STRLEN("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
|
char id_field[STRLEN("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
|
||||||
type_field[STRLEN("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)];
|
type_field[STRLEN("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)];
|
||||||
struct iovec iovec[N_IOVEC_META_FIELDS + 7 + N_IOVEC_AUDIT_FIELDS];
|
struct iovec iovec[N_IOVEC_META_FIELDS + 7 + N_IOVEC_AUDIT_FIELDS];
|
||||||
|
char *mm, *type_field_name;
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
@ -394,11 +395,7 @@ void process_audit_string(Manager *m, int type, const char *data, size_t size) {
|
|||||||
type_field_name = strjoina("_AUDIT_TYPE_NAME=", type_name);
|
type_field_name = strjoina("_AUDIT_TYPE_NAME=", type_name);
|
||||||
iovec[n++] = IOVEC_MAKE_STRING(type_field_name);
|
iovec[n++] = IOVEC_MAKE_STRING(type_field_name);
|
||||||
|
|
||||||
_cleanup_free_ char *mm_alloc = strjoin("MESSAGE=", type_name, " ", p);
|
mm = strjoina("MESSAGE=", type_name, " ", p);
|
||||||
if (mm_alloc)
|
|
||||||
mm = mm_alloc;
|
|
||||||
else
|
|
||||||
mm = strjoina("MESSAGE=", type_name, " (message is truncated because of OOM)");
|
|
||||||
iovec[n++] = IOVEC_MAKE_STRING(mm);
|
iovec[n++] = IOVEC_MAKE_STRING(mm);
|
||||||
|
|
||||||
z = n;
|
z = n;
|
||||||
@ -409,8 +406,9 @@ void process_audit_string(Manager *m, int type, const char *data, size_t size) {
|
|||||||
TIMEVAL_STORE((usec_t) seconds * USEC_PER_SEC + (usec_t) msec * USEC_PER_MSEC),
|
TIMEVAL_STORE((usec_t) seconds * USEC_PER_SEC + (usec_t) msec * USEC_PER_MSEC),
|
||||||
LOG_NOTICE, 0);
|
LOG_NOTICE, 0);
|
||||||
|
|
||||||
/* free() all entries that map_all_fields() added. All others are allocated on the stack, constant,
|
/* free() all entries that map_all_fields() added. All others
|
||||||
* or freed by their _cleanup_ attributes. */
|
* are allocated on the stack or are constant. */
|
||||||
|
|
||||||
for (; z < n; z++)
|
for (; z < n; z++)
|
||||||
free(iovec[z].iov_base);
|
free(iovec[z].iov_base);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
#include "sd-forward.h"
|
#include "sd-forward.h"
|
||||||
|
|
||||||
#include "alloc-util.h" /* IWYU pragma: keep */
|
|
||||||
|
|
||||||
DECLARE_STRING_TABLE_LOOKUP(audit_type, int);
|
DECLARE_STRING_TABLE_LOOKUP(audit_type, int);
|
||||||
|
|
||||||
/* This is inspired by DNS TYPEnnn formatting */
|
/* This is inspired by DNS TYPEnnn formatting */
|
||||||
|
|||||||
@ -117,7 +117,8 @@ int rtnl_resolve_ifname_full(
|
|||||||
r = sd_netlink_call(*rtnl, message, 0, &reply);
|
r = sd_netlink_call(*rtnl, message, 0, &reply);
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
return parse_newlink_message(reply, ret_name, ret_altnames);
|
return parse_newlink_message(reply, ret_name, ret_altnames);
|
||||||
if (r != -ENODEV)
|
/* The kernels older than 76c9ac0ee878f6693d398d3a95ccaf85e1f597a6 (v5.5) return -EINVAL. */
|
||||||
|
if (!IN_SET(r, -ENODEV, -EINVAL))
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1704,8 +1704,6 @@ static int varlink_idl_validate_symbol(const sd_varlink_symbol *symbol, sd_json_
|
|||||||
|
|
||||||
static int varlink_idl_validate_field_element_type(const sd_varlink_field *field, sd_json_variant *v) {
|
static int varlink_idl_validate_field_element_type(const sd_varlink_field *field, sd_json_variant *v) {
|
||||||
assert(field);
|
assert(field);
|
||||||
assert(v);
|
|
||||||
assert(!sd_json_variant_is_null(v));
|
|
||||||
|
|
||||||
switch (field->field_type) {
|
switch (field->field_type) {
|
||||||
|
|
||||||
@ -1766,8 +1764,7 @@ static int varlink_idl_validate_field_element_type(const sd_varlink_field *field
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SD_VARLINK_ANY:
|
case SD_VARLINK_ANY:
|
||||||
/* The any type accepts any non-null JSON value, no validation needed. (Note that null is
|
/* The any type accepts any JSON value, no validation needed */
|
||||||
* already handled by the caller.) */
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case _SD_VARLINK_FIELD_COMMENT:
|
case _SD_VARLINK_FIELD_COMMENT:
|
||||||
|
|||||||
@ -2767,8 +2767,16 @@ static int reset_audit_loginuid(void) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = write_string_file("/proc/self/loginuid", "4294967295", WRITE_STRING_FILE_DISABLE_BUFFER);
|
r = write_string_file("/proc/self/loginuid", "4294967295", WRITE_STRING_FILE_DISABLE_BUFFER);
|
||||||
if (r < 0)
|
if (r < 0) {
|
||||||
return log_error_errno(r, "Failed to reset audit login UID: %m");
|
log_error_errno(r,
|
||||||
|
"Failed to reset audit login UID. This probably means that your kernel is too\n"
|
||||||
|
"old and you have audit enabled. Note that the auditing subsystem is known to\n"
|
||||||
|
"be incompatible with containers on old kernels. Please make sure to upgrade\n"
|
||||||
|
"your kernel or to off auditing with 'audit=0' on the kernel command line before\n"
|
||||||
|
"using systemd-nspawn. Sleeping for 5s... (%m)");
|
||||||
|
|
||||||
|
sleep(5);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -3767,7 +3775,7 @@ static int setup_unix_export_dir_outside(char **ret) {
|
|||||||
"tmpfs",
|
"tmpfs",
|
||||||
q,
|
q,
|
||||||
"tmpfs",
|
"tmpfs",
|
||||||
MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_NOSYMFOLLOW,
|
MS_NODEV|MS_NOEXEC|MS_NOSUID|ms_nosymfollow_supported(),
|
||||||
"size=4M,nr_inodes=64,mode=0755");
|
"size=4M,nr_inodes=64,mode=0755");
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -3781,7 +3789,7 @@ static int setup_unix_export_dir_outside(char **ret) {
|
|||||||
/* what= */ NULL,
|
/* what= */ NULL,
|
||||||
w,
|
w,
|
||||||
/* fstype= */ NULL,
|
/* fstype= */ NULL,
|
||||||
MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_NOSYMFOLLOW,
|
MS_BIND|MS_REMOUNT|MS_RDONLY|MS_NODEV|MS_NOEXEC|MS_NOSUID|ms_nosymfollow_supported(),
|
||||||
/* options= */ NULL);
|
/* options= */ NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -3826,7 +3834,7 @@ static int setup_unix_export_host_inside(const char *directory, const char *unix
|
|||||||
/* what= */ NULL,
|
/* what= */ NULL,
|
||||||
p,
|
p,
|
||||||
/* fstype= */ NULL,
|
/* fstype= */ NULL,
|
||||||
MS_BIND|MS_REMOUNT|MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_NOSYMFOLLOW,
|
MS_BIND|MS_REMOUNT|MS_NODEV|MS_NOEXEC|MS_NOSUID|ms_nosymfollow_supported(),
|
||||||
/* options= */ NULL);
|
/* options= */ NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|||||||
@ -27,7 +27,6 @@
|
|||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
#include "glyph-util.h"
|
#include "glyph-util.h"
|
||||||
#include "image-policy.h"
|
|
||||||
#include "install.h"
|
#include "install.h"
|
||||||
#include "iovec-util.h"
|
#include "iovec-util.h"
|
||||||
#include "libmount-util.h"
|
#include "libmount-util.h"
|
||||||
@ -365,12 +364,10 @@ static int portable_extract_by_path(
|
|||||||
const ImagePolicy *image_policy,
|
const ImagePolicy *image_policy,
|
||||||
PortableMetadata **ret_os_release,
|
PortableMetadata **ret_os_release,
|
||||||
Hashmap **ret_unit_files,
|
Hashmap **ret_unit_files,
|
||||||
ImagePolicy **ret_pinned_image_policy,
|
|
||||||
sd_bus_error *error) {
|
sd_bus_error *error) {
|
||||||
|
|
||||||
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
|
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
|
||||||
_cleanup_(portable_metadata_unrefp) PortableMetadata* os_release = NULL;
|
_cleanup_(portable_metadata_unrefp) PortableMetadata* os_release = NULL;
|
||||||
_cleanup_(image_policy_freep) ImagePolicy *pinned_image_policy = NULL;
|
|
||||||
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
|
_cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -400,7 +397,6 @@ static int portable_extract_by_path(
|
|||||||
} else if (r < 0)
|
} else if (r < 0)
|
||||||
return log_debug_errno(r, "Failed to set up loopback device for %s: %m", path);
|
return log_debug_errno(r, "Failed to set up loopback device for %s: %m", path);
|
||||||
else {
|
else {
|
||||||
_cleanup_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT;
|
|
||||||
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
|
_cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
|
||||||
_cleanup_(rmdir_and_freep) char *tmpdir = NULL;
|
_cleanup_(rmdir_and_freep) char *tmpdir = NULL;
|
||||||
_cleanup_close_pair_ int seq[2] = EBADF_PAIR;
|
_cleanup_close_pair_ int seq[2] = EBADF_PAIR;
|
||||||
@ -453,24 +449,6 @@ static int portable_extract_by_path(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = verity_settings_load(&verity, path, NULL, NULL);
|
|
||||||
if (r < 0)
|
|
||||||
return log_debug_errno(r, "Failed to load root hash: %m");
|
|
||||||
|
|
||||||
r = dissected_image_load_verity_sig_partition(m, d->fd, &verity);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = dissected_image_guess_verity_roothash(m, &verity);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
if (ret_pinned_image_policy) {
|
|
||||||
pinned_image_policy = image_policy_new_from_dissected(m, &verity);
|
|
||||||
if (!pinned_image_policy)
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, seq) < 0)
|
if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, seq) < 0)
|
||||||
return log_debug_errno(errno, "Failed to allocated SOCK_SEQPACKET socket: %m");
|
return log_debug_errno(errno, "Failed to allocated SOCK_SEQPACKET socket: %m");
|
||||||
|
|
||||||
@ -580,9 +558,6 @@ static int portable_extract_by_path(
|
|||||||
if (ret_os_release)
|
if (ret_os_release)
|
||||||
*ret_os_release = TAKE_PTR(os_release);
|
*ret_os_release = TAKE_PTR(os_release);
|
||||||
|
|
||||||
if (ret_pinned_image_policy)
|
|
||||||
*ret_pinned_image_policy = TAKE_PTR(pinned_image_policy);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,12 +575,9 @@ static int extract_image_and_extensions(
|
|||||||
PortableMetadata **ret_os_release,
|
PortableMetadata **ret_os_release,
|
||||||
Hashmap **ret_unit_files,
|
Hashmap **ret_unit_files,
|
||||||
char ***ret_valid_prefixes,
|
char ***ret_valid_prefixes,
|
||||||
ImagePolicy **ret_pinned_root_image_policy,
|
|
||||||
ImagePolicy **ret_pinned_ext_image_policy,
|
|
||||||
sd_bus_error *error) {
|
sd_bus_error *error) {
|
||||||
|
|
||||||
_cleanup_free_ char *id = NULL, *id_like = NULL, *version_id = NULL, *sysext_level = NULL, *confext_level = NULL;
|
_cleanup_free_ char *id = NULL, *id_like = NULL, *version_id = NULL, *sysext_level = NULL, *confext_level = NULL;
|
||||||
_cleanup_(image_policy_freep) ImagePolicy *pinned_root_image_policy = NULL, *pinned_ext_image_policy = NULL;
|
|
||||||
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
|
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
|
||||||
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL, *extension_releases = NULL;
|
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL, *extension_releases = NULL;
|
||||||
_cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
|
_cleanup_(pick_result_done) PickResult result = PICK_RESULT_NULL;
|
||||||
@ -697,7 +669,6 @@ static int extract_image_and_extensions(
|
|||||||
image_policy,
|
image_policy,
|
||||||
&os_release,
|
&os_release,
|
||||||
&unit_files,
|
&unit_files,
|
||||||
&pinned_root_image_policy,
|
|
||||||
error);
|
error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -729,7 +700,6 @@ static int extract_image_and_extensions(
|
|||||||
|
|
||||||
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
|
ORDERED_HASHMAP_FOREACH(ext, extension_images) {
|
||||||
_cleanup_(portable_metadata_unrefp) PortableMetadata *extension_release_meta = NULL;
|
_cleanup_(portable_metadata_unrefp) PortableMetadata *extension_release_meta = NULL;
|
||||||
_cleanup_(image_policy_freep) ImagePolicy *policy = NULL;
|
|
||||||
_cleanup_hashmap_free_ Hashmap *extra_unit_files = NULL;
|
_cleanup_hashmap_free_ Hashmap *extra_unit_files = NULL;
|
||||||
_cleanup_strv_free_ char **extension_release = NULL;
|
_cleanup_strv_free_ char **extension_release = NULL;
|
||||||
const char *e;
|
const char *e;
|
||||||
@ -743,7 +713,6 @@ static int extract_image_and_extensions(
|
|||||||
image_policy,
|
image_policy,
|
||||||
&extension_release_meta,
|
&extension_release_meta,
|
||||||
&extra_unit_files,
|
&extra_unit_files,
|
||||||
&policy,
|
|
||||||
error);
|
error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -752,19 +721,6 @@ static int extract_image_and_extensions(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (!pinned_ext_image_policy && policy)
|
|
||||||
pinned_ext_image_policy = TAKE_PTR(policy);
|
|
||||||
else if (policy) {
|
|
||||||
_cleanup_(image_policy_freep) ImagePolicy *intersected_policy = NULL;
|
|
||||||
|
|
||||||
/* There is a single policy for all extension images, so we need a union */
|
|
||||||
r = image_policy_union(pinned_ext_image_policy, policy, &intersected_policy);
|
|
||||||
if (r < 0)
|
|
||||||
return log_debug_errno(r, "Failed to merge extension image policies: %m");
|
|
||||||
|
|
||||||
free_and_replace(pinned_ext_image_policy, intersected_policy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!validate_extension && !ret_valid_prefixes && !ret_extension_releases)
|
if (!validate_extension && !ret_valid_prefixes && !ret_extension_releases)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -812,10 +768,6 @@ static int extract_image_and_extensions(
|
|||||||
*ret_unit_files = TAKE_PTR(unit_files);
|
*ret_unit_files = TAKE_PTR(unit_files);
|
||||||
if (ret_valid_prefixes)
|
if (ret_valid_prefixes)
|
||||||
*ret_valid_prefixes = TAKE_PTR(valid_prefixes);
|
*ret_valid_prefixes = TAKE_PTR(valid_prefixes);
|
||||||
if (ret_pinned_root_image_policy)
|
|
||||||
*ret_pinned_root_image_policy = TAKE_PTR(pinned_root_image_policy);
|
|
||||||
if (ret_pinned_ext_image_policy)
|
|
||||||
*ret_pinned_ext_image_policy = TAKE_PTR(pinned_ext_image_policy);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -856,8 +808,6 @@ int portable_extract(
|
|||||||
&os_release,
|
&os_release,
|
||||||
&unit_files,
|
&unit_files,
|
||||||
ret_valid_prefixes ? &valid_prefixes : NULL,
|
ret_valid_prefixes ? &valid_prefixes : NULL,
|
||||||
/* pinned_root_image_policy= */ NULL,
|
|
||||||
/* pinned_ext_image_policy= */ NULL,
|
|
||||||
error);
|
error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -1160,8 +1110,6 @@ static int install_chroot_dropin(
|
|||||||
ImageType type,
|
ImageType type,
|
||||||
OrderedHashmap *extension_images,
|
OrderedHashmap *extension_images,
|
||||||
OrderedHashmap *extension_releases,
|
OrderedHashmap *extension_releases,
|
||||||
const ImagePolicy *pinned_root_image_policy,
|
|
||||||
const ImagePolicy *pinned_ext_image_policy,
|
|
||||||
const PortableMetadata *m,
|
const PortableMetadata *m,
|
||||||
const PortableMetadata *os_release,
|
const PortableMetadata *os_release,
|
||||||
const char *dropin_dir,
|
const char *dropin_dir,
|
||||||
@ -1204,18 +1152,6 @@ static int install_chroot_dropin(
|
|||||||
"LogExtraFields=PORTABLE=", base_name, "\n"))
|
"LogExtraFields=PORTABLE=", base_name, "\n"))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (pinned_root_image_policy) {
|
|
||||||
_cleanup_free_ char *policy_str = NULL;
|
|
||||||
|
|
||||||
r = image_policy_to_string(pinned_root_image_policy, /* simplify= */ true, &policy_str);
|
|
||||||
if (r < 0)
|
|
||||||
return log_debug_errno(r, "Failed to serialize pinned image policy: %m");
|
|
||||||
|
|
||||||
if (!strextend(&text,
|
|
||||||
"RootImagePolicy=", policy_str, "\n"))
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If we have a single image then PORTABLE= will point to it, so we add
|
/* If we have a single image then PORTABLE= will point to it, so we add
|
||||||
* PORTABLE_NAME_AND_VERSION= with the os-release fields and we are done. But if we have
|
* PORTABLE_NAME_AND_VERSION= with the os-release fields and we are done. But if we have
|
||||||
* extensions, PORTABLE= will point to the image where the current unit was found in. So we
|
* extensions, PORTABLE= will point to the image where the current unit was found in. So we
|
||||||
@ -1265,18 +1201,6 @@ static int install_chroot_dropin(
|
|||||||
"LogExtraFields=PORTABLE_EXTENSION=", extension_base_name, "\n"))
|
"LogExtraFields=PORTABLE_EXTENSION=", extension_base_name, "\n"))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
if (pinned_ext_image_policy) {
|
|
||||||
_cleanup_free_ char *policy_str = NULL;
|
|
||||||
|
|
||||||
r = image_policy_to_string(pinned_ext_image_policy, /* simplify= */ true, &policy_str);
|
|
||||||
if (r < 0)
|
|
||||||
return log_debug_errno(r, "Failed to serialize pinned image policy: %m");
|
|
||||||
|
|
||||||
if (!strextend(&text,
|
|
||||||
"ExtensionImagePolicy=", policy_str, "\n"))
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Look for image/version identifiers in the extension release files. We
|
/* Look for image/version identifiers in the extension release files. We
|
||||||
* look for all possible IDs, but typically only 1 or 2 will be set, so
|
* look for all possible IDs, but typically only 1 or 2 will be set, so
|
||||||
* the number of fields added shouldn't be too large. We prefix the DDI
|
* the number of fields added shouldn't be too large. We prefix the DDI
|
||||||
@ -1393,8 +1317,6 @@ static int attach_unit_file(
|
|||||||
ImageType type,
|
ImageType type,
|
||||||
OrderedHashmap *extension_images,
|
OrderedHashmap *extension_images,
|
||||||
OrderedHashmap *extension_releases,
|
OrderedHashmap *extension_releases,
|
||||||
const ImagePolicy *pinned_root_image_policy,
|
|
||||||
const ImagePolicy *pinned_ext_image_policy,
|
|
||||||
const PortableMetadata *m,
|
const PortableMetadata *m,
|
||||||
const PortableMetadata *os_release,
|
const PortableMetadata *os_release,
|
||||||
const char *profile,
|
const char *profile,
|
||||||
@ -1440,20 +1362,7 @@ static int attach_unit_file(
|
|||||||
* is reloaded while we are creating things here: as long as only the drop-ins exist the unit doesn't exist at
|
* is reloaded while we are creating things here: as long as only the drop-ins exist the unit doesn't exist at
|
||||||
* all for PID 1. */
|
* all for PID 1. */
|
||||||
|
|
||||||
r = install_chroot_dropin(
|
r = install_chroot_dropin(image_path, type, extension_images, extension_releases, m, os_release, dropin_dir, flags, &chroot_dropin, changes, n_changes);
|
||||||
image_path,
|
|
||||||
type,
|
|
||||||
extension_images,
|
|
||||||
extension_releases,
|
|
||||||
pinned_root_image_policy,
|
|
||||||
pinned_ext_image_policy,
|
|
||||||
m,
|
|
||||||
os_release,
|
|
||||||
dropin_dir,
|
|
||||||
flags,
|
|
||||||
&chroot_dropin,
|
|
||||||
changes,
|
|
||||||
n_changes);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -1722,7 +1631,6 @@ int portable_attach(
|
|||||||
size_t *n_changes,
|
size_t *n_changes,
|
||||||
sd_bus_error *error) {
|
sd_bus_error *error) {
|
||||||
|
|
||||||
_cleanup_(image_policy_freep) ImagePolicy *pinned_root_image_policy = NULL, *pinned_ext_image_policy = NULL;
|
|
||||||
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL, *extension_releases = NULL;
|
_cleanup_ordered_hashmap_free_ OrderedHashmap *extension_images = NULL, *extension_releases = NULL;
|
||||||
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
|
_cleanup_(portable_metadata_unrefp) PortableMetadata *os_release = NULL;
|
||||||
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
|
_cleanup_hashmap_free_ Hashmap *unit_files = NULL;
|
||||||
@ -1748,8 +1656,6 @@ int portable_attach(
|
|||||||
&os_release,
|
&os_release,
|
||||||
&unit_files,
|
&unit_files,
|
||||||
&valid_prefixes,
|
&valid_prefixes,
|
||||||
&pinned_root_image_policy,
|
|
||||||
&pinned_ext_image_policy,
|
|
||||||
error);
|
error);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -1814,20 +1720,8 @@ int portable_attach(
|
|||||||
}
|
}
|
||||||
|
|
||||||
HASHMAP_FOREACH(item, unit_files) {
|
HASHMAP_FOREACH(item, unit_files) {
|
||||||
r = attach_unit_file(
|
r = attach_unit_file(&paths, image->path, image->type, extension_images, extension_releases,
|
||||||
&paths,
|
item, os_release, profile, flags, changes, n_changes);
|
||||||
image->path,
|
|
||||||
image->type,
|
|
||||||
extension_images,
|
|
||||||
extension_releases,
|
|
||||||
pinned_root_image_policy,
|
|
||||||
pinned_ext_image_policy,
|
|
||||||
item,
|
|
||||||
os_release,
|
|
||||||
profile,
|
|
||||||
flags,
|
|
||||||
changes,
|
|
||||||
n_changes);
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return sd_bus_error_set_errnof(error, r, "Failed to attach unit '%s': %m", item->name);
|
return sd_bus_error_set_errnof(error, r, "Failed to attach unit '%s': %m", item->name);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -318,7 +318,6 @@ typedef struct PartitionEncryptedVolume {
|
|||||||
char *name;
|
char *name;
|
||||||
char *keyfile;
|
char *keyfile;
|
||||||
char *options;
|
char *options;
|
||||||
bool fixate_volume_key;
|
|
||||||
} PartitionEncryptedVolume;
|
} PartitionEncryptedVolume;
|
||||||
|
|
||||||
static PartitionEncryptedVolume* partition_encrypted_volume_free(PartitionEncryptedVolume *c) {
|
static PartitionEncryptedVolume* partition_encrypted_volume_free(PartitionEncryptedVolume *c) {
|
||||||
@ -2548,8 +2547,7 @@ static int config_parse_encrypted_volume(
|
|||||||
void *data,
|
void *data,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
_cleanup_free_ char *volume = NULL, *keyfile = NULL, *options = NULL, *extra = NULL;
|
_cleanup_free_ char *volume = NULL, *keyfile = NULL, *options = NULL;
|
||||||
bool fixate_volume_key = false;
|
|
||||||
Partition *p = ASSERT_PTR(data);
|
Partition *p = ASSERT_PTR(data);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -2560,7 +2558,7 @@ static int config_parse_encrypted_volume(
|
|||||||
|
|
||||||
const char *q = rvalue;
|
const char *q = rvalue;
|
||||||
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNQUOTE,
|
r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_UNQUOTE,
|
||||||
&volume, &keyfile, &options, &extra);
|
&volume, &keyfile, &options);
|
||||||
if (r == -ENOMEM)
|
if (r == -ENOMEM)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@ -2591,29 +2589,10 @@ static int config_parse_encrypted_volume(
|
|||||||
if (!p->encrypted_volume)
|
if (!p->encrypted_volume)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
for (const char *e = extra;;) {
|
|
||||||
_cleanup_free_ char *word = NULL;
|
|
||||||
|
|
||||||
r = extract_first_word(&e, &word, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS);
|
|
||||||
if (r < 0) {
|
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
|
||||||
"Failed to parse extra options '%s', ignoring", word);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (r == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (streq(word, "fixate-volume-key"))
|
|
||||||
fixate_volume_key = true;
|
|
||||||
else
|
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown extra option '%s', ignoring", word);
|
|
||||||
}
|
|
||||||
|
|
||||||
*p->encrypted_volume = (PartitionEncryptedVolume) {
|
*p->encrypted_volume = (PartitionEncryptedVolume) {
|
||||||
.name = TAKE_PTR(volume),
|
.name = TAKE_PTR(volume),
|
||||||
.keyfile = TAKE_PTR(keyfile),
|
.keyfile = TAKE_PTR(keyfile),
|
||||||
.options = TAKE_PTR(options),
|
.options = TAKE_PTR(options),
|
||||||
.fixate_volume_key = fixate_volume_key,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -5195,44 +5174,6 @@ static int partition_encrypt(Context *context, Partition *p, PartitionTarget *ta
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to LUKS2 format future partition: %m");
|
return log_error_errno(r, "Failed to LUKS2 format future partition: %m");
|
||||||
|
|
||||||
if (p->encrypted_volume && p->encrypted_volume->fixate_volume_key) {
|
|
||||||
_cleanup_free_ char *key_id = NULL, *hash_option = NULL;
|
|
||||||
|
|
||||||
r = sym_crypt_get_volume_key_size(cd);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to determine volume key size: %m");
|
|
||||||
if (r == 0)
|
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume key has zero size and 'fixate-volume-key' is used");
|
|
||||||
|
|
||||||
_cleanup_(iovec_done) struct iovec vk = {
|
|
||||||
.iov_base = malloc(r),
|
|
||||||
.iov_len = r,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!vk.iov_base)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
r = sym_crypt_volume_key_get(cd, CRYPT_ANY_SLOT, (char *) vk.iov_base, &vk.iov_len, NULL, 0);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to get volume key: %m");
|
|
||||||
|
|
||||||
r = cryptsetup_get_volume_key_id(
|
|
||||||
cd,
|
|
||||||
/* volume_name= */ p->encrypted_volume->name,
|
|
||||||
/* volume_key= */ vk.iov_base,
|
|
||||||
/* volume_key_size= */ vk.iov_len,
|
|
||||||
/* ret= */ &key_id);
|
|
||||||
if (r < 0)
|
|
||||||
return log_error_errno(r, "Failed to get volume key hash: %m");
|
|
||||||
|
|
||||||
hash_option = strjoin("fixate-volume-key=", key_id);
|
|
||||||
if (!hash_option)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
if (!strextend_with_separator(&p->encrypted_volume->options, ",", hash_option))
|
|
||||||
return log_oom();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IN_SET(p->encrypt, ENCRYPT_KEY_FILE, ENCRYPT_KEY_FILE_TPM2)) {
|
if (IN_SET(p->encrypt, ENCRYPT_KEY_FILE, ENCRYPT_KEY_FILE_TPM2)) {
|
||||||
/* Use partition-specific key if available, otherwise fall back to global key */
|
/* Use partition-specific key if available, otherwise fall back to global key */
|
||||||
struct iovec *iovec_key = arg_key.iov_base ? &arg_key : &p->key;
|
struct iovec *iovec_key = arg_key.iov_base ? &arg_key : &p->key;
|
||||||
@ -10778,6 +10719,14 @@ static int run(int argc, char *argv[]) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
r = context_fstab(context);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
r = context_crypttab(context);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
r = context_update_verity_size(context);
|
r = context_update_verity_size(context);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
@ -10833,14 +10782,6 @@ static int run(int argc, char *argv[]) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = context_fstab(context);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
r = context_crypttab(context);
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
(void) context_dump(context, /* late= */ true);
|
(void) context_dump(context, /* late= */ true);
|
||||||
|
|
||||||
context_disarm_auto_removal(context);
|
context_disarm_auto_removal(context);
|
||||||
|
|||||||
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
BUS_DEFINE_PROPERTY_GET_GLOBAL(bus_property_get_bool_false, "b", 0);
|
BUS_DEFINE_PROPERTY_GET_GLOBAL(bus_property_get_bool_false, "b", 0);
|
||||||
BUS_DEFINE_PROPERTY_GET_GLOBAL(bus_property_get_bool_true, "b", 1);
|
BUS_DEFINE_PROPERTY_GET_GLOBAL(bus_property_get_bool_true, "b", 1);
|
||||||
BUS_DEFINE_PROPERTY_GET_GLOBAL(bus_property_get_uint64_0, "t", UINT64_C(0));
|
|
||||||
BUS_DEFINE_PROPERTY_GET_GLOBAL(bus_property_get_uint64_max, "t", UINT64_MAX);
|
BUS_DEFINE_PROPERTY_GET_GLOBAL(bus_property_get_uint64_max, "t", UINT64_MAX);
|
||||||
|
|
||||||
int bus_property_get_bool(
|
int bus_property_get_bool(
|
||||||
|
|||||||
@ -107,5 +107,4 @@ int bus_property_get_pidfdid(sd_bus *bus, const char *path, const char *interfac
|
|||||||
/* For deprecated properties. */
|
/* For deprecated properties. */
|
||||||
int bus_property_get_bool_false(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *reterr_error);
|
int bus_property_get_bool_false(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *reterr_error);
|
||||||
int bus_property_get_bool_true(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *reterr_error);
|
int bus_property_get_bool_true(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *reterr_error);
|
||||||
int bus_property_get_uint64_0(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *reterr_error);
|
|
||||||
int bus_property_get_uint64_max(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *reterr_error);
|
int bus_property_get_uint64_max(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *reterr_error);
|
||||||
|
|||||||
@ -342,6 +342,8 @@ static int bus_append_parse_resource_limit(sd_bus_message *m, const char *field,
|
|||||||
if (isempty(eq) || streq(eq, "infinity")) {
|
if (isempty(eq) || streq(eq, "infinity")) {
|
||||||
uint64_t x = streq(eq, "infinity") ? CGROUP_LIMIT_MAX :
|
uint64_t x = streq(eq, "infinity") ? CGROUP_LIMIT_MAX :
|
||||||
STR_IN_SET(field,
|
STR_IN_SET(field,
|
||||||
|
"DefaultMemoryLow",
|
||||||
|
"DefaultMemoryMin",
|
||||||
"MemoryLow",
|
"MemoryLow",
|
||||||
"MemoryMin") ? CGROUP_LIMIT_MIN : CGROUP_LIMIT_MAX;
|
"MemoryMin") ? CGROUP_LIMIT_MIN : CGROUP_LIMIT_MAX;
|
||||||
|
|
||||||
@ -2346,6 +2348,8 @@ static const BusProperty cgroup_properties[] = {
|
|||||||
{ "DisableControllers", bus_append_strv },
|
{ "DisableControllers", bus_append_strv },
|
||||||
{ "Delegate", bus_append_parse_delegate },
|
{ "Delegate", bus_append_parse_delegate },
|
||||||
{ "MemoryMin", bus_append_parse_resource_limit },
|
{ "MemoryMin", bus_append_parse_resource_limit },
|
||||||
|
{ "DefaultMemoryLow", bus_append_parse_resource_limit },
|
||||||
|
{ "DefaultMemoryMin", bus_append_parse_resource_limit },
|
||||||
{ "MemoryLow", bus_append_parse_resource_limit },
|
{ "MemoryLow", bus_append_parse_resource_limit },
|
||||||
{ "MemoryHigh", bus_append_parse_resource_limit },
|
{ "MemoryHigh", bus_append_parse_resource_limit },
|
||||||
{ "MemoryMax", bus_append_parse_resource_limit },
|
{ "MemoryMax", bus_append_parse_resource_limit },
|
||||||
@ -2382,8 +2386,6 @@ static const BusProperty cgroup_properties[] = {
|
|||||||
{ "BlockIOReadBandwidth", warn_deprecated },
|
{ "BlockIOReadBandwidth", warn_deprecated },
|
||||||
{ "BlockIOWriteBandwidth", warn_deprecated },
|
{ "BlockIOWriteBandwidth", warn_deprecated },
|
||||||
{ "CPUAccounting", warn_deprecated },
|
{ "CPUAccounting", warn_deprecated },
|
||||||
{ "DefaultMemoryMin", warn_deprecated },
|
|
||||||
{ "DefaultMemoryLow", warn_deprecated },
|
|
||||||
|
|
||||||
{ NULL, bus_try_append_parse_cgroup_io_limit, cgroup_io_limits_list },
|
{ NULL, bus_try_append_parse_cgroup_io_limit, cgroup_io_limits_list },
|
||||||
{}
|
{}
|
||||||
|
|||||||
@ -7,9 +7,6 @@
|
|||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "cryptsetup-util.h"
|
#include "cryptsetup-util.h"
|
||||||
#include "dlfcn-util.h"
|
#include "dlfcn-util.h"
|
||||||
#include "escape.h"
|
|
||||||
#include "hexdecoct.h"
|
|
||||||
#include "hmac.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
@ -201,64 +198,6 @@ int cryptsetup_add_token_json(struct crypt_device *cd, sd_json_variant *v) {
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cryptsetup_get_volume_key_prefix(
|
|
||||||
struct crypt_device *cd,
|
|
||||||
const char *volume_name,
|
|
||||||
char **ret) {
|
|
||||||
|
|
||||||
_cleanup_free_ char *volume = NULL;
|
|
||||||
const char *uuid;
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
uuid = sym_crypt_get_uuid(cd);
|
|
||||||
if (!uuid)
|
|
||||||
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to get LUKS UUID.");
|
|
||||||
|
|
||||||
if (volume_name)
|
|
||||||
/* avoid ambiguity around ":" once we join things below */
|
|
||||||
volume = xescape(volume_name, ":");
|
|
||||||
else
|
|
||||||
volume = strjoin("luks-", uuid);
|
|
||||||
if (!volume)
|
|
||||||
return log_oom_debug();
|
|
||||||
|
|
||||||
s = strjoin("cryptsetup:", volume, ":", uuid);
|
|
||||||
if (!s)
|
|
||||||
return log_oom_debug();
|
|
||||||
|
|
||||||
*ret = s;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The hash must match what measure_volume_key() extends to the SHA256 bank of the TPM2. */
|
|
||||||
int cryptsetup_get_volume_key_id(
|
|
||||||
struct crypt_device *cd,
|
|
||||||
const char *volume_name,
|
|
||||||
const void *volume_key,
|
|
||||||
size_t volume_key_size,
|
|
||||||
char **ret) {
|
|
||||||
|
|
||||||
_cleanup_free_ char *prefix = NULL;
|
|
||||||
uint8_t digest[SHA256_DIGEST_SIZE];
|
|
||||||
char *hex;
|
|
||||||
int r;
|
|
||||||
|
|
||||||
r = cryptsetup_get_volume_key_prefix(cd, volume_name, &prefix);
|
|
||||||
if (r < 0)
|
|
||||||
return log_debug_errno(r, "Failed to get LUKS volume key prefix.");
|
|
||||||
|
|
||||||
hmac_sha256(volume_key, volume_key_size, prefix, strlen(prefix), digest);
|
|
||||||
|
|
||||||
hex = hexmem(digest, sizeof(digest));
|
|
||||||
if (!hex)
|
|
||||||
return log_oom_debug();
|
|
||||||
|
|
||||||
*ret = hex;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int dlopen_cryptsetup(void) {
|
int dlopen_cryptsetup(void) {
|
||||||
|
|||||||
@ -66,9 +66,6 @@ int cryptsetup_set_minimal_pbkdf(struct crypt_device *cd);
|
|||||||
|
|
||||||
int cryptsetup_get_token_as_json(struct crypt_device *cd, int idx, const char *verify_type, sd_json_variant **ret);
|
int cryptsetup_get_token_as_json(struct crypt_device *cd, int idx, const char *verify_type, sd_json_variant **ret);
|
||||||
int cryptsetup_add_token_json(struct crypt_device *cd, sd_json_variant *v);
|
int cryptsetup_add_token_json(struct crypt_device *cd, sd_json_variant *v);
|
||||||
int cryptsetup_get_volume_key_prefix(struct crypt_device *cd, const char *volume_name, char **ret);
|
|
||||||
int cryptsetup_get_volume_key_id(struct crypt_device *cd, const char *volume_name, const void *volume_key,
|
|
||||||
size_t volume_key_size, char **ret);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int dlopen_cryptsetup(void);
|
int dlopen_cryptsetup(void);
|
||||||
|
|||||||
@ -471,7 +471,7 @@ static int partition_is_luks2_integrity(int part_fd, uint64_t offset, uint64_t s
|
|||||||
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read LUKS JSON header.");
|
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read LUKS JSON header.");
|
||||||
json[sz] = '\0';
|
json[sz] = '\0';
|
||||||
|
|
||||||
r = sd_json_parse(json, /* flags= */ 0, &v, /* reterr_line= */ NULL, /* reterr_column= */ NULL);
|
r = sd_json_parse(json, /* flags = */ 0, &v, /* reterr_line = */ NULL, /* reterr_column = */ NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to parse LUKS JSON header.");
|
return log_error_errno(r, "Failed to parse LUKS JSON header.");
|
||||||
|
|
||||||
@ -567,7 +567,7 @@ static int dissected_image_probe_filesystems(
|
|||||||
m->encrypted = true;
|
m->encrypted = true;
|
||||||
|
|
||||||
if (p->mount_node_fd >= 0)
|
if (p->mount_node_fd >= 0)
|
||||||
r = partition_is_luks2_integrity(p->mount_node_fd, /* offset= */ 0, /* size= */ UINT64_MAX);
|
r = partition_is_luks2_integrity(p->mount_node_fd, /* offset = */ 0, /* size = */ UINT64_MAX);
|
||||||
else
|
else
|
||||||
r = partition_is_luks2_integrity(fd, p->offset, p->size);
|
r = partition_is_luks2_integrity(fd, p->offset, p->size);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -1168,7 +1168,7 @@ static int dissect_image(
|
|||||||
if (verity_settings_data_covers(verity, PARTITION_ROOT))
|
if (verity_settings_data_covers(verity, PARTITION_ROOT))
|
||||||
found_flags = iovec_is_set(&verity->root_hash_sig) ? PARTITION_POLICY_SIGNED : PARTITION_POLICY_VERITY;
|
found_flags = iovec_is_set(&verity->root_hash_sig) ? PARTITION_POLICY_SIGNED : PARTITION_POLICY_VERITY;
|
||||||
else if (encrypted) {
|
else if (encrypted) {
|
||||||
r = partition_is_luks2_integrity(fd, /* offset= */ 0, /* size= */ UINT64_MAX);
|
r = partition_is_luks2_integrity(fd, /* offset = */ 0, /* size = */ UINT64_MAX);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
@ -2383,7 +2383,7 @@ int partition_pick_mount_options(
|
|||||||
|
|
||||||
case PARTITION_ESP:
|
case PARTITION_ESP:
|
||||||
case PARTITION_XBOOTLDR:
|
case PARTITION_XBOOTLDR:
|
||||||
flags |= MS_NOSUID|MS_NOEXEC|MS_NOSYMFOLLOW;
|
flags |= MS_NOSUID|MS_NOEXEC|ms_nosymfollow_supported();
|
||||||
|
|
||||||
/* The ESP might contain a pre-boot random seed. Let's make this unaccessible to regular
|
/* The ESP might contain a pre-boot random seed. Let's make this unaccessible to regular
|
||||||
* userspace. ESP/XBOOTLDR is almost certainly VFAT, hence if we don't know assume it is. */
|
* userspace. ESP/XBOOTLDR is almost certainly VFAT, hence if we don't know assume it is. */
|
||||||
@ -4631,7 +4631,9 @@ int mount_options_set_and_consume(MountOptions **options, PartitionDesignator d,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return free_and_replace((*options)->options[d], s);
|
free_and_replace((*options)->options[d], s);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mount_options_dup(const MountOptions *source, MountOptions **ret) {
|
int mount_options_dup(const MountOptions *source, MountOptions **ret) {
|
||||||
@ -4642,7 +4644,7 @@ int mount_options_dup(const MountOptions *source, MountOptions **ret) {
|
|||||||
|
|
||||||
options = new0(MountOptions, 1);
|
options = new0(MountOptions, 1);
|
||||||
if (!options)
|
if (!options)
|
||||||
return log_oom_debug();
|
return log_oom();
|
||||||
|
|
||||||
for (PartitionDesignator d = 0; d < _PARTITION_DESIGNATOR_MAX; d++)
|
for (PartitionDesignator d = 0; d < _PARTITION_DESIGNATOR_MAX; d++)
|
||||||
if (source->options[d]) {
|
if (source->options[d]) {
|
||||||
|
|||||||
@ -1060,6 +1060,7 @@ static int fw_nftables_add_local_dnat_internal(
|
|||||||
|
|
||||||
sd_netlink_message *messages[3] = {};
|
sd_netlink_message *messages[3] = {};
|
||||||
_unused_ _cleanup_(netlink_message_unref_manyp) sd_netlink_message **unref = messages;
|
_unused_ _cleanup_(netlink_message_unref_manyp) sd_netlink_message **unref = messages;
|
||||||
|
static bool ipv6_supported = true;
|
||||||
uint32_t data[5], key[2], dlen;
|
uint32_t data[5], key[2], dlen;
|
||||||
size_t msgcnt = 0;
|
size_t msgcnt = 0;
|
||||||
int r;
|
int r;
|
||||||
@ -1068,6 +1069,9 @@ static int fw_nftables_add_local_dnat_internal(
|
|||||||
assert(add || !previous_remote);
|
assert(add || !previous_remote);
|
||||||
assert(IN_SET(af, AF_INET, AF_INET6));
|
assert(IN_SET(af, AF_INET, AF_INET6));
|
||||||
|
|
||||||
|
if (!ipv6_supported && af == AF_INET6)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
if (!IN_SET(protocol, IPPROTO_TCP, IPPROTO_UDP))
|
if (!IN_SET(protocol, IPPROTO_TCP, IPPROTO_UDP))
|
||||||
return -EPROTONOSUPPORT;
|
return -EPROTONOSUPPORT;
|
||||||
|
|
||||||
@ -1121,6 +1125,14 @@ static int fw_nftables_add_local_dnat_internal(
|
|||||||
|
|
||||||
assert(msgcnt < ELEMENTSOF(messages));
|
assert(msgcnt < ELEMENTSOF(messages));
|
||||||
r = sd_nfnl_call_batch(nfnl, messages, msgcnt, NFNL_DEFAULT_TIMEOUT_USECS);
|
r = sd_nfnl_call_batch(nfnl, messages, msgcnt, NFNL_DEFAULT_TIMEOUT_USECS);
|
||||||
|
if (r == -EOVERFLOW && af == AF_INET6) {
|
||||||
|
/* The current implementation of DNAT in systemd requires kernel's
|
||||||
|
* fdb9c405e35bdc6e305b9b4e20ebc141ed14fc81 (v5.8), and the older kernel returns
|
||||||
|
* -EOVERFLOW. Let's treat the error as -EOPNOTSUPP. */
|
||||||
|
log_debug_errno(r, "The current implementation of IPv6 DNAT in systemd requires kernel 5.8 or newer, ignoring: %m");
|
||||||
|
ipv6_supported = false;
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "dissect-image.h"
|
|
||||||
#include "extract-word.h"
|
#include "extract-word.h"
|
||||||
#include "image-policy.h"
|
#include "image-policy.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -177,28 +176,6 @@ PartitionPolicyFlags image_policy_get_exhaustively(const ImagePolicy *policy, Pa
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PartitionPolicyFlags policy_flag_from_fstype(const char *s) {
|
|
||||||
if (!s)
|
|
||||||
return _PARTITION_POLICY_FLAGS_INVALID;
|
|
||||||
|
|
||||||
if (streq(s, "btrfs"))
|
|
||||||
return PARTITION_POLICY_BTRFS;
|
|
||||||
if (streq(s, "erofs"))
|
|
||||||
return PARTITION_POLICY_EROFS;
|
|
||||||
if (streq(s, "ext4"))
|
|
||||||
return PARTITION_POLICY_EXT4;
|
|
||||||
if (streq(s, "f2fs"))
|
|
||||||
return PARTITION_POLICY_F2FS;
|
|
||||||
if (streq(s, "squashfs"))
|
|
||||||
return PARTITION_POLICY_SQUASHFS;
|
|
||||||
if (streq(s, "vfat"))
|
|
||||||
return PARTITION_POLICY_VFAT;
|
|
||||||
if (streq(s, "xfs"))
|
|
||||||
return PARTITION_POLICY_XFS;
|
|
||||||
|
|
||||||
return _PARTITION_POLICY_FLAGS_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PartitionPolicyFlags policy_flag_from_string_one(const char *s) {
|
static PartitionPolicyFlags policy_flag_from_string_one(const char *s) {
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
@ -230,8 +207,22 @@ static PartitionPolicyFlags policy_flag_from_string_one(const char *s) {
|
|||||||
return PARTITION_POLICY_GROWFS_ON;
|
return PARTITION_POLICY_GROWFS_ON;
|
||||||
if (streq(s, "growfs-off"))
|
if (streq(s, "growfs-off"))
|
||||||
return PARTITION_POLICY_GROWFS_OFF;
|
return PARTITION_POLICY_GROWFS_OFF;
|
||||||
|
if (streq(s, "btrfs"))
|
||||||
|
return PARTITION_POLICY_BTRFS;
|
||||||
|
if (streq(s, "erofs"))
|
||||||
|
return PARTITION_POLICY_EROFS;
|
||||||
|
if (streq(s, "ext4"))
|
||||||
|
return PARTITION_POLICY_EXT4;
|
||||||
|
if (streq(s, "f2fs"))
|
||||||
|
return PARTITION_POLICY_F2FS;
|
||||||
|
if (streq(s, "squashfs"))
|
||||||
|
return PARTITION_POLICY_SQUASHFS;
|
||||||
|
if (streq(s, "vfat"))
|
||||||
|
return PARTITION_POLICY_VFAT;
|
||||||
|
if (streq(s, "xfs"))
|
||||||
|
return PARTITION_POLICY_XFS;
|
||||||
|
|
||||||
return policy_flag_from_fstype(s);
|
return _PARTITION_POLICY_FLAGS_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
PartitionPolicyFlags partition_policy_flags_from_string(const char *s, bool graceful) {
|
PartitionPolicyFlags partition_policy_flags_from_string(const char *s, bool graceful) {
|
||||||
@ -284,60 +275,6 @@ static ImagePolicy* image_policy_new(size_t n_policies) {
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImagePolicy* image_policy_new_from_dissected(const DissectedImage *image, const VeritySettings *verity) {
|
|
||||||
assert(image);
|
|
||||||
|
|
||||||
ImagePolicy *image_policy = image_policy_new(_PARTITION_DESIGNATOR_MAX);
|
|
||||||
if (!image_policy)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Default to 'absent', only what we find is allowed to be used */
|
|
||||||
image_policy->default_flags = PARTITION_POLICY_ABSENT;
|
|
||||||
|
|
||||||
for (PartitionDesignator pd = 0; pd < _PARTITION_DESIGNATOR_MAX; pd++) {
|
|
||||||
PartitionPolicyFlags f = 0;
|
|
||||||
|
|
||||||
if (!image->partitions[pd].found)
|
|
||||||
f |= PARTITION_POLICY_ABSENT;
|
|
||||||
else {
|
|
||||||
if (streq_ptr(image->partitions[pd].fstype, "crypto_LUKS"))
|
|
||||||
f |= PARTITION_POLICY_ENCRYPTED;
|
|
||||||
else {
|
|
||||||
PartitionPolicyFlags fstype_flag = policy_flag_from_fstype(image->partitions[pd].fstype);
|
|
||||||
if (fstype_flag >= 0)
|
|
||||||
f |= fstype_flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!verity || verity->designator < 0 || verity->designator == pd) {
|
|
||||||
if (image->verity_sig_ready || (verity && iovec_is_set(&verity->root_hash_sig)))
|
|
||||||
f |= PARTITION_POLICY_SIGNED;
|
|
||||||
else if (image->verity_ready || (verity && iovec_is_set(&verity->root_hash)))
|
|
||||||
f |= PARTITION_POLICY_VERITY;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!image->single_file_system) {
|
|
||||||
if (image->partitions[pd].growfs)
|
|
||||||
f |= PARTITION_POLICY_GROWFS_ON;
|
|
||||||
else
|
|
||||||
f |= PARTITION_POLICY_GROWFS_OFF;
|
|
||||||
|
|
||||||
if (image->partitions[pd].rw)
|
|
||||||
f |= PARTITION_POLICY_READ_ONLY_OFF;
|
|
||||||
else
|
|
||||||
f |= PARTITION_POLICY_READ_ONLY_ON;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
image_policy->policies[pd] = (PartitionPolicy) {
|
|
||||||
.designator = pd,
|
|
||||||
.flags = f,
|
|
||||||
};
|
|
||||||
image_policy->n_policies++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return image_policy;
|
|
||||||
}
|
|
||||||
|
|
||||||
int image_policy_from_string(const char *s, bool graceful, ImagePolicy **ret) {
|
int image_policy_from_string(const char *s, bool graceful, ImagePolicy **ret) {
|
||||||
_cleanup_free_ ImagePolicy *p = NULL;
|
_cleanup_free_ ImagePolicy *p = NULL;
|
||||||
uint64_t dmask = 0;
|
uint64_t dmask = 0;
|
||||||
@ -848,35 +785,21 @@ static bool partition_policy_flags_has_unspecified(PartitionPolicyFlags flags) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PartitionPolicyFlags policy_flags_or(PartitionPolicyFlags a, PartitionPolicyFlags b) {
|
int image_policy_intersect(const ImagePolicy *a, const ImagePolicy *b, ImagePolicy **ret) {
|
||||||
return a | b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PartitionPolicyFlags policy_flags_and(PartitionPolicyFlags a, PartitionPolicyFlags b) {
|
|
||||||
return a & b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int policy_intersect_or_union(
|
|
||||||
const ImagePolicy *a,
|
|
||||||
const ImagePolicy *b,
|
|
||||||
PartitionPolicyFlags (*op)(PartitionPolicyFlags a, PartitionPolicyFlags b),
|
|
||||||
ImagePolicy **ret) {
|
|
||||||
|
|
||||||
_cleanup_(image_policy_freep) ImagePolicy *p = NULL;
|
_cleanup_(image_policy_freep) ImagePolicy *p = NULL;
|
||||||
|
|
||||||
assert(op);
|
/* Calculates the intersection of the specified policies, i.e. only what is permitted in both. This
|
||||||
|
* might fail with -ENAVAIL if the intersection is an "impossible policy". For example, if a root
|
||||||
/* Calculates the intersection or union of the specified policies, i.e. only what is permitted in
|
* partition my neither be used, nor be absent, nor be unused then this is considered
|
||||||
* both or either. This might fail with -ENAVAIL if the intersection is an "impossible policy". For
|
* "impossible". */
|
||||||
* example, if a root partition my neither be used, nor be absent, nor be unused then this is
|
|
||||||
* considered "impossible". */
|
|
||||||
|
|
||||||
p = image_policy_new(_PARTITION_DESIGNATOR_MAX);
|
p = image_policy_new(_PARTITION_DESIGNATOR_MAX);
|
||||||
if (!p)
|
if (!p)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
p->default_flags = op(partition_policy_flags_extend(image_policy_default(a)),
|
p->default_flags =
|
||||||
partition_policy_flags_extend(image_policy_default(b)));
|
partition_policy_flags_extend(image_policy_default(a)) &
|
||||||
|
partition_policy_flags_extend(image_policy_default(b));
|
||||||
|
|
||||||
if (partition_policy_flags_has_unspecified(p->default_flags)) /* Intersection empty? */
|
if (partition_policy_flags_has_unspecified(p->default_flags)) /* Intersection empty? */
|
||||||
return -ENAVAIL;
|
return -ENAVAIL;
|
||||||
@ -901,12 +824,10 @@ static int policy_intersect_or_union(
|
|||||||
return y;
|
return y;
|
||||||
|
|
||||||
/* Mask it */
|
/* Mask it */
|
||||||
z = op(x, y);
|
z = x & y;
|
||||||
|
|
||||||
/* Check if the intersection is empty for this partition. If so, generate a clear error.
|
/* Check if the intersection is empty for this partition. If so, generate a clear error */
|
||||||
* If the partition has to be absent, then it won't have read-only/growfs flags, as
|
if (partition_policy_flags_has_unspecified(z))
|
||||||
* image_policy_get_exhaustively() intentionally strips them, so skip the check. */
|
|
||||||
if (z != PARTITION_POLICY_ABSENT && partition_policy_flags_has_unspecified(z))
|
|
||||||
return -ENAVAIL;
|
return -ENAVAIL;
|
||||||
|
|
||||||
df = partition_policy_normalized_flags(
|
df = partition_policy_normalized_flags(
|
||||||
@ -936,14 +857,6 @@ static int policy_intersect_or_union(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int image_policy_intersect(const ImagePolicy *a, const ImagePolicy *b, ImagePolicy **ret) {
|
|
||||||
return policy_intersect_or_union(a, b, policy_flags_and, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
int image_policy_union(const ImagePolicy *a, const ImagePolicy *b, ImagePolicy **ret) {
|
|
||||||
return policy_intersect_or_union(a, b, policy_flags_or, ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImagePolicy* image_policy_free(ImagePolicy *p) {
|
ImagePolicy* image_policy_free(ImagePolicy *p) {
|
||||||
return mfree(p);
|
return mfree(p);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "conf-parser-forward.h"
|
#include "conf-parser-forward.h"
|
||||||
#include "dissect-image.h"
|
|
||||||
#include "shared-forward.h"
|
#include "shared-forward.h"
|
||||||
#include "gpt.h"
|
#include "gpt.h"
|
||||||
|
|
||||||
@ -112,9 +111,7 @@ bool image_policy_equal(const ImagePolicy *a, const ImagePolicy *b); /* ch
|
|||||||
int image_policy_equivalent(const ImagePolicy *a, const ImagePolicy *b); /* checks if the outcome is the same, i.e. for all partitions results in the same decisions. */
|
int image_policy_equivalent(const ImagePolicy *a, const ImagePolicy *b); /* checks if the outcome is the same, i.e. for all partitions results in the same decisions. */
|
||||||
|
|
||||||
int image_policy_intersect(const ImagePolicy *a, const ImagePolicy *b, ImagePolicy **ret);
|
int image_policy_intersect(const ImagePolicy *a, const ImagePolicy *b, ImagePolicy **ret);
|
||||||
int image_policy_union(const ImagePolicy *a, const ImagePolicy *b, ImagePolicy **ret);
|
|
||||||
|
|
||||||
ImagePolicy* image_policy_new_from_dissected(const DissectedImage *image, const VeritySettings *verity);
|
|
||||||
ImagePolicy* image_policy_free(ImagePolicy *p);
|
ImagePolicy* image_policy_free(ImagePolicy *p);
|
||||||
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(ImagePolicy*, image_policy_free);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(ImagePolicy*, image_policy_free);
|
||||||
|
|||||||
@ -349,7 +349,7 @@ int journal_importer_process_data(JournalImporter *imp) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* replace '\n' with '=' */
|
/* replace \n with = */
|
||||||
line[n-1] = '=';
|
line[n-1] = '=';
|
||||||
|
|
||||||
imp->field_len = n;
|
imp->field_len = n;
|
||||||
|
|||||||
@ -64,6 +64,9 @@ static bool is_in_survivor_cgroup(const PidRef *pid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
r = cg_get_xattr_bool(cgroup_path, "user.survive_final_kill_signal");
|
r = cg_get_xattr_bool(cgroup_path, "user.survive_final_kill_signal");
|
||||||
|
/* user xattr support was added to kernel v5.7, try with the trusted namespace as a fallback */
|
||||||
|
if (ERRNO_IS_NEG_XATTR_ABSENT(r))
|
||||||
|
r = cg_get_xattr_bool(cgroup_path, "trusted.survive_final_kill_signal");
|
||||||
if (r < 0 && !ERRNO_IS_NEG_XATTR_ABSENT(r))
|
if (r < 0 && !ERRNO_IS_NEG_XATTR_ABSENT(r))
|
||||||
log_debug_errno(r,
|
log_debug_errno(r,
|
||||||
"Failed to get survive_final_kill_signal xattr of %s, ignoring: %m",
|
"Failed to get survive_final_kill_signal xattr of %s, ignoring: %m",
|
||||||
|
|||||||
@ -1951,7 +1951,7 @@ int trigger_automount_at(int dir_fd, const char *path) {
|
|||||||
|
|
||||||
unsigned long credentials_fs_mount_flags(bool ro) {
|
unsigned long credentials_fs_mount_flags(bool ro) {
|
||||||
/* A tight set of mount flags for credentials mounts */
|
/* A tight set of mount flags for credentials mounts */
|
||||||
return MS_NODEV|MS_NOEXEC|MS_NOSUID|MS_NOSYMFOLLOW|(ro ? MS_RDONLY : 0);
|
return MS_NODEV|MS_NOEXEC|MS_NOSUID|ms_nosymfollow_supported()|(ro ? MS_RDONLY : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fsmount_credentials_fs(int *ret_fsfd) {
|
int fsmount_credentials_fs(int *ret_fsfd) {
|
||||||
|
|||||||
@ -166,7 +166,7 @@ int make_mount_point_inode_from_path(const char *source, const char *dest, mode_
|
|||||||
|
|
||||||
int trigger_automount_at(int dir_fd, const char *path);
|
int trigger_automount_at(int dir_fd, const char *path);
|
||||||
|
|
||||||
unsigned long credentials_fs_mount_flags(bool ro) _const_;
|
unsigned long credentials_fs_mount_flags(bool ro);
|
||||||
int fsmount_credentials_fs(int *ret_fsfd);
|
int fsmount_credentials_fs(int *ret_fsfd);
|
||||||
int mount_credentials_fs(const char *path);
|
int mount_credentials_fs(const char *path);
|
||||||
|
|
||||||
|
|||||||
@ -5441,11 +5441,6 @@ int tpm2_seal(Tpm2Context *c,
|
|||||||
seal_key_handle);
|
seal_key_handle);
|
||||||
|
|
||||||
primary_alg = primary_public->publicArea.type;
|
primary_alg = primary_public->publicArea.type;
|
||||||
|
|
||||||
/* Propagate fixedTPM/fixedParent flags from sealing key to hmac key */
|
|
||||||
hmac_template.objectAttributes = (hmac_template.objectAttributes & ~(TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT)) |
|
|
||||||
(primary_public->publicArea.objectAttributes & (TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT));
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (seal_key_handle != 0)
|
if (seal_key_handle != 0)
|
||||||
log_debug("Using primary alg sealing, but seal key handle also provided; ignoring seal key handle.");
|
log_debug("Using primary alg sealing, but seal key handle also provided; ignoring seal key handle.");
|
||||||
|
|||||||
@ -151,7 +151,7 @@ typedef enum Tpm2UserspaceEventType {
|
|||||||
|
|
||||||
DECLARE_STRING_TABLE_LOOKUP(tpm2_userspace_event_type, Tpm2UserspaceEventType);
|
DECLARE_STRING_TABLE_LOOKUP(tpm2_userspace_event_type, Tpm2UserspaceEventType);
|
||||||
|
|
||||||
int tpm2_pcr_extend_bytes(Tpm2Context *c, char **banks, unsigned pcr_index, const struct iovec *data, const struct iovec *secret, Tpm2UserspaceEventType event_type, const char *description);
|
int tpm2_pcr_extend_bytes(Tpm2Context *c, char **banks, unsigned pcr_index, const struct iovec *data, const struct iovec *secret, Tpm2UserspaceEventType event, const char *description);
|
||||||
int tpm2_nvpcr_get_index(const char *name, uint32_t *ret);
|
int tpm2_nvpcr_get_index(const char *name, uint32_t *ret);
|
||||||
int tpm2_nvpcr_extend_bytes(Tpm2Context *c, const Tpm2Handle *session, const char *name, const struct iovec *data, const struct iovec *secret, Tpm2UserspaceEventType event_type, const char *description);
|
int tpm2_nvpcr_extend_bytes(Tpm2Context *c, const Tpm2Handle *session, const char *name, const struct iovec *data, const struct iovec *secret, Tpm2UserspaceEventType event_type, const char *description);
|
||||||
int tpm2_nvpcr_acquire_anchor_secret(struct iovec *ret, bool sync_secondary);
|
int tpm2_nvpcr_acquire_anchor_secret(struct iovec *ret, bool sync_secondary);
|
||||||
|
|||||||
@ -111,9 +111,15 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
|
|||||||
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#MemoryMin=bytes,%20MemoryLow=bytes"),
|
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#MemoryMin=bytes,%20MemoryLow=bytes"),
|
||||||
SD_VARLINK_DEFINE_FIELD(MemoryMin, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
SD_VARLINK_DEFINE_FIELD(MemoryMin, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||||
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#MemoryMin=bytes,%20MemoryLow=bytes"),
|
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#MemoryMin=bytes,%20MemoryLow=bytes"),
|
||||||
|
SD_VARLINK_DEFINE_FIELD(DefaultMemoryMin, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||||
|
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#MemoryMin=bytes,%20MemoryLow=bytes"),
|
||||||
SD_VARLINK_DEFINE_FIELD(MemoryLow, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
SD_VARLINK_DEFINE_FIELD(MemoryLow, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||||
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#MemoryMin=bytes,%20MemoryLow=bytes"),
|
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#MemoryMin=bytes,%20MemoryLow=bytes"),
|
||||||
|
SD_VARLINK_DEFINE_FIELD(DefaultMemoryLow, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||||
|
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#MemorySwapMax=bytes"),
|
||||||
SD_VARLINK_DEFINE_FIELD(StartupMemoryLow, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
SD_VARLINK_DEFINE_FIELD(StartupMemoryLow, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||||
|
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#MemoryMin=bytes,%20MemoryLow=bytes"),
|
||||||
|
SD_VARLINK_DEFINE_FIELD(DefaultStartupMemoryLow, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||||
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#MemoryHigh=bytes"),
|
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#MemoryHigh=bytes"),
|
||||||
SD_VARLINK_DEFINE_FIELD(MemoryHigh, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
SD_VARLINK_DEFINE_FIELD(MemoryHigh, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
|
||||||
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#MemoryHigh=bytes"),
|
SD_VARLINK_FIELD_COMMENT("https://www.freedesktop.org/software/systemd/man/"PROJECT_VERSION_STR"/systemd.resource-control.html#MemoryHigh=bytes"),
|
||||||
|
|||||||
@ -302,6 +302,10 @@ typedef struct UnitStatusInfo {
|
|||||||
uint64_t io_read_bytes;
|
uint64_t io_read_bytes;
|
||||||
uint64_t io_write_bytes;
|
uint64_t io_write_bytes;
|
||||||
|
|
||||||
|
uint64_t default_memory_min;
|
||||||
|
uint64_t default_memory_low;
|
||||||
|
uint64_t default_startup_memory_low;
|
||||||
|
|
||||||
/* Exec Quotas */
|
/* Exec Quotas */
|
||||||
QuotaInfo exec_directories_quota[_EXEC_DIRECTORY_TYPE_MAX];
|
QuotaInfo exec_directories_quota[_EXEC_DIRECTORY_TYPE_MAX];
|
||||||
|
|
||||||
@ -2244,6 +2248,9 @@ static int show_one(
|
|||||||
{ "MemorySwapPeak", "t", NULL, offsetof(UnitStatusInfo, memory_swap_peak) },
|
{ "MemorySwapPeak", "t", NULL, offsetof(UnitStatusInfo, memory_swap_peak) },
|
||||||
{ "MemoryZSwapCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_zswap_current) },
|
{ "MemoryZSwapCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_zswap_current) },
|
||||||
{ "MemoryAvailable", "t", NULL, offsetof(UnitStatusInfo, memory_available) },
|
{ "MemoryAvailable", "t", NULL, offsetof(UnitStatusInfo, memory_available) },
|
||||||
|
{ "DefaultMemoryMin", "t", NULL, offsetof(UnitStatusInfo, default_memory_min) },
|
||||||
|
{ "DefaultMemoryLow", "t", NULL, offsetof(UnitStatusInfo, default_memory_low) },
|
||||||
|
{ "DefaultStartupMemoryLow", "t", NULL, offsetof(UnitStatusInfo, default_startup_memory_low) },
|
||||||
{ "MemoryMin", "t", NULL, offsetof(UnitStatusInfo, memory_min) },
|
{ "MemoryMin", "t", NULL, offsetof(UnitStatusInfo, memory_min) },
|
||||||
{ "MemoryLow", "t", NULL, offsetof(UnitStatusInfo, memory_low) },
|
{ "MemoryLow", "t", NULL, offsetof(UnitStatusInfo, memory_low) },
|
||||||
{ "StartupMemoryLow", "t", NULL, offsetof(UnitStatusInfo, startup_memory_low) },
|
{ "StartupMemoryLow", "t", NULL, offsetof(UnitStatusInfo, startup_memory_low) },
|
||||||
|
|||||||
@ -540,6 +540,9 @@ executables += [
|
|||||||
'sources' : files('test-cgroup-mask.c'),
|
'sources' : files('test-cgroup-mask.c'),
|
||||||
'dependencies' : common_test_dependencies,
|
'dependencies' : common_test_dependencies,
|
||||||
},
|
},
|
||||||
|
core_test_template + {
|
||||||
|
'sources' : files('test-cgroup-unit-default.c'),
|
||||||
|
},
|
||||||
core_test_template + {
|
core_test_template + {
|
||||||
'sources' : files('test-chown-rec.c'),
|
'sources' : files('test-chown-rec.c'),
|
||||||
},
|
},
|
||||||
|
|||||||
136
src/test/test-cgroup-unit-default.c
Normal file
136
src/test/test-cgroup-unit-default.c
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include "cgroup.h"
|
||||||
|
#include "manager.h"
|
||||||
|
#include "rm-rf.h"
|
||||||
|
#include "tests.h"
|
||||||
|
#include "unit.h"
|
||||||
|
|
||||||
|
TEST_RET(default_memory_low, .sd_booted = true) {
|
||||||
|
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
|
||||||
|
_cleanup_(manager_freep) Manager *m = NULL;
|
||||||
|
Unit *root, *dml,
|
||||||
|
*dml_passthrough, *dml_passthrough_empty, *dml_passthrough_set_dml, *dml_passthrough_set_ml,
|
||||||
|
*dml_override, *dml_override_empty,
|
||||||
|
*dml_discard, *dml_discard_empty, *dml_discard_set_ml;
|
||||||
|
uint64_t dml_tree_default;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = enter_cgroup_subroot(NULL);
|
||||||
|
if (r == -ENOMEDIUM)
|
||||||
|
return log_tests_skipped("cgroupfs not available");
|
||||||
|
|
||||||
|
_cleanup_free_ char *unit_dir = NULL;
|
||||||
|
ASSERT_OK(get_testdata_dir("test-cgroup-unit-default", &unit_dir));
|
||||||
|
ASSERT_OK(setenv_unit_path(unit_dir));
|
||||||
|
assert_se(runtime_dir = setup_fake_runtime_dir());
|
||||||
|
r = manager_new(RUNTIME_SCOPE_USER, MANAGER_TEST_RUN_BASIC, &m);
|
||||||
|
if (IN_SET(r, -EPERM, -EACCES)) {
|
||||||
|
log_error_errno(r, "manager_new: %m");
|
||||||
|
return log_tests_skipped("cannot create manager");
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT_OK(r);
|
||||||
|
ASSERT_OK(manager_startup(m, NULL, NULL, NULL));
|
||||||
|
|
||||||
|
/* dml.slice has DefaultMemoryLow=50. Beyond that, individual subhierarchies look like this:
|
||||||
|
*
|
||||||
|
* 1. dml-passthrough.slice sets MemoryLow=100. This should not affect its children, as only
|
||||||
|
* DefaultMemoryLow is propagated, not MemoryLow. As such, all leaf services should end up with
|
||||||
|
* memory.low as 50, inherited from dml.slice, *except* for dml-passthrough-set-ml.service, which
|
||||||
|
* should have the value of 0, as it has MemoryLow explicitly set.
|
||||||
|
*
|
||||||
|
* ┌───────────┐
|
||||||
|
* │ dml.slice │
|
||||||
|
* └─────┬─────┘
|
||||||
|
* MemoryLow=100
|
||||||
|
* ┌───────────┴───────────┐
|
||||||
|
* │ dml-passthrough.slice │
|
||||||
|
* └───────────┬───────────┘
|
||||||
|
* ┌───────────────────────────────────┼───────────────────────────────────┐
|
||||||
|
* no new settings DefaultMemoryLow=15 MemoryLow=0
|
||||||
|
* ┌───────────────┴───────────────┐ ┌────────────────┴────────────────┐ ┌───────────────┴────────────────┐
|
||||||
|
* │ dml-passthrough-empty.service │ │ dml-passthrough-set-dml.service │ │ dml-passthrough-set-ml.service │
|
||||||
|
* └───────────────────────────────┘ └─────────────────────────────────┘ └────────────────────────────────┘
|
||||||
|
*
|
||||||
|
* 2. dml-override.slice sets DefaultMemoryLow=10. As such, dml-override-empty.service should also
|
||||||
|
* end up with a memory.low of 10. dml-override.slice should still have a memory.low of 50.
|
||||||
|
*
|
||||||
|
* ┌───────────┐
|
||||||
|
* │ dml.slice │
|
||||||
|
* └─────┬─────┘
|
||||||
|
* DefaultMemoryLow=10
|
||||||
|
* ┌─────────┴──────────┐
|
||||||
|
* │ dml-override.slice │
|
||||||
|
* └─────────┬──────────┘
|
||||||
|
* no new settings
|
||||||
|
* ┌─────────────┴──────────────┐
|
||||||
|
* │ dml-override-empty.service │
|
||||||
|
* └────────────────────────────┘
|
||||||
|
*
|
||||||
|
* 3. dml-discard.slice sets DefaultMemoryLow= with no rvalue. As such,
|
||||||
|
* dml-discard-empty.service should end up with a value of 0.
|
||||||
|
* dml-discard-set-ml.service sets MemoryLow=15, and as such should have that override the
|
||||||
|
* reset DefaultMemoryLow value. dml-discard.slice should still have an eventual memory.low of 50.
|
||||||
|
*
|
||||||
|
* ┌───────────┐
|
||||||
|
* │ dml.slice │
|
||||||
|
* └─────┬─────┘
|
||||||
|
* DefaultMemoryLow=
|
||||||
|
* ┌─────────┴─────────┐
|
||||||
|
* │ dml-discard.slice │
|
||||||
|
* └─────────┬─────────┘
|
||||||
|
* ┌──────────────┴───────────────┐
|
||||||
|
* no new settings MemoryLow=15
|
||||||
|
* ┌─────────────┴─────────────┐ ┌─────────────┴──────────────┐
|
||||||
|
* │ dml-discard-empty.service │ │ dml-discard-set-ml.service │
|
||||||
|
* └───────────────────────────┘ └────────────────────────────┘
|
||||||
|
*/
|
||||||
|
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml.slice", NULL, &dml));
|
||||||
|
|
||||||
|
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-passthrough.slice", NULL, &dml_passthrough));
|
||||||
|
assert_se(UNIT_GET_SLICE(dml_passthrough) == dml);
|
||||||
|
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-passthrough-empty.service", NULL, &dml_passthrough_empty));
|
||||||
|
assert_se(UNIT_GET_SLICE(dml_passthrough_empty) == dml_passthrough);
|
||||||
|
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-passthrough-set-dml.service", NULL, &dml_passthrough_set_dml));
|
||||||
|
assert_se(UNIT_GET_SLICE(dml_passthrough_set_dml) == dml_passthrough);
|
||||||
|
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-passthrough-set-ml.service", NULL, &dml_passthrough_set_ml));
|
||||||
|
assert_se(UNIT_GET_SLICE(dml_passthrough_set_ml) == dml_passthrough);
|
||||||
|
|
||||||
|
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-override.slice", NULL, &dml_override));
|
||||||
|
assert_se(UNIT_GET_SLICE(dml_override) == dml);
|
||||||
|
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-override-empty.service", NULL, &dml_override_empty));
|
||||||
|
assert_se(UNIT_GET_SLICE(dml_override_empty) == dml_override);
|
||||||
|
|
||||||
|
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-discard.slice", NULL, &dml_discard));
|
||||||
|
assert_se(UNIT_GET_SLICE(dml_discard) == dml);
|
||||||
|
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-discard-empty.service", NULL, &dml_discard_empty));
|
||||||
|
assert_se(UNIT_GET_SLICE(dml_discard_empty) == dml_discard);
|
||||||
|
ASSERT_OK(manager_load_startable_unit_or_warn(m, "dml-discard-set-ml.service", NULL, &dml_discard_set_ml));
|
||||||
|
assert_se(UNIT_GET_SLICE(dml_discard_set_ml) == dml_discard);
|
||||||
|
|
||||||
|
assert_se(root = UNIT_GET_SLICE(dml));
|
||||||
|
assert_se(!UNIT_GET_SLICE(root));
|
||||||
|
|
||||||
|
assert_se(unit_get_ancestor_memory_low(root) == CGROUP_LIMIT_MIN);
|
||||||
|
|
||||||
|
assert_se(unit_get_ancestor_memory_low(dml) == CGROUP_LIMIT_MIN);
|
||||||
|
dml_tree_default = unit_get_cgroup_context(dml)->default_memory_low;
|
||||||
|
assert_se(dml_tree_default == 50);
|
||||||
|
|
||||||
|
assert_se(unit_get_ancestor_memory_low(dml_passthrough) == 100);
|
||||||
|
assert_se(unit_get_ancestor_memory_low(dml_passthrough_empty) == dml_tree_default);
|
||||||
|
assert_se(unit_get_ancestor_memory_low(dml_passthrough_set_dml) == 50);
|
||||||
|
assert_se(unit_get_ancestor_memory_low(dml_passthrough_set_ml) == 0);
|
||||||
|
|
||||||
|
assert_se(unit_get_ancestor_memory_low(dml_override) == dml_tree_default);
|
||||||
|
assert_se(unit_get_ancestor_memory_low(dml_override_empty) == 10);
|
||||||
|
|
||||||
|
assert_se(unit_get_ancestor_memory_low(dml_discard) == dml_tree_default);
|
||||||
|
assert_se(unit_get_ancestor_memory_low(dml_discard_empty) == CGROUP_LIMIT_MIN);
|
||||||
|
assert_se(unit_get_ancestor_memory_low(dml_discard_set_ml) == 15);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||||
@ -142,17 +142,14 @@ TEST(extend) {
|
|||||||
assert_se(partition_policy_flags_extend(PARTITION_POLICY_GROWFS_ON) == (PARTITION_POLICY_GROWFS_ON|_PARTITION_POLICY_USE_MASK|_PARTITION_POLICY_READ_ONLY_MASK));
|
assert_se(partition_policy_flags_extend(PARTITION_POLICY_GROWFS_ON) == (PARTITION_POLICY_GROWFS_ON|_PARTITION_POLICY_USE_MASK|_PARTITION_POLICY_READ_ONLY_MASK));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_policy_intersect_one(const char *a, const char *b, const char *c, bool intersect) {
|
static void test_policy_intersect_one(const char *a, const char *b, const char *c) {
|
||||||
_cleanup_(image_policy_freep) ImagePolicy *x = NULL, *y = NULL, *z = NULL, *t = NULL;
|
_cleanup_(image_policy_freep) ImagePolicy *x = NULL, *y = NULL, *z = NULL, *t = NULL;
|
||||||
|
|
||||||
assert_se(image_policy_from_string(a, /* graceful= */ false, &x) >= 0);
|
assert_se(image_policy_from_string(a, /* graceful= */ false, &x) >= 0);
|
||||||
assert_se(image_policy_from_string(b, /* graceful= */ false, &y) >= 0);
|
assert_se(image_policy_from_string(b, /* graceful= */ false, &y) >= 0);
|
||||||
assert_se(image_policy_from_string(c, /* graceful= */ false, &z) >= 0);
|
assert_se(image_policy_from_string(c, /* graceful= */ false, &z) >= 0);
|
||||||
|
|
||||||
if (intersect)
|
assert_se(image_policy_intersect(x, y, &t) >= 0);
|
||||||
assert_se(image_policy_intersect(x, y, &t) >= 0);
|
|
||||||
else
|
|
||||||
assert_se(image_policy_union(x, y, &t) >= 0);
|
|
||||||
|
|
||||||
_cleanup_free_ char *s1 = NULL, *s2 = NULL, *s3 = NULL, *s4 = NULL;
|
_cleanup_free_ char *s1 = NULL, *s2 = NULL, *s3 = NULL, *s4 = NULL;
|
||||||
assert_se(image_policy_to_string(x, false, &s1) >= 0);
|
assert_se(image_policy_to_string(x, false, &s1) >= 0);
|
||||||
@ -160,33 +157,21 @@ static void test_policy_intersect_one(const char *a, const char *b, const char *
|
|||||||
assert_se(image_policy_to_string(z, false, &s3) >= 0);
|
assert_se(image_policy_to_string(z, false, &s3) >= 0);
|
||||||
assert_se(image_policy_to_string(t, false, &s4) >= 0);
|
assert_se(image_policy_to_string(t, false, &s4) >= 0);
|
||||||
|
|
||||||
log_info("%s %s %s → %s vs. %s", s1, intersect ? "^" : "U", s2, s3, s4);
|
log_info("%s ^ %s → %s vs. %s", s1, s2, s3, s4);
|
||||||
|
|
||||||
assert_se(image_policy_equivalent(z, t) > 0);
|
assert_se(image_policy_equivalent(z, t) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(image_policy_intersect) {
|
TEST(image_policy_intersect) {
|
||||||
test_policy_intersect_one("", "", "", /* intersect= */ true);
|
test_policy_intersect_one("", "", "");
|
||||||
test_policy_intersect_one("-", "-", "-", /* intersect= */ true);
|
test_policy_intersect_one("-", "-", "-");
|
||||||
test_policy_intersect_one("*", "*", "*", /* intersect= */ true);
|
test_policy_intersect_one("*", "*", "*");
|
||||||
test_policy_intersect_one("~", "~", "~", /* intersect= */ true);
|
test_policy_intersect_one("~", "~", "~");
|
||||||
test_policy_intersect_one("root=verity+signed", "root=signed+verity", "root=verity+signed", /* intersect= */ true);
|
test_policy_intersect_one("root=verity+signed", "root=signed+verity", "root=verity+signed");
|
||||||
test_policy_intersect_one("root=verity+signed", "root=signed", "root=signed", /* intersect= */ true);
|
test_policy_intersect_one("root=verity+signed", "root=signed", "root=signed");
|
||||||
test_policy_intersect_one("root=verity+signed", "root=verity", "root=verity", /* intersect= */ true);
|
test_policy_intersect_one("root=verity+signed", "root=verity", "root=verity");
|
||||||
test_policy_intersect_one("root=open", "root=verity", "root=verity", /* intersect= */ true);
|
test_policy_intersect_one("root=open", "root=verity", "root=verity");
|
||||||
test_policy_intersect_one("root=open", "=verity+ignore", "root=verity+ignore:=ignore", /* intersect= */ true);
|
test_policy_intersect_one("root=open", "=verity+ignore", "root=verity+ignore:=ignore");
|
||||||
}
|
|
||||||
|
|
||||||
TEST(image_policy_union) {
|
|
||||||
test_policy_intersect_one("root=verity+signed", "root=signed+verity", "root=verity+signed", /* intersect= */ false);
|
|
||||||
test_policy_intersect_one("root=verity+signed", "root=signed", "root=verity+signed", /* intersect= */ false);
|
|
||||||
test_policy_intersect_one("root=verity+signed", "root=verity", "root=verity+signed", /* intersect= */ false);
|
|
||||||
test_policy_intersect_one("root=signed", "root=verity", "root=verity+signed", /* intersect= */ false);
|
|
||||||
test_policy_intersect_one("root=signed:=absent", "root=verity:=unused", "root=verity+signed", /* intersect= */ false);
|
|
||||||
test_policy_intersect_one("root=open", "root=verity", "root=open", /* intersect= */ false);
|
|
||||||
test_policy_intersect_one("root=open", "=verity+ignore", "root=open:=verity+ignore", /* intersect= */ false);
|
|
||||||
test_policy_intersect_one("root=open:usr=absent", "root=open:usr=absent", "root=open:usr=absent", /* intersect= */ false);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_policy_ignore_designators_one(const char *a, const PartitionDesignator array[], size_t n, const char *b) {
|
static void test_policy_ignore_designators_one(const char *a, const PartitionDesignator array[], size_t n, const char *b) {
|
||||||
@ -280,382 +265,4 @@ TEST(partition_policy_determine_fstype) {
|
|||||||
ASSERT_FALSE(encrypted);
|
ASSERT_FALSE(encrypted);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(image_policy_new_from_dissected) {
|
|
||||||
_cleanup_(image_policy_freep) ImagePolicy *policy = NULL;
|
|
||||||
DissectedImage image;
|
|
||||||
VeritySettings verity;
|
|
||||||
uint8_t dummy_data[4];
|
|
||||||
|
|
||||||
/* Test 1: Empty image - all partitions should be absent */
|
|
||||||
image = (DissectedImage) {};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
ASSERT_EQ(image_policy_default(policy), PARTITION_POLICY_ABSENT);
|
|
||||||
ASSERT_EQ(image_policy_n_entries(policy), (size_t) _PARTITION_DESIGNATOR_MAX);
|
|
||||||
|
|
||||||
/* All partitions should have PARTITION_POLICY_ABSENT */
|
|
||||||
for (PartitionDesignator pd = 0; pd < _PARTITION_DESIGNATOR_MAX; pd++)
|
|
||||||
ASSERT_EQ(policy->policies[pd].flags, (PartitionPolicyFlags) PARTITION_POLICY_ABSENT);
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 2: Image with a single ext4 root partition */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "ext4",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_EXT4 | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_USR].flags, (PartitionPolicyFlags) PARTITION_POLICY_ABSENT);
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 3: Image with encrypted root partition (LUKS) */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "crypto_LUKS",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_ENCRYPTED | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 4: Image with verity ready (without signature) */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.verity_ready = true,
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "squashfs",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_SQUASHFS | PARTITION_POLICY_VERITY | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 5: Image with verity signature ready */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.verity_sig_ready = true,
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "erofs",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_EROFS | PARTITION_POLICY_SIGNED | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 6: Image with growfs enabled */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "btrfs",
|
|
||||||
.growfs = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_BTRFS | PARTITION_POLICY_GROWFS_ON | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 7: Multiple partitions with different filesystems */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "ext4",
|
|
||||||
},
|
|
||||||
[PARTITION_USR] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "xfs",
|
|
||||||
},
|
|
||||||
[PARTITION_HOME] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "btrfs",
|
|
||||||
.growfs = true,
|
|
||||||
},
|
|
||||||
[PARTITION_ESP] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "vfat",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_EXT4 | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_USR].flags, (PartitionPolicyFlags) (PARTITION_POLICY_XFS | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_HOME].flags, (PartitionPolicyFlags) (PARTITION_POLICY_BTRFS | PARTITION_POLICY_GROWFS_ON | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ESP].flags, (PartitionPolicyFlags) (PARTITION_POLICY_VFAT | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_SWAP].flags, (PartitionPolicyFlags) PARTITION_POLICY_ABSENT);
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 8: VeritySettings with root_hash set (no signature) */
|
|
||||||
dummy_data[0] = 0xde; dummy_data[1] = 0xad; dummy_data[2] = 0xbe; dummy_data[3] = 0xef;
|
|
||||||
verity = (VeritySettings) {
|
|
||||||
.designator = _PARTITION_DESIGNATOR_INVALID,
|
|
||||||
.root_hash = IOVEC_MAKE(dummy_data, sizeof(dummy_data)),
|
|
||||||
};
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "squashfs",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, &verity);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_SQUASHFS | PARTITION_POLICY_VERITY | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 9: VeritySettings with root_hash_sig set */
|
|
||||||
dummy_data[0] = 0x01; dummy_data[1] = 0x02; dummy_data[2] = 0x03; dummy_data[3] = 0x04;
|
|
||||||
verity = (VeritySettings) {
|
|
||||||
.designator = _PARTITION_DESIGNATOR_INVALID,
|
|
||||||
.root_hash_sig = IOVEC_MAKE(dummy_data, sizeof(dummy_data)),
|
|
||||||
};
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "erofs",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, &verity);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_EROFS | PARTITION_POLICY_SIGNED | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 10: VeritySettings with designator targeting specific partition */
|
|
||||||
dummy_data[0] = 0xab; dummy_data[1] = 0xcd;
|
|
||||||
verity = (VeritySettings) {
|
|
||||||
.designator = PARTITION_USR,
|
|
||||||
.root_hash = IOVEC_MAKE(dummy_data, 2),
|
|
||||||
};
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "ext4",
|
|
||||||
},
|
|
||||||
[PARTITION_USR] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "squashfs",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, &verity);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
/* Root should NOT have verity since verity targets USR */
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_EXT4 | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
/* USR should have verity */
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_USR].flags, (PartitionPolicyFlags) (PARTITION_POLICY_SQUASHFS | PARTITION_POLICY_VERITY | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 11: Unknown filesystem type (should have no fstype flag) */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "unknown_fs",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
/* Should only have GROWFS_OFF and READ_ONLY_ON for unknown filesystem */
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 12: NULL filesystem type (should have no fstype flag) */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = NULL,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
/* Should only have GROWFS_OFF and READ_ONLY_ON for NULL fstype */
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 13: Combination of verity_ready from image and verity settings - image takes precedence for sig */
|
|
||||||
dummy_data[0] = 0x11; dummy_data[1] = 0x22;
|
|
||||||
verity = (VeritySettings) {
|
|
||||||
.designator = _PARTITION_DESIGNATOR_INVALID,
|
|
||||||
.root_hash = IOVEC_MAKE(dummy_data, 2),
|
|
||||||
};
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.verity_sig_ready = true, /* This should take precedence */
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "squashfs",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, &verity);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
/* verity_sig_ready should result in SIGNED, not just VERITY */
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_SQUASHFS | PARTITION_POLICY_SIGNED | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 14: All known filesystem types */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = { .found = true, .fstype = (char*) "ext4" },
|
|
||||||
[PARTITION_USR] = { .found = true, .fstype = (char*) "btrfs" },
|
|
||||||
[PARTITION_HOME] = { .found = true, .fstype = (char*) "xfs" },
|
|
||||||
[PARTITION_SRV] = { .found = true, .fstype = (char*) "f2fs" },
|
|
||||||
[PARTITION_VAR] = { .found = true, .fstype = (char*) "erofs" },
|
|
||||||
[PARTITION_TMP] = { .found = true, .fstype = (char*) "squashfs" },
|
|
||||||
[PARTITION_ESP] = { .found = true, .fstype = (char*) "vfat" },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_EXT4 | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_USR].flags, (PartitionPolicyFlags) (PARTITION_POLICY_BTRFS | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_HOME].flags, (PartitionPolicyFlags) (PARTITION_POLICY_XFS | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_SRV].flags, (PartitionPolicyFlags) (PARTITION_POLICY_F2FS | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_VAR].flags, (PartitionPolicyFlags) (PARTITION_POLICY_EROFS | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_TMP].flags, (PartitionPolicyFlags) (PARTITION_POLICY_SQUASHFS | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ESP].flags, (PartitionPolicyFlags) (PARTITION_POLICY_VFAT | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 15: Encrypted partition with verity (LUKS takes precedence, no verity flag) */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.verity_ready = true,
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "crypto_LUKS",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
/* crypto_LUKS check happens first, then verity is added */
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_ENCRYPTED | PARTITION_POLICY_VERITY | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 16: Multiple flags combined - encrypted + growfs */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_HOME] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "crypto_LUKS",
|
|
||||||
.growfs = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_HOME].flags, (PartitionPolicyFlags) (PARTITION_POLICY_ENCRYPTED | PARTITION_POLICY_GROWFS_ON | PARTITION_POLICY_READ_ONLY_ON));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 17: single_file_system=true should NOT set growfs or read-only flags */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.single_file_system = true,
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "ext4",
|
|
||||||
.rw = true,
|
|
||||||
.growfs = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
/* single_file_system=true means no growfs/read-only flags */
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) PARTITION_POLICY_EXT4);
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 18: rw=true should set READ_ONLY_OFF instead of READ_ONLY_ON */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "ext4",
|
|
||||||
.rw = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_EXT4 | PARTITION_POLICY_GROWFS_OFF | PARTITION_POLICY_READ_ONLY_OFF));
|
|
||||||
|
|
||||||
policy = image_policy_free(policy);
|
|
||||||
|
|
||||||
/* Test 19: rw=true with growfs=true */
|
|
||||||
image = (DissectedImage) {
|
|
||||||
.partitions = {
|
|
||||||
[PARTITION_ROOT] = {
|
|
||||||
.found = true,
|
|
||||||
.fstype = (char*) "btrfs",
|
|
||||||
.rw = true,
|
|
||||||
.growfs = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
policy = image_policy_new_from_dissected(&image, /* verity= */ NULL);
|
|
||||||
ASSERT_NOT_NULL(policy);
|
|
||||||
ASSERT_EQ(policy->policies[PARTITION_ROOT].flags, (PartitionPolicyFlags) (PARTITION_POLICY_BTRFS | PARTITION_POLICY_GROWFS_ON | PARTITION_POLICY_READ_ONLY_OFF));
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_TEST_MAIN(LOG_INFO);
|
DEFINE_TEST_MAIN(LOG_INFO);
|
||||||
|
|||||||
@ -359,6 +359,10 @@ TEST(is_mount_point_at) {
|
|||||||
ASSERT_OK(is_mount_point_at(fd, "regular", 0));
|
ASSERT_OK(is_mount_point_at(fd, "regular", 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ms_nosymfollow_supported) {
|
||||||
|
log_info("MS_NOSYMFOLLOW supported: %s", yes_no(ms_nosymfollow_supported()));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(mount_option_supported) {
|
TEST(mount_option_supported) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
|||||||
@ -537,38 +537,4 @@ TEST(enums_idl) {
|
|||||||
TEST_IDL_ENUM(ResolveSupport, resolve_support, vl_type_ResolveSupport);
|
TEST_IDL_ENUM(ResolveSupport, resolve_support, vl_type_ResolveSupport);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SD_VARLINK_DEFINE_METHOD(
|
|
||||||
AnyTestStrict,
|
|
||||||
SD_VARLINK_DEFINE_INPUT(foo, SD_VARLINK_ANY, 0),
|
|
||||||
SD_VARLINK_DEFINE_INPUT(foo2, SD_VARLINK_ANY, 0),
|
|
||||||
SD_VARLINK_DEFINE_INPUT(foo3, SD_VARLINK_ANY, 0),
|
|
||||||
SD_VARLINK_DEFINE_INPUT(foo4, SD_VARLINK_ANY, 0));
|
|
||||||
|
|
||||||
static SD_VARLINK_DEFINE_METHOD(
|
|
||||||
AnyTestNullable,
|
|
||||||
SD_VARLINK_DEFINE_INPUT(foo, SD_VARLINK_ANY, SD_VARLINK_NULLABLE),
|
|
||||||
SD_VARLINK_DEFINE_INPUT(foo2, SD_VARLINK_ANY, SD_VARLINK_NULLABLE),
|
|
||||||
SD_VARLINK_DEFINE_INPUT(foo3, SD_VARLINK_ANY, SD_VARLINK_NULLABLE),
|
|
||||||
SD_VARLINK_DEFINE_INPUT(foo4, SD_VARLINK_ANY, SD_VARLINK_NULLABLE));
|
|
||||||
|
|
||||||
TEST(any) {
|
|
||||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
|
||||||
|
|
||||||
ASSERT_OK(sd_json_buildo(&v,
|
|
||||||
SD_JSON_BUILD_PAIR_STRING("foo", "bar"),
|
|
||||||
SD_JSON_BUILD_PAIR_INTEGER("foo2", 47),
|
|
||||||
SD_JSON_BUILD_PAIR_NULL("foo3"),
|
|
||||||
SD_JSON_BUILD_PAIR_BOOLEAN("foo4", true)));
|
|
||||||
|
|
||||||
/* "any" shall mean any type – but null */
|
|
||||||
const char *bad_field = NULL;
|
|
||||||
ASSERT_ERROR(varlink_idl_validate_method_call(&vl_method_AnyTestStrict, v, /* flags= */ 0, &bad_field), ENOANO);
|
|
||||||
ASSERT_STREQ(bad_field, "foo3");
|
|
||||||
|
|
||||||
/* "any?" shall many truly any type */
|
|
||||||
bad_field = NULL;
|
|
||||||
ASSERT_OK(varlink_idl_validate_method_call(&vl_method_AnyTestNullable, v, /* flags= */ 0, &bad_field));
|
|
||||||
ASSERT_NULL(bad_field);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||||
|
|||||||
@ -2408,8 +2408,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
for (size_t j = 0; j < arg_runtime_mounts.n_mounts; j++) {
|
FOREACH_ARRAY(mount, arg_runtime_mounts.mounts, arg_runtime_mounts.n_mounts) {
|
||||||
RuntimeMount *m = arg_runtime_mounts.mounts + j;
|
|
||||||
_cleanup_free_ char *listen_address = NULL;
|
_cleanup_free_ char *listen_address = NULL;
|
||||||
_cleanup_(fork_notify_terminate) PidRef child = PIDREF_NULL;
|
_cleanup_(fork_notify_terminate) PidRef child = PIDREF_NULL;
|
||||||
|
|
||||||
@ -2418,9 +2417,9 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
|||||||
|
|
||||||
r = start_virtiofsd(
|
r = start_virtiofsd(
|
||||||
unit,
|
unit,
|
||||||
m->source,
|
mount->source,
|
||||||
/* source_uid= */ m->source_uid,
|
/* source_uid= */ mount->source_uid,
|
||||||
/* target_uid= */ m->target_uid,
|
/* target_uid= */ mount->target_uid,
|
||||||
/* uid_range= */ 1U,
|
/* uid_range= */ 1U,
|
||||||
runtime_dir,
|
runtime_dir,
|
||||||
sd_socket_activate,
|
sd_socket_activate,
|
||||||
@ -2445,7 +2444,7 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
|||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
_cleanup_free_ char *id = NULL;
|
_cleanup_free_ char *id = NULL;
|
||||||
if (asprintf(&id, "mnt%zu", j) < 0)
|
if (asprintf(&id, "mnt%zi", mount - arg_runtime_mounts.mounts) < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
if (strv_extendf(&cmdline, "socket,id=%s,path=%s", id, escaped_listen_address) < 0)
|
if (strv_extendf(&cmdline, "socket,id=%s,path=%s", id, escaped_listen_address) < 0)
|
||||||
@ -2457,12 +2456,12 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
|||||||
if (strv_extendf(&cmdline, "vhost-user-fs-pci,queue-size=1024,chardev=%1$s,tag=%1$s", id) < 0)
|
if (strv_extendf(&cmdline, "vhost-user-fs-pci,queue-size=1024,chardev=%1$s,tag=%1$s", id) < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
_cleanup_free_ char *clean_target = xescape(m->target, "\":");
|
_cleanup_free_ char *clean_target = xescape(mount->target, "\":");
|
||||||
if (!clean_target)
|
if (!clean_target)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
if (strv_extendf(&arg_kernel_cmdline_extra, "systemd.mount-extra=\"%s:%s:virtiofs:%s\"",
|
if (strv_extendf(&arg_kernel_cmdline_extra, "systemd.mount-extra=\"%s:%s:virtiofs:%s\"",
|
||||||
id, clean_target, m->read_only ? "ro" : "rw") < 0)
|
id, clean_target, mount->read_only ? "ro" : "rw") < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
19
test/fuzz/.gitattributes
vendored
19
test/fuzz/.gitattributes
vendored
@ -1,10 +1,9 @@
|
|||||||
/*/* -whitespace
|
/*/* -whitespace
|
||||||
/fuzz-bus-match/* binary
|
/fuzz-bus-match/* binary
|
||||||
/fuzz-compress/* binary
|
/fuzz-compress/* binary
|
||||||
/fuzz-dhcp*/* binary
|
/fuzz-dhcp*/* binary
|
||||||
/fuzz-dns-packet/* binary
|
/fuzz-dns-packet/* binary
|
||||||
/fuzz-fido-id-desc/* binary
|
/fuzz-fido-id-desc/ binary
|
||||||
/fuzz-journald-audit/* binary
|
/fuzz-lldp-rx/* binary
|
||||||
/fuzz-lldp-rx/* binary
|
/fuzz-ndisc-rs/* binary
|
||||||
/fuzz-ndisc-rs/* binary
|
/*/* generated
|
||||||
/*/* generated
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -332,6 +332,7 @@ if install_tests
|
|||||||
'journal-data',
|
'journal-data',
|
||||||
'knot-data',
|
'knot-data',
|
||||||
'test-cgroup-mask',
|
'test-cgroup-mask',
|
||||||
|
'test-cgroup-unit-default',
|
||||||
'test-engine',
|
'test-engine',
|
||||||
'test-execute',
|
'test-execute',
|
||||||
'test-fstab-generator',
|
'test-fstab-generator',
|
||||||
|
|||||||
8
test/test-cgroup-unit-default/dml-discard-empty.service
Normal file
8
test/test-cgroup-unit-default/dml-discard-empty.service
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[Unit]
|
||||||
|
Description=DML discard empty service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Slice=dml-discard.slice
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=true
|
||||||
9
test/test-cgroup-unit-default/dml-discard-set-ml.service
Normal file
9
test/test-cgroup-unit-default/dml-discard-set-ml.service
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[Unit]
|
||||||
|
Description=DML discard set ml service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Slice=dml-discard.slice
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=true
|
||||||
|
MemoryLow=15
|
||||||
6
test/test-cgroup-unit-default/dml-discard.slice
Normal file
6
test/test-cgroup-unit-default/dml-discard.slice
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[Unit]
|
||||||
|
Description=DML discard slice
|
||||||
|
|
||||||
|
[Slice]
|
||||||
|
DefaultMemoryLow=
|
||||||
8
test/test-cgroup-unit-default/dml-override-empty.service
Normal file
8
test/test-cgroup-unit-default/dml-override-empty.service
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[Unit]
|
||||||
|
Description=DML override empty service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Slice=dml-override.slice
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=true
|
||||||
6
test/test-cgroup-unit-default/dml-override.slice
Normal file
6
test/test-cgroup-unit-default/dml-override.slice
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[Unit]
|
||||||
|
Description=DML override slice
|
||||||
|
|
||||||
|
[Slice]
|
||||||
|
DefaultMemoryLow=10
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[Unit]
|
||||||
|
Description=DML passthrough empty service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Slice=dml-passthrough.slice
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=true
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[Unit]
|
||||||
|
Description=DML passthrough set DML service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Slice=dml-passthrough.slice
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=true
|
||||||
|
DefaultMemoryLow=15
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[Unit]
|
||||||
|
Description=DML passthrough set ML service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Slice=dml-passthrough.slice
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=true
|
||||||
|
MemoryLow=0
|
||||||
6
test/test-cgroup-unit-default/dml-passthrough.slice
Normal file
6
test/test-cgroup-unit-default/dml-passthrough.slice
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[Unit]
|
||||||
|
Description=DML passthrough slice
|
||||||
|
|
||||||
|
[Slice]
|
||||||
|
MemoryLow=100
|
||||||
6
test/test-cgroup-unit-default/dml.slice
Normal file
6
test/test-cgroup-unit-default/dml.slice
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[Unit]
|
||||||
|
Description=DML slice
|
||||||
|
|
||||||
|
[Slice]
|
||||||
|
DefaultMemoryLow=50
|
||||||
@ -25,10 +25,6 @@ systemctl is-active minimal-app0.service
|
|||||||
systemctl is-active minimal-app0-foo.service
|
systemctl is-active minimal-app0-foo.service
|
||||||
systemctl is-active minimal-app0-bar.service && exit 1
|
systemctl is-active minimal-app0-bar.service && exit 1
|
||||||
|
|
||||||
# Ensure pinning by policy works
|
|
||||||
cat /run/systemd/system.attached/minimal-app0-foo.service.d/20-portable.conf
|
|
||||||
grep -q -F 'root=signed+squashfs:' /run/systemd/system.attached/minimal-app0-foo.service.d/20-portable.conf
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" reattach --now --runtime /usr/share/minimal_1.raw minimal-app0
|
portablectl "${ARGS[@]}" reattach --now --runtime /usr/share/minimal_1.raw minimal-app0
|
||||||
|
|
||||||
portablectl is-attached minimal-app0
|
portablectl is-attached minimal-app0
|
||||||
@ -95,9 +91,6 @@ status="$(portablectl is-attached --extension app0 minimal_0)"
|
|||||||
grep -q -F "LogExtraFields=PORTABLE_ROOT=minimal_0.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
grep -q -F "LogExtraFields=PORTABLE_ROOT=minimal_0.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION=app0.raw" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
grep -q -F "LogExtraFields=PORTABLE_EXTENSION_NAME_AND_VERSION=app" /run/systemd/system.attached/app0.service.d/20-portable.conf
|
||||||
# Ensure pinning by policy works
|
|
||||||
grep -q -F 'RootImagePolicy=root=signed+squashfs:' /run/systemd/system.attached/app0.service.d/20-portable.conf >/dev/null
|
|
||||||
grep -q -F 'ExtensionImagePolicy=root=signed+squashfs:' /run/systemd/system.attached/app0.service.d/20-portable.conf >/dev/null
|
|
||||||
|
|
||||||
portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app0.raw /usr/share/minimal_1.raw app0
|
portablectl "${ARGS[@]}" reattach --now --runtime --extension /tmp/app0.raw /usr/share/minimal_1.raw app0
|
||||||
|
|
||||||
|
|||||||
@ -1942,61 +1942,6 @@ EOF
|
|||||||
cmp "$imgs/test1.img" "$imgs/test2.img"
|
cmp "$imgs/test1.img" "$imgs/test2.img"
|
||||||
}
|
}
|
||||||
|
|
||||||
testcase_luks2_keyhash() {
|
|
||||||
local defs imgs output root
|
|
||||||
|
|
||||||
defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
|
|
||||||
imgs="$(mktemp --directory "/var/tmp/test-repart.imgs.XXXXXXXXXX")"
|
|
||||||
root="$(mktemp --directory "/var/test-repart.root.XXXXXXXXXX")"
|
|
||||||
# shellcheck disable=SC2064
|
|
||||||
trap "rm -rf '$defs' '$imgs' '$root'" RETURN
|
|
||||||
chmod 0755 "$defs"
|
|
||||||
|
|
||||||
echo "*** testcase for fixate-volume-key ***"
|
|
||||||
|
|
||||||
volume="test-repart-lukskeyhash-$RANDOM"
|
|
||||||
|
|
||||||
tee "$defs/root.conf" <<EOF
|
|
||||||
[Partition]
|
|
||||||
Type=linux-generic
|
|
||||||
Format=ext4
|
|
||||||
Encrypt=key-file
|
|
||||||
EncryptedVolume=$volume:::fixate-volume-key
|
|
||||||
EOF
|
|
||||||
|
|
||||||
systemd-repart --pretty=yes \
|
|
||||||
--definitions "$defs" \
|
|
||||||
--empty=create \
|
|
||||||
--size=100M \
|
|
||||||
--seed="$seed" \
|
|
||||||
--dry-run=no \
|
|
||||||
--offline="$OFFLINE" \
|
|
||||||
--generate-crypttab="$imgs/crypttab" \
|
|
||||||
"$imgs/enckeyhash.img"
|
|
||||||
|
|
||||||
loop="$(losetup -P --show --find "$imgs/enckeyhash.img")"
|
|
||||||
udevadm wait --timeout=60 --settle "${loop:?}p1"
|
|
||||||
|
|
||||||
touch "$imgs/empty-password"
|
|
||||||
|
|
||||||
# Check that the volume can be attached with the correct hash
|
|
||||||
expected_hash="$(grep UUID= "$imgs/crypttab" | sed s,.*fixate-volume-key=,,)"
|
|
||||||
echo "Expected hash: $expected_hash"
|
|
||||||
echo "Trying to attach the volume"
|
|
||||||
systemd-cryptsetup attach $volume "${loop}p1" "$imgs/empty-password" "fixate-volume-key=$expected_hash"
|
|
||||||
echo "Trying to detach the volume"
|
|
||||||
systemd-cryptsetup detach $volume
|
|
||||||
echo "Success!"
|
|
||||||
|
|
||||||
# Check that the volume cannot be attached with incorrect hash
|
|
||||||
echo "Trying to attach the volume with wrong hash"
|
|
||||||
systemd-cryptsetup attach $volume "${loop}p1" "$imgs/empty-password" "fixate-volume-key=aaaaaabbbbbbccccccddddddeeeeeeffffff1111112222223333334444445555" && exit 1
|
|
||||||
# Verify the volume is not attached
|
|
||||||
[ ! -f "/dev/mapper/$volume" ] || exit 1
|
|
||||||
|
|
||||||
losetup -d "$loop"
|
|
||||||
}
|
|
||||||
|
|
||||||
OFFLINE="yes"
|
OFFLINE="yes"
|
||||||
run_testcases
|
run_testcases
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user