]> git.ipfire.org Git - thirdparty/dracut.git/commitdiff
fix(dracut.sh): use dynamically uefi's sections offset
authorValentin Lefebvre <valentin.lefebvre@suse.com>
Mon, 13 Mar 2023 11:06:13 +0000 (12:06 +0100)
committerJóhann B. Guðmundsson <johannbg@gmail.com>
Mon, 20 Mar 2023 11:56:24 +0000 (11:56 +0000)
* Uefi section are creating by `objcopy` with hardcoded sections
offset. This commit allow to have the correct offset between
each part of the efi file, needed to create an UKI. Offsets
are simply calculated so no sections overlap, as recommended
in  https://wiki.archlinux.org/title/Unified_kernel_image#Manually
Moreover, efi stub file's header is parsed to apply the correct
offsets according the section alignment factor.
* Remove EFI_SECTION_VMA_INITRD, no need anymore as initrd
section offset dynamically calculated

Fixes dracutdevs#2275

Signed-off-by: Valentin Lefebvre <valentin.lefebvre@suse.com>
dracut-functions.sh
dracut.sh

index 80f3b44ce93cbbd158d964f85b5ab9cc7a913d17..f3c0c88b6431352dc9628c5eb824f5e1fc3a34b5 100755 (executable)
@@ -1023,3 +1023,26 @@ get_dev_module() {
     fi
     echo "$dev_drivers"
 }
+
+# Check if file is in PE format
+pe_file_format() {
+    if [[ $# -eq 1 ]]; then
+        local magic
+        magic=$(objdump -p "$1" \
+            | awk '{if ($1 == "Magic"){print strtonum("0x"$2)}}')
+        magic=$(printf "0x%x" "$magic")
+        # 0x10b (PE32), 0x20b (PE32+)
+        [[ $magic == 0x20b || $magic == 0x10b ]] && return 0
+    fi
+    return 1
+}
+
+# Get the sectionAlignment data from the PE header
+pe_get_section_align() {
+    local align_hex
+    [[ $# -ne "1" ]] && return 1
+    [[ $(pe_file_format "$1") -eq 1 ]] && return 1
+    align_hex=$(objdump -p "$1" \
+        | awk '{if ($1 == "SectionAlignment"){print $2}}')
+    echo "$((16#$align_hex))"
+}
index 0c0f85c2dbc15f4ca526333eb975d64a56f56a25..1f6f0aee80c9904bbf8e74c1e62fbecc482f31af 100755 (executable)
--- a/dracut.sh
+++ b/dracut.sh
@@ -1506,7 +1506,6 @@ if [[ ! $print_cmdline ]]; then
             exit 1
         fi
         unset EFI_MACHINE_TYPE_NAME
-        EFI_SECTION_VMA_INITRD=0x3000000
         case "${DRACUT_ARCH:-$(uname -m)}" in
             x86_64)
                 EFI_MACHINE_TYPE_NAME=x64
@@ -1516,8 +1515,6 @@ if [[ ! $print_cmdline ]]; then
                 ;;
             aarch64)
                 EFI_MACHINE_TYPE_NAME=aa64
-                # aarch64 kernels are uncompressed and thus larger, so we need a bigger gap between vma sections
-                EFI_SECTION_VMA_INITRD=0x4000000
                 ;;
             *)
                 dfatal "Architecture '${DRACUT_ARCH:-$(uname -m)}' not supported to create a UEFI executable"
@@ -2467,29 +2464,57 @@ if [[ $uefi == yes ]]; then
         fi
     fi
 
+    offs=$(objdump -h "$uefi_stub" 2> /dev/null | awk 'NF==7 {size=strtonum("0x"$3);\
+                offset=strtonum("0x"$4)} END {print size + offset}')
+    if [[ $offs -eq 0 ]]; then
+        dfatal "Failed to get the size of $uefi_stub to create UEFI image file"
+        exit 1
+    fi
+    align=$(pe_get_section_align "$uefi_stub")
+    if [[ $? -eq 1 ]]; then
+        dfatal "Failed to get the sectionAlignment of the stub PE header to create the UEFI image file"
+        exit 1
+    fi
+    offs=$((offs + "$align" - offs % "$align"))
+    [[ -s $dracutsysrootdir/usr/lib/os-release ]] && uefi_osrelease="$dracutsysrootdir/usr/lib/os-release"
+    [[ -s $dracutsysrootdir/etc/os-release ]] && uefi_osrelease="$dracutsysrootdir/etc/os-release"
+    [[ -s $uefi_osrelease ]] \
+        && uefi_osrelease_offs=${offs} \
+        && offs=$((offs + $(stat -Lc%s "$uefi_osrelease"))) \
+        && offs=$((offs + "$align" - offs % "$align"))
+
     if [[ $kernel_cmdline ]] || [[ $hostonly_cmdline == yes && -e "${uefi_outdir}/cmdline.txt" ]]; then
         echo -ne "\x00" >> "$uefi_outdir/cmdline.txt"
         dinfo "Using UEFI kernel cmdline:"
         dinfo "$(tr -d '\000' < "$uefi_outdir/cmdline.txt")"
         uefi_cmdline="${uefi_outdir}/cmdline.txt"
+        uefi_cmdline_offs=${offs}
+        offs=$((offs + $(stat -Lc%s "$uefi_cmdline")))
+        offs=$((offs + "$align" - offs % "$align"))
     else
         unset uefi_cmdline
     fi
 
-    [[ -s $dracutsysrootdir/usr/lib/os-release ]] && uefi_osrelease="$dracutsysrootdir/usr/lib/os-release"
-    [[ -s $dracutsysrootdir/etc/os-release ]] && uefi_osrelease="$dracutsysrootdir/etc/os-release"
     if [[ -s ${dracutsysrootdir}${uefi_splash_image} ]]; then
         uefi_splash_image="${dracutsysrootdir}${uefi_splash_image}"
+        uefi_splash_offs=${offs}
+        offs=$((offs + $(stat -Lc%s "$uefi_splash_image")))
+        offs=$((offs + "$align" - offs % "$align"))
     else
         unset uefi_splash_image
     fi
 
+    uefi_linux_offs="${offs}"
+    offs=$((offs + $(stat -Lc%s "$kernel_image")))
+    offs=$((offs + "$align" - offs % "$align"))
+    uefi_initrd_offs="${offs}"
+
     if objcopy \
-        ${uefi_osrelease:+--add-section .osrel="$uefi_osrelease" --change-section-vma .osrel=0x20000} \
-        ${uefi_cmdline:+--add-section .cmdline="$uefi_cmdline" --change-section-vma .cmdline=0x30000} \
-        ${uefi_splash_image:+--add-section .splash="$uefi_splash_image" --change-section-vma .splash=0x40000} \
-        --add-section .linux="$kernel_image" --change-section-vma .linux=0x2000000 \
-        --add-section .initrd="${DRACUT_TMPDIR}/initramfs.img" --change-section-vma .initrd="${EFI_SECTION_VMA_INITRD}" \
+        ${uefi_osrelease:+--add-section .osrel="$uefi_osrelease" --change-section-vma .osrel=$(printf 0x%x "$uefi_osrelease_offs")} \
+        ${uefi_cmdline:+--add-section .cmdline="$uefi_cmdline" --change-section-vma .cmdline=$(printf 0x%x "$uefi_cmdline_offs")} \
+        ${uefi_splash_image:+--add-section .splash="$uefi_splash_image" --change-section-vma .splash=$(printf 0x%x "$uefi_splash_offs")} \
+        --add-section .linux="$kernel_image" --change-section-vma .linux="$(printf 0x%x "$uefi_linux_offs")" \
+        --add-section .initrd="${DRACUT_TMPDIR}/initramfs.img" --change-section-vma .initrd="$(printf 0x%x "$uefi_initrd_offs")" \
         "$uefi_stub" "${uefi_outdir}/linux.efi"; then
         if [[ -n ${uefi_secureboot_key} && -n ${uefi_secureboot_cert} ]]; then
             if sbsign \