diff options
author | Nowa Ammerlaan <nowa@gentoo.org> | 2025-01-09 19:22:39 +0100 |
---|---|---|
committer | Nowa Ammerlaan <nowa@gentoo.org> | 2025-01-10 17:44:19 +0100 |
commit | 422a7e51c1e1a7774e406e3f0856b4e415fee46f (patch) | |
tree | 93bf71d3be96812f57dc86f565462ea46cc3f39b /eclass | |
parent | media-gfx/freecad: new revision 1.0.0-r3 (diff) | |
download | gentoo-422a7e51c1e1a7774e406e3f0856b4e415fee46f.tar.gz gentoo-422a7e51c1e1a7774e406e3f0856b4e415fee46f.tar.bz2 gentoo-422a7e51c1e1a7774e406e3f0856b4e415fee46f.zip |
kernel-install.eclass: verify uki/kernel image before installing
This avoids accidentally installing a kernel image or generic UKI with an
invalid signature in both gentoo-kernel and gentoo-kernel-bin. This means we
will catch regressions such as described below earlier, notably it will now
error out when building the binpkgs for gentoo-kernel-bin.
We also add some logic to recover from the case where the kernel image is
larger then it should be. This may be the case with ukify>=257 because starting
from this version onwards the space that the kernel needs to extract and run
is reserved in the .linux section of the UKI as padding. Objcopy unfortunately
copies this padding along with the rest of the data, invalidating the signature.
In previous versions of ukify this was not an issue because the .linux section
was always the last section in the UKI and you could therefore usually get away
with not reserving the extra required space.
Sbverify helpfully reports a warning about this padding with the exact size
the kernel image should have. We use this to strip the padding from the
kernel image, and verify if the signature problem is now resolved. There may be
a better way to do this that does not involve parsing the output of sbverify,
but I have not been able to find any.
See-also: https://github.com/systemd/systemd/issues/35851
See-also: https://forums.gentoo.org/viewtopic-t-1172386.html
Signed-off-by: Nowa Ammerlaan <nowa@gentoo.org>
Diffstat (limited to 'eclass')
-rw-r--r-- | eclass/kernel-install.eclass | 59 |
1 files changed, 56 insertions, 3 deletions
diff --git a/eclass/kernel-install.eclass b/eclass/kernel-install.eclass index 1cc2bd0bb737..cf34007844a8 100644 --- a/eclass/kernel-install.eclass +++ b/eclass/kernel-install.eclass @@ -204,6 +204,7 @@ if [[ ${KERNEL_IUSE_GENERIC_UKI} ]]; then " IDEPEND=" generic-uki? ( + app-crypt/sbsigntools >=sys-kernel/installkernel-14[-dracut(-),-ugrd(-),-ukify(-)] ) !generic-uki? ( @@ -660,13 +661,65 @@ kernel-install_extract_from_uki() { local extract_type=${1} local uki=${2} local out=${3} + local out_temp=${T}/${extract_type}-section-dumped # objcopy overwrites input if there is no output, dump the output in T. # We unfortunately cannot use /dev/null here $(tc-getOBJCOPY) "${uki}" "${T}/dump.efi" \ - --dump-section ".${extract_type}=${out}" || - die "Failed to extract ${extract_type}" - chmod 644 "${out}" || die + --dump-section ".${extract_type}=${out_temp}" || + die "Failed to extract ${extract_type}" + + # Sanity checks for kernel images + if [[ ${extract_type} == linux ]] && + { ! in_iuse secureboot || use secureboot ;} + then + # Extract the used SECUREBOOT_SIGN_CERT to verify the kernel image + local cert=${T}/pcrpkey + kernel-install_extract_from_uki pcrpkey "${uki}" "${cert}" + if [[ $(head -n1 "${cert}") != "-----BEGIN CERTIFICATE-----" ]]; then + # This is a DER format certificate, convert it to PEM + openssl x509 \ + -inform DER -in "${cert}" \ + -outform PEM -out "${cert}" || + die "Failed to convert pcrpkey to PEM format" + fi + + # Check if the signature on the UKI is valid + sbverify --cert "${cert}" "${uki}" || + die "ERROR: UKI signature is invalid" + + # Check if the signature on the kernel image is valid + local sbverify_err=$( + sbverify --cert "${cert}" "${out_temp}" 2>&1 >/dev/null + ) + + # Check if there was a padding warning + if [[ ${sbverify_err} == "warning: data remaining"*": gaps between PE/COFF sections?"* ]] + then + # https://github.com/systemd/systemd/issues/35851 + local proper_size=${sbverify_err#"warning: data remaining["} + proper_size=${proper_size%" vs"*} + # Strip the padding + head "${out_temp}" --bytes "${proper_size}" \ + >"${out_temp}_trimmed" || die + # Check if the signature verifies now + sbverify_err=$( + sbverify --cert "${cert}" "${out_temp}_trimmed" 2>&1 >/dev/null + ) + [[ -z ${sbverify_err} ]] && out_temp=${out_temp}_trimmed + fi + + # Something has gone wrong, stop here to prevent installing a kernel + # with an invalid signature or a completely broken kernel image. + if [[ -n ${sbverify_err} ]]; then + eerror "${sbverify_err}" + die "ERROR: Kernel image signature is invalid" + else + einfo "Signature verification OK" + fi + fi + + install -m 644 "${out_temp}" "${out}" || die } # @FUNCTION: kernel-install_install_all |