From 0885b25bee32fec25244edac2874d05cb69669c1 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 VirtualSize rather than SizeOfRawData since the latter is rounded up to the section alignment and therefore contains non-certificate data. Signed-off-by: Ross Lagerwall --- shim.c | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/shim.c b/shim.c index a85c87120..8d65f011f 100644 --- a/shim.c +++ b/shim.c @@ -1518,6 +1518,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; @@ -1535,22 +1536,36 @@ load_cert_file(EFI_HANDLE image_handle, CHAR16 *filename, CHAR16 *PathName) Section = context.FirstSection; for (i = 0; i < context.NumberOfSections; i++, Section++) { - 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; + if (CompareMem(Section->Name, ".db\0\0\0\0\0", 8) == 0 && + Section->Misc.VirtualSize <= Section->SizeOfRawData) { + offset = 0; + while ((Section->Misc.VirtualSize - offset) >= sizeof(EFI_SIGNATURE_LIST)) { + 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 > Section->Misc.VirtualSize || + checked_add(user_cert_size, certlist->SignatureListSize, + &user_cert_size)) { + break; + } + + user_cert = ReallocatePool(user_cert, original, + user_cert_size); + if (!user_cert) { + FreePool(data); + return EFI_OUT_OF_RESOURCES; + } + + 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);