aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2023-06-08 11:29:07 +0100
committerMichael Brown <mcb30@ipxe.org>2023-06-08 11:29:07 +0100
commit212c3a35009dedfc0c100fdcdc76b19e37928210 (patch)
tree49f928e45a45b6b146c86aec598d119ee970d50b
parent8ab9bdca4f3aa5dbd6c277e5340b4071b952e061 (diff)
downloadipxe-esx.zip
ipxe-esx.tar.gz
ipxe-esx.tar.bz2
[efi] Veto the VMware UefiPxeBcDxe driveresx
The EDK2 UefiPxeBcDxe driver includes some remarkably convoluted and unsafe logic in its driver binding protocol Start() and Stop() methods in order to support a pair of nominally independent driver binding protocols (one for IPv4, one for IPv6) sharing a single dynamically allocated data structure. This PXEBC_PRIVATE_DATA structure is installed as a dummy protocol on the NIC handle in order to allow both IPv4 and IPv6 driver binding protocols to locate it as needed. The error handling code path in the UefiPxeBcDxe driver's Start() method may attempt to uninstall the dummy protocol but fail to do so. This failure is ignored and the containing memory is subsequently freed anyway. On the next invocation of the driver binding protocol, it will find and use the already freed block of memory. At some point another memory allocation will occur, the PXEBC_PRIVATE_DATA structure will be corrupted, and some undefined behaviour will occur. The UEFI firmware used in VMware ESX 8 includes some proprietary changes which attempt to install copies of the EFI_LOAD_FILE_PROTOCOL and EFI_PXE_BASE_CODE_PROTOCOL instances from the IPv4 child handle onto the NIC handle (along with a VMware-specific protocol with GUID 5190120d-453b-4d48-958d-f0bab3bc2161 and a NULL instance pointer). This will inevitably fail with iPXE, since the NIC handle already includes an EFI_LOAD_FILE_PROTOCOL instance. These VMware proprietary changes end up triggering the unsafe error handling code path described above. The typical symptom is that an attempt to exit from iPXE back to the UEFI firmware will crash the VM with a General Protection fault from within the UefiPxeBcDxe driver: this happens when the UefiPxeBcDriver's Stop() method attempts to call through a function pointer in the (freed) PXEBC_PRIVATE_DATA structure, but the function pointer has been overwritten by UCS-2 character data from a separate memory allocation. Work around this failure by adding the VMware UefiPxeBcDxe driver to the driver veto list. Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/interface/efi/efi_veto.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/src/interface/efi/efi_veto.c b/src/interface/efi/efi_veto.c
index b616539..19e529a 100644
--- a/src/interface/efi/efi_veto.c
+++ b/src/interface/efi/efi_veto.c
@@ -435,6 +435,37 @@ efi_veto_hp_xhci ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
return 0;
}
+/**
+ * Veto VMware UefiPxeBcDxe driver
+ *
+ * @v binding Driver binding protocol
+ * @v loaded Loaded image protocol
+ * @v wtf Component name protocol, if present
+ * @v manufacturer Manufacturer name, if present
+ * @v name Driver name, if present
+ * @ret vetoed Driver is to be vetoed
+ */
+static int
+efi_veto_vmware_uefipxebc ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
+ EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
+ EFI_COMPONENT_NAME_PROTOCOL *wtf __unused,
+ const char *manufacturer, const CHAR16 *name ) {
+ static const CHAR16 uefipxebc[] = L"UEFI PXE Base Code Driver";
+ static const char *vmware = "VMware, Inc.";
+
+ /* Check manufacturer and driver name */
+ if ( ! manufacturer )
+ return 0;
+ if ( ! name )
+ return 0;
+ if ( strcmp ( manufacturer, vmware ) != 0 )
+ return 0;
+ if ( memcmp ( name, uefipxebc, sizeof ( uefipxebc ) ) != 0 )
+ return 0;
+
+ return 1;
+}
+
/** Driver vetoes */
static struct efi_veto efi_vetoes[] = {
{
@@ -445,6 +476,10 @@ static struct efi_veto efi_vetoes[] = {
.name = "HP Xhci",
.veto = efi_veto_hp_xhci,
},
+ {
+ .name = "VMware UefiPxeBc",
+ .veto = efi_veto_vmware_uefipxebc,
+ },
};
/**