summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoss Lagerwall <ross.lagerwall@citrix.com>2024-02-29 16:59:21 +0000
committerPeter Jones <pjones@redhat.com>2025-02-04 11:56:11 -0500
commit2daf1db9aa27e5d03335bc75818bd8a03e4b84e2 (patch)
tree9f352506efe9b6f976cfec0eef704cfb6ff5f0cd
parent11252121f853a0a3aac102b72a279204b9c69a00 (diff)
downloadefi-boot-shim-2daf1db9aa27e5d03335bc75818bd8a03e4b84e2.tar.gz
efi-boot-shim-2daf1db9aa27e5d03335bc75818bd8a03e4b84e2.zip
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 <ross.lagerwall@citrix.com>
-rw-r--r--shim.c47
1 files changed, 33 insertions, 14 deletions
diff --git a/shim.c b/shim.c
index 9c43f6b8..42b5bbcb 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);