From 5889d8a22634c46bc9e21013276fed53a4642ac0 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 cbdf74eed..78ba1d412 100644 --- a/shim.c +++ b/shim.c @@ -1483,6 +1483,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; @@ -1500,22 +1501,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);