]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
boot: exclude the trailing padding from initrd size in initrd_prepare()
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Fri, 6 Dec 2024 12:11:02 +0000 (13:11 +0100)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 9 Dec 2024 14:14:03 +0000 (15:14 +0100)
This is a follow-up for f8fa4222c9ac3e74e91c64e25e9532c99559cf99 (boot: Make
initrd_prepare() semantically equivalent to combine_initrds()). That commit
changed the way that the initrd is prepared for type#1 boot loader entries,
also effectively rounding up the sizes to a multiple of 4. In [1], downstream
packagers report that the trailing zeroes result in the calculated hash being
different. To restore compatibility with previous hash calculations and
signatures, change the reported size by excluding the trailing padding. This
should restore the calculation results for the case where only one initrd is
used.

This patch doesn't touch the stub, i.e. doesn't change behaviour for UKIs. The
seems fine, since we didn't change that recently, so any changes there would
break compatiblity. The measurement results for type#1 and type#2 entries are
generally going to be different anyway. ukify and systemd-measure are also out
of scope here, because they are for UKIs.

Fixes https://github.com/systemd/systemd/issues/35439.
The other changes to the way the initrd is constructed are kept, so hopefully
the original issue with booting in qemu is not recreated.

[1] https://bugzilla.suse.com/show_bug.cgi?id=1233752

My simple test: I'm booting a QEMU VM with systemd-boot and a type#1 entry.
With old systemd-boot:
$ sudo systemd-pcrlock log | grep 'kernel-initrd.*event-tag'
  9 █ kernel-initrd  event-tag  - a337a8321bf81de5c53a842843e8f9a926f73a676e5620ff76df94d1c66bc931 F   - Linux: kernel command line
  9 █ kernel-initrd  event-tag  - aec1aee5358bde36f5498f2dc243dec2b103f81242de57b887a11f53677f1272 F   - Linux: initrd
With updated systemd-boot:
$ sudo systemd-pcrlock log | grep 'kernel-initrd.*event-tag'
  9 █ kernel-initrd  event-tag  - a337a8321bf81de5c53a842843e8f9a926f73a676e5620ff76df94d1c66bc931 F   - Linux: kernel command line
  9 █ kernel-initrd  event-tag  - 3ccaa710304aef8734a20265ea7fd3dd67d5461c6b3309c6d30d5c7d2a3ae7f9 F   - Linux: initrd
This matches the initrd hash:
$ sudo sha256sum /efi//26f948d2082e4ae89f5a3af351b63149/6.12.0-rc4+/initrd-dracut
3ccaa710304aef8734a20265ea7fd3dd67d5461c6b3309c6d30d5c7d2a3ae7f9  /efi//26f948d2082e4ae89f5a3af351b63149/6.12.0-rc4+/initrd-dracut

src/boot/boot.c

index 129d6f8f5d3eb7e0cd46daaf450220794254a50a..4ef519d404062ec6ecdd2807d3792e9c3962c673 100644 (file)
@@ -2446,7 +2446,7 @@ static EFI_STATUS initrd_prepare(
         _cleanup_free_ char16_t *options = NULL;
 
         EFI_STATUS err;
-        size_t size = 0;
+        size_t size = 0, padded_size = 0;
 
         STRV_FOREACH(i, entry->initrd) {
                 _cleanup_free_ char16_t *o = options;
@@ -2465,11 +2465,14 @@ static EFI_STATUS initrd_prepare(
                 if (err != EFI_SUCCESS)
                         return err;
 
-                if (!INC_SAFE(&size, ALIGN4(info->FileSize)))
+                size_t inc = info->FileSize;
+
+                if (!INC_SAFE(&padded_size, ALIGN4(inc)))
                         return EFI_OUT_OF_RESOURCES;
+                assert_se(INC_SAFE(&size, *(i + 1) ? ALIGN4(inc) : inc));
         }
 
-        _cleanup_pages_ Pages pages = xmalloc_initrd_pages(size);
+        _cleanup_pages_ Pages pages = xmalloc_initrd_pages(padded_size);
         uint8_t *p = PHYSICAL_ADDRESS_TO_POINTER(pages.addr);
 
         STRV_FOREACH(i, entry->initrd) {
@@ -2501,7 +2504,11 @@ static EFI_STATUS initrd_prepare(
                         continue;
 
                 memzero(p, pad);
-                p += pad;
+                /* Exclude the trailing pad from size calculations. This would change the
+                 * calculated hash, see https://github.com/systemd/systemd/issues/35439
+                 * and https://bugzilla.suse.com/show_bug.cgi?id=1233752. */
+                if (*(i + 1))
+                        p += pad;
         }
 
         assert(PHYSICAL_ADDRESS_TO_POINTER(pages.addr + size) == p);