ShellPkg/UefiHandleParsingLib: support handle list growth Refactor GetHandleListByProtocol() to support additions to the handle list during its execution. Replace LocateHandle() with LocateHandleBuffer() to avoid the possibility that the buffer allocated for LocateHandle() is too small if additional handles are added during GetHandleListByProtocol() execution. Note that the previous implementation did not detect the handle list growth and would cause memory corruption when writing the terminating NULL handle to the allocated buffer. Signed-off-by: Bob Morgan <bobm@nvidia.com>
diff --git a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c index 023a4bc..0c65d36 100644 --- a/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c +++ b/ShellPkg/Library/UefiHandleParsingLib/UefiHandleParsingLib.c
@@ -3761,7 +3761,7 @@ @param[in] ProtocolGuid The guid of the protocol to get handles for. If NULL then the function will return all handles. - @retval NULL A memory allocation failed. + @retval NULL Could not get handles or memory allocation failed. @return A NULL terminated list of handles. **/ EFI_HANDLE * @@ -3771,45 +3771,43 @@ ) { EFI_HANDLE *HandleList; - UINTN Size; + EFI_HANDLE *OriginalHandleList; + UINTN OriginalHandleCount; EFI_STATUS Status; - Size = 0; - HandleList = NULL; - - // - // We cannot use LocateHandleBuffer since we need that NULL item on the ends of the list! - // - if (ProtocolGuid == NULL) { - Status = gBS->LocateHandle (AllHandles, NULL, NULL, &Size, HandleList); - if (Status == EFI_BUFFER_TOO_SMALL) { - HandleList = AllocateZeroPool (Size + sizeof (EFI_HANDLE)); - if (HandleList == NULL) { - return (NULL); - } - - Status = gBS->LocateHandle (AllHandles, NULL, NULL, &Size, HandleList); - HandleList[Size/sizeof (EFI_HANDLE)] = NULL; + OriginalHandleList = NULL; + Status = gBS->LocateHandleBuffer ( + (ProtocolGuid == NULL) ? AllHandles : ByProtocol, + (EFI_GUID *)ProtocolGuid, + NULL, + &OriginalHandleCount, + &OriginalHandleList + ); + if (EFI_ERROR (Status)) { + if (Status != EFI_NOT_FOUND) { + DEBUG (( + DEBUG_ERROR, + "%a: LocateHandleBuffer %a failed: %r\n", + __func__, + (ProtocolGuid == NULL) ? "AllHandles" : "ByProtocol", + Status + )); } - } else { - Status = gBS->LocateHandle (ByProtocol, (EFI_GUID *)ProtocolGuid, NULL, &Size, HandleList); - if (Status == EFI_BUFFER_TOO_SMALL) { - HandleList = AllocateZeroPool (Size + sizeof (EFI_HANDLE)); - if (HandleList == NULL) { - return (NULL); - } - Status = gBS->LocateHandle (ByProtocol, (EFI_GUID *)ProtocolGuid, NULL, &Size, HandleList); - HandleList[Size/sizeof (EFI_HANDLE)] = NULL; - } + return NULL; } - if (EFI_ERROR (Status)) { - if (HandleList != NULL) { - FreePool (HandleList); + // create new list with one more slot for the NULL terminator + HandleList = ReallocatePool ( + OriginalHandleCount * sizeof (EFI_HANDLE), + (OriginalHandleCount + 1) * sizeof (EFI_HANDLE), + OriginalHandleList + ); + if (HandleList == NULL) { + DEBUG ((DEBUG_ERROR, "%a: reallocate failed\n", __func__)); + if (OriginalHandleList != NULL) { + FreePool (OriginalHandleList); } - - return (NULL); } return (HandleList);