commit:     940eefc07945dbf5d50dc818c3557e90a0d860f4
Author:     Andrew Ammerlaan <andrewammerlaan <AT> gentoo <DOT> org>
AuthorDate: Wed Aug  7 14:31:33 2024 +0000
Commit:     Andrew Ammerlaan <andrewammerlaan <AT> gentoo <DOT> org>
CommitDate: Wed Aug  7 19:21:21 2024 +0000
URL:        https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=940eefc0

sys-boot/grub: implement USE=secureboot via grub-mkstandalone

This makes it possible to create a pre-built grub EFI executable signed for
secureboot via portage/`secureboot.eclass`.

It greatly simplifies setting up grub with secureboot, which is now a bit of a
tricky section in the handbook, and makes it possible to get a signed grub EFI
executable on systems that do not have the `SECUREBOOT_SIGN_KEY` available via
a `sys-boot/grub[secureboot]` binpkg.

Unfortunately, since the use of boot partitions, and the mounting point of
ESP's varies between systems we cannot rely on the default
`/boot/grub/grub.cfg` location to configure grub. Instead the standalone
executable reads the `grub.cfg` in the same directory it is in.

It is then up to the user to either:
- configure `sys-kernel/installkernel` to put the `grub.cfg` in a different
        location via `GRUB_CFG=`, or
- add a little `grub.cfg` that chainloads the real `grub.cfg`.

To make this even easier we could write some wrapper around grub-install which
would optionally install the prebuilt standalone EFI executable plus an
appropriate little `grub.cfg` to chainload the usual `grub.cfg`. But lets
leave that for later.

Signed-off-by: Andrew Ammerlaan <andrewammerlaan <AT> gentoo.org>
Closes: https://github.com/gentoo/gentoo/pull/38007
Signed-off-by: Andrew Ammerlaan <andrewammerlaan <AT> gentoo.org>

 .../grub/{grub-9999.ebuild => grub-2.12-r5.ebuild} | 99 ++++++++++++++++++++--
 sys-boot/grub/grub-9999.ebuild                     | 86 ++++++++++++++++++-
 2 files changed, 178 insertions(+), 7 deletions(-)

diff --git a/sys-boot/grub/grub-9999.ebuild b/sys-boot/grub/grub-2.12-r5.ebuild
similarity index 73%
copy from sys-boot/grub/grub-9999.ebuild
copy to sys-boot/grub/grub-2.12-r5.ebuild
index f007f3aaa884..1e22477b727a 100644
--- a/sys-boot/grub/grub-9999.ebuild
+++ b/sys-boot/grub/grub-2.12-r5.ebuild
@@ -16,11 +16,7 @@ EAPI=7
 # If any of the above applies to a user patch, the user should set the
 # corresponding variable in make.conf or the environment.
 
-if [[ ${PV} == 9999  ]]; then
-       GRUB_AUTORECONF=1
-       GRUB_BOOTSTRAP=1
-fi
-
+GRUB_AUTORECONF=1
 PYTHON_COMPAT=( python3_{10..12} )
 WANT_LIBTOOL=none
 VERIFY_SIG_OPENPGP_KEY_PATH=/usr/share/openpgp-keys/dkiper.gpg
@@ -29,7 +25,8 @@ if [[ -n ${GRUB_AUTORECONF} ]]; then
        inherit autotools
 fi
 
-inherit bash-completion-r1 flag-o-matic multibuild optfeature python-any-r1 
toolchain-funcs
+inherit bash-completion-r1 flag-o-matic multibuild optfeature python-any-r1
+inherit secureboot toolchain-funcs
 
 DESCRIPTION="GNU GRUB boot loader"
 HOMEPAGE="https://www.gnu.org/software/grub/";
@@ -49,6 +46,7 @@ if [[ ${PV} != 9999 ]]; then
        else
                SRC_URI="
                        mirror://gnu/${PN}/${P}.tar.xz
+                       
https://dev.gentoo.org/~floppym/dist/${P}-bash-completion.patch.gz
                        verify-sig? ( mirror://gnu/${PN}/${P}.tar.xz.sig )
                "
                S=${WORKDIR}/${P%_*}
@@ -161,6 +159,8 @@ src_prepare() {
                "${FILESDIR}"/gfxpayload.patch
                "${FILESDIR}"/grub-2.02_beta2-KERNEL_GLOBS.patch
                "${FILESDIR}"/grub-2.06-test-words.patch
+               "${FILESDIR}"/grub-2.12-fwsetup.patch
+               "${WORKDIR}"/grub-2.12-bash-completion.patch
        )
 
        default
@@ -177,6 +177,10 @@ src_prepare() {
        if [[ -n ${GRUB_AUTORECONF} ]]; then
                eautoreconf
        fi
+
+       # Avoid error due to extra_deps.lst missing from source tarball:
+       #       make[3]: *** No rule to make target 'grub-core/extra_deps.lst', 
needed by 'syminfo.lst'.  Stop.
+       echo "depends bli part_gpt" > grub-core/extra_deps.lst || die
 }
 
 grub_do() {
@@ -291,6 +295,70 @@ src_test() {
        grub_do emake -j1 check
 }
 
+grub_mkstandalone_secureboot() {
+       use secureboot || return
+
+       if tc-is-cross-compiler; then
+               ewarn "USE=secureboot is not supported when cross-compiling."
+               ewarn "No standalone EFI executable will be built."
+               return 1
+       fi
+
+       local standalone_targets
+
+       case ${CTARGET:-${CHOST}} in
+               i?86* | x86_64*)
+                       use grub_platforms_efi-32 && standalone_targets+=( 
i386-efi )
+                       use grub_platforms_efi-64 && standalone_targets+=( 
x86_64-efi )
+                       ;;
+               arm* | aarch64*)
+                       use grub_platforms_efi-32 && standalone_targets+=( 
arm-efi )
+                       use grub_platforms_efi-64 && standalone_targets+=( 
arm64-efi )
+                       ;;
+               riscv*)
+                       use grub_platforms_efi-32 && standalone_targets+=( 
riscv32-efi )
+                       use grub_platforms_efi-64 && standalone_targets+=( 
riscv64-efi )
+                       ;;
+               ia64*)
+                       use grub_platforms_efi-64 && standalone_targets+=( 
ia64-efi )
+                       ;;
+               loongarch64*)
+                       use grub_platforms_efi-64 && standalone_targets+=( 
loongarch64-efi )
+                       ;;
+       esac
+
+       if [[ ${#standalone_targets[@]} -eq 0 ]]; then
+               ewarn "USE=secureboot is enabled, but no suitable EFI target in 
GRUB_PLATFORMS."
+               ewarn "No standalone EFI executable will be built."
+               return 1
+       fi
+
+       local target mkstandalone_args
+
+       # grub-mkstandalone embeds a config file, make this config file 
chainload
+       # a config file in the same directory grub is installed in. This 
requires
+       # pre-loading the part_gpt and part_msdos modules.
+       echo 'configfile ${cmdpath}/grub.cfg' > "${T}/grub.cfg" || die
+       for target in "${standalone_targets[@]}"; do
+               ebegin "Building standalone EFI executable for ${target}"
+               mkstandalone_args=(
+                       --verbose
+                       --directory="${ED}/usr/lib/grub/${target}"
+                       --locale-directory="${ED}/usr/share/locale"
+                       --format="${target}"
+                       --modules="part_gpt part_msdos"
+                       --sbat="${ED}/usr/share/grub/sbat.csv"
+                       --output="${ED}/usr/lib/grub/grub-${target%-efi}.efi"
+                       "boot/grub/grub.cfg=${T}/grub.cfg"
+               )
+
+               "${ED}/usr/bin/grub-mkstandalone" "${mkstandalone_args[@]}"
+               eend ${?} || die "grub-mkstandalone failed to build EFI 
executable"
+       done
+
+       secureboot_auto_sign
+}
+
 src_install() {
        grub_do emake install DESTDIR="${D}" 
bashcompletiondir="$(get_bashcompdir)"
        use doc && grub_do_once emake -C docs install-html DESTDIR="${D}"
@@ -311,6 +379,8 @@ src_install() {
                # https://bugs.gentoo.org/900348
                QA_CONFIG_IMPL_DECL_SKIP=( 
re_{compile_pattern,match,search,set_syntax} )
        fi
+
+       grub_mkstandalone_secureboot
 }
 
 pkg_postinst() {
@@ -345,4 +415,21 @@ pkg_postinst() {
                ewarn "Due to security concerns, os-prober is disabled by 
default."
                ewarn "Set GRUB_DISABLE_OS_PROBER=false in /etc/default/grub to 
enable it."
        fi
+
+       if use secureboot; then
+               elog
+               elog "The signed standalone grub EFI executable(s) are 
available in:"
+               elog "    /usr/lib/grub/grub-<target>.efi(.signed)"
+               elog "These EFI executables should be copied to the usual 
location at:"
+               elog "    ESP/EFI/Gentoo/grub<arch>.efi"
+               elog "Note that 'grub-install' does not install these images."
+               elog
+               elog "These standalone grub executables read the grub config 
file from"
+               elog "the grub.cfg in the same directory instead of the default"
+               elog "/boot/grub/grub.cfg. When sys-kernel/installkernel[grub] 
is used,"
+               elog "the location of the grub.cfg may be overridden by setting 
the"
+               elog "GRUB_CFG environment variable:"
+               elog "     GRUB_CFG=ESP/EFI/Gentoo/grub.cfg"
+               elog
+       fi
 }

diff --git a/sys-boot/grub/grub-9999.ebuild b/sys-boot/grub/grub-9999.ebuild
index f007f3aaa884..2b24a0433912 100644
--- a/sys-boot/grub/grub-9999.ebuild
+++ b/sys-boot/grub/grub-9999.ebuild
@@ -29,7 +29,8 @@ if [[ -n ${GRUB_AUTORECONF} ]]; then
        inherit autotools
 fi
 
-inherit bash-completion-r1 flag-o-matic multibuild optfeature python-any-r1 
toolchain-funcs
+inherit bash-completion-r1 flag-o-matic multibuild optfeature python-any-r1
+inherit secureboot toolchain-funcs
 
 DESCRIPTION="GNU GRUB boot loader"
 HOMEPAGE="https://www.gnu.org/software/grub/";
@@ -291,6 +292,70 @@ src_test() {
        grub_do emake -j1 check
 }
 
+grub_mkstandalone_secureboot() {
+       use secureboot || return
+
+       if tc-is-cross-compiler; then
+               ewarn "USE=secureboot is not supported when cross-compiling."
+               ewarn "No standalone EFI executable will be built."
+               return 1
+       fi
+
+       local standalone_targets
+
+       case ${CTARGET:-${CHOST}} in
+               i?86* | x86_64*)
+                       use grub_platforms_efi-32 && standalone_targets+=( 
i386-efi )
+                       use grub_platforms_efi-64 && standalone_targets+=( 
x86_64-efi )
+                       ;;
+               arm* | aarch64*)
+                       use grub_platforms_efi-32 && standalone_targets+=( 
arm-efi )
+                       use grub_platforms_efi-64 && standalone_targets+=( 
arm64-efi )
+                       ;;
+               riscv*)
+                       use grub_platforms_efi-32 && standalone_targets+=( 
riscv32-efi )
+                       use grub_platforms_efi-64 && standalone_targets+=( 
riscv64-efi )
+                       ;;
+               ia64*)
+                       use grub_platforms_efi-64 && standalone_targets+=( 
ia64-efi )
+                       ;;
+               loongarch64*)
+                       use grub_platforms_efi-64 && standalone_targets+=( 
loongarch64-efi )
+                       ;;
+       esac
+
+       if [[ ${#standalone_targets[@]} -eq 0 ]]; then
+               ewarn "USE=secureboot is enabled, but no suitable EFI target in 
GRUB_PLATFORMS."
+               ewarn "No standalone EFI executable will be built."
+               return 1
+       fi
+
+       local target mkstandalone_args
+
+       # grub-mkstandalone embeds a config file, make this config file 
chainload
+       # a config file in the same directory grub is installed in. This 
requires
+       # pre-loading the part_gpt and part_msdos modules.
+       echo 'configfile ${cmdpath}/grub.cfg' > "${T}/grub.cfg" || die
+       for target in "${standalone_targets[@]}"; do
+               ebegin "Building standalone EFI executable for ${target}"
+               mkstandalone_args=(
+                       --verbose
+                       --directory="${ED}/usr/lib/grub/${target}"
+                       --locale-directory="${ED}/usr/share/locale"
+                       --format="${target}"
+                       --modules="part_gpt part_msdos"
+                       --sbat="${ED}/usr/share/grub/sbat.csv"
+                       --output="${ED}/usr/lib/grub/grub-${target%-efi}.efi"
+                       "boot/grub/grub.cfg=${T}/grub.cfg"
+               )
+
+               "${ED}/usr/bin/grub-mkstandalone" "${mkstandalone_args[@]}"
+               eend ${?} || die "grub-mkstandalone failed to build EFI 
executable"
+       done
+
+       secureboot_auto_sign
+}
+
 src_install() {
        grub_do emake install DESTDIR="${D}" 
bashcompletiondir="$(get_bashcompdir)"
        use doc && grub_do_once emake -C docs install-html DESTDIR="${D}"
@@ -311,6 +376,8 @@ src_install() {
                # https://bugs.gentoo.org/900348
                QA_CONFIG_IMPL_DECL_SKIP=( 
re_{compile_pattern,match,search,set_syntax} )
        fi
+
+       grub_mkstandalone_secureboot
 }
 
 pkg_postinst() {
@@ -345,4 +412,21 @@ pkg_postinst() {
                ewarn "Due to security concerns, os-prober is disabled by 
default."
                ewarn "Set GRUB_DISABLE_OS_PROBER=false in /etc/default/grub to 
enable it."
        fi
+
+       if use secureboot; then
+               elog
+               elog "The signed standalone grub EFI executable(s) are 
available in:"
+               elog "    /usr/lib/grub/grub-<target>.efi(.signed)"
+               elog "These EFI executables should be copied to the usual 
location at:"
+               elog "    ESP/EFI/Gentoo/grub<arch>.efi"
+               elog "Note that 'grub-install' does not install these images."
+               elog
+               elog "These standalone grub executables read the grub config 
file from"
+               elog "the grub.cfg in the same directory instead of the default"
+               elog "/boot/grub/grub.cfg. When sys-kernel/installkernel[grub] 
is used,"
+               elog "the location of the grub.cfg may be overridden by setting 
the"
+               elog "GRUB_CFG environment variable:"
+               elog "     GRUB_CFG=ESP/EFI/Gentoo/grub.cfg"
+               elog
+       fi
 }

Reply via email to