summaryrefslogtreecommitdiffstats
path: root/src/interface/efi/efi_snp.c
diff options
context:
space:
mode:
authorMichael Brown2020-12-17 21:37:27 +0100
committerMichael Brown2020-12-17 22:32:49 +0100
commit6769a7c3c669cbb0455c7d83a3257c4582cf683d (patch)
treed2fe6e941df207b447fb823923e1d35bf08af10c /src/interface/efi/efi_snp.c
parent[efi] Nullify interfaces unconditionally on error and shutdown paths (diff)
downloadipxe-6769a7c3c669cbb0455c7d83a3257c4582cf683d.tar.gz
ipxe-6769a7c3c669cbb0455c7d83a3257c4582cf683d.tar.xz
ipxe-6769a7c3c669cbb0455c7d83a3257c4582cf683d.zip
[efi] Skip interface uninstallation during shutdown
iPXE seems to be almost alone in the UEFI world in attempting to shut down cleanly, free resources, and leave hardware in a well-defined reset state before handing over to the booted operating system. The UEFI driver model does allow for graceful shutdown via uninstallation of protocol interfaces. However, virtually no other UEFI drivers do this, and the external code paths that react to uninstallation are consequently poorly tested. This leads to a proliferation of bugs found in UEFI implementations in the wild, as described in commits such as 1295b4a ("[efi] Allow initialisation via SNP interface even while claimed") or b6e2ea0 ("[efi] Veto the HP XhciDxe Driver"). Try to avoid triggering such bugs by unconditionally skipping the protocol interface uninstallation during UEFI boot services shutdown, leaving the interfaces present but nullified and deliberately leaking the containing memory. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/interface/efi/efi_snp.c')
-rw-r--r--src/interface/efi/efi_snp.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c
index c08383e49..6649eb1b0 100644
--- a/src/interface/efi/efi_snp.c
+++ b/src/interface/efi/efi_snp.c
@@ -1873,7 +1873,7 @@ static void efi_snp_notify ( struct net_device *netdev ) {
static void efi_snp_remove ( struct net_device *netdev ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
struct efi_snp_device *snpdev;
- int leak = 0;
+ int leak = efi_shutdown_in_progress;
EFI_STATUS efirc;
/* Locate SNP device */
@@ -1892,7 +1892,8 @@ static void efi_snp_remove ( struct net_device *netdev ) {
efi_image_handle, snpdev->handle );
bs->CloseProtocol ( snpdev->handle, &efi_nii31_protocol_guid,
efi_image_handle, snpdev->handle );
- if ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
+ if ( ( ! efi_shutdown_in_progress ) &&
+ ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
snpdev->handle,
&efi_simple_network_protocol_guid, &snpdev->snp,
&efi_device_path_protocol_guid, snpdev->path,
@@ -1900,7 +1901,7 @@ static void efi_snp_remove ( struct net_device *netdev ) {
&efi_nii31_protocol_guid, &snpdev->nii,
&efi_component_name2_protocol_guid, &snpdev->name2,
&efi_load_file_protocol_guid, &snpdev->load_file,
- NULL ) ) != 0 ) {
+ NULL ) ) != 0 ) ) {
DBGC ( snpdev, "SNPDEV %p could not uninstall: %s\n",
snpdev, strerror ( -EEFI ( efirc ) ) );
leak = 1;
@@ -1918,7 +1919,7 @@ static void efi_snp_remove ( struct net_device *netdev ) {
}
/* Report leakage, if applicable */
- if ( leak )
+ if ( leak && ( ! efi_shutdown_in_progress ) )
DBGC ( snpdev, "SNPDEV %p nullified and leaked\n", snpdev );
}