From 3a2248b45e25c9043582aeb0a0f4f849f57f387b1e3ad8694a344bf7eec0db0a Mon Sep 17 00:00:00 2001 From: Gary Ching-Pang Lin Date: Wed, 7 Jun 2023 05:25:24 +0000 Subject: [PATCH] Accepting request 1091184 from home:gary_lin:branches:devel:openSUSE:Factory - Update shim-install to support FDE + Read GRUB_CRYPTODISK_PASSWORD and GRUB_TPM2_SEALED_KEY to create the proper cryptomount command for grub.cfg + Save the PCR snapshot if grub2 supports the command + Support 'no_grub_install' to skip grub2-install + Detect the OS ID of openSUSE Leap OBS-URL: https://build.opensuse.org/request/show/1091184 OBS-URL: https://build.opensuse.org/package/show/devel:openSUSE:Factory/shim-leap?expand=0&rev=38 --- shim-install | 504 ++++++++++++++++++++++++++++++++++++++++++++++ shim-leap.changes | 10 + shim-leap.spec | 4 + 3 files changed, 518 insertions(+) create mode 100644 shim-install diff --git a/shim-install b/shim-install new file mode 100644 index 0000000..50ef385 --- /dev/null +++ b/shim-install @@ -0,0 +1,504 @@ +#! /bin/bash -e + +arch=`uname -m` +rootdir= +bootdir= +efidir= +install_device= +efibootdir= +ca_string= +no_nvram=no +removable=no +clean=no +sysconfdir="/etc" +libdir="/usr/lib64" # Beware, this is arch dependent! +datadir="/usr/share" +source_dir="${datadir}/efi/${arch}" +efibootmgr="/usr/sbin/efibootmgr" +grub_probe="/usr/sbin/grub2-probe" +grub_mkrelpath="/usr/bin/grub2-mkrelpath" +no_grub_install=no +grub_install="/usr/sbin/grub2-install" +grub_install_target= +self="`basename $0`" +grub_cfg="/boot/grub2/grub.cfg" +update_boot=no +def_grub_efi="${source_dir}/grub.efi" +def_boot_efi= + +[ ! -r /usr/etc/default/shim ] || . /usr/etc/default/shim +[ ! -r /etc/default/shim ] || . /etc/default/shim + +if [ -z "$def_shim_efi" -o ! -e ${source_dir}/${def_shim_efi} ] ; then + def_shim_efi="shim.efi" +fi + +source_shim_efi="${source_dir}/${def_shim_efi}" + +if [ x${arch} = xx86_64 ] ; then + grub_install_target="x86_64-efi" + def_boot_efi="bootx64.efi" +elif [ x${arch} = xaarch64 ] ; then + grub_install_target="arm64-efi" + def_boot_efi="bootaa64.efi" +else + echo "Unsupported architecture: ${arch}" + exit 1 +fi + +if [ ! -d "${source_dir}" -o ! -e "${def_grub_efi}" ] ; then + # for outdated packages fall back to previous behavior + source_dir="$libdir/efi" + def_grub_efi="${source_dir}/grub.efi" +fi + +# Get GRUB_DISTRIBUTOR. +if test -f "${sysconfdir}/default/grub" ; then + . "${sysconfdir}/default/grub" +fi + +if [ x"${GRUB_DISTRIBUTOR}" = x ] && [ -f "${sysconfdir}/os-release" ] ; then + . "${sysconfdir}/os-release" + GRUB_DISTRIBUTOR="${NAME} ${VERSION}" + OS_ID="${ID}" +fi + +bootloader_id="$(echo "$GRUB_DISTRIBUTOR" | tr 'A-Z' 'a-z' | cut -d' ' -f1)" +if test -z "$bootloader_id"; then + bootloader_id=grub +fi + +efi_distributor="$bootloader_id" +bootloader_id="${bootloader_id}-secureboot" + +case "$bootloader_id" in + "sle"*) + ca_string='SUSE Linux Enterprise Secure Boot CA1';; + "opensuse"*) + ca_string='openSUSE Secure Boot CA1';; + *) ca_string="";; +esac + +case "$OS_ID" in + "opensuse-leap") + ca_string='SUSE Linux Enterprise Secure Boot CA1';; +esac + +is_azure () { + local bios_vendor; + local product_name; + local sys_vendor; + + local sysfs_dmi_id="/sys/class/dmi/id" + + if test -e "${sysfs_dmi_id}/bios_vendor"; then + bios_vendor=$(cat "${sysfs_dmi_id}/bios_vendor") + fi + if test -e "${sysfs_dmi_id}/product_name"; then + product_name=$(cat "${sysfs_dmi_id}/product_name") + fi + if test -e "${sysfs_dmi_id}/sys_vendor"; then + sys_vendor=$(cat "${sysfs_dmi_id}/sys_vendor") + fi + + if test "x${bios_vendor}" != "xMicrosoft Corporation"; then + # return false + return 1 + fi + + if test "x${product_name}" != "xVirtual Machine"; then + # return false + return 1 + fi + + if test "x${sys_vendor}" != "xMicrosoft Corporation"; then + # return false + return 1 + fi + + # return true + return 0 +} + +usage () { + echo "Usage: $self [OPTION] [INSTALL_DEVICE]" + echo + echo "Install Secure Boot Loaders on your drive." + echo + echo "--directory=DIR use images from DIR." + echo "--grub-probe=FILE use FILE as grub-probe." + echo "--removable the installation device is removable." + echo "--no-nvram don't update the NVRAM variable." + echo "--bootloader-id=ID the ID of bootloader." + echo "--efi-directory=DIR use DIR as the EFI System Partition root." + echo "--config-file=FILE use FILE as config file, default is $grub_cfg." + echo "--clean remove all installed files and configs." + echo "--suse-enable-tpm install grub.efi with TPM support." + echo "--no-grub-install Do not run grub2-install." + echo + echo "INSTALL_DEVICE must be system device filename." +} + +argument () { + opt="$1" + shift + + if test $# -eq 0; then + echo "$0: option requires an argument -- \`$opt'" 1>&2 + exit 1 + fi + echo "$1" +} + +# Check the arguments. +while test $# -gt 0 +do + option=$1 + shift + + case "$option" in + -h | --help) + usage + exit 0 ;; + + --root-directory) + rootdir="`argument $option "$@"`"; shift;; + --root-directory=*) + rootdir="`echo "$option" | sed 's/--root-directory=//'`" ;; + + --efi-directory) + efidir="`argument $option "$@"`"; shift;; + --efi-directory=*) + efidir="`echo "$option" | sed 's/--efi-directory=//'`" ;; + + --directory | -d) + source_dir="`argument $option "$@"`"; shift;; + --directory=*) + source_dir="`echo "$option" | sed 's/--directory=//'`" ;; + + --bootloader-id) + bootloader_id="`argument $option "$@"`"; shift;; + --bootloader-id=*) + bootloader_id="`echo "$option" | sed 's/--bootloader-id=//'`" ;; + + --grub-probe) + grub_probe="`argument "$option" "$@"`"; shift;; + --grub-probe=*) + grub_probe="`echo "$option" | sed 's/--grub-probe=//'`" ;; + + --config-file) + grub_cfg="`argument "$option" "$@"`"; shift;; + --config-file=*) + grub_cfg="`echo "$option" | sed 's/--config-file=//'`" ;; + + --removable) + no_nvram=yes + removable=yes ;; + + --no-nvram) + no_nvram=yes ;; + + --suse-enable-tpm) + # bsc#1174320 shim-install uses wrong paths for EFI files + # There are 3 possible locations of grub-tpm.efi and we will check them + # one by one. + if [ -e "${source_dir}/grub-tpm.efi" ]; then + source_grub_efi="${source_dir}/grub-tpm.efi" + elif [ -e "${datadir}/grub2/${grub_install_target}/grub-tpm.efi" ] ; then + source_grub_efi="${datadir}/grub2/${grub_install_target}/grub-tpm.efi" + else + source_grub_efi="/usr/lib/grub2/${grub_install_target}/grub-tpm.efi" + fi + ;; + + --clean) + clean=yes ;; + + --no-grub-install) + no_grub_install=yes ;; + + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + *) + if test "x$install_device" != x; then + echo "More than one install device?" 1>&2 + usage + exit 1 + fi + install_device="${option}" ;; + esac +done + +if test -n "$efidir"; then + efi_fs=`"$grub_probe" --target=fs "${efidir}"` + if test "x$efi_fs" = xfat; then :; else + echo "$efidir doesn't look like an EFI partition." 1>&2 + efidir= + fi +fi + + +if [ -z "$bootdir" ]; then + bootdir="/boot" + if [ -n "$rootdir" ] ; then + # Initialize bootdir if rootdir was initialized. + bootdir="${rootdir}/boot" + fi +fi + +# Find the EFI System Partition. +if test -n "$efidir"; then + install_device="`"$grub_probe" --target=device --device-map= "${efidir}"`" +else + if test -d "${bootdir}/efi"; then + install_device="`"$grub_probe" --target=device --device-map= "${bootdir}/efi"`" + # Is it a mount point? + if test "x$install_device" != "x`"$grub_probe" --target=device --device-map= "${bootdir}"`"; then + efidir="${bootdir}/efi" + fi + elif test -d "${bootdir}/EFI"; then + install_device="`"$grub_probe" --target=device --device-map= "${bootdir}/EFI"`" + # Is it a mount point? + if test "x$install_device" != "x`"$grub_probe" --target=device --device-map= "${bootdir}"`"; then + efidir="${bootdir}/EFI" + fi + elif test -n "$rootdir" && test "x$rootdir" != "x/"; then + # The EFI System Partition may have been given directly using + # --root-directory. + install_device="`"$grub_probe" --target=device --device-map= "${rootdir}"`" + # Is it a mount point? + if test "x$install_device" != "x`"$grub_probe" --target=device --device-map= "${rootdir}/.."`"; then + efidir="${rootdir}" + fi + fi + + if test -n "$efidir"; then + efi_fs=`"$grub_probe" --target=fs "${efidir}"` + if test "x$efi_fs" = xfat; then :; else + echo "$efidir doesn't look like an EFI partition." 1>&2 + efidir= + fi + fi +fi + +if test -n "$efidir"; then + efi_file=shim.efi + efibootdir="$efidir/EFI/boot" + mkdir -p "$efibootdir" || exit 1 + if test "$removable" = "yes" ; then + efidir="$efibootdir" + else + efidir="$efidir/EFI/$efi_distributor" + mkdir -p "$efidir" || exit 1 + fi +else + echo "No valid EFI partition" 1>&2 + exit 1; +fi + +if test "$removable" = "no" -a -f "$efibootdir/$def_boot_efi"; then + if test -n "$ca_string" && (grep -q "$ca_string" "$efibootdir/$def_boot_efi"); then + update_boot=yes + fi +else + update_boot=yes +fi + +if test "$clean" = "yes"; then + rm -f "${efidir}/shim.efi" + rm -f "${efidir}/MokManager.efi" + rm -f "${efidir}/grub.efi" + rm -f "${efidir}/grub.cfg" + rm -f "${efidir}/boot.csv" + if test "$update_boot" = "yes"; then + rm -f "${efibootdir}/${def_boot_efi}" + rm -f "${efibootdir}/fallback.efi" + # bsc#1175626, bsc#1175656 also clean up MokManager + rm -f "${efibootdir}/MokManager.efi" + fi + if test "$no_nvram" = no && test -n "$bootloader_id"; then + # Delete old entries from the same distributor. + for bootnum in `$efibootmgr | grep '^Boot[0-9]' | \ + fgrep -i " $bootloader_id" | cut -b5-8`; do + $efibootmgr -b "$bootnum" -B + done + fi + exit 0 +fi + +cp "${source_dir}/MokManager.efi" "${efidir}" + +if test -n "$source_grub_efi" && ! test -f "$source_grub_efi"; then + echo "File $source_grub_efi doesn't exist, fallback to default one" 1>&2 + source_grub_efi="" +fi + +if test -z "$source_grub_efi"; then + source_grub_efi="$def_grub_efi" +fi + +echo "copying $source_grub_efi to ${efidir}/grub.efi" +cp "$source_grub_efi" "${efidir}/grub.efi" + +if test "$efidir" != "$efibootdir" ; then + cp "${source_shim_efi}" "${efidir}/shim.efi" + if test -n "$bootloader_id"; then + echo "shim.efi,${bootloader_id}" | iconv -f ascii -t ucs2 > "${efidir}/boot.csv" + fi +fi + +if test "$update_boot" = "yes"; then + cp "$source_shim_efi" "${efibootdir}/${def_boot_efi}" + if test "$removable" = "no"; then + cp "${source_dir}/fallback.efi" "${efibootdir}" + # bsc#1175626, bsc#1175656 Since shim 15, loading MokManager becomes + # mandatory if a MOK request exists. Copy MokManager to \EFI\boot so + # that boot*.efi can load MokManager to process the request instead + # of shutting down the system immediately. + cp "${source_dir}/MokManager.efi" "${efibootdir}" + fi +fi + + +prepare_cryptodisk () { + uuid="$1" + + if [ "x$GRUB_CRYPTODISK_PASSWORD" != x ]; then + echo "cryptomount -u $uuid -p \"$GRUB_CRYPTODISK_PASSWORD\"" + return + fi + + if [ "x$GRUB_TPM2_SEALED_KEY" = x ]; then + echo "cryptomount -u $uuid" + return + fi + + tpm_sealed_key="${GRUB_TPM2_SEALED_KEY}" + + declare -g TPM_PCR_SNAPSHOT_TAKEN + + if [ -z "$TPM_PCR_SNAPSHOT_TAKEN" ]; then + TPM_PCR_SNAPSHOT_TAKEN=1 + + # Check if tpm_record_pcrs is available and set the command to + # grub.cfg. + if grep -q "tpm_record_pcrs" ${datadir}/grub2/${arch}-efi/command.lst ; then + echo "tpm_record_pcrs 0-9" + fi + fi + + cat < "${efidir}/grub.cfg" + +if test "$no_nvram" = no && test -n "$bootloader_id"; then + + modprobe -q efivars 2>/dev/null || true + + # Delete old entries from the same distributor. + for bootnum in `$efibootmgr | grep '^Boot[0-9]' | \ + fgrep -i " $bootloader_id" | cut -b5-8`; do + $efibootmgr -b "$bootnum" -B + done + + efidir_drive="$("$grub_probe" --target=drive --device-map= "$efidir")" + efidir_disk="$("$grub_probe" --target=disk --device-map= "$efidir")" + if test -z "$efidir_drive" || test -z "$efidir_disk"; then + echo "Can't find GRUB drive for $efidir; unable to create EFI Boot Manager entry." >&2 + # bsc#1119762 If the MD device is partitioned, we just need to create one + # boot entry since the partitions are nested partitions and the mirrored + # partitions share the same UUID. + elif [[ "$efidir_drive" == \(mduuid/* && "$efidir_drive" != \(mduuid/*,* ]]; then + eval $(mdadm --detail --export "$efidir_disk" | + perl -ne 'print if m{^MD_LEVEL=}; push( @D, $1) if (m{^MD_DEVICE_\S+_DEV=(\S+)$}); + sub END() {print "MD_DEVS=\"", join( " ", @D), "\"\n";};') + if [ "$MD_LEVEL" != "raid1" ]; then + echo "GRUB drive for $efidir not on RAID1; unable to create EFI Boot Manager entry." >&2 + fi + for mddev in $MD_DEVS; do + efidir_drive="$("$grub_probe" --target=drive --device-map= -d "$mddev")" + efidir_disk="$("$grub_probe" --target=disk --device-map= -d "$mddev")" + efidir_part="$(echo "$efidir_drive" | sed 's/^([^,]*,[^0-9]*//; s/[^0-9].*//')" + efidir_d=${mddev#/dev/} + $efibootmgr -c -d "$efidir_disk" -p "$efidir_part" -w \ + -L "$bootloader_id ($efidir_d)" -l "\\EFI\\$efi_distributor\\$efi_file" + done + else + efidir_part="$(echo "$efidir_drive" | sed 's/^([^,]*,[^0-9]*//; s/[^0-9].*//')" + $efibootmgr -c -d "$efidir_disk" -p "$efidir_part" -w \ + -L "$bootloader_id" -l "\\EFI\\$efi_distributor\\$efi_file" + fi +fi + +# bsc#1185464 bsc#1185961 +# The Azure firmware sometimes doesn't respect the boot option created by +# either efibootmgr or fallback.efi so we have to remove fallback.efi to +# avoid the endless reset loop. +if is_azure; then + # Skip the workaround if we don't own \EFI\Boot or the removable + # option is used + if test "$update_boot" = "yes" && test "$removable" = "no"; then + # Remove fallback.efi which could cause the reset loop in Azure + rm -f "${efibootdir}/fallback.efi" + # Remove the older grub binary and config + rm -f "${efibootdir}/grub.efi" + rm -f "${efibootdir}/grub.cfg" + # Install new grub binary and config file to \EFI\Boot as + # the "removable" option + cp "${efidir}/grub.cfg" "${efibootdir}/grub.cfg" + cp "${efidir}/grub.efi" "${efibootdir}/grub.efi" + fi +fi diff --git a/shim-leap.changes b/shim-leap.changes index 28906d6..efd6d02 100644 --- a/shim-leap.changes +++ b/shim-leap.changes @@ -1,3 +1,13 @@ +------------------------------------------------------------------- +Wed Jun 7 02:29:44 UTC 2023 - Gary Ching-Pang Lin + +- Update shim-install to support FDE + + Read GRUB_CRYPTODISK_PASSWORD and GRUB_TPM2_SEALED_KEY to + create the proper cryptomount command for grub.cfg + + Save the PCR snapshot if grub2 supports the command + + Support 'no_grub_install' to skip grub2-install + + Detect the OS ID of openSUSE Leap + ------------------------------------------------------------------- Thu May 25 07:48:54 UTC 2023 - Gary Ching-Pang Lin diff --git a/shim-leap.spec b/shim-leap.spec index d9219e9..2d057c5 100644 --- a/shim-leap.spec +++ b/shim-leap.spec @@ -32,6 +32,7 @@ License: BSD-2-Clause Group: System/Boot Source: shim-15.4-lp152.4.17.1.x86_64.rpm Source1: README +Source2: shim-install BuildRoot: %{_tmppath}/%{name}-%{version}-build ExclusiveArch: x86_64 @@ -57,6 +58,9 @@ rpm2cpio %{SOURCE0} | cpio --extract --unconditional --preserve-modification-tim cp -a * %{buildroot} cp %{S:1} . +# Override shim-install +install -m 755 %{S:2} %{buildroot}/%{_sbindir}/shim-install + %if %{undefined shim_lib64_share_compat} # Remove the sym-links in /usr/lib64/efi rm -rf %{buildroot}/usr/lib64/efi