Procházet zdrojové kódy

[efi] Blacklist the Dell Ip4ConfigDxe driver

On a Dell OptiPlex 7010, calling DisconnectController() on the LOM
device handle will lock up the system.  Debugging shows that execution
is trapped in an infinite loop that is somehow trying to reconnect
drivers (without going via ConnectController()).

The problem can be reproduced in the UEFI shell with no iPXE code
present, by using the "disconnect" command.  Experimentation shows
that the only fix is to unload (rather than just disconnect) the
"Ip4ConfigDxe" driver.

Add the concept of a blacklist of UEFI drivers that will be
automatically unloaded when iPXE runs as an application, and add the
Dell Ip4ConfigDxe driver to this blacklist.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown před 5 roky
rodič
revize
64b4452bca

+ 13
- 0
src/include/ipxe/efi/efi_blacklist.h Zobrazit soubor

@@ -0,0 +1,13 @@
1
+#ifndef _IPXE_EFI_BLACKLIST_H
2
+#define _IPXE_EFI_BLACKLIST_H
3
+
4
+/** @file
5
+ *
6
+ * EFI driver blacklist
7
+ */
8
+
9
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
10
+
11
+extern void efi_unload_blacklist ( void );
12
+
13
+#endif /* _IPXE_EFI_BLACKLIST_H */

+ 1
- 0
src/include/ipxe/errfile.h Zobrazit soubor

@@ -375,6 +375,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
375 375
 #define ERRFILE_cert_cmd	      ( ERRFILE_OTHER | 0x004f0000 )
376 376
 #define ERRFILE_acpi_settings	      ( ERRFILE_OTHER | 0x00500000 )
377 377
 #define ERRFILE_ntlm		      ( ERRFILE_OTHER | 0x00510000 )
378
+#define ERRFILE_efi_blacklist	      ( ERRFILE_OTHER | 0x00520000 )
378 379
 
379 380
 /** @} */
380 381
 

+ 237
- 0
src/interface/efi/efi_blacklist.c Zobrazit soubor

@@ -0,0 +1,237 @@
1
+/*
2
+ * Copyright (C) 2019 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ */
19
+
20
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
21
+
22
+#include <stddef.h>
23
+#include <string.h>
24
+#include <errno.h>
25
+#include <ipxe/settings.h>
26
+#include <ipxe/efi/efi.h>
27
+#include <ipxe/efi/Protocol/DriverBinding.h>
28
+#include <ipxe/efi/Protocol/LoadedImage.h>
29
+#include <ipxe/efi/Protocol/ComponentName.h>
30
+#include <ipxe/efi/efi_blacklist.h>
31
+
32
+/** @file
33
+ *
34
+ * EFI driver blacklist
35
+ *
36
+ */
37
+
38
+/** A blacklisted driver */
39
+struct efi_blacklist {
40
+	/** Name */
41
+	const char *name;
42
+	/**
43
+	 * Check if driver is blacklisted
44
+	 *
45
+	 * @v binding		Driver binding protocol
46
+	 * @v loaded		Loaded image protocol
47
+	 * @v wtf		Component name protocol, if present
48
+	 * @ret blacklisted	Driver is the blacklisted driver
49
+	 */
50
+	int ( * blacklist ) ( EFI_DRIVER_BINDING_PROTOCOL *binding,
51
+			      EFI_LOADED_IMAGE_PROTOCOL *loaded,
52
+			      EFI_COMPONENT_NAME_PROTOCOL *wtf );
53
+};
54
+
55
+/**
56
+ * Blacklist Dell Ip4ConfigDxe driver
57
+ *
58
+ * @v binding		Driver binding protocol
59
+ * @v loaded		Loaded image protocol
60
+ * @v wtf		Component name protocol, if present
61
+ * @ret blacklisted	Driver is the blacklisted driver
62
+ */
63
+static int
64
+efi_blacklist_dell_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
65
+			       EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
66
+			       EFI_COMPONENT_NAME_PROTOCOL *wtf ) {
67
+	static const CHAR16 ip4cfg[] = L"IP4 CONFIG Network Service Driver";
68
+	static const char dell[] = "Dell Inc.";
69
+	char manufacturer[ sizeof ( dell ) ];
70
+	CHAR16 *name;
71
+
72
+	/* Check driver name */
73
+	if ( ! wtf )
74
+		return 0;
75
+	if ( wtf->GetDriverName ( wtf, "eng", &name ) != 0 )
76
+		return 0;
77
+	if ( memcmp ( name, ip4cfg, sizeof ( ip4cfg ) ) != 0 )
78
+		return 0;
79
+
80
+	/* Check manufacturer */
81
+	fetch_string_setting ( NULL, &manufacturer_setting, manufacturer,
82
+			       sizeof ( manufacturer ) );
83
+	if ( strcmp ( manufacturer, dell ) != 0 )
84
+		return 0;
85
+
86
+	return 1;
87
+}
88
+
89
+/** Blacklisted drivers */
90
+static struct efi_blacklist efi_blacklists[] = {
91
+	{
92
+		.name = "Dell Ip4Config",
93
+		.blacklist = efi_blacklist_dell_ip4config,
94
+	},
95
+};
96
+
97
+/**
98
+ * Find driver blacklisting, if any
99
+ *
100
+ * @v driver		Driver binding handle
101
+ * @ret blacklist	Driver blacklisting, or NULL
102
+ * @ret rc		Return status code
103
+ */
104
+static int efi_blacklist ( EFI_HANDLE driver,
105
+			   struct efi_blacklist **blacklist ) {
106
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
107
+	union {
108
+		EFI_DRIVER_BINDING_PROTOCOL *binding;
109
+		void *interface;
110
+	} binding;
111
+	union {
112
+		EFI_LOADED_IMAGE_PROTOCOL *loaded;
113
+		void *interface;
114
+	} loaded;
115
+	union {
116
+		EFI_COMPONENT_NAME_PROTOCOL *wtf;
117
+		void *interface;
118
+	} wtf;
119
+	unsigned int i;
120
+	EFI_HANDLE image;
121
+	EFI_STATUS efirc;
122
+	int rc;
123
+
124
+	DBGC2 ( &efi_blacklists, "EFIBL checking %s\n",
125
+		efi_handle_name ( driver ) );
126
+
127
+	/* Mark as not blacklisted */
128
+	*blacklist = NULL;
129
+
130
+	/* Open driver binding protocol */
131
+	if ( ( efirc = bs->OpenProtocol (
132
+			driver, &efi_driver_binding_protocol_guid,
133
+			&binding.interface, efi_image_handle, driver,
134
+			EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
135
+		rc = -EEFI ( efirc );
136
+		DBGC ( driver, "EFIBL %s could not open driver binding "
137
+		       "protocol: %s\n", efi_handle_name ( driver ),
138
+		       strerror ( rc ) );
139
+		goto err_binding;
140
+	}
141
+	image = binding.binding->ImageHandle;
142
+
143
+	/* Open loaded image protocol */
144
+	if ( ( efirc = bs->OpenProtocol (
145
+			image, &efi_loaded_image_protocol_guid,
146
+			&loaded.interface, efi_image_handle, image,
147
+			EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
148
+		rc = -EEFI ( efirc );
149
+		DBGC ( driver, "EFIBL %s could not open",
150
+		       efi_handle_name ( driver ) );
151
+		DBGC ( driver, " %s loaded image protocol: %s\n",
152
+		       efi_handle_name ( image ), strerror ( rc ) );
153
+		goto err_loaded;
154
+	}
155
+
156
+	/* Open component name protocol, if present*/
157
+	if ( ( efirc = bs->OpenProtocol (
158
+			driver, &efi_component_name_protocol_guid,
159
+			&wtf.interface, efi_image_handle, driver,
160
+			EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
161
+		/* Ignore failure; is not required to be present */
162
+		wtf.interface = NULL;
163
+	}
164
+
165
+	/* Check blacklistings */
166
+	for ( i = 0 ; i < ( sizeof ( efi_blacklists ) /
167
+			    sizeof ( efi_blacklists[0] ) ) ; i++ ) {
168
+		if ( efi_blacklists[i].blacklist ( binding.binding,
169
+						   loaded.loaded, wtf.wtf ) ) {
170
+			*blacklist = &efi_blacklists[i];
171
+			break;
172
+		}
173
+	}
174
+
175
+	/* Success */
176
+	rc = 0;
177
+
178
+	/* Close protocols */
179
+	if ( wtf.wtf ) {
180
+		bs->CloseProtocol ( driver, &efi_component_name_protocol_guid,
181
+				    efi_image_handle, driver );
182
+	}
183
+	bs->CloseProtocol ( image, &efi_loaded_image_protocol_guid,
184
+			    efi_image_handle, image );
185
+ err_loaded:
186
+	bs->CloseProtocol ( driver, &efi_driver_binding_protocol_guid,
187
+			    efi_image_handle, driver );
188
+ err_binding:
189
+	return rc;
190
+}
191
+
192
+/**
193
+ * Unload any blacklisted drivers
194
+ *
195
+ */
196
+void efi_unload_blacklist ( void ) {
197
+	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
198
+	struct efi_blacklist *blacklist;
199
+	EFI_HANDLE *drivers;
200
+	EFI_HANDLE driver;
201
+	UINTN num_drivers;
202
+	unsigned int i;
203
+	EFI_STATUS efirc;
204
+	int rc;
205
+
206
+	/* Locate all driver binding protocol handles */
207
+	if ( ( efirc = bs->LocateHandleBuffer (
208
+			ByProtocol, &efi_driver_binding_protocol_guid,
209
+			NULL, &num_drivers, &drivers ) ) != 0 ) {
210
+		rc = -EEFI ( efirc );
211
+		DBGC ( &efi_blacklists, "EFIBL could not list all drivers: "
212
+		       "%s\n", strerror ( rc ) );
213
+		return;
214
+	}
215
+
216
+	/* Unload any blacklisted drivers */
217
+	for ( i = 0 ; i < num_drivers ; i++ ) {
218
+		driver = drivers[i];
219
+		if ( ( rc = efi_blacklist ( driver, &blacklist ) ) != 0 ) {
220
+			DBGC ( driver, "EFIBL could not determine "
221
+			       "blacklisting for %s: %s\n",
222
+			       efi_handle_name ( driver ), strerror ( rc ) );
223
+			continue;
224
+		}
225
+		if ( ! blacklist )
226
+			continue;
227
+		DBGC ( driver, "EFIBL unloading %s (%s)\n",
228
+		       efi_handle_name ( driver ), blacklist->name );
229
+		if ( ( efirc = bs->UnloadImage ( driver ) ) != 0 ) {
230
+			DBGC ( driver, "EFIBL could not unload %s: %s\n",
231
+			       efi_handle_name ( driver ), strerror ( rc ) );
232
+		}
233
+	}
234
+
235
+	/* Free handle list */
236
+	bs->FreePool ( drivers );
237
+}

+ 6
- 0
src/interface/efi/efiprefix.c Zobrazit soubor

@@ -27,6 +27,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
27 27
 #include <ipxe/efi/efi_snp.h>
28 28
 #include <ipxe/efi/efi_autoboot.h>
29 29
 #include <ipxe/efi/efi_watchdog.h>
30
+#include <ipxe/efi/efi_blacklist.h>
30 31
 
31 32
 /**
32 33
  * EFI entry point
@@ -75,6 +76,10 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
75 76
  */
76 77
 static int efi_probe ( struct root_device *rootdev __unused ) {
77 78
 
79
+	/* Unloaded any blacklisted drivers */
80
+	efi_unload_blacklist();
81
+
82
+	/* Connect our drivers */
78 83
 	return efi_driver_connect_all();
79 84
 }
80 85
 
@@ -85,6 +90,7 @@ static int efi_probe ( struct root_device *rootdev __unused ) {
85 90
  */
86 91
 static void efi_remove ( struct root_device *rootdev __unused ) {
87 92
 
93
+	/* Disconnect our drivers */
88 94
 	efi_driver_disconnect_all();
89 95
 }
90 96
 

Načítá se…
Zrušit
Uložit