summaryrefslogtreecommitdiff
path: root/lib/efi_loader
diff options
context:
space:
mode:
authorHeinrich Schuchardt <xypron.glpk@gmx.de>2019-05-30 14:16:31 +0200
committerHeinrich Schuchardt <xypron.glpk@gmx.de>2019-05-31 23:27:12 +0200
commitdae7ce451c5eaaae98014a4062950cd646f78c2d (patch)
treebef9ee3104e539a4fc3c3f95fa9b6efa7dfa810d /lib/efi_loader
parent399a39e34af00e7342406405dc0300da0557277b (diff)
efi_loader: avoid crash in OpenProtocol()
When trying to open a protocol exclusively attached drivers have to be removed. This removes entries in the open protocol information linked list over which we are looping. As additionally child controllers may have been removed the only safe thing to do is to restart the loop over the linked list when a driver is removed. By observing the return code of DisconnectController() we can eliminate a loop. Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
Diffstat (limited to 'lib/efi_loader')
-rw-r--r--lib/efi_loader/efi_boottime.c26
1 files changed, 17 insertions, 9 deletions
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 610eea463e..f71268440b 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -2658,21 +2658,29 @@ static efi_status_t efi_protocol_open(
/* Prepare exclusive opening */
if (attributes & EFI_OPEN_PROTOCOL_EXCLUSIVE) {
/* Try to disconnect controllers */
+disconnect_next:
+ opened_by_driver = false;
list_for_each_entry(item, &handler->open_infos, link) {
+ efi_status_t ret;
+
if (item->info.attributes ==
- EFI_OPEN_PROTOCOL_BY_DRIVER)
- EFI_CALL(efi_disconnect_controller(
+ EFI_OPEN_PROTOCOL_BY_DRIVER) {
+ ret = EFI_CALL(efi_disconnect_controller(
item->info.controller_handle,
item->info.agent_handle,
NULL));
+ if (ret == EFI_SUCCESS)
+ /*
+ * Child controllers may have been
+ * removed from the open_infos list. So
+ * let's restart the loop.
+ */
+ goto disconnect_next;
+ else
+ opened_by_driver = true;
+ }
}
- opened_by_driver = false;
- /* Check if all controllers are disconnected */
- list_for_each_entry(item, &handler->open_infos, link) {
- if (item->info.attributes & EFI_OPEN_PROTOCOL_BY_DRIVER)
- opened_by_driver = true;
- }
- /* Only one controller can be connected */
+ /* Only one driver can be connected */
if (opened_by_driver)
return EFI_ACCESS_DENIED;
}