@@ -33,7 +33,7 @@ struct fmp_payload_header {
u32 signature;
u32 header_size;
u32 fw_version;
- u32 lowest_supported_version;
+ u32 lowest_supported_version; /* not used */
};
__weak void set_dfu_alt_info(char *interface, char *devstr)
@@ -250,8 +250,6 @@ efi_status_t efi_firmware_capsule_authenticate(const void **p_image,
{
const void *image = *p_image;
efi_uintn_t image_size = *p_image_size;
- u32 fmp_hdr_signature;
- struct fmp_payload_header *header;
void *capsule_payload;
efi_status_t status;
efi_uintn_t capsule_payload_size;
@@ -264,7 +262,7 @@ efi_status_t efi_firmware_capsule_authenticate(const void **p_image,
&capsule_payload_size);
if (status == EFI_SECURITY_VIOLATION) {
- printf("Capsule authentication check failed. Aborting update\n");
+ log_err("Capsule authentication check failed. Aborting update\n");
return status;
} else if (status != EFI_SUCCESS) {
return status;
@@ -278,21 +276,6 @@ efi_status_t efi_firmware_capsule_authenticate(const void **p_image,
debug("Updating capsule without authenticating.\n");
}
- fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
- header = (void *)image;
-
- if (!memcmp(&header->signature, &fmp_hdr_signature,
- sizeof(fmp_hdr_signature))) {
- /*
- * When building the capsule with the scripts in
- * edk2, a FMP header is inserted above the capsule
- * payload. Compensate for this header to get the
- * actual payload that is to be updated.
- */
- image += header->header_size;
- image_size -= header->header_size;
- }
-
*p_image = image;
*p_image_size = image_size;
return EFI_SUCCESS;
@@ -349,6 +332,105 @@ efi_status_t EFIAPI efi_firmware_get_image_info(
return EFI_EXIT(ret);
}
+/**
+ * efi_firmware_get_image_type_id - get image_type_id
+ * @image_index: image index
+ *
+ * Return the image_type_id identified by the image index.
+ *
+ * Return: pointer to the image_type_id, NULL if image_index is invalid
+ */
+static
+efi_guid_t *efi_firmware_get_image_type_id(u8 image_index)
+{
+ int i;
+ struct efi_fw_image *fw_array;
+
+ fw_array = update_info.images;
+ for (i = 0; i < num_image_type_guids; i++) {
+ if (fw_array[i].image_index == image_index)
+ return &fw_array[i].image_type_id;
+ }
+
+ return NULL;
+}
+
+/**
+ * efi_firmware_check_lowest_supported_version - check the lowest supported version
+ * @p_image: Pointer to new image
+ * @p_image_size: Pointer to size of new image
+ * @image_index: image_index
+ *
+ * Check the fw_version in FMP payload header is equal to or greather than the
+ * lowest_supported_version stored in the device tree
+ *
+ * Return: status code
+ */
+static
+efi_status_t efi_firmware_check_lowest_supported_version(const void **p_image,
+ efi_uintn_t *p_image_size,
+ u8 image_index)
+{
+ const void *image = *p_image;
+ efi_uintn_t image_size = *p_image_size;
+ const struct fmp_payload_header *header;
+ u32 fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
+
+ /* FMP header is inserted above the capsule payload */
+ header = image;
+ if (header->signature == fmp_hdr_signature) {
+ efi_guid_t *image_type_id;
+ u32 version = 0, lsv = 0;
+
+ image_type_id = efi_firmware_get_image_type_id(image_index);
+ if (!image_type_id)
+ return EFI_INVALID_PARAMETER;
+
+ efi_firmware_get_firmware_version(image_index, image_type_id,
+ &version, &lsv);
+
+ if (header->fw_version >= lsv) {
+ image += header->header_size;
+ image_size -= header->header_size;
+ } else {
+ log_err("Firmware version %u too low. Expecting >= %u. Aborting update\n",
+ header->fw_version, lsv);
+ return EFI_INCOMPATIBLE_VERSION;
+ }
+ }
+
+ *p_image = image;
+ *p_image_size = image_size;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ * efi_firmware_verify_image - verify image
+ * @p_image: Pointer to new image
+ * @p_image_size: Pointer to size of new image
+ * @image_index Image index
+ *
+ * Verify the capsule file
+ *
+ * Return: status code
+ */
+static
+efi_status_t efi_firmware_verify_image(const void **p_image,
+ efi_uintn_t *p_image_size,
+ u8 image_index)
+{
+ efi_status_t ret;
+
+ ret = efi_firmware_capsule_authenticate(p_image, p_image_size);
+ if (ret != EFI_SUCCESS)
+ return ret;
+
+ ret = efi_firmware_check_lowest_supported_version(p_image, p_image_size, image_index);
+
+ return ret;
+}
+
#ifdef CONFIG_EFI_CAPSULE_FIRMWARE_FIT
/*
* This FIRMWARE_MANAGEMENT_PROTOCOL driver provides a firmware update
@@ -393,7 +475,7 @@ efi_status_t EFIAPI efi_firmware_fit_set_image(
if (!image || image_index != 1)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- status = efi_firmware_capsule_authenticate(&image, &image_size);
+ status = efi_firmware_verify_image(&image, &image_size, image_index);
if (status != EFI_SUCCESS)
return EFI_EXIT(status);
@@ -454,7 +536,7 @@ efi_status_t EFIAPI efi_firmware_raw_set_image(
if (!image)
return EFI_EXIT(EFI_INVALID_PARAMETER);
- status = efi_firmware_capsule_authenticate(&image, &image_size);
+ status = efi_firmware_verify_image(&image, &image_size, image_index);
if (status != EFI_SUCCESS)
return EFI_EXIT(status);
The FMP Payload Header which EDK II capsule generation scripts insert has a firmware version. This commit reads the lowest supported version stored in the device tree, then check if the firmware version in FMP payload header of the ongoing capsule is equal or greater than the lowest supported version. If the firmware version is lower than lowest supported version, capsule update fails. Signed-off-by: Masahisa Kojima <masahisa.kojima@linaro.org> --- Changes in v5: - newly implement the device tree based versioning Changes in v4: - use log_err() instead of printf() Changes in v2: - add error message when the firmware version is lower than lowest supported version lib/efi_loader/efi_firmware.c | 124 ++++++++++++++++++++++++++++------ 1 file changed, 103 insertions(+), 21 deletions(-)