From 2daf1db9aa27e5d03335bc75818bd8a03e4b84e2 Mon Sep 17 00:00:00 2001 From: Ross Lagerwall Date: Thu, 29 Feb 2024 16:59:21 +0000 Subject: [PATCH] Load concatenated EFI_SIGNATURE_LISTs from shim_certificate.efi For multiple reasons, it may be useful for different keys to be used to sign different parts of the boot chain (e.g. a different key for GRUB and the Linux kernel). Allow this by loading concatenated EFI_SIGNATURE_LISTs from shim_certificate.efi rather than only the first. At the same time, be a bit more robust by checking for allocation failures and overflows due to invalid data in the binary. Use the smaller of VirtualSize and SizeOfRawData since the latter is rounded up to the section alignment and therefore may contain non-certificate data. Signed-off-by: Ross Lagerwall --- shim.c | 47 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/shim.c b/shim.c index 9c43f6b84..42b5bbcba 100644 --- a/shim.c +++ b/shim.c @@ -1488,6 +1488,7 @@ load_cert_file(EFI_HANDLE image_handle, CHAR16 *filename, CHAR16 *PathName) EFI_SIGNATURE_LIST *certlist; void *pointer; UINT32 original; + UINT32 offset; int datasize = 0; void *data = NULL; int i; @@ -1505,22 +1506,40 @@ load_cert_file(EFI_HANDLE image_handle, CHAR16 *filename, CHAR16 *PathName) Section = context.FirstSection; for (i = 0; i < context.NumberOfSections; i++, Section++) { + UINT32 sec_size = MIN(Section->Misc.VirtualSize, Section->SizeOfRawData); + if (CompareMem(Section->Name, ".db\0\0\0\0\0", 8) == 0) { - original = user_cert_size; - if (Section->SizeOfRawData < sizeof(EFI_SIGNATURE_LIST)) { - continue; - } - pointer = ImageAddress(data, datasize, - Section->PointerToRawData); - if (!pointer) { - continue; + offset = 0; + while ((sec_size - offset) >= sizeof(EFI_SIGNATURE_LIST)) { + UINT8 *tmp; + + original = user_cert_size; + pointer = ImageAddress(data, datasize, + Section->PointerToRawData + offset); + if (!pointer) { + break; + } + certlist = pointer; + + if (certlist->SignatureListSize < sizeof(EFI_SIGNATURE_LIST) || + checked_add(offset, certlist->SignatureListSize, &offset) || + offset > sec_size || + checked_add(user_cert_size, certlist->SignatureListSize, + &user_cert_size)) { + break; + } + + tmp = ReallocatePool(user_cert, original, + user_cert_size); + if (!tmp) { + FreePool(data); + return EFI_OUT_OF_RESOURCES; + } + user_cert = tmp; + + CopyMem(user_cert + original, pointer, + certlist->SignatureListSize); } - certlist = pointer; - user_cert_size += certlist->SignatureListSize;; - user_cert = ReallocatePool(user_cert, original, - user_cert_size); - CopyMem(user_cert + original, pointer, - certlist->SignatureListSize); } } FreePool(data);