All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ana Bobillo <anabobillo3@gmail.com>
To: u-boot@lists.u-boot-project.org
Cc: Heinrich Schuchardt <xypron.glpk@gmx.de>,
	Ilias Apalodimas <ilias.apalodimas@linaro.org>,
	Tom Rini <trini@konsulko.com>
Subject: [PATCH RESEND 3/6] efi_loader: capsule: check the FMP capsule against its size
Date: Mon, 26 Oct 2026 13:19:11 +0000	[thread overview]
Message-ID: <475a43be-9eb7-416a-a501-77f39f9d94fc@gmail.com> (raw)
In-Reply-To: <f58ee8d2-b69f-48a5-99f5-a1bbcd3a920b@gmail.com>

From: Ana Bobillo <anabobillo3@gmail.com>

efi_capsule_update_firmware() reads the FMP capsule header, its item
offset list and each image header without checking them against the
size of the capsule:

- the capsule may end before the end of the FMP capsule header;
- the item offset list is indexed up to embedded_driver_count +
  payload_item_count - 1, which may run past the end of the capsule;
- the check of an item offset adds the image header size to a 64-bit
  offset and can wrap around, letting an offset close to U64_MAX
  through;
- update_image_size is passed on to the FMP driver without checking
  that the image fits in the capsule.

On the capsule on disk path all of this happens before the FMP driver
authenticates the image: a capsule file in \EFI\UpdateCapsule on the
ESP makes U-Boot read outside the capsule buffer the next time capsule
on disk runs.

Check each of them against the capsule size, and check that the vendor
code fits after the image too, along the lines of EDK2's
ValidateFmpCapsule().

Fixes: 8d99026f0697 ("efi_loader: capsule: support firmware update")
Signed-off-by: Ana Bobillo <anabobillo3@gmail.com>
---
 lib/efi_loader/efi_capsule.c | 45 ++++++++++++++++++++++++++----------
 1 file changed, 33 insertions(+), 12 deletions(-)

diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c
index e8835315e86..a8d57630a6f 100644
--- a/lib/efi_loader/efi_capsule.c
+++ b/lib/efi_loader/efi_capsule.c
@@ -538,11 +538,13 @@ 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, image_binary_size;
+	size_t capsule_size, image_binary_size, remaining;
 	void *image_binary, *vendor_code;
 	efi_handle_t *handles;
 	efi_uintn_t no_handles;
 	int item;
+	uint item_count;
+	u64 item_offset;
 	struct efi_firmware_management_protocol *fmp;
 	u16 *abort_reason;
 	efi_guid_t *image_type_id;
@@ -588,18 +590,27 @@ static efi_status_t efi_capsule_update_firmware(
 		return EFI_UNSUPPORTED;
 	}
 
-	/* sanity check */
-	if (capsule_data->header_size < sizeof(*capsule) ||
-	    capsule_data->header_size >= capsule_data->capsule_image_size)
-		return EFI_INVALID_PARAMETER;
-
 	capsule = (void *)capsule_data + capsule_data->header_size;
 	capsule_size = capsule_data->capsule_image_size
 			- capsule_data->header_size;
 
+	/* sanity check */
+	if (capsule_size < sizeof(*capsule)) {
+		log_err("Capsule does not have enough data\n");
+		return EFI_INVALID_PARAMETER;
+	}
+
 	if (capsule->version != 0x00000001)
 		return EFI_UNSUPPORTED;
 
+	item_count = capsule->embedded_driver_count +
+		     capsule->payload_item_count;
+	if (item_count > (capsule_size - sizeof(*capsule)) /
+			 sizeof(*capsule->item_offset_list)) {
+		log_err("Capsule does not have enough data\n");
+		return EFI_INVALID_PARAMETER;
+	}
+
 	handles = NULL;
 	ret = EFI_CALL(efi_locate_handle_buffer(
 			BY_PROTOCOL,
@@ -609,24 +620,34 @@ static efi_status_t efi_capsule_update_firmware(
 		return EFI_UNSUPPORTED;
 
 	/* Payload */
-	for (item = capsule->embedded_driver_count;
-	     item < capsule->embedded_driver_count
-		    + capsule->payload_item_count; item++) {
+	for (item = capsule->embedded_driver_count; item < item_count;
+	     item++) {
 		/* sanity check */
-		if ((capsule->item_offset_list[item] + sizeof(*image)
-				 >= capsule_size)) {
+		item_offset = capsule->item_offset_list[item];
+		if (item_offset >= capsule_size ||
+		    capsule_size - item_offset <= sizeof(*image)) {
 			log_err("Capsule does not have enough data\n");
 			ret = EFI_INVALID_PARAMETER;
 			goto out;
 		}
 
-		image = (void *)capsule + capsule->item_offset_list[item];
+		image = (void *)capsule + item_offset;
 
 		if (image->version != 0x00000003) {
 			ret = EFI_UNSUPPORTED;
 			goto out;
 		}
 
+		/* the image and the vendor code must fit in the capsule */
+		remaining = capsule_size - item_offset - sizeof(*image);
+		if (image->update_image_size > remaining ||
+		    image->update_vendor_code_size >
+				remaining - image->update_image_size) {
+			log_err("Capsule does not have enough data\n");
+			ret = EFI_INVALID_PARAMETER;
+			goto out;
+		}
+
 		/* find a device for update firmware */
 		fmp = efi_fmp_find(&image->update_image_type_id,
 				   image->update_image_index,

  parent reply	other threads:[~2026-10-26 13:19 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-26 13:18 [PATCH RESEND 0/6] efi_loader: capsule: check sizes against the capsule Ana Bobillo
2026-10-26 13:18 ` [PATCH RESEND 1/6] efi_loader: capsule: check the size of a capsule file Ana Bobillo
2026-10-26 14:29   ` Ilias Apalodimas
2026-10-26 13:19 ` [PATCH RESEND 2/6] efi_loader: capsule: check the capsule header size Ana Bobillo
2026-10-26 13:19 ` Ana Bobillo [this message]
2026-10-26 16:23   ` [PATCH RESEND 3/6] efi_loader: capsule: check the FMP capsule against its size Heinrich Schuchardt
2026-10-26 13:19 ` [PATCH RESEND 4/6] efi_loader: capsule: check the certificate length of an image Ana Bobillo
2026-10-26 13:19 ` [PATCH RESEND 5/6] efi_loader: firmware: check the FMP payload header size Ana Bobillo
2026-10-26 13:19 ` [PATCH RESEND 6/6] test: lib: add tests for the capsule size checks Ana Bobillo
2026-10-26 16:38   ` Heinrich Schuchardt

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=475a43be-9eb7-416a-a501-77f39f9d94fc@gmail.com \
    --to=anabobillo3@gmail.com \
    --cc=ilias.apalodimas@linaro.org \
    --cc=trini@konsulko.com \
    --cc=u-boot@lists.u-boot-project.org \
    --cc=xypron.glpk@gmx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.