[PATCH 3/4] efi: loader: fix SizeOfBlock underflow in relocation processing

Sascha Hauer
2026-04-13T12:37:19Z

From: Sascha Hauer <sascha@saschahauer.de>

rel->SizeOfBlock is a uint32_t read from the PE image. If it is smaller
than sizeof(IMAGE_BASE_RELOCATION) (8 bytes), the subtraction
SizeOfBlock - sizeof(*rel) underflows. On 32-bit architectures (ARM,
i386, riscv32) the resulting huge unsigned value divided by 2 fits in a
positive int, causing the relocation loop to iterate billions of times,
reading and writing far past the relocation block.

Reject relocation blocks with SizeOfBlock smaller than the base
relocation header.

Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---
efi/loader/pe.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/efi/loader/pe.c b/efi/loader/pe.c
index 3190718df5..ea385c8795 100644
--- a/efi/loader/pe.c
+++ b/efi/loader/pe.c
@@ -120,6 +120,10 @@ static efi_status_t efi_loader_relocate(const IMAGE_BASE_RELOCATION *rel,
end = (const IMAGE_BASE_RELOCATION *)((const char *)rel + rel_size);
while (rel + 1 < end && rel->SizeOfBlock) {
const uint16_t *relocs = (const uint16_t *)(rel + 1);
+
+ if (rel->SizeOfBlock < sizeof(*rel))
+ return EFI_LOAD_ERROR;
+
i = (rel->SizeOfBlock - sizeof(*rel)) / sizeof(uint16_t);
while (i--) {
uint32_t offset = (uint32_t)(*relocs & 0xfff) +
--
2.47.3