Package: systemd
Version: 257.5-2
Severity: minor
Tags: patch
Dear developers,
TL;DR postinst should remove its previous boot entry when first
installed, install mm alongside shim and fb in the default boot path,
and either not use `--make-machine-id-directory=auto` or fix
`$ESP/loader/loader.conf`
Long version:
The current systemd-boot maintainer scripts work pretty well for the
vast majority of cases, but may fail to do the right thing in some rare
scenarios (hence the "Severity: minor" tag).
Please note: all the facts described here were tested on a Bookworm
install, with systemd-boot from backports, and homemade helper packages
to mimic the current systemd-boot maintainer scripts and sign
systemd-boot with a MOK, but in theory the errors described here would
also apply to Trixie, and should IMHO be fixed.
Here is the faulty scenario: let's say debian-installer is customized to
not install GRUB, install systemd-boot, generate a MOK, sign
systemd-boot with it (on Bookworm), and generate UKIs also signed by the
MOK, all before first boot. The MOK is imported, the system boots for
the first time, shim chainloads systemd-boot and everything works
perfectly well as intended.
Now, let's say that the machine must be reinstalled for some reason, and
the same procedure runs again, without wiping the boot entries and/or ESP.
Here's what happens during the second install:
- sd-boot postinst runs `bootctl install` again, which blindly adds its
boot entry (plain sd-boot without shim) at the top of boot order
- postinst checks for shim's boot entry, finds it and does nothing,
despite that it's not the default one anymore
Then, on first boot:
- UEFI boots plain sd-boot (without shim), which fails. To fix this,
postinst should check if the entry it previously created is still first
in boot order, and also if the ESP's GUID did not change. The simplest
thing to do is to simply delete the entry when the package is installed
for the first time (i.e. if $2 is empty)
- UEFI tries the default boot path, but since a MOK import was requested
during installation, shim tries to run mm, which fails. To fix this,
postinst should also copy mm to the default path, in addition of shim
and fb.
After this step, if mm is copied to the default path by other means,
UEFI tries again the default boot path, shim runs mm, and the MOK is
imported. After a reboot, UEFI again boots plain systemd-boot without
shim and fails, and tries again the default boot path, shim then runs
fb, which fixes the boot entry to chainload sd-boot through shim.
Finally, after another reboot, UEFI at last loads shim which chainloads
systemd-boot, but there's still another problem: if d-i reuses the ESP
without formating it, systemd-boot tries to boot the kernels/UKIs from
the previous install, due to the presence of a `default` directive in
`$ESP/loader/loader.conf`, and since those entries have the `root=`
parameter which refers to the old (now missing) partition, this of
course fails.
This directive is inserted by `bootctl install` because it's called in
the postinst with the undocumented option
`--make-machine-id-directory=auto`, **and** systemd-boot is configured
to use Type #1 entries (i.e. there's no `/etc/kernel/install.conf` with
`layout=uki`, or not yet).
To fix this, either remove this option from the postint and let
systemd-boot decide by itself which entry should be considered the
default (as intended by upstream), or fix `$ESP/loader/loader.conf`
afterwards to set the `default` directive and boot the new kernels/UKIs,
which would be consistent with the "take over ESP and EFI boot entry"
logic of the postinst.
You'll find attached a series of patches to fix all of those three
problems. Patches numbered "0003" are mutually exclusive. I tried to
mimic your coding style as much as I could, but they may not be perfect
in this regard.
By the way, I won't open a new bug report for that, but when you fixed
#1106024, you didn't add code to the `remove_shim` function to remove
fb, and since mm would also need this, I also attached a patch to clean
up those files.
Regards,
--
Raphaël Halimi
From 2f8c6e0778c4d16a4153c06ada56ed9938c5227a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rapha=C3=ABl=20Halimi?= <raphael.hal...@gmail.com>
Date: Sat, 31 May 2025 19:09:01 +0200
Subject: [PATCH 1/4] Fix boot entry not set ad default
---
debian/systemd-boot.postinst | 77 ++++++++++++++++--------------------
1 file changed, 35 insertions(+), 42 deletions(-)
diff --git a/debian/systemd-boot.postinst b/debian/systemd-boot.postinst
index 7b9557bda6..f15014ca9b 100644
--- a/debian/systemd-boot.postinst
+++ b/debian/systemd-boot.postinst
@@ -13,27 +13,32 @@
set -e
-remove_shim() {
- case "$(dpkg --print-architecture)" in
- amd64)
- efi_arch_upper=X64
- efi_arch=x64
- grub_arch=x86_64
- ;;
- arm64)
- efi_arch_upper=AA64
- efi_arch=aa64
- grub_arch=arm64
- ;;
- *)
- return
- esac
-
- # shellcheck disable=SC1091
- . /etc/os-release || . /usr/lib/os-release
- vendor="${ID:-debian}"
- vendor_upper="$(echo "$vendor" | cut -c1 | tr '[:lower:]' '[:upper:]')$(echo "$vendor" | cut -c2-)"
+case "$(dpkg --print-architecture)" in
+ amd64)
+ efi_arch_upper=X64
+ efi_arch=x64
+ grub_arch=x86_64
+ ;;
+ arm64)
+ efi_arch_upper=AA64
+ efi_arch=aa64
+ grub_arch=arm64
+ ;;
+ *)
+ return
+esac
+
+# shellcheck disable=SC1091
+. /etc/os-release || . /usr/lib/os-release
+vendor="${ID:-debian}"
+vendor_upper="$(echo "$vendor" | cut -c1 | tr '[:lower:]' '[:upper:]')$(echo "$vendor" | cut -c2-)"
+
+get_boot_entry () {
+ # 730079007300740065006d0064002d0062006f006f007400 is 'systemd-boot' encoded in UTF-16-LE"
+ efibootmgr | grep -i -q "Boot.*${vendor_upper}.*EFI\\\\${vendor}\\\\shim${efi_arch}.efi.*systemd-boot${efi_arch}.efi\|Boot.*${vendor_upper}.*EFI\\\\${vendor}\\\\shim${efi_arch}.efi.*730079007300740065006d0064002d0062006f006f007400" | cut -d' ' -f1 | sed -e 's/Boot//' -e 's/*//'
+}
+remove_shim() {
esp_path="$(bootctl --quiet --print-esp-path 2>/dev/null)"
if [ -z "$esp_path" ]; then
return
@@ -65,21 +70,6 @@ remove_shim() {
}
install_shim() {
- case "$(dpkg --print-architecture)" in
- amd64)
- efi_arch_upper=X64
- efi_arch=x64
- grub_arch=x86_64
- ;;
- arm64)
- efi_arch_upper=AA64
- efi_arch=aa64
- grub_arch=arm64
- ;;
- *)
- return
- esac
-
if [ ! -f "/usr/lib/shim/shim${efi_arch}.efi.signed" ] || [ ! -f "/usr/lib/systemd/boot/efi/systemd-boot${efi_arch}.efi.signed" ]; then
if [ "$1" = trigger ]; then
remove_shim
@@ -96,11 +86,6 @@ install_shim() {
return
fi
- # shellcheck disable=SC1091
- . /etc/os-release || . /usr/lib/os-release
- vendor="${ID:-debian}"
- vendor_upper="$(echo "$vendor" | cut -c1 | tr '[:lower:]' '[:upper:]')$(echo "$vendor" | cut -c2-)"
-
for f in shim fb mm; do
if [ ! -f "/usr/lib/shim/${f}${efi_arch}.efi.signed" ]; then
continue
@@ -123,10 +108,9 @@ install_shim() {
printf "shim%s.efi,%s,\\\\EFI\\\\systemd\\\\systemd-boot%s.efi \\\\0,This is the boot entry for %s\n" "${efi_arch}" "${vendor_upper}" "${efi_arch}" "${vendor_upper}" | iconv -t UCS-2LE > "${esp_path}/EFI/${vendor}/BOOT${efi_arch_upper}.CSV"
fi
- # 730079007300740065006d0064002d0062006f006f007400 is 'systemd-boot' encoded in UTF-16-LE"
if ! command -v efibootmgr >/dev/null 2>&1; then
echo "efibootmgr not found, skipping boot entry creation"
- elif ! efibootmgr | grep -i -q "Boot.*${vendor_upper}.*EFI\\\\${vendor}\\\\shim${efi_arch}.efi.*systemd-boot${efi_arch}.efi\|Boot.*${vendor_upper}.*EFI\\\\${vendor}\\\\shim${efi_arch}.efi.*730079007300740065006d0064002d0062006f006f007400"; then
+ elif [ -z "$(get_boot_entry)" ]; then
blkpart="$(findmnt -nvo SOURCE "$esp_path")"
if [ ! -L "/sys/class/block/${blkpart##*/}" ]; then
return
@@ -139,6 +123,15 @@ install_shim() {
fi
}
+if [ "$1" = "configure" ] && [ -z "$2" ]; then
+ if command -v efibootmgr >/dev/null 2>&1; then
+ bootentry="$(get_boot_entry)"
+ if [ -n "$bootentry" ]; then
+ efibootmgr -q --delete-bootnum --bootnum "$bootentry"
+ fi
+ fi
+fi
+
if [ "$1" = configure ] && bootctl --print-esp-path > /dev/null 2>&1; then
if bootctl is-installed > /dev/null 2>&1; then
bootctl update --graceful
--
2.49.0
From e0b5ac45f28f600c53d1e2bc3ec74d253f304046 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rapha=C3=ABl=20Halimi?= <raphael.hal...@gmail.com>
Date: Sat, 31 May 2025 19:15:36 +0200
Subject: [PATCH 2/4] Copy Mok Manager to default boot path
---
debian/systemd-boot.postinst | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/debian/systemd-boot.postinst b/debian/systemd-boot.postinst
index f15014ca9b..86d1977b87 100644
--- a/debian/systemd-boot.postinst
+++ b/debian/systemd-boot.postinst
@@ -100,9 +100,11 @@ install_shim() {
install -p -D "/usr/lib/shim/shim${efi_arch}.efi.signed" "${esp_path}/EFI/BOOT/BOOT${efi_arch_upper}.efi"
fi
- if [ ! -f "${esp_path}/EFI/BOOT/fb${efi_arch}.efi" ] || [ "$(<"${esp_path}/EFI/BOOT/fb${efi_arch}.efi" sha256sum)" != "$(<"/usr/lib/shim/fb${efi_arch}.efi.signed" sha256sum)" ]; then
- install -p -D "/usr/lib/shim/fb${efi_arch}.efi.signed" "${esp_path}/EFI/BOOT/fb${efi_arch}.efi"
- fi
+ for f in fb mm; do
+ if [ ! -f "${esp_path}/EFI/BOOT/${f}${efi_arch}.efi" ] || [ "$(<"${esp_path}/EFI/BOOT/${f}${efi_arch}.efi" sha256sum)" != "$(<"/usr/lib/shim/${f}${efi_arch}.efi.signed" sha256sum)" ]; then
+ install -p -D "/usr/lib/shim/${f}${efi_arch}.efi.signed" "${esp_path}/EFI/BOOT/${f}${efi_arch}.efi"
+ fi
+ done
if [ ! -f "${esp_path}/EFI/${vendor}/BOOT${efi_arch_upper}.CSV" ] && command -v iconv >/dev/null 2>&1; then
printf "shim%s.efi,%s,\\\\EFI\\\\systemd\\\\systemd-boot%s.efi \\\\0,This is the boot entry for %s\n" "${efi_arch}" "${vendor_upper}" "${efi_arch}" "${vendor_upper}" | iconv -t UCS-2LE > "${esp_path}/EFI/${vendor}/BOOT${efi_arch_upper}.CSV"
--
2.49.0
From 8a003fb02862f7b9403e02b84e9567277030058c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rapha=C3=ABl=20Halimi?= <raphael.hal...@gmail.com>
Date: Sat, 31 May 2025 19:22:36 +0200
Subject: [PATCH 3/4] Drop make-machine-id-directory option
---
debian/systemd-boot.postinst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/debian/systemd-boot.postinst b/debian/systemd-boot.postinst
index 86d1977b87..a932e01edb 100644
--- a/debian/systemd-boot.postinst
+++ b/debian/systemd-boot.postinst
@@ -138,7 +138,7 @@ if [ "$1" = configure ] && bootctl --print-esp-path > /dev/null 2>&1; then
if bootctl is-installed > /dev/null 2>&1; then
bootctl update --graceful
else
- bootctl install --make-machine-id-directory=auto
+ bootctl install
fi
install_shim install
--
2.49.0
From 1ec6dd86038d13651de1c893d08f215248ef7eee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rapha=C3=ABl=20Halimi?= <raphael.hal...@gmail.com>
Date: Sat, 31 May 2025 19:24:28 +0200
Subject: [PATCH 3/4] Fix loader.conf
---
debian/systemd-boot.postinst | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/debian/systemd-boot.postinst b/debian/systemd-boot.postinst
index 86d1977b87..25e177f421 100644
--- a/debian/systemd-boot.postinst
+++ b/debian/systemd-boot.postinst
@@ -33,13 +33,30 @@ esac
vendor="${ID:-debian}"
vendor_upper="$(echo "$vendor" | cut -c1 | tr '[:lower:]' '[:upper:]')$(echo "$vendor" | cut -c2-)"
+esp_path="$(bootctl --quiet --print-esp-path 2>/dev/null)"
+
get_boot_entry () {
# 730079007300740065006d0064002d0062006f006f007400 is 'systemd-boot' encoded in UTF-16-LE"
efibootmgr | grep -i -q "Boot.*${vendor_upper}.*EFI\\\\${vendor}\\\\shim${efi_arch}.efi.*systemd-boot${efi_arch}.efi\|Boot.*${vendor_upper}.*EFI\\\\${vendor}\\\\shim${efi_arch}.efi.*730079007300740065006d0064002d0062006f006f007400" | cut -d' ' -f1 | sed -e 's/Boot//' -e 's/*//'
}
+fix_loader_conf () {
+ if [ -z "${esp_path}" ]; then
+ return
+ fi
+ if [ -f "/etc/machine-id" ] ; then
+ machine_id="$(cat "/etc/machine-id")"
+ loader_conf="${esp_path}/loader/loader.conf"
+ if [ -f "$loader_conf" ] ; then
+ if grep -q "^default" "$loader_conf" && ! grep -q "^default $machine_id" "$loader_conf" ; then
+ sed -i 's/^default /#&/' "$loader_conf"
+ printf "default %s-*\n" "$machine_id" >> "$loader_conf"
+ fi
+ fi
+ fi
+}
+
remove_shim() {
- esp_path="$(bootctl --quiet --print-esp-path 2>/dev/null)"
if [ -z "$esp_path" ]; then
return
fi
@@ -81,7 +98,6 @@ install_shim() {
return
fi
- esp_path="$(bootctl --quiet --print-esp-path 2>/dev/null)"
if [ -z "$esp_path" ]; then
return
fi
@@ -139,6 +155,7 @@ if [ "$1" = configure ] && bootctl --print-esp-path > /dev/null 2>&1; then
bootctl update --graceful
else
bootctl install --make-machine-id-directory=auto
+ fix_loader_conf
fi
install_shim install
--
2.49.0
From 19b3022f2641932c96aef52f14156b2b894aa92c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rapha=C3=ABl=20Halimi?= <raphael.hal...@gmail.com>
Date: Sat, 31 May 2025 19:37:13 +0200
Subject: [PATCH 4/4] Cleanup shim helpers on remove
---
debian/systemd-boot.postinst | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/debian/systemd-boot.postinst b/debian/systemd-boot.postinst
index 25e177f421..ff9ed72921 100644
--- a/debian/systemd-boot.postinst
+++ b/debian/systemd-boot.postinst
@@ -73,6 +73,12 @@ remove_shim() {
rm -f "${esp_path}/EFI/BOOT/BOOT${efi_arch_upper}.efi"
fi
+ for f in fb mm; do
+ if [ -f "${esp_path}/EFI/BOOT/${f}${efi_arch}.efi" ] && [ "$(<"${esp_path}/EFI/BOOT/${f}${efi_arch}.efi" sha256sum)" = "$(<"${esp_path}/EFI/${vendor}/${f}${efi_arch}.efi" sha256sum)" ]; then
+ rm -f "${esp_path}/EFI/BOOT/${f}${efi_arch}.efi"
+ fi
+ done
+
for f in shim fb mm; do
rm -f "${esp_path}/EFI/${vendor}/${f}${efi_arch}.efi"
done
--
2.49.0