From: Ana Bobillo <[email protected]>

efi_load_pe() computes the end of each section as the sum of its
VirtualAddress and its size, both u32, so the sum wraps around before it
is widened to unsigned long. A section near 4 GiB then yields a small
virt_size, and the memset() and memcpy() of the section write far past
the allocated image.

Relative virtual addresses are 32 bit, so reject a section whose end
does not fit into 32 bits. barebox, whose EFI loader is based on this
file, fixed the same in b6598389d46d ("efi: loader: fix integer overflow
in PE virt_size calculation").

This runs before the image is rejected when Secure Boot fails to verify
it.

Fixes: cb149c66342c ("efi_loader: Add PE image loader")
Signed-off-by: Ana Bobillo <[email protected]>
Reviewed-by: Ilias Apalodimas <[email protected]>
---
 lib/efi_loader/efi_image_loader.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/lib/efi_loader/efi_image_loader.c 
b/lib/efi_loader/efi_image_loader.c
index 7be5b6f2a9b..f81ccd62ab1 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -1048,9 +1048,21 @@ efi_status_t efi_load_pe(struct efi_loaded_image_obj 
*handle,
        /* Calculate upper virtual address boundary */
        for (i = num_sections - 1; i >= 0; i--) {
                IMAGE_SECTION_HEADER *sec = &sections[i];
+               u32 end;
 
-               virt_size = max_t(unsigned long, virt_size,
-                                 sec->VirtualAddress + section_size(sec));
+               /*
+                * VirtualAddress and section_size() are both u32, so their sum
+                * wraps around at 4 GiB, on 64bit systems too. A wrapped end
+                * would make virt_size too small for the memset() and memcpy()
+                * below.
+                */
+               if (__builtin_add_overflow(sec->VirtualAddress,
+                                          section_size(sec), &end)) {
+                       log_err("Section %d virtual address overflow\n", i);
+                       return EFI_LOAD_ERROR;
+               }
+
+               virt_size = max_t(unsigned long, virt_size, end);
        }
 
        /* Read 32/64bit specific header bits */

Reply via email to