From: Ana Bobillo <[email protected]>

efi_firmware_get_fw_version() reads an FMP payload header at the start
of an image without checking that the image holds one, and skips it by
its header_size without checking that against the image size. A
header_size larger than the image makes the image size wrap around
before the image is written.

Only look for the header in an image large enough to hold it, and
reject a header_size smaller than the header or larger than the image.

With CONFIG_EFI_CAPSULE_AUTHENTICATE the header is part of the signed
image, so there this is hardening.

Fixes: 675b62e12f9d ("efi_loader: Add logic to parse EDKII specific fmp payload 
header")
Signed-off-by: Ana Bobillo <[email protected]>
---
 lib/efi_loader/efi_firmware.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/lib/efi_loader/efi_firmware.c b/lib/efi_loader/efi_firmware.c
index 84de95f5c23..4a5249e5d4a 100644
--- a/lib/efi_loader/efi_firmware.c
+++ b/lib/efi_loader/efi_firmware.c
@@ -499,22 +499,32 @@ efi_status_t efi_firmware_set_fmp_state_var(struct 
fmp_state *state, u8 image_in
  * Parse the FMP payload header and fill the fmp_state structure.
  * If no FMP payload header is found, fmp_state structure is not updated.
  *
+ * Return:             EFI_SUCCESS, or EFI_INVALID_PARAMETER for a bad 
header_size
  */
-static void efi_firmware_get_fw_version(const void **p_image,
-                                       efi_uintn_t *p_image_size,
-                                       struct fmp_state *state)
+static efi_status_t efi_firmware_get_fw_version(const void **p_image,
+                                               efi_uintn_t *p_image_size,
+                                               struct fmp_state *state)
 {
        const struct fmp_payload_header *header;
        u32 fmp_hdr_signature = FMP_PAYLOAD_HDR_SIGNATURE;
 
+       if (*p_image_size < sizeof(*header))
+               return EFI_SUCCESS;
+
        header = *p_image;
        if (header->signature == fmp_hdr_signature) {
+               if (header->header_size < sizeof(*header) ||
+                   header->header_size > *p_image_size)
+                       return EFI_INVALID_PARAMETER;
+
                /* FMP header is inserted above the capsule payload */
                state->fw_version = header->fw_version;
 
                *p_image += header->header_size;
                *p_image_size -= header->header_size;
        }
+
+       return EFI_SUCCESS;
 }
 
 /**
@@ -543,7 +553,9 @@ efi_status_t efi_firmware_verify_image(const void **p_image,
        if (ret != EFI_SUCCESS)
                return ret;
 
-       efi_firmware_get_fw_version(p_image, p_image_size, state);
+       ret = efi_firmware_get_fw_version(p_image, p_image_size, state);
+       if (ret != EFI_SUCCESS)
+               return ret;
 
        image_type_id = efi_firmware_get_image_type_id(image_index);
        if (!image_type_id)

Reply via email to