New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[efi] Improve ELF to PE conversion #313
Conversation
Actually this may be incomplete. When trying to boot shimx64.efi, I realised the binary's relocations are malformed, i.e. it is not ensured that relocation blocks have a size aligned by 4 Bytes as per the PE spec. While I did not have any error with my generated PE iPXE binary, I do not quite see (yet?) where in the code this condition is ensured. Should it not be around here? If the logic is indeed missing, I can probably help writing it, but testing will be hard with no malformed binary discovered so far. Thank you. |
Thank you. Some issues observed from a quick initial check of the patch:
|
The existing code will pad the section filesize to 32-byte alignment and zero-fill any unused space. PE relocation records are two bytes each, so if the PE spec requires 4-byte alignment of the size of relocation records then that seems to be a bug in the PE spec. Do you have a direct link to the relevant requirement? |
From a closer look at the code, it looks as though we already ensure that the relocation section size is 4-byte aligned:
|
OK, sorry.
ELF segments do not have names, so it's sort of expected. I suppose we could have heuristics for ".text", ".data", and other common ones? I dislike heuristics and lack of information equally, so I am fine with whatever you prefer. I also just realised that this change alone will not be acceptable as the source ELF file has one rwx segment and applies more granular permissions per section. For this change to be extensive, this needs to be fixed too somehow. I will change the state to Draft and hope you have a good suggestion at hand, otherwise I will have to go back to the ELF docs. :)
This one is funny because it's heavily implied and basically the only sensical way I see to implement it, but not strictly spelled out. The two relevant pieces are these:
While the records themselves are 2 bytes each as you say and thus only require a 2 byte alignment, the block headers have 2 records of 4 bytes each and hence require a 4 byte alignment. This can be accomplished by inserting an absolute relocation to reach an even amount of entries in a block. The spec is very vague on this, but let's be honest, the spec is very vague on everything. I do not think there is an alternative interpretation that makes sense in context of other, similar examples. EDIT:
Aha, totally missed it because I was looking for explicit initialisation. ABSOLUTE is 0, so it is implicit. I think this resolves this matter, thank you a lot. [1] PE format, "The .reloc Section (Image Only)" (https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#the-reloc-section-image-only) |
I would like the existing section names (as defined deliberately in This avoids any kind of heuristics, and matches the existing behaviour. As far as I'm concerned, the linker scripts are definitive to describe the intended layouts of the final binaries across all platforms (not just UEFI). The function of
I would probably suggest retaining the existing behaviour of copying sections rather than segments, since that seems to already more closely match what you are aiming to achieve. Would it suffice to simply change the section alignment ( |
That would be fine by me, just I researched the ELF format a little and like the Mach-O format, a loader should not be concerned with sections (linker info) but segments. Another concern is that the PE sections must be adjacent. If both conditions are fulfilled however, I see no reason to not take your route. I will do the edits you suggested locally and verify with fully constrained loading. If it works, I will submit a new PR. Sorry, I'm just not familiar with ELF or GNU utilities. :) |
@mcb30 Sorry to bother again, but I faced an unaligned ".pci_dev" section in the resulting PE. It is neither declared nor |
Good catch! That must be It's irrelevant for UEFI, where we don't have any such capability to mark a ROM as supporting multple PCI IDs. Doesn't show up in It should be safe to add it to the discard list. If that doesn't work (e.g. because the link-time check complains about an explicitly requested symbol being discarded), then just add it in to |
@mcb30 Sorry, misclicked. Confirmed working, will submit a V2. Tyvm! |
As per ipxe#313 (comment), these sections are not required for EFI execution. Discard them to avoid implementation-defined alignment malforming binaries. Signed-off-by: Marvin Häuser <8659494+mhaeuser@users.noreply.github.com>
As per ipxe#313 (comment), these sections are not required for EFI execution. Discard them to avoid implementation-defined alignment malforming binaries. Signed-off-by: Marvin Häuser <8659494+mhaeuser@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks much better: thank you for updating it! One minor whitespace fix required (see inline), plus some tweaks to the commit messages:
- "Discard .pci_devlist_* sections" should read "Discard .pci_devlist.* sections"
- The second commit has a stray "af843d" after your Signed-off-by line
- If you have a real email address (rather than
@users.noreply.github.com
) then that would be preferable, but not essential - I realise that my "80 character width" request was not specific enough, sorry. The code is fine, but the commit messages need to wrap such that the output of
git log
will look correct in an 80-column terminal. Sincegit log
adds 4 extra spaces, this requires wrapping the original message at fewer than 80 columns. I'd suggest wrapping at 70 (which is what the One True Editor will do by default 🙂 )
I could fix these up myself if you prefer, but then you wouldn't get the satisfaction of a "Merged" status in the GitHub UI.
As per ipxe#313 (comment), these sections are not required for EFI execution. Discard them to avoid implementation-defined alignment malforming binaries. Signed-off-by: Marvin Häuser <mhaeuser@posteo.de>
For optimal memory permission management, PE sections need to be aligned by the platform's minimum page size. Currently, the PE section alignment is fixed to 32 Bytes, which is below the typical 4 KB page size. Align all sections to 4 KB and adjust ELF to PE image conversion accordingly. Signed-off-by: Marvin Häuser <mhaeuser@posteo.de>
After a PE image is fully loaded and relocated, the loader code may opt to zero discardable sections for security reasons. This includes relocation and debug information, as both contain hints about specific locations within the binary. Mark both generated sections as discardable, which follows the PE specification. Signed-off-by: Marvin Häuser <mhaeuser@posteo.de>
@mcb30 Sorry for the hassle, I believe I corrected everything. Thanks for the fast review! |
As per #313 (comment), these sections are not required for EFI execution. Discard them to avoid implementation-defined alignment malforming binaries. Signed-off-by: Marvin Häuser <mhaeuser@posteo.de>
@mhaeuser Only the author email still needed fixing, so I just did that one myself. Thanks for the improvements! |
As per ipxe#313 (comment), these sections are not required for EFI execution. Discard them to avoid implementation-defined alignment malforming binaries. Signed-off-by: Marvin Häuser <mhaeuser@posteo.de>
As currently ELF sections rather than segments are converted to PE sections, PE section alignment is hard-coded, and some fields describing virtual properties are assigned values based on file alignment, EFI PE drivers generated by elf2efi are generally not well-aligned. This can cause issues when enforcing strict PE parsing rules (as I am currently proposing for EDK II / OVMF), or when enforcing section permissions.
This PR fixes all discovered issues regarding PE image alignment. Furthermore, the constructed debug and relocation sections are marked as discardable for security reasons. All changes made are in conformance with the PE specification.
The changes have been validated using a stricter EDK II image loader, with OVMF booting and successfully loading the appropriate EFI ROM. Images created by the old utility are rejected as expected. Please note that I have not been able to test the full functionality of the ROM image, only that it loads successfully.