]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Allow EFI_USB_IO_PROTOCOL interfaces to be nullified and leaked
authorMichael Brown <mcb30@ipxe.org>
Thu, 17 Dec 2020 21:46:52 +0000 (21:46 +0000)
committerMichael Brown <mcb30@ipxe.org>
Thu, 17 Dec 2020 21:46:52 +0000 (21:46 +0000)
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/include/ipxe/efi/efi_null.h
src/interface/efi/efi_null.c
src/interface/efi/efi_usb.c

index cc91e09bbb2b4b429510967ebd21fe3333fe48e4..297457081817e81f1cac48266b89a94b362c08ab 100644 (file)
@@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h>
 #include <ipxe/efi/Protocol/PxeBaseCode.h>
 #include <ipxe/efi/Protocol/SimpleNetwork.h>
+#include <ipxe/efi/Protocol/UsbIo.h>
 
 extern void efi_nullify_snp ( EFI_SIMPLE_NETWORK_PROTOCOL *snp );
 extern void efi_nullify_nii ( EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *nii );
@@ -27,5 +28,6 @@ extern void efi_nullify_hii ( EFI_HII_CONFIG_ACCESS_PROTOCOL *hii );
 extern void efi_nullify_block ( EFI_BLOCK_IO_PROTOCOL *block );
 extern void efi_nullify_pxe ( EFI_PXE_BASE_CODE_PROTOCOL *pxe );
 extern void efi_nullify_apple ( EFI_APPLE_NET_BOOT_PROTOCOL *apple );
+extern void efi_nullify_usbio ( EFI_USB_IO_PROTOCOL *usbio );
 
 #endif /* _IPXE_EFI_NULL_H */
index aa27ab67401672498135d5670528cec29f881f09..29ca5b9b6c85803e62c29f58d565cf00c99f3b9f 100644 (file)
@@ -530,3 +530,143 @@ void efi_nullify_apple ( EFI_APPLE_NET_BOOT_PROTOCOL *apple ) {
 
        memcpy ( apple, &efi_null_apple, sizeof ( *apple ) );
 }
+
+/******************************************************************************
+ *
+ * USB I/O Protocol
+ *
+ ******************************************************************************
+ */
+
+static EFI_STATUS EFIAPI
+efi_null_usb_control_transfer ( EFI_USB_IO_PROTOCOL *usbio __unused,
+                               EFI_USB_DEVICE_REQUEST *packet __unused,
+                               EFI_USB_DATA_DIRECTION direction __unused,
+                               UINT32 timeout __unused, VOID *data __unused,
+                               UINTN len __unused, UINT32 *status __unused ) {
+       return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_usb_bulk_transfer ( EFI_USB_IO_PROTOCOL *usbio __unused,
+                            UINT8 endpoint __unused, VOID *data __unused,
+                            UINTN *len __unused, UINTN timeout __unused,
+                            UINT32 *status __unused ) {
+       return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_usb_sync_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio __unused,
+                                      UINT8 endpoint __unused,
+                                      VOID *data __unused,
+                                      UINTN *len __unused,
+                                      UINTN timeout __unused,
+                                      UINT32 *status __unused ) {
+       return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_usb_async_interrupt_transfer ( EFI_USB_IO_PROTOCOL *usbio __unused,
+                                       UINT8 endpoint __unused,
+                                       BOOLEAN start __unused,
+                                       UINTN interval __unused,
+                                       UINTN len __unused,
+                                       EFI_ASYNC_USB_TRANSFER_CALLBACK
+                                       callback __unused,
+                                       VOID *context __unused ) {
+       return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_usb_isochronous_transfer ( EFI_USB_IO_PROTOCOL *usbio __unused,
+                                   UINT8 endpoint __unused,
+                                   VOID *data __unused, UINTN len __unused,
+                                   UINT32 *status __unused ) {
+       return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_usb_async_isochronous_transfer ( EFI_USB_IO_PROTOCOL *usbio __unused,
+                                         UINT8 endpoint __unused,
+                                         VOID *data __unused,
+                                         UINTN len __unused,
+                                         EFI_ASYNC_USB_TRANSFER_CALLBACK
+                                         callback __unused,
+                                         VOID *context __unused ) {
+       return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_usb_get_device_descriptor ( EFI_USB_IO_PROTOCOL *usbio __unused,
+                                    EFI_USB_DEVICE_DESCRIPTOR
+                                    *efidesc __unused ) {
+       return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_usb_get_config_descriptor ( EFI_USB_IO_PROTOCOL *usbio __unused,
+                                    EFI_USB_CONFIG_DESCRIPTOR
+                                    *efidesc __unused ) {
+       return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_usb_get_interface_descriptor ( EFI_USB_IO_PROTOCOL *usbio __unused,
+                                       EFI_USB_INTERFACE_DESCRIPTOR
+                                       *efidesc __unused ) {
+       return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_usb_get_endpoint_descriptor ( EFI_USB_IO_PROTOCOL *usbio __unused,
+                                      UINT8 index __unused,
+                                      EFI_USB_ENDPOINT_DESCRIPTOR
+                                      *efidesc __unused ) {
+       return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_usb_get_string_descriptor ( EFI_USB_IO_PROTOCOL *usbio __unused,
+                                    UINT16 language __unused,
+                                    UINT8 index __unused,
+                                    CHAR16 **string __unused ) {
+       return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_usb_get_supported_languages ( EFI_USB_IO_PROTOCOL *usbio __unused,
+                                      UINT16 **languages __unused,
+                                      UINT16 *len __unused ) {
+       return EFI_UNSUPPORTED;
+}
+
+static EFI_STATUS EFIAPI
+efi_null_usb_port_reset ( EFI_USB_IO_PROTOCOL *usbio __unused ) {
+       return EFI_UNSUPPORTED;
+}
+
+static EFI_USB_IO_PROTOCOL efi_null_usbio = {
+       .UsbControlTransfer          = efi_null_usb_control_transfer,
+       .UsbBulkTransfer             = efi_null_usb_bulk_transfer,
+       .UsbAsyncInterruptTransfer   = efi_null_usb_async_interrupt_transfer,
+       .UsbSyncInterruptTransfer    = efi_null_usb_sync_interrupt_transfer,
+       .UsbIsochronousTransfer      = efi_null_usb_isochronous_transfer,
+       .UsbAsyncIsochronousTransfer = efi_null_usb_async_isochronous_transfer,
+       .UsbGetDeviceDescriptor      = efi_null_usb_get_device_descriptor,
+       .UsbGetConfigDescriptor      = efi_null_usb_get_config_descriptor,
+       .UsbGetInterfaceDescriptor   = efi_null_usb_get_interface_descriptor,
+       .UsbGetEndpointDescriptor    = efi_null_usb_get_endpoint_descriptor,
+       .UsbGetStringDescriptor      = efi_null_usb_get_string_descriptor,
+       .UsbGetSupportedLanguages    = efi_null_usb_get_supported_languages,
+       .UsbPortReset                = efi_null_usb_port_reset,
+};
+
+/**
+ * Nullify USB I/O protocol
+ *
+ * @v usbio            USB I/O protocol
+ */
+void efi_nullify_usbio ( EFI_USB_IO_PROTOCOL *usbio ) {
+
+       memcpy ( usbio, &efi_null_usbio, sizeof ( *usbio ) );
+}
index bcf156999da8ff9da2040ba1ff5d777822def8c2..df66df45f1b5e3d1e401e422b7800ef5b81cd14b 100644 (file)
@@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 #include <ipxe/efi/efi.h>
 #include <ipxe/efi/efi_path.h>
 #include <ipxe/efi/efi_driver.h>
+#include <ipxe/efi/efi_null.h>
 #include <ipxe/efi/efi_usb.h>
 #include <ipxe/usb.h>
 
@@ -1106,6 +1107,7 @@ static int efi_usb_install ( struct efi_usb_device *usbdev,
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct usb_function *func = usbdev->func;
        struct efi_usb_interface *usbintf;
+       int leak = 0;
        EFI_STATUS efirc;
        int rc;
 
@@ -1148,19 +1150,30 @@ static int efi_usb_install ( struct efi_usb_device *usbdev,
               usbintf->name, efi_handle_name ( usbintf->handle ) );
        return 0;
 
-       bs->UninstallMultipleProtocolInterfaces (
+       if ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
                        usbintf->handle,
                        &efi_usb_io_protocol_guid, &usbintf->usbio,
                        &efi_device_path_protocol_guid, usbintf->path,
-                       NULL );
+                       NULL ) ) != 0 ) {
+               DBGC ( usbdev, "USBDEV %s could not uninstall: %s\n",
+                      usbintf->name, strerror ( -EEFI ( efirc ) ) );
+               leak = 1;
+       }
+       efi_nullify_usbio ( &usbintf->usbio );
  err_install_protocol:
        efi_usb_close_all ( usbintf );
        efi_usb_free_all ( usbintf );
        list_del ( &usbintf->list );
-       free ( usbintf->path );
+       if ( ! leak )
+               free ( usbintf->path );
  err_path:
-       free ( usbintf );
+       if ( ! leak )
+               free ( usbintf );
  err_alloc:
+       if ( leak ) {
+               DBGC ( usbdev, "USBDEV %s nullified and leaked\n",
+                      usbintf->name );
+       }
        return rc;
 }
 
@@ -1172,6 +1185,8 @@ static int efi_usb_install ( struct efi_usb_device *usbdev,
 static void efi_usb_uninstall ( struct efi_usb_interface *usbintf ) {
        EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
        struct efi_usb_device *usbdev = usbintf->usbdev;
+       int leak = efi_shutdown_in_progress;
+       EFI_STATUS efirc;
 
        DBGC ( usbdev, "USBDEV %s uninstalling %s\n",
               usbintf->name, efi_handle_name ( usbintf->handle ) );
@@ -1180,14 +1195,21 @@ static void efi_usb_uninstall ( struct efi_usb_interface *usbintf ) {
         * seems to be required on some platforms to avoid failures
         * when uninstalling protocols.
         */
-       bs->DisconnectController ( usbintf->handle, NULL, NULL );
+       if ( ! efi_shutdown_in_progress )
+               bs->DisconnectController ( usbintf->handle, NULL, NULL );
 
        /* Uninstall protocols */
-       bs->UninstallMultipleProtocolInterfaces (
+       if ( ( ! efi_shutdown_in_progress ) &&
+            ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
                        usbintf->handle,
                        &efi_usb_io_protocol_guid, &usbintf->usbio,
                        &efi_device_path_protocol_guid, usbintf->path,
-                       NULL );
+                       NULL ) ) != 0 ) ) {
+               DBGC ( usbdev, "USBDEV %s could not uninstall: %s\n",
+                      usbintf->name, strerror ( -EEFI ( efirc ) ) );
+               leak = 1;
+       }
+       efi_nullify_usbio ( &usbintf->usbio );
 
        /* Close and free all endpoints */
        efi_usb_close_all ( usbintf );
@@ -1197,10 +1219,18 @@ static void efi_usb_uninstall ( struct efi_usb_interface *usbintf ) {
        list_del ( &usbintf->list );
 
        /* Free device path */
-       free ( usbintf->path );
+       if ( ! leak )
+               free ( usbintf->path );
 
        /* Free interface */
-       free ( usbintf );
+       if ( ! leak )
+               free ( usbintf );
+
+       /* Report leakage, if applicable */
+       if ( leak && ( ! efi_shutdown_in_progress ) ) {
+               DBGC ( usbdev, "USBDEV %s nullified and leaked\n",
+                      usbintf->name );
+       }
 }
 
 /**