summaryrefslogtreecommitdiff
path: root/lib/efi_loader/efi_image_loader.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/efi_loader/efi_image_loader.c')
-rw-r--r--lib/efi_loader/efi_image_loader.c126
1 files changed, 109 insertions, 17 deletions
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index f53ef367ec1..bcd57f7fccc 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -213,7 +213,68 @@ static void efi_set_code_and_data_type(
}
}
-#ifdef CONFIG_EFI_SECURE_BOOT
+/**
+ * efi_image_region_add() - add an entry of region
+ * @regs: Pointer to array of regions
+ * @start: Start address of region (included)
+ * @end: End address of region (excluded)
+ * @nocheck: flag against overlapped regions
+ *
+ * Take one entry of region [@start, @end[ and insert it into the list.
+ *
+ * * If @nocheck is false, the list will be sorted ascending by address.
+ * Overlapping entries will not be allowed.
+ *
+ * * If @nocheck is true, the list will be sorted ascending by sequence
+ * of adding the entries. Overlapping is allowed.
+ *
+ * Return: status code
+ */
+efi_status_t efi_image_region_add(struct efi_image_regions *regs,
+ const void *start, const void *end,
+ int nocheck)
+{
+ struct image_region *reg;
+ int i, j;
+
+ if (regs->num >= regs->max) {
+ EFI_PRINT("%s: no more room for regions\n", __func__);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (end < start)
+ return EFI_INVALID_PARAMETER;
+
+ for (i = 0; i < regs->num; i++) {
+ reg = &regs->reg[i];
+ if (nocheck)
+ continue;
+
+ /* new data after registered region */
+ if (start >= reg->data + reg->size)
+ continue;
+
+ /* new data preceding registered region */
+ if (end <= reg->data) {
+ for (j = regs->num - 1; j >= i; j--)
+ memcpy(&regs->reg[j + 1], &regs->reg[j],
+ sizeof(*reg));
+ break;
+ }
+
+ /* new data overlapping registered region */
+ EFI_PRINT("%s: new region already part of another\n", __func__);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ reg = &regs->reg[i];
+ reg->data = start;
+ reg->size = end - start;
+ regs->num++;
+
+ return EFI_SUCCESS;
+}
+
/**
* cmp_pe_section() - compare virtual addresses of two PE image sections
* @arg1: pointer to pointer to first section header
@@ -242,6 +303,38 @@ static int cmp_pe_section(const void *arg1, const void *arg2)
}
/**
+ * efi_prepare_aligned_image() - prepare 8-byte aligned image
+ * @efi: pointer to the EFI binary
+ * @efi_size: size of @efi binary
+ *
+ * If @efi is not 8-byte aligned, this function newly allocates
+ * the image buffer.
+ *
+ * Return: valid pointer to a image, return NULL if allocation fails.
+ */
+void *efi_prepare_aligned_image(void *efi, u64 *efi_size)
+{
+ size_t new_efi_size;
+ void *new_efi;
+
+ /*
+ * Size must be 8-byte aligned and the trailing bytes must be
+ * zero'ed. Otherwise hash value may be incorrect.
+ */
+ if (!IS_ALIGNED(*efi_size, 8)) {
+ new_efi_size = ALIGN(*efi_size, 8);
+ new_efi = calloc(new_efi_size, 1);
+ if (!new_efi)
+ return NULL;
+ memcpy(new_efi, efi, *efi_size);
+ *efi_size = new_efi_size;
+ return new_efi;
+ } else {
+ return efi;
+ }
+}
+
+/**
* efi_image_parse() - parse a PE image
* @efi: Pointer to image
* @len: Size of @efi
@@ -422,6 +515,7 @@ err:
return false;
}
+#ifdef CONFIG_EFI_SECURE_BOOT
/**
* efi_image_unsigned_authenticate() - authenticate unsigned image with
* SHA256 hash
@@ -499,7 +593,7 @@ static bool efi_image_authenticate(void *efi, size_t efi_size)
struct efi_signature_store *db = NULL, *dbx = NULL;
void *new_efi = NULL;
u8 *auth, *wincerts_end;
- size_t new_efi_size, auth_size;
+ size_t auth_size;
bool ret = false;
EFI_PRINT("%s: Enter, %d\n", __func__, ret);
@@ -507,21 +601,11 @@ static bool efi_image_authenticate(void *efi, size_t efi_size)
if (!efi_secure_boot_enabled())
return true;
- /*
- * Size must be 8-byte aligned and the trailing bytes must be
- * zero'ed. Otherwise hash value may be incorrect.
- */
- if (efi_size & 0x7) {
- new_efi_size = (efi_size + 0x7) & ~0x7ULL;
- new_efi = calloc(new_efi_size, 1);
- if (!new_efi)
- return false;
- memcpy(new_efi, efi, efi_size);
- efi = new_efi;
- efi_size = new_efi_size;
- }
+ new_efi = efi_prepare_aligned_image(efi, (u64 *)&efi_size);
+ if (!new_efi)
+ return false;
- if (!efi_image_parse(efi, efi_size, &regs, &wincerts,
+ if (!efi_image_parse(new_efi, efi_size, &regs, &wincerts,
&wincerts_len)) {
EFI_PRINT("Parsing PE executable image failed\n");
goto err;
@@ -663,7 +747,8 @@ err:
efi_sigstore_free(dbx);
pkcs7_free_message(msg);
free(regs);
- free(new_efi);
+ if (new_efi != efi)
+ free(new_efi);
EFI_PRINT("%s: Exit, %d\n", __func__, ret);
return ret;
@@ -829,6 +914,13 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj *handle,
goto err;
}
+#if CONFIG_IS_ENABLED(EFI_TCG2_PROTOCOL)
+ /* Measure an PE/COFF image */
+ if (tcg2_measure_pe_image(efi, efi_size, handle,
+ loaded_image_info))
+ log_err("PE image measurement failed\n");
+#endif
+
/* Copy PE headers */
memcpy(efi_reloc, efi,
sizeof(*dos)