87 lines
2.9 KiB
Diff
87 lines
2.9 KiB
Diff
|
|
From f93d9d8c546eed520314ce435c26b184663e1032 Mon Sep 17 00:00:00 2001
|
||
|
|
From: jinlun <jinlun@huawei.com>
|
||
|
|
Date: Thu, 25 Jan 2024 14:50:03 +0800
|
||
|
|
Subject: [PATCH] CVE-2023-40551: pe-relocate: Fix bounds check for MZ binaries
|
||
|
|
|
||
|
|
In read_header(), we attempt to parse the PE binary headers. In doing
|
||
|
|
so, if there is an MZ (i.e. MS-DOS) header, we locate the PE header by
|
||
|
|
finding the offset in that header. Unfortunately that is not correctly
|
||
|
|
bounds checked, and carefully chosen values can cause an out-of-bounds
|
||
|
|
ready beyond the end of the loaded binary.
|
||
|
|
|
||
|
|
Unfortunately the trivial fix (bounds check that value) also makes it
|
||
|
|
clear that the way we were determining if an image is loadable on this
|
||
|
|
platform and distinguishing between PE32 and PE32+ binaries has the
|
||
|
|
exact same issue going on, and so the fix includes reworking that logic
|
||
|
|
to correctly bounds check all of those tests as well.
|
||
|
|
h
|
||
|
|
It's not currently known if this is actually exploitable beyond creating
|
||
|
|
a denial of service, and an attacker who is in a position to use it for
|
||
|
|
a denial of service attack must already be able to do so.
|
||
|
|
|
||
|
|
Resolves: CVE-2023-40551
|
||
|
|
Reported-by: gkirkpatrick@google.com
|
||
|
|
Signed-off-by: Peter Jones <pjones@redhat.com>
|
||
|
|
---
|
||
|
|
pe.c | 24 ++++++++++++++++++++++--
|
||
|
|
post-process-pe.c | 2 +-
|
||
|
|
2 files changed, 23 insertions(+), 3 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/pe.c b/pe.c
|
||
|
|
index 96f9c0e..d14f2ff 100644
|
||
|
|
--- a/pe.c
|
||
|
|
+++ b/pe.c
|
||
|
|
@@ -771,14 +771,34 @@ read_header(void *data, unsigned int datasize,
|
||
|
|
unsigned long HeaderWithoutDataDir, SectionHeaderOffset, OptHeaderSize;
|
||
|
|
unsigned long FileAlignment = 0;
|
||
|
|
UINT16 DllFlags;
|
||
|
|
+ size_t dos_sz = 0;
|
||
|
|
|
||
|
|
- if (datasize < sizeof (PEHdr->Pe32)) {
|
||
|
|
+ if (datasize < sizeof (*DosHdr)) {
|
||
|
|
perror(L"Invalid image\n");
|
||
|
|
return EFI_UNSUPPORTED;
|
||
|
|
}
|
||
|
|
|
||
|
|
- if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE)
|
||
|
|
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
|
||
|
|
+ if (DosHdr->e_lfanew < sizeof (*DosHdr) ||
|
||
|
|
+ DosHdr->e_lfanew > datasize - 4) {
|
||
|
|
+ perror(L"Invalid image\n");
|
||
|
|
+ return EFI_UNSUPPORTED;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ dos_sz = DosHdr->e_lfanew;
|
||
|
|
PEHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((char *)data + DosHdr->e_lfanew);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (datasize - dos_sz < sizeof (PEHdr->Pe32)) {
|
||
|
|
+ perror(L"Invalid image\n");
|
||
|
|
+ return EFI_UNSUPPORTED;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (image_is_64_bit(PEHdr) &&
|
||
|
|
+ (datasize - dos_sz < sizeof (PEHdr->Pe32Plus))) {
|
||
|
|
+ perror(L"Invalid image\n");
|
||
|
|
+ return EFI_UNSUPPORTED;
|
||
|
|
+ }
|
||
|
|
|
||
|
|
if (!image_is_loadable(PEHdr)) {
|
||
|
|
perror(L"Platform does not support this image\n");
|
||
|
|
diff --git a/post-process-pe.c b/post-process-pe.c
|
||
|
|
index de8f4a3..86350ce 100644
|
||
|
|
--- a/post-process-pe.c
|
||
|
|
+++ b/post-process-pe.c
|
||
|
|
@@ -110,7 +110,7 @@ static int
|
||
|
|
image_is_64_bit(EFI_IMAGE_OPTIONAL_HEADER_UNION *PEHdr)
|
||
|
|
{
|
||
|
|
/* .Magic is the same offset in all cases */
|
||
|
|
- if (PEHdr->Pe32Plus.OptionalHeader.Magic ==
|
||
|
|
+ if (PEHdr->Pe32.OptionalHeader.Magic ==
|
||
|
|
EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC)
|
||
|
|
return 1;
|
||
|
|
return 0;
|
||
|
|
--
|
||
|
|
2.33.0
|
||
|
|
|