summaryrefslogtreecommitdiff
path: root/src
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 /src
parentd27cd8196de031c306e7c103df5711bb55e68fdd (diff)
downloadqemu-ipxe-master.tar.gz
[efi] Attempt to detect EFI images that fail Secure Boot verificationHEADmastercoverity_scan
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>
Diffstat (limited to 'src')
-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 0be48564..6a7bba01 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,
+ },
};