summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAKASHI Takahiro <takahiro.akashi@linaro.org>2021-07-20 08:52:05 +0300
committerHeinrich Schuchardt <xypron.glpk@gmx.de>2021-07-24 11:49:51 +0300
commitc2cc60c1f93b9935c493fbe107ef8111e8baf200 (patch)
tree3072aff66cc1538f32af41494e75dc26af80be10
parentef890f6331f77911a911714bf289f9e290138d4b (diff)
downloadu-boot-c2cc60c1f93b9935c493fbe107ef8111e8baf200.tar.xz
efi_loader: capsule: remove authentication data
If capsule authentication is disabled and yet a capsule file is signed, its signature must be removed from image data to flush. Otherwise, the firmware will be corrupted after update. Fixes: 04be98bd6bcf ("efi: capsule: Add support for uefi capsule authentication") Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
-rw-r--r--lib/efi_loader/efi_capsule.c70
1 files changed, 57 insertions, 13 deletions
diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index 3c029378de..26990bc2df 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -218,6 +218,39 @@ skip:
return NULL;
}
+/**
+ * efi_remove_auth_hdr - remove authentication data from image
+ * @image: Pointer to pointer to Image
+ * @image_size: Pointer to Image size
+ *
+ * Remove the authentication data from image if possible.
+ * Update @image and @image_size.
+ *
+ * Return: status code
+ */
+static efi_status_t efi_remove_auth_hdr(void **image, efi_uintn_t *image_size)
+{
+ struct efi_firmware_image_authentication *auth_hdr;
+ efi_status_t ret = EFI_INVALID_PARAMETER;
+
+ auth_hdr = (struct efi_firmware_image_authentication *)*image;
+ if (*image_size < sizeof(*auth_hdr))
+ goto out;
+
+ if (auth_hdr->auth_info.hdr.dwLength <=
+ offsetof(struct win_certificate_uefi_guid, cert_data))
+ goto out;
+
+ *image = (uint8_t *)*image + sizeof(auth_hdr->monotonic_count) +
+ auth_hdr->auth_info.hdr.dwLength;
+ *image_size = *image_size - auth_hdr->auth_info.hdr.dwLength -
+ sizeof(auth_hdr->monotonic_count);
+
+ ret = EFI_SUCCESS;
+out:
+ return ret;
+}
+
#if defined(CONFIG_EFI_CAPSULE_AUTHENTICATE)
static int efi_get_public_key_data(void **pkey, efi_uintn_t *pkey_len)
@@ -254,21 +287,15 @@ efi_status_t efi_capsule_authenticate(const void *capsule, efi_uintn_t capsule_s
if (capsule == NULL || capsule_size == 0)
goto out;
- auth_hdr = (struct efi_firmware_image_authentication *)capsule;
- if (capsule_size < sizeof(*auth_hdr))
- goto out;
-
- if (auth_hdr->auth_info.hdr.dwLength <=
- offsetof(struct win_certificate_uefi_guid, cert_data))
+ *image = (uint8_t *)capsule;
+ *image_size = capsule_size;
+ if (efi_remove_auth_hdr(image, image_size) != EFI_SUCCESS)
goto out;
+ auth_hdr = (struct efi_firmware_image_authentication *)capsule;
if (guidcmp(&auth_hdr->auth_info.cert_type, &efi_guid_cert_type_pkcs7))
goto out;
- *image = (uint8_t *)capsule + sizeof(auth_hdr->monotonic_count) +
- auth_hdr->auth_info.hdr.dwLength;
- *image_size = capsule_size - auth_hdr->auth_info.hdr.dwLength -
- sizeof(auth_hdr->monotonic_count);
memcpy(&monotonic_count, &auth_hdr->monotonic_count,
sizeof(monotonic_count));
@@ -348,7 +375,7 @@ static efi_status_t efi_capsule_update_firmware(
{
struct efi_firmware_management_capsule_header *capsule;
struct efi_firmware_management_capsule_image_header *image;
- size_t capsule_size;
+ size_t capsule_size, image_binary_size;
void *image_binary, *vendor_code;
efi_handle_t *handles;
efi_uintn_t no_handles;
@@ -410,13 +437,30 @@ static efi_status_t efi_capsule_update_firmware(
}
/* do update */
+ if (IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE) &&
+ !(image->image_capsule_support &
+ CAPSULE_SUPPORT_AUTHENTICATION)) {
+ /* no signature */
+ ret = EFI_SECURITY_VIOLATION;
+ goto out;
+ }
+
image_binary = (void *)image + sizeof(*image);
- vendor_code = image_binary + image->update_image_size;
+ image_binary_size = image->update_image_size;
+ vendor_code = image_binary + image_binary_size;
+ if (!IS_ENABLED(CONFIG_EFI_CAPSULE_AUTHENTICATE) &&
+ (image->image_capsule_support &
+ CAPSULE_SUPPORT_AUTHENTICATION)) {
+ ret = efi_remove_auth_hdr(&image_binary,
+ &image_binary_size);
+ if (ret != EFI_SUCCESS)
+ goto out;
+ }
abort_reason = NULL;
ret = EFI_CALL(fmp->set_image(fmp, image->update_image_index,
image_binary,
- image->update_image_size,
+ image_binary_size,
vendor_code, NULL,
&abort_reason));
if (ret != EFI_SUCCESS) {