iPXE
efi_blacklist.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2019 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  */
00019 
00020 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00021 
00022 #include <stddef.h>
00023 #include <string.h>
00024 #include <errno.h>
00025 #include <ipxe/settings.h>
00026 #include <ipxe/efi/efi.h>
00027 #include <ipxe/efi/Protocol/DriverBinding.h>
00028 #include <ipxe/efi/Protocol/LoadedImage.h>
00029 #include <ipxe/efi/Protocol/ComponentName.h>
00030 #include <ipxe/efi/efi_blacklist.h>
00031 
00032 /** @file
00033  *
00034  * EFI driver blacklist
00035  *
00036  */
00037 
00038 /** A blacklisted driver */
00039 struct efi_blacklist {
00040         /** Name */
00041         const char *name;
00042         /**
00043          * Check if driver is blacklisted
00044          *
00045          * @v binding           Driver binding protocol
00046          * @v loaded            Loaded image protocol
00047          * @v wtf               Component name protocol, if present
00048          * @ret blacklisted     Driver is the blacklisted driver
00049          */
00050         int ( * blacklist ) ( EFI_DRIVER_BINDING_PROTOCOL *binding,
00051                               EFI_LOADED_IMAGE_PROTOCOL *loaded,
00052                               EFI_COMPONENT_NAME_PROTOCOL *wtf );
00053 };
00054 
00055 /**
00056  * Blacklist Dell Ip4ConfigDxe driver
00057  *
00058  * @v binding           Driver binding protocol
00059  * @v loaded            Loaded image protocol
00060  * @v wtf               Component name protocol, if present
00061  * @ret blacklisted     Driver is the blacklisted driver
00062  */
00063 static int
00064 efi_blacklist_dell_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
00065                                EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
00066                                EFI_COMPONENT_NAME_PROTOCOL *wtf ) {
00067         static const CHAR16 ip4cfg[] = L"IP4 CONFIG Network Service Driver";
00068         static const char dell[] = "Dell Inc.";
00069         char manufacturer[ sizeof ( dell ) ];
00070         CHAR16 *name;
00071 
00072         /* Check driver name */
00073         if ( ! wtf )
00074                 return 0;
00075         if ( wtf->GetDriverName ( wtf, "eng", &name ) != 0 )
00076                 return 0;
00077         if ( memcmp ( name, ip4cfg, sizeof ( ip4cfg ) ) != 0 )
00078                 return 0;
00079 
00080         /* Check manufacturer */
00081         fetch_string_setting ( NULL, &manufacturer_setting, manufacturer,
00082                                sizeof ( manufacturer ) );
00083         if ( strcmp ( manufacturer, dell ) != 0 )
00084                 return 0;
00085 
00086         return 1;
00087 }
00088 
00089 /** Blacklisted drivers */
00090 static struct efi_blacklist efi_blacklists[] = {
00091         {
00092                 .name = "Dell Ip4Config",
00093                 .blacklist = efi_blacklist_dell_ip4config,
00094         },
00095 };
00096 
00097 /**
00098  * Find driver blacklisting, if any
00099  *
00100  * @v driver            Driver binding handle
00101  * @ret blacklist       Driver blacklisting, or NULL
00102  * @ret rc              Return status code
00103  */
00104 static int efi_blacklist ( EFI_HANDLE driver,
00105                            struct efi_blacklist **blacklist ) {
00106         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00107         union {
00108                 EFI_DRIVER_BINDING_PROTOCOL *binding;
00109                 void *interface;
00110         } binding;
00111         union {
00112                 EFI_LOADED_IMAGE_PROTOCOL *loaded;
00113                 void *interface;
00114         } loaded;
00115         union {
00116                 EFI_COMPONENT_NAME_PROTOCOL *wtf;
00117                 void *interface;
00118         } wtf;
00119         unsigned int i;
00120         EFI_HANDLE image;
00121         EFI_STATUS efirc;
00122         int rc;
00123 
00124         DBGC2 ( &efi_blacklists, "EFIBL checking %s\n",
00125                 efi_handle_name ( driver ) );
00126 
00127         /* Mark as not blacklisted */
00128         *blacklist = NULL;
00129 
00130         /* Open driver binding protocol */
00131         if ( ( efirc = bs->OpenProtocol (
00132                         driver, &efi_driver_binding_protocol_guid,
00133                         &binding.interface, efi_image_handle, driver,
00134                         EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
00135                 rc = -EEFI ( efirc );
00136                 DBGC ( driver, "EFIBL %s could not open driver binding "
00137                        "protocol: %s\n", efi_handle_name ( driver ),
00138                        strerror ( rc ) );
00139                 goto err_binding;
00140         }
00141         image = binding.binding->ImageHandle;
00142 
00143         /* Open loaded image protocol */
00144         if ( ( efirc = bs->OpenProtocol (
00145                         image, &efi_loaded_image_protocol_guid,
00146                         &loaded.interface, efi_image_handle, image,
00147                         EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
00148                 rc = -EEFI ( efirc );
00149                 DBGC ( driver, "EFIBL %s could not open",
00150                        efi_handle_name ( driver ) );
00151                 DBGC ( driver, " %s loaded image protocol: %s\n",
00152                        efi_handle_name ( image ), strerror ( rc ) );
00153                 goto err_loaded;
00154         }
00155 
00156         /* Open component name protocol, if present*/
00157         if ( ( efirc = bs->OpenProtocol (
00158                         driver, &efi_component_name_protocol_guid,
00159                         &wtf.interface, efi_image_handle, driver,
00160                         EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
00161                 /* Ignore failure; is not required to be present */
00162                 wtf.interface = NULL;
00163         }
00164 
00165         /* Check blacklistings */
00166         for ( i = 0 ; i < ( sizeof ( efi_blacklists ) /
00167                             sizeof ( efi_blacklists[0] ) ) ; i++ ) {
00168                 if ( efi_blacklists[i].blacklist ( binding.binding,
00169                                                    loaded.loaded, wtf.wtf ) ) {
00170                         *blacklist = &efi_blacklists[i];
00171                         break;
00172                 }
00173         }
00174 
00175         /* Success */
00176         rc = 0;
00177 
00178         /* Close protocols */
00179         if ( wtf.wtf ) {
00180                 bs->CloseProtocol ( driver, &efi_component_name_protocol_guid,
00181                                     efi_image_handle, driver );
00182         }
00183         bs->CloseProtocol ( image, &efi_loaded_image_protocol_guid,
00184                             efi_image_handle, image );
00185  err_loaded:
00186         bs->CloseProtocol ( driver, &efi_driver_binding_protocol_guid,
00187                             efi_image_handle, driver );
00188  err_binding:
00189         return rc;
00190 }
00191 
00192 /**
00193  * Unload any blacklisted drivers
00194  *
00195  */
00196 void efi_unload_blacklist ( void ) {
00197         EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
00198         struct efi_blacklist *blacklist;
00199         EFI_HANDLE *drivers;
00200         EFI_HANDLE driver;
00201         UINTN num_drivers;
00202         unsigned int i;
00203         EFI_STATUS efirc;
00204         int rc;
00205 
00206         /* Locate all driver binding protocol handles */
00207         if ( ( efirc = bs->LocateHandleBuffer (
00208                         ByProtocol, &efi_driver_binding_protocol_guid,
00209                         NULL, &num_drivers, &drivers ) ) != 0 ) {
00210                 rc = -EEFI ( efirc );
00211                 DBGC ( &efi_blacklists, "EFIBL could not list all drivers: "
00212                        "%s\n", strerror ( rc ) );
00213                 return;
00214         }
00215 
00216         /* Unload any blacklisted drivers */
00217         for ( i = 0 ; i < num_drivers ; i++ ) {
00218                 driver = drivers[i];
00219                 if ( ( rc = efi_blacklist ( driver, &blacklist ) ) != 0 ) {
00220                         DBGC ( driver, "EFIBL could not determine "
00221                                "blacklisting for %s: %s\n",
00222                                efi_handle_name ( driver ), strerror ( rc ) );
00223                         continue;
00224                 }
00225                 if ( ! blacklist )
00226                         continue;
00227                 DBGC ( driver, "EFIBL unloading %s (%s)\n",
00228                        efi_handle_name ( driver ), blacklist->name );
00229                 if ( ( efirc = bs->UnloadImage ( driver ) ) != 0 ) {
00230                         DBGC ( driver, "EFIBL could not unload %s: %s\n",
00231                                efi_handle_name ( driver ), strerror ( rc ) );
00232                 }
00233         }
00234 
00235         /* Free handle list */
00236         bs->FreePool ( drivers );
00237 }