Skip to content

Commit 212c3a3

Browse files
committed
[efi] Veto the VMware UefiPxeBcDxe driver
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 <[email protected]>
1 parent 8ab9bdc commit 212c3a3

File tree

1 file changed

+35
-0
lines changed

1 file changed

+35
-0
lines changed

src/interface/efi/efi_veto.c

+35
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,37 @@ efi_veto_hp_xhci ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
435435
return 0;
436436
}
437437

438+
/**
439+
* Veto VMware UefiPxeBcDxe driver
440+
*
441+
* @v binding Driver binding protocol
442+
* @v loaded Loaded image protocol
443+
* @v wtf Component name protocol, if present
444+
* @v manufacturer Manufacturer name, if present
445+
* @v name Driver name, if present
446+
* @ret vetoed Driver is to be vetoed
447+
*/
448+
static int
449+
efi_veto_vmware_uefipxebc ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
450+
EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
451+
EFI_COMPONENT_NAME_PROTOCOL *wtf __unused,
452+
const char *manufacturer, const CHAR16 *name ) {
453+
static const CHAR16 uefipxebc[] = L"UEFI PXE Base Code Driver";
454+
static const char *vmware = "VMware, Inc.";
455+
456+
/* Check manufacturer and driver name */
457+
if ( ! manufacturer )
458+
return 0;
459+
if ( ! name )
460+
return 0;
461+
if ( strcmp ( manufacturer, vmware ) != 0 )
462+
return 0;
463+
if ( memcmp ( name, uefipxebc, sizeof ( uefipxebc ) ) != 0 )
464+
return 0;
465+
466+
return 1;
467+
}
468+
438469
/** Driver vetoes */
439470
static struct efi_veto efi_vetoes[] = {
440471
{
@@ -445,6 +476,10 @@ static struct efi_veto efi_vetoes[] = {
445476
.name = "HP Xhci",
446477
.veto = efi_veto_hp_xhci,
447478
},
479+
{
480+
.name = "VMware UefiPxeBc",
481+
.veto = efi_veto_vmware_uefipxebc,
482+
},
448483
};
449484

450485
/**

0 commit comments

Comments
 (0)