From 2a8a7655d3bf499d22f7af692207d6c0a08358dd Mon Sep 17 00:00:00 2001 From: Jonathon Hall Date: Thu, 10 Nov 2022 10:09:16 -0500 Subject: [PATCH 1/3] kexec-parse-boot: Trim device specifications from GRUB entries Some configs specify kernel/initrd paths relative to a device (often found in a variable). Assume the device is the /boot partition and ignore the device specification. Signed-off-by: Jonathon Hall --- initrd/bin/kexec-parse-boot | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/initrd/bin/kexec-parse-boot b/initrd/bin/kexec-parse-boot index d54d6285..b3dc6c0c 100755 --- a/initrd/bin/kexec-parse-boot +++ b/initrd/bin/kexec-parse-boot @@ -94,11 +94,17 @@ grub_entry() { modules="$modules|module $path" ;; linux*) - kernel=`echo $trimcmd | cut -d\ -f2` + # Some configs have a device specification in the kernel + # or initrd path. Assume this would be /boot and remove + # it. Keep the '/' following the device, since this + # path is relative to the device root, not the config + # location. + kernel=`echo $trimcmd | sed "s/([^)]*)//g" | cut -d\ -f2` append=`echo $trimcmd | cut -d\ -f3-` ;; initrd*) - initrd="$val" + # Trim off device specification as above + initrd="$(echo "$val" | sed "s/([^)]*)//g")" ;; esac } From 698360199c9aa75f109c31814010d8bfb8abf019 Mon Sep 17 00:00:00 2001 From: Jonathon Hall Date: Thu, 10 Nov 2022 10:13:38 -0500 Subject: [PATCH 2/3] kexec-parse-boot: Ensure kernel/initrd paths exist in boot option If a boot option doesn't refer to a valid file for the kernel/initrd, ignore it. Such an option is never bootable, because we would fail to find the kernel/initrd. This could happen if the path contained GRUB variables, or specified a device that wasn't /boot, etc. This is checked before expanding GRUB variables. It's unlikely that any kernel/initrd path containing variables would end up working when all variables expand to nothing (since we do not handle GRUB variables). Signed-off-by: Jonathon Hall --- initrd/bin/kexec-parse-boot | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/initrd/bin/kexec-parse-boot b/initrd/bin/kexec-parse-boot index b3dc6c0c..0aacd07e 100755 --- a/initrd/bin/kexec-parse-boot +++ b/initrd/bin/kexec-parse-boot @@ -28,15 +28,31 @@ fix_path() { fi } +# GRUB kernel lines (linux/multiboot) can include a command line. Check whether +# the file path exists in $bootdir. +check_path() { + local checkpath firstval + checkpath="$1" + firstval="$(echo "$checkpath" | cut -d\ -f1)" + if ! [ -r "$bootdir$firstval" ]; then return 1; fi + return 0 +} + echo_entry() { if [ "$kexectype" = "elf" ]; then if [ -z "$kernel" ]; then return; fi fix_path $kernel + # The kernel must exist - if it doesn't, ignore this entry, it + # wouldn't work anyway. This could happen if there was a + # GRUB variable in the kernel path, etc. + if ! check_path "$path"; then return; fi entry="$name|$kexectype|kernel $path" if [ -n "$initrd" ]; then for init in $(echo $initrd | tr ',' ' '); do fix_path $init + # The initrd must also exist + if ! check_path "$path"; then return; fi entry="$entry|initrd $path" done fi @@ -44,12 +60,18 @@ echo_entry() { entry="$entry|append $append" fi + # Double-expand here in case there are variables in the kernel + # parameters - some configs do this and can boot with empty + # expansions (Debian Live ISOs use this for loopback boots) echo $(eval "echo \"$entry\"") fi if [ "$kexectype" = "multiboot" -o "$kexectype" = "xen" ]; then if [ -z "$kernel" ]; then return; fi fix_path $kernel + # The kernel must exist + if ! check_path "$path"; then return; fi + # Double-expand to clear variable expansions echo $(eval "echo \"$name|$kexectype|kernel $path$modules\"") fi } From 3c0e5c06c60eb862f3d9b51d91d0972f68e9d5a5 Mon Sep 17 00:00:00 2001 From: Jonathon Hall Date: Thu, 10 Nov 2022 10:26:20 -0500 Subject: [PATCH 3/3] kexec-parse-boot: Refactor common parts of echo_entry() A lot of echo_entry() is now common to elf/multiboot/xen kernels, just branch for the type-specific logic. Signed-off-by: Jonathon Hall --- initrd/bin/kexec-parse-boot | 64 ++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/initrd/bin/kexec-parse-boot b/initrd/bin/kexec-parse-boot index 0aacd07e..7bba7d26 100755 --- a/initrd/bin/kexec-parse-boot +++ b/initrd/bin/kexec-parse-boot @@ -39,41 +39,41 @@ check_path() { } echo_entry() { - if [ "$kexectype" = "elf" ]; then - if [ -z "$kernel" ]; then return; fi + if [ -z "$kernel" ]; then return; fi - fix_path $kernel - # The kernel must exist - if it doesn't, ignore this entry, it - # wouldn't work anyway. This could happen if there was a - # GRUB variable in the kernel path, etc. - if ! check_path "$path"; then return; fi - entry="$name|$kexectype|kernel $path" - if [ -n "$initrd" ]; then - for init in $(echo $initrd | tr ',' ' '); do - fix_path $init - # The initrd must also exist - if ! check_path "$path"; then return; fi - entry="$entry|initrd $path" - done - fi - if [ -n "$append" ]; then - entry="$entry|append $append" - fi + fix_path $kernel + # The kernel must exist - if it doesn't, ignore this entry, it + # wouldn't work anyway. This could happen if there was a + # GRUB variable in the kernel path, etc. + if ! check_path "$path"; then return; fi + entry="$name|$kexectype|kernel $path" - # Double-expand here in case there are variables in the kernel - # parameters - some configs do this and can boot with empty - # expansions (Debian Live ISOs use this for loopback boots) - echo $(eval "echo \"$entry\"") - fi - if [ "$kexectype" = "multiboot" -o "$kexectype" = "xen" ]; then - if [ -z "$kernel" ]; then return; fi + case "$kexectype" in + elf) + if [ -n "$initrd" ]; then + for init in $(echo $initrd | tr ',' ' '); do + fix_path $init + # The initrd must also exist + if ! check_path "$path"; then return; fi + entry="$entry|initrd $path" + done + fi + if [ -n "$append" ]; then + entry="$entry|append $append" + fi + ;; + multiboot|xen) + entry="$entry$modules" + ;; + *) + return + ;; + esac - fix_path $kernel - # The kernel must exist - if ! check_path "$path"; then return; fi - # Double-expand to clear variable expansions - echo $(eval "echo \"$name|$kexectype|kernel $path$modules\"") - fi + # Double-expand here in case there are variables in the kernel + # parameters - some configs do this and can boot with empty + # expansions (Debian Live ISOs use this for loopback boots) + echo $(eval "echo \"$entry\"") } search_entry() {