]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Do not assume canonical PE section ordering
authorMichael Brown <mcb30@ipxe.org>
Fri, 24 Nov 2023 15:55:41 +0000 (15:55 +0000)
committerMichael Brown <mcb30@ipxe.org>
Fri, 24 Nov 2023 16:45:11 +0000 (16:45 +0000)
The BaseOfCode (and, in PE32, BaseOfData) fields imply an assumption
that binaries are laid out as code followed by initialised data
followed by uninitialised data.  This assumption may not be valid for
complex binaries such as wimboot.

Remove this implicit assumption, and use arguably justifiable values
for the assorted summary start and size fields within the PE headers.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/util/elf2efi.c

index 171e2b58ccb37efc70767cc38ef2308e11026630..72d50d386c85b57d2012fc748141480e2cf81cc5 100644 (file)
@@ -602,31 +602,29 @@ static struct pe_section * process_section ( struct elf_file *elf,
        size_t name_len;
        size_t section_memsz;
        size_t section_filesz;
-       unsigned long code_start;
-       unsigned long code_end;
-       unsigned long data_start;
-       unsigned long data_mid;
-       unsigned long data_end;
-       unsigned long start;
-       unsigned long end;
-       unsigned long *applicable_start;
-       unsigned long *applicable_end;
+       uint32_t start;
+       uint32_t end;
+       uint32_t *code_start;
+       uint32_t *data_start;
+       uint32_t *code_size;
+       uint32_t *data_size;
+       uint32_t *bss_size;
+       uint32_t *applicable_start;
+       uint32_t *applicable_size;
 
        /* Get section name */
        name = elf_string ( elf, elf->ehdr->e_shstrndx, shdr->sh_name );
 
-       /* Extract current RVA limits from file header */
-       code_start = pe_header->nt.OptionalHeader.BaseOfCode;
-       code_end = ( code_start + pe_header->nt.OptionalHeader.SizeOfCode );
+       /* Identify start and size limit fields from file header */
+       code_start = &pe_header->nt.OptionalHeader.BaseOfCode;
+       code_size = &pe_header->nt.OptionalHeader.SizeOfCode;
 #if defined(EFI_TARGET32)
-       data_start = pe_header->nt.OptionalHeader.BaseOfData;
+       data_start = &pe_header->nt.OptionalHeader.BaseOfData;
 #elif defined(EFI_TARGET64)
-       data_start = code_end;
+       data_start = NULL;
 #endif
-       data_mid = ( data_start +
-                    pe_header->nt.OptionalHeader.SizeOfInitializedData );
-       data_end = ( data_mid +
-                    pe_header->nt.OptionalHeader.SizeOfUninitializedData );
+       data_size = &pe_header->nt.OptionalHeader.SizeOfInitializedData;
+       bss_size = &pe_header->nt.OptionalHeader.SizeOfUninitializedData;
 
        /* Allocate PE section */
        section_memsz = shdr->sh_size;
@@ -659,7 +657,7 @@ static struct pe_section * process_section ( struct elf_file *elf,
                new->hidden = 1;
        }
 
-       /* Fill in section characteristics and update RVA limits */
+       /* Fill in section characteristics and identify applicable limits */
        if ( ( shdr->sh_type == SHT_PROGBITS ) &&
             ( shdr->sh_flags & SHF_WRITE ) ) {
                /* .data-type section */
@@ -668,8 +666,8 @@ static struct pe_section * process_section ( struct elf_file *elf,
                          EFI_IMAGE_SCN_MEM_NOT_PAGED |
                          EFI_IMAGE_SCN_MEM_READ |
                          EFI_IMAGE_SCN_MEM_WRITE );
-               applicable_start = &data_start;
-               applicable_end = &data_mid;
+               applicable_start = data_start;
+               applicable_size = data_size;
        } else if ( ( shdr->sh_type == SHT_PROGBITS ) &&
                    ( shdr->sh_flags & SHF_EXECINSTR ) ) {
                /* .text-type section */
@@ -678,16 +676,16 @@ static struct pe_section * process_section ( struct elf_file *elf,
                          EFI_IMAGE_SCN_MEM_NOT_PAGED |
                          EFI_IMAGE_SCN_MEM_EXECUTE |
                          EFI_IMAGE_SCN_MEM_READ );
-               applicable_start = &code_start;
-               applicable_end = &code_end;
+               applicable_start = code_start;
+               applicable_size = code_size;
        } else if ( shdr->sh_type == SHT_PROGBITS ) {
                /* .rodata-type section */
                new->hdr.Characteristics =
                        ( EFI_IMAGE_SCN_CNT_INITIALIZED_DATA |
                          EFI_IMAGE_SCN_MEM_NOT_PAGED |
                          EFI_IMAGE_SCN_MEM_READ );
-               applicable_start = &data_start;
-               applicable_end = &data_mid;
+               applicable_start = data_start;
+               applicable_size = data_size;
        } else if ( shdr->sh_type == SHT_NOBITS ) {
                /* .bss-type section */
                new->hdr.Characteristics =
@@ -695,8 +693,8 @@ static struct pe_section * process_section ( struct elf_file *elf,
                          EFI_IMAGE_SCN_MEM_NOT_PAGED |
                          EFI_IMAGE_SCN_MEM_READ |
                          EFI_IMAGE_SCN_MEM_WRITE );
-               applicable_start = &data_mid;
-               applicable_end = &data_end;
+               applicable_start = data_start;
+               applicable_size = bss_size;
        } else {
                eprintf ( "Unrecognised characteristics for section %s\n",
                          name );
@@ -709,41 +707,24 @@ static struct pe_section * process_section ( struct elf_file *elf,
                         shdr->sh_size );
        }
 
-       /* Update RVA limits */
+       /* Update file header fields */
        start = new->hdr.VirtualAddress;
-       end = ( start + new->hdr.Misc.VirtualSize );
-       if ( ! new->hidden ) {
-               if ( ( ! *applicable_start ) || ( *applicable_start >= start ) )
-                       *applicable_start = start;
-               if ( *applicable_end < end )
-                       *applicable_end = end;
-       }
-       if ( data_start < code_end )
-               data_start = code_end;
-       if ( data_mid < data_start )
-               data_mid = data_start;
-       if ( data_end < data_mid )
-               data_end = data_mid;
-
-       /* Write RVA limits back to file header */
-       pe_header->nt.OptionalHeader.BaseOfCode = code_start;
-       pe_header->nt.OptionalHeader.SizeOfCode = ( code_end - code_start );
-#if defined(EFI_TARGET32)
-       pe_header->nt.OptionalHeader.BaseOfData = data_start;
-#endif
-       pe_header->nt.OptionalHeader.SizeOfInitializedData =
-               ( data_mid - data_start );
-       pe_header->nt.OptionalHeader.SizeOfUninitializedData =
-               ( data_end - data_mid );
-
-       /* Update remaining file header fields */
        if ( ! new->hidden ) {
                pe_header->nt.FileHeader.NumberOfSections++;
                pe_header->nt.OptionalHeader.SizeOfHeaders +=
                        sizeof ( new->hdr );
+               if ( applicable_start && ( ( *applicable_start == 0 ) ||
+                                          ( start < *applicable_start ) ) ) {
+                       *applicable_start = start;
+               }
+               if ( applicable_size ) {
+                       *applicable_size += section_memsz;
+               }
+       }
+       end = efi_image_align ( start + section_memsz );
+       if ( end > pe_header->nt.OptionalHeader.SizeOfImage ) {
+               pe_header->nt.OptionalHeader.SizeOfImage = end;
        }
-       pe_header->nt.OptionalHeader.SizeOfImage =
-               efi_image_align ( data_end );
 
        return new;
 }