| From 5a5147d1e19cf90ec280990c84061ac3f67ea1ab Mon Sep 17 00:00:00 2001 |
| From: Peter Jones <pjones@redhat.com> |
| Date: Wed, 26 Jul 2023 14:47:45 -0400 |
| 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. |
| |
| 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 | 26 +++++++++++++++++++++++--- |
| 1 file changed, 23 insertions(+), 3 deletions(-) |
| |
| diff --git a/pe.c b/pe.c |
| index ba3e2bb..78d6532 100644 |
| --- a/pe.c |
| +++ b/pe.c |
| @@ -631,7 +631,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; |
| @@ -697,14 +697,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"); |
| -- |
| 2.43.0.594.gd9cf4e227d-goog |