1
0
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.

75 changed files with 959 additions and 1148 deletions

23
README
View File

@ -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
View File

@ -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)

View File

@ -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>

View File

@ -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"/>

View File

@ -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"/>

View File

@ -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>

View File

@ -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

View File

@ -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$//' \

View File

@ -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)) {

View File

@ -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,

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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 });
} }

View File

@ -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))

View File

@ -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);

View File

@ -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;
} }
if (STR_IN_SET(name,
/* deprecated CGroup v1 properties */ /* deprecated CGroup v1 properties */
if (STR_IN_SET(name,
"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)

View File

@ -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;

View File

@ -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;
} }

View File

@ -267,18 +267,19 @@ 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))
@ -289,6 +290,15 @@ int bus_read_mount_options(
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);
/* Need to store the options with the escapes, so that they can be parsed again */
escaped = shell_escape(mount_options, ":");
if (!escaped)
return -ENOMEM;
if (!isempty(escaped)) {
if (!strextend_with_separator(&format_str, separator, partition, ":", escaped))
return -ENOMEM;
if (!options) { if (!options) {
options = new0(MountOptions, 1); options = new0(MountOptions, 1);
if (!options) if (!options)
@ -298,19 +308,8 @@ int bus_read_mount_options(
r = free_and_strdup(&options->options[partition_designator], mount_options); r = free_and_strdup(&options->options[partition_designator], mount_options);
if (r < 0) if (r < 0)
return r; return r;
} else if (options)
if (in_out_format_str && !isempty(mount_options)) { options->options[partition_designator] = mfree(options->options[partition_designator]);
/* 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;
r = strextendf_with_separator(&format_str, separator, "%s:%s", partition, escaped);
if (r < 0)
return r;
}
} }
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 (options) {
if (in_out_format_str && !strextend_with_separator(in_out_format_str, separator, format_str)) if (in_out_format_str && !strextend_with_separator(in_out_format_str, separator, format_str))
return -ENOMEM; return -ENOMEM;
*ret_options = TAKE_PTR(options); *ret_options = TAKE_PTR(options);
}
return 0; return 0;
} }

View File

@ -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)

View File

@ -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)

View File

@ -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"))

View File

@ -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 requested. To make sure this logic succeeds only on kernels where hidepid= is
* 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. */
const char *hpv = p->protect_proc == PROTECT_PROC_DEFAULT ?
"off" :
protect_proc_to_string(p->protect_proc);
/* 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) if (!opts)
return -ENOMEM; return -ENOMEM;
if (p->proc_subset != PROC_SUBSET_ALL) {
r = strextendf_with_separator(&opts, ",", "subset=%s", proc_subset_to_string(p->proc_subset));
if (r < 0)
return r;
} }
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

View File

@ -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),

View File

@ -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(

View File

@ -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. */

View File

@ -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);
} }

View File

@ -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 */

View File

@ -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;
} }

View File

@ -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:

View File

@ -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;

View File

@ -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);
} }

View File

@ -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);

View File

@ -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(

View File

@ -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);

View File

@ -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 },
{} {}

View File

@ -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) {

View File

@ -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);

View File

@ -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]) {

View File

@ -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;

View File

@ -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);
} }

View File

@ -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);

View File

@ -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;

View File

@ -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",

View File

@ -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) {

View File

@ -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);

View File

@ -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.");

View File

@ -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);

View File

@ -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"),

View File

@ -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) },

View File

@ -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'),
}, },

View 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);

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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();
} }

View File

@ -3,8 +3,7 @@
/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

View File

@ -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',

View 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

View 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

View File

@ -0,0 +1,6 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Unit]
Description=DML discard slice
[Slice]
DefaultMemoryLow=

View 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

View File

@ -0,0 +1,6 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Unit]
Description=DML override slice
[Slice]
DefaultMemoryLow=10

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,6 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Unit]
Description=DML passthrough slice
[Slice]
MemoryLow=100

View File

@ -0,0 +1,6 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Unit]
Description=DML slice
[Slice]
DefaultMemoryLow=50

View File

@ -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

View File

@ -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