From e99bdbb827a50cde019393d3ca1e89397db221a7 Mon Sep 17 00:00:00 2001
From: Chris Coulson <chris.coulson@canonical.com>
Date: Tue, 3 May 2022 15:41:00 +0200
Subject: [PATCH] pe: Fix a buffer overflow when SizeOfRawData > VirtualSize

During image loading, the size of the destination buffer for the image
is determined by the SizeOfImage field in the optional header. The start
and end virtual addresses of each section, as determined by each section's
VirtualAddress and VirtualSize fields, are bounds checked against the
allocated buffer. However, the amount of data copied to the destination
buffer is determined by the section's SizeOfRawData filed. If this is
larger than the VirtualSize, then the copy can overflow the destination
buffer.

Fix this by limiting the amount of data to copy to the section's
VirtualSize. In the case where a section has SizeOfRawData > VirtualSize,
the excess data is discarded.

This fixes CVE-2022-28737

Signed-off-by: Chris Coulson <chris.coulson@canonical.com>

Reference:https://github.com/rhboot/shim/commit/e99bdbb827a50cde019393d3ca1e89397db221a7
Conflict:NA
---
 shim.c | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/shim.c b/shim.c
index 5d0c6b0b..1eb3f59a 100644
--- a/shim.c
+++ b/shim.c
@@ -1089,6 +1089,7 @@ handle_image (void *data, unsigned int datasize,
 	int i;
 	EFI_IMAGE_SECTION_HEADER *Section;
 	char *base, *end;
+	UINT32 size;
 	PE_COFF_LOADER_IMAGE_CONTEXT context;
 	unsigned int alignment, alloc_size;
 	int found_entry_point = 0;
@@ -1274,13 +1275,15 @@ handle_image (void *data, unsigned int datasize,
 				return EFI_UNSUPPORTED;
 			}
 
-			if (Section->SizeOfRawData > 0)
-				CopyMem(base, data + Section->PointerToRawData,
-					Section->SizeOfRawData);
+			size = Section->Misc.VirtualSize;
+			if (size > Section->SizeOfRawData)
+				size = Section->SizeOfRawData;
 
-			if (Section->SizeOfRawData < Section->Misc.VirtualSize)
-				ZeroMem(base + Section->SizeOfRawData,
-					Section->Misc.VirtualSize - Section->SizeOfRawData);
+			if (size > 0)
+				CopyMem(base, data + Section->PointerToRawData, size);
+
+			if (size < Section->Misc.VirtualSize)
+				ZeroMem(base + size, Section->Misc.VirtualSize - size);
 		}
 	}
 
