From 27a326dafb621269c501225fd4842615ca4adf73 Mon Sep 17 00:00:00 2001
From: Steve Baker <sbaker@redhat.com>
Date: Fri, 5 Mar 2021 16:35:21 +1300
Subject: [PATCH] Support secure-boot bootloader where possible

As of grub2 >= 2.02-95 on redhat family distros, calling grub2-install
on an EFI partition will fail with: "this utility cannot be used for
EFI platforms because it does not support UEFI Secure Boot."

This version of grub is now in centos8-stream and non-eus repos of
RHEL-8. It is not currently possible to build whole-disk UEFI images
on these distros, and when this package is promoted this will also
affect centos8 and RHEL-8 eus. The grub maintainers made this change
because the grub2-install generated /boot/efi/EFI/BOOT/BOOTX64.EFI
will never be capable of booting with Secure Boot.

This change defines a $EFI_BOOT_DIR for every distro element. When
directory /boot/efi/$EFI_BOOT_DIR exists a grub.cfg file in will be
generated there. This change also installs the shim package on redhat
family distros, which installs a copy of the shim bootloader to
/boot/efi/EFI/BOOT/BOOTX64.EFI. Using centos as an example, this
allows UEFI to boot the shim /boot/efi/EFI/BOOT/BOOTX64.EFI which
then chains to /boot/efi/EFI/centos/grubx64.efi.

If /boot/efi/$EFI_BOOT_DIR doesn't exist (such as for Ubuntu,
/boot/efi/EFI/ubuntu) the current behaviour of running grub-install to
generate /boot/efi/EFI/BOOT/BOOTX64.EFI will continue. For distros
such as Ubutnu where packaging does not populate /boot/efi/EFI/ubuntu
with .efi files, secure boot can be added in the future by copying
.efi files to /boot/efi/EFI/ubuntu and copying the shim file to
/boot/efi/EFI/BOOT/BOOTX64.EFI.

Change-Id: I90925218ff2aa4c4daffcf86e686b6d98d6b0f21
---
 .../bootloader/finalise.d/50-bootloader       | 24 ++++++++++++-------
 diskimage_builder/elements/bootloader/pkg-map | 10 ++++----
 .../environment.d/10-centos-distro-name.bash  |  1 +
 .../environment.d/10-centos-distro-name.bash  |  1 +
 .../environment.d/10-centos7-distro-name.bash |  1 +
 .../environment.d/10-debian-minimal.bash      |  1 +
 .../environment.d/10-fedora-distro-name.bash  |  1 +
 .../environment.d/10-fedora-distro-name.bash  |  1 +
 .../environment.d/00-gentoo-envars.bash       |  1 +
 .../elements/iso/cleanup.d/100-build-iso      |  3 ---
 .../10-opensuse-distro-name.bash              |  1 +
 .../10-opensuse-distro-name.bash              |  1 +
 .../environment.d/10-rhel-distro-name.bash    |  1 +
 .../environment.d/10-ubuntu-distro-name.bash  |  1 +
 14 files changed, 31 insertions(+), 17 deletions(-)

diff --git a/diskimage_builder/elements/bootloader/finalise.d/50-bootloader b/diskimage_builder/elements/bootloader/finalise.d/50-bootloader
index 8a48d3204..ed79b069a 100755
--- a/diskimage_builder/elements/bootloader/finalise.d/50-bootloader
+++ b/diskimage_builder/elements/bootloader/finalise.d/50-bootloader
@@ -79,6 +79,12 @@ function install_grub2 {
         GRUBNAME=$(type -p grub2-install)
     fi
 
+    if type grub2-mkconfig >/dev/null; then
+        GRUB_MKCONFIG="grub2-mkconfig"
+    else
+        GRUB_MKCONFIG="grub-mkconfig"
+    fi
+
     # If no GRUB2 is found, fallback to extlinux
     if [ -z "$GRUBNAME" ] || [ $($GRUBNAME --version | grep "0.97" | wc -l) -ne 0 ]; then
         echo "No GRUB2 found. Fallback to Extlinux..."
@@ -150,7 +156,7 @@ function install_grub2 {
         modules="part_msdos part_gpt lvm"
         extra_options=""
         if [[ ${DIB_BLOCK_DEVICE} == "mbr" || ${DIB_BLOCK_DEVICE} == "gpt" ]]; then
-            modules="$modules biosdisk"
+            $GRUBNAME --modules="$modules biosdisk" $GRUB_OPTS $BOOT_DEV
         elif [[ ${DIB_BLOCK_DEVICE} == "efi" ]]; then
             # This tells the EFI install to put the EFI binaries into
             # the generic /BOOT directory and avoids trying to update
@@ -168,8 +174,14 @@ function install_grub2 {
                 # At this point, we don't need to override the target
                 # for any other architectures.
             esac
+            if [ -d /boot/efi/$EFI_BOOT_DIR ]; then
+                # Make the grub config in the EFI directory for UEFI boot
+                $GRUB_MKCONFIG -o /boot/efi/$EFI_BOOT_DIR/grub.cfg
+            else
+                echo "WARNING: /boot/efi/$EFI_BOOT_DIR does not exist, UEFI secure boot not supported"
+                $GRUBNAME --modules="$modules" $extra_options $GRUB_OPTS $BOOT_DEV
+            fi
         fi
-        $GRUBNAME --modules="$modules" $extra_options $GRUB_OPTS $BOOT_DEV
     fi
 
     # This might be better factored out into a per-distro 'install-bootblock'
@@ -204,12 +216,6 @@ function install_grub2 {
     echo "GRUB_CMDLINE_LINUX_DEFAULT=\"${GRUB_CMDLINE_LINUX_DEFAULT} ${DIB_BOOTLOADER_DEFAULT_CMDLINE}\"" >>/etc/default/grub
     echo 'GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"' >>/etc/default/grub
 
-    if type grub2-mkconfig >/dev/null; then
-        GRUB_MKCONFIG="grub2-mkconfig -o $GRUB_CFG"
-    else
-        GRUB_MKCONFIG="grub-mkconfig -o $GRUB_CFG"
-    fi
-
     # os-prober leaks /dev/sda into config file in dual-boot host
     # Disable grub-os-prober to avoid the issue  while running
     # grub-mkconfig
@@ -220,7 +226,7 @@ function install_grub2 {
         echo 'GRUB_DISABLE_OS_PROBER=true' >> /etc/default/grub
     fi
 
-    $GRUB_MKCONFIG
+    $GRUB_MKCONFIG -o $GRUB_CFG
 
     # Remove the fix to disable os_prober
     if [ -n "$PROBER_DISABLED" ]; then
diff --git a/diskimage_builder/elements/bootloader/pkg-map b/diskimage_builder/elements/bootloader/pkg-map
index e57aaf521..016f21a95 100644
--- a/diskimage_builder/elements/bootloader/pkg-map
+++ b/diskimage_builder/elements/bootloader/pkg-map
@@ -18,11 +18,11 @@
     "redhat": {
       "extlinux": "syslinux-extlinux",
       "grub-pc": "grub2-tools grub2",
-      "grub-efi-amd64": "grub2-tools grub2-pc grub2-efi-x64 grub2-efi-x64-modules efibootmgr",
-      "grub-efi-arm64": "grub2-tools grub2-efi-aa64 grub2-efi-aa64-modules efibootmgr",
-      "grub-efi-aarch64": "grub2-tools grub2-efi-aa64 grub2-efi-aa64-modules efibootmgr",
+      "grub-efi-amd64": "grub2-tools grub2 grub2-pc grub2-efi-x64 grub2-efi-x64-modules efibootmgr shim-x64",
+      "grub-efi-arm64": "grub2-tools grub2-efi-aa64 grub2-efi-aa64-modules efibootmgr shim-aa64",
+      "grub-efi-aarch64": "grub2-tools grub2-efi-aa64 grub2-efi-aa64-modules efibootmgr shim-aa64",
       "grub-efi": "grub2-tools grub2-efi efibootmgr",
-      "grub-efi-x86_64": "grub2-tools grub2-efi-x64 grub2-efi-x64-modules efibootmgr",
+      "grub-efi-x86_64": "grub2-tools grub2 grub2-efi-x64 grub2-efi-x64-modules efibootmgr shim-x64",
       "grub-ppc64": "grub2-tools grub2"
     }
   },
@@ -31,7 +31,7 @@
     "extlinux": "extlinux",
     "grub-pc": "grub-pc",
     "grub-efi-amd64": "grub-efi grub-pc-bin efibootmgr",
-    "grub-efi-arm64": "grub-efi-arm64 efibootmgr",
+    "grub-efi-arm64": "grub-efi-arm64 grub-efi-arm64-bin efibootmgr",
     "grub-ppc64": "grub-ieee1275"
   }
 }
diff --git a/diskimage_builder/elements/centos-minimal/environment.d/10-centos-distro-name.bash b/diskimage_builder/elements/centos-minimal/environment.d/10-centos-distro-name.bash
index d9e49a4db..fc55bec96 100644
--- a/diskimage_builder/elements/centos-minimal/environment.d/10-centos-distro-name.bash
+++ b/diskimage_builder/elements/centos-minimal/environment.d/10-centos-distro-name.bash
@@ -1,5 +1,6 @@
 export DISTRO_NAME=centos
 export DIB_RELEASE=${DIB_RELEASE:-7}
+export EFI_BOOT_DIR="EFI/centos"
 
 # by default, enable DHCP configuration of eth0 & eth1 in network
 # scripts for centos 7.  See yum-minimal for full details.  CentOS 8
diff --git a/diskimage_builder/elements/centos/environment.d/10-centos-distro-name.bash b/diskimage_builder/elements/centos/environment.d/10-centos-distro-name.bash
index 9864057dd..ca893816e 100644
--- a/diskimage_builder/elements/centos/environment.d/10-centos-distro-name.bash
+++ b/diskimage_builder/elements/centos/environment.d/10-centos-distro-name.bash
@@ -1,2 +1,3 @@
 export DISTRO_NAME=centos
 export DIB_RELEASE=${DIB_RELEASE:-8}
+export EFI_BOOT_DIR="EFI/centos"
diff --git a/diskimage_builder/elements/centos7/environment.d/10-centos7-distro-name.bash b/diskimage_builder/elements/centos7/environment.d/10-centos7-distro-name.bash
index 66a7fdc51..11aa38c02 100644
--- a/diskimage_builder/elements/centos7/environment.d/10-centos7-distro-name.bash
+++ b/diskimage_builder/elements/centos7/environment.d/10-centos7-distro-name.bash
@@ -1,5 +1,6 @@
 export DISTRO_NAME=centos7
 export DIB_RELEASE=7
+export EFI_BOOT_DIR="EFI/centos"
 
 # Useful for elements that work with fedora (dnf) & centos
 export YUM=${YUM:-yum}
diff --git a/diskimage_builder/elements/debian-minimal/environment.d/10-debian-minimal.bash b/diskimage_builder/elements/debian-minimal/environment.d/10-debian-minimal.bash
index 62f95fe9a..2f565305f 100644
--- a/diskimage_builder/elements/debian-minimal/environment.d/10-debian-minimal.bash
+++ b/diskimage_builder/elements/debian-minimal/environment.d/10-debian-minimal.bash
@@ -1,6 +1,7 @@
 export DISTRO_NAME=debian
 export DIB_RELEASE=${DIB_RELEASE:-stable}
 export DIB_INIT_SYSTEM=systemd
+export EFI_BOOT_DIR="EFI/debian"
 
 if [ -n "${DIB_DEBIAN_DISTRIBUTION_MIRROR:-}" ]; then
     DIB_DISTRIBUTION_MIRROR=$DIB_DEBIAN_DISTRIBUTION_MIRROR
diff --git a/diskimage_builder/elements/fedora-minimal/environment.d/10-fedora-distro-name.bash b/diskimage_builder/elements/fedora-minimal/environment.d/10-fedora-distro-name.bash
index 161e01b5a..ae38976c5 100644
--- a/diskimage_builder/elements/fedora-minimal/environment.d/10-fedora-distro-name.bash
+++ b/diskimage_builder/elements/fedora-minimal/environment.d/10-fedora-distro-name.bash
@@ -1,2 +1,3 @@
 export DISTRO_NAME=fedora
 export DIB_RELEASE=${DIB_RELEASE:-32}
+export EFI_BOOT_DIR="EFI/fedora"
diff --git a/diskimage_builder/elements/fedora/environment.d/10-fedora-distro-name.bash b/diskimage_builder/elements/fedora/environment.d/10-fedora-distro-name.bash
index 6b032b01a..b7acaefeb 100644
--- a/diskimage_builder/elements/fedora/environment.d/10-fedora-distro-name.bash
+++ b/diskimage_builder/elements/fedora/environment.d/10-fedora-distro-name.bash
@@ -1,5 +1,6 @@
 export DISTRO_NAME=fedora
 export DIB_RELEASE=${DIB_RELEASE:-32}
+export EFI_BOOT_DIR="EFI/fedora"
 
 # Note the filename URL has a "sub-release" in it
 #  http:// ... Fedora-Cloud-Base-25-1.3.x86_64.qcow2
diff --git a/diskimage_builder/elements/gentoo/environment.d/00-gentoo-envars.bash b/diskimage_builder/elements/gentoo/environment.d/00-gentoo-envars.bash
index 649dabdf9..b7a617559 100644
--- a/diskimage_builder/elements/gentoo/environment.d/00-gentoo-envars.bash
+++ b/diskimage_builder/elements/gentoo/environment.d/00-gentoo-envars.bash
@@ -1,5 +1,6 @@
 export DIB_RELEASE=gentoo
 export DISTRO_NAME=gentoo
+export EFI_BOOT_DIR="EFI/gentoo"
 export GENTOO_PROFILE=${GENTOO_PROFILE:-'default/linux/amd64/17.1'}
 export GENTOO_PORTAGE_CLEANUP=${GENTOO_PORTAGE_CLEANUP:-'True'}
 export GENTOO_PYTHON_TARGETS=${GENTOO_PYTHON_TARGETS:-'python3_8'}
diff --git a/diskimage_builder/elements/iso/cleanup.d/100-build-iso b/diskimage_builder/elements/iso/cleanup.d/100-build-iso
index 9f9febf5d..dfe8a669e 100755
--- a/diskimage_builder/elements/iso/cleanup.d/100-build-iso
+++ b/diskimage_builder/elements/iso/cleanup.d/100-build-iso
@@ -63,15 +63,12 @@ function build_iso() {
     SCRIPTDIR=$(dirname $0)
     MKISOFS="/usr/bin/mkisofs"
     if [ $DISTRO_NAME = "fedora" ]; then
-        EFI_BOOT_DIR="EFI/fedora"
         EXTRA_KERNEL_PARAMS="usbcore.autosuspend=-1"
     #debian
     elif [ $DISTRO_NAME = "debian" ]; then
-        EFI_BOOT_DIR="EFI/debian"
         EXTRA_KERNEL_PARAMS=""
     #ubuntu:
     else
-        EFI_BOOT_DIR="EFI/ubuntu"
         EXTRA_KERNEL_PARAMS=""
     fi
 
diff --git a/diskimage_builder/elements/opensuse-minimal/environment.d/10-opensuse-distro-name.bash b/diskimage_builder/elements/opensuse-minimal/environment.d/10-opensuse-distro-name.bash
index 23834bbb3..1ea3fef09 100644
--- a/diskimage_builder/elements/opensuse-minimal/environment.d/10-opensuse-distro-name.bash
+++ b/diskimage_builder/elements/opensuse-minimal/environment.d/10-opensuse-distro-name.bash
@@ -1,5 +1,6 @@
 export DISTRO_NAME=opensuse
 DIB_RELEASE=${DIB_RELEASE:-15.1}
 export DIB_RELEASE=${DIB_RELEASE,,}
+export EFI_BOOT_DIR="EFI/opensuse"
 export DIB_OPENSUSE_PATTERNS=patterns-openSUSE-base
 export DIB_INIT_SYSTEM=systemd
diff --git a/diskimage_builder/elements/opensuse/environment.d/10-opensuse-distro-name.bash b/diskimage_builder/elements/opensuse/environment.d/10-opensuse-distro-name.bash
index 2f656212b..cf41925b5 100644
--- a/diskimage_builder/elements/opensuse/environment.d/10-opensuse-distro-name.bash
+++ b/diskimage_builder/elements/opensuse/environment.d/10-opensuse-distro-name.bash
@@ -1,5 +1,6 @@
 export DISTRO_NAME=opensuse
 export DIB_RELEASE=${DIB_RELEASE:-15.1}
+export EFI_BOOT_DIR="EFI/opensuse"
 export DIB_OPENSUSE_PATTERNS=patterns-openSUSE-base
 export DIB_INIT_SYSTEM=systemd
 case ${DIB_RELEASE} in
diff --git a/diskimage_builder/elements/rhel/environment.d/10-rhel-distro-name.bash b/diskimage_builder/elements/rhel/environment.d/10-rhel-distro-name.bash
index 0fe70cd12..ab8126eaf 100644
--- a/diskimage_builder/elements/rhel/environment.d/10-rhel-distro-name.bash
+++ b/diskimage_builder/elements/rhel/environment.d/10-rhel-distro-name.bash
@@ -1,2 +1,3 @@
 export DISTRO_NAME=rhel
 export DIB_RELEASE=${DIB_RELEASE:-8}
+export EFI_BOOT_DIR="EFI/redhat"
diff --git a/diskimage_builder/elements/ubuntu-common/environment.d/10-ubuntu-distro-name.bash b/diskimage_builder/elements/ubuntu-common/environment.d/10-ubuntu-distro-name.bash
index 06e5651c1..8261112da 100644
--- a/diskimage_builder/elements/ubuntu-common/environment.d/10-ubuntu-distro-name.bash
+++ b/diskimage_builder/elements/ubuntu-common/environment.d/10-ubuntu-distro-name.bash
@@ -1,6 +1,7 @@
 export DISTRO_NAME=${DISTRO_NAME:-ubuntu}
 export DIB_RELEASE=${DIB_RELEASE:-bionic}
 export DIB_DEBIAN_COMPONENTS=${DIB_DEBIAN_COMPONENTS:-main,universe}
+export EFI_BOOT_DIR="EFI/ubuntu"
 
 # There are two default distro mirrors depending on architecture
 ARCH=${ARCH:-}