aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2023-05-17 14:36:25 +0100
committerMichael Brown <mcb30@ipxe.org>2023-05-17 14:40:50 +0100
commit79d85e29aa09c47f1d5a2be9eddd10e61fb22035 (patch)
tree1ee9b6e740ac7d1d114fb7d66fdddd30d3ae96ee
parentd27cd8196de031c306e7c103df5711bb55e68fdd (diff)
downloadipxe-79d85e29aa09c47f1d5a2be9eddd10e61fb22035.zip
ipxe-79d85e29aa09c47f1d5a2be9eddd10e61fb22035.tar.gz
ipxe-79d85e29aa09c47f1d5a2be9eddd10e61fb22035.tar.bz2
[efi] Attempt to detect EFI images that fail Secure Boot verification
An EFI image that is rejected by LoadImage() due to failing Secure Boot verification is still an EFI image. Unfortunately, the extremely broken UEFI Secure Boot model provides no way for us to unambiguously determine that a valid EFI executable image was rejected only because it failed signature verification. We must therefore use heuristics to guess whether not an image that was rejected by LoadImage() could still be loaded via a separate PE loader such as the UEFI shim. Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/image/efi_image.c76
1 files changed, 71 insertions, 5 deletions
diff --git a/src/image/efi_image.c b/src/image/efi_image.c
index 0be4856..6a7bba0 100644
--- a/src/image/efi_image.c
+++ b/src/image/efi_image.c
@@ -356,9 +356,75 @@ static int efi_image_probe ( struct image *image ) {
return rc;
}
-/** EFI image type */
-struct image_type efi_image_type __image_type ( PROBE_NORMAL ) = {
- .name = "EFI",
- .probe = efi_image_probe,
- .exec = efi_image_exec,
+/**
+ * Probe EFI PE image
+ *
+ * @v image EFI file
+ * @ret rc Return status code
+ *
+ * The extremely broken UEFI Secure Boot model provides no way for us
+ * to unambiguously determine that a valid EFI executable image was
+ * rejected by LoadImage() because it failed signature verification.
+ * We must therefore use heuristics to guess whether not an image that
+ * was rejected by LoadImage() could still be loaded via a separate PE
+ * loader such as the UEFI shim.
+ */
+static int efi_pe_image_probe ( struct image *image ) {
+ const UINT16 magic = ( ( sizeof ( UINTN ) == sizeof ( uint32_t ) ) ?
+ EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC :
+ EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC );
+ union {
+ EFI_IMAGE_DOS_HEADER dos;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION pe;
+ } u;
+
+ /* Check for existence of DOS header */
+ if ( image->len < sizeof ( u.dos ) ) {
+ DBGC ( image, "EFIIMAGE %s too short for DOS header\n",
+ image->name );
+ return -ENOEXEC;
+ }
+ copy_from_user ( &u.dos, image->data, 0, sizeof ( u.dos ) );
+ if ( u.dos.e_magic != EFI_IMAGE_DOS_SIGNATURE ) {
+ DBGC ( image, "EFIIMAGE %s missing MZ signature\n",
+ image->name );
+ return -ENOEXEC;
+ }
+
+ /* Check for existence of PE header */
+ if ( ( image->len < u.dos.e_lfanew ) ||
+ ( ( image->len - u.dos.e_lfanew ) < sizeof ( u.pe ) ) ) {
+ DBGC ( image, "EFIIMAGE %s too short for PE header\n",
+ image->name );
+ return -ENOEXEC;
+ }
+ copy_from_user ( &u.pe, image->data, u.dos.e_lfanew, sizeof ( u.pe ) );
+ if ( u.pe.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE ) {
+ DBGC ( image, "EFIIMAGE %s missing PE signature\n",
+ image->name );
+ return -ENOEXEC;
+ }
+
+ /* Check PE header magic */
+ if ( u.pe.Pe32.OptionalHeader.Magic != magic ) {
+ DBGC ( image, "EFIIMAGE %s incorrect magic %04x\n",
+ image->name, u.pe.Pe32.OptionalHeader.Magic );
+ return -ENOEXEC;
+ }
+
+ return 0;
+}
+
+/** EFI image types */
+struct image_type efi_image_type[] __image_type ( PROBE_NORMAL ) = {
+ {
+ .name = "EFI",
+ .probe = efi_image_probe,
+ .exec = efi_image_exec,
+ },
+ {
+ .name = "EFIPE",
+ .probe = efi_pe_image_probe,
+ .exec = efi_image_exec,
+ },
};