From 693e9702f42b5efad0b02c7e7b95e1b7de485635 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Fri, 31 Mar 2023 15:39:54 +0200 Subject: [PATCH] Further improve load_certs() for non-compliant drivers/firmwares Following the discovery of more problematic firmwares and drivers affected by the issue c28b9855d0befbd07f46ced5c06c6d799c9d9d00 is designed to address (e.g. https://github.com/rhboot/shim/issues/558), this patch further improves the code so that, instead of simply bailing out, we progressively increase the buffer sizes, until either success or a maximum size limit is reached. In most cases, this workaround should be enough to ensure completion of the directory read and thus provide full shim functionality (while still warning the user about the non-compliance of their environment). --- shim.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/shim.c b/shim.c index 27a8c112f..02b8ce568 100644 --- a/shim.c +++ b/shim.c @@ -1486,18 +1486,28 @@ load_certs(EFI_HANDLE image_handle) UINTN old = buffersize; efi_status = dir->Read(dir, &buffersize, buffer); if (efi_status == EFI_BUFFER_TOO_SMALL) { - if (buffersize != old) { - buffer = ReallocatePool(buffer, old, buffersize); - if (buffer == NULL) { - perror(L"Failed to read directory %s - %r\n", - PathName, EFI_OUT_OF_RESOURCES); + if (buffersize == old) { + /* + * Some UEFI drivers or firmwares are not compliant with + * the EFI_FILE_PROTOCOL.Read() specs and do not return the + * required buffer size along with EFI_BUFFER_TOO_SMALL. + * Work around this by progressively increasing the buffer + * size, up to a certain point, until the call succeeds. + */ + perror(L"Error reading directory %s - " + L"non-compliant UEFI driver or firmware!\n", + PathName); + buffersize = (buffersize < 4) ? 4 : buffersize * 2; + if (buffersize > 1024) goto done; - } - continue; } - perror(L"Failed to read directory %s - buggy firmware\n", - PathName); - goto done; + buffer = ReallocatePool(buffer, old, buffersize); + if (buffer == NULL) { + perror(L"Failed to read directory %s - %r\n", + PathName, EFI_OUT_OF_RESOURCES); + goto done; + } + continue; } else if (EFI_ERROR(efi_status)) { perror(L"Failed to read directory %s - %r\n", PathName, efi_status);