2024-02-05 02:06:51

by Bagas Sanjaya

[permalink] [raw]
Subject: Re: Broken section alignment in 6.7 and 6.8rc EFI stub

On Mon, Feb 05, 2024 at 12:08:00AM +0000, Mike Beaton wrote:
> Good evening.
>
> Linux kernels from 6.7 upwards (including 6.8rc) appear to have broken
> PE section alignment in their EFI stub.
>
> Up to 6.6, we see monotonically increasing and contiguous VMA and LMA,
> as expected for a well-formed PE/COFF file.
>
> In 6.7 and 6.8 these addresses basically jump around all over the place.
>
> At least one loader which is believed to be enforcing strong but
> reasonable rules on PE section layout refuses to load these:
> https://github.com/acidanthera/bugtracker/issues/2371#issuecomment-1925801292
>
> objdumps of some example kernels (two good, three bad) follow:
>
> $ objdump -h vmlinuz-5.15.0-92-generic
>
> vmlinuz-5.15.0-92-generic: file format pei-x86-64
>
> Sections:
> Idx Name Size VMA LMA File off Algn
> 0 .setup 00003bc0 0000000001000200 0000000001000200 00000200 2**4
> CONTENTS, ALLOC, LOAD, READONLY, CODE
> 1 .reloc 00000020 0000000001003dc0 0000000001003dc0 00003dc0 2**0
> CONTENTS, ALLOC, LOAD, READONLY, DATA
> 2 .compat 00000020 0000000001003de0 0000000001003de0 00003de0 2**0
> CONTENTS, ALLOC, LOAD, READONLY, DATA
> 3 .text 00b0f4c0 0000000001003e00 0000000001003e00 00003e00 2**4
> CONTENTS, ALLOC, LOAD, READONLY, CODE
> $ objdump -h vmlinuz-6.6.11-zabbly+
>
> vmlinuz-6.6.11-zabbly+: file format pei-x86-64
>
> Sections:
> Idx Name Size VMA LMA File off Algn
> 0 .setup 00003dc0 0000000001000200 0000000001000200 00000200 2**4
> CONTENTS, ALLOC, LOAD, READONLY, CODE
> 1 .reloc 00000020 0000000001003fc0 0000000001003fc0 00003fc0 2**0
> CONTENTS, ALLOC, LOAD, READONLY, DATA
> 2 .compat 00000020 0000000001003fe0 0000000001003fe0 00003fe0 2**0
> CONTENTS, ALLOC, LOAD, READONLY, DATA
> 3 .text 00d6e400 0000000001004000 0000000001004000 00004000 2**4
> CONTENTS, ALLOC, LOAD, READONLY, CODE
> $ objdump -h vmlinuz-6.7.3-3-liquorix-amd64
>
> vmlinuz-6.7.3-3-liquorix-amd64: file format pei-x86-64
>
> Sections:
> Idx Name Size VMA LMA File off Algn
> 0 .setup 00003000 0000000000001000 0000000000001000 00001000 2**2
> CONTENTS, ALLOC, LOAD, READONLY, DATA
> 1 .compat 00000008 0000000000c0e000 0000000000c0e000 00004000 2**2
> CONTENTS, ALLOC, LOAD, READONLY, DATA
> 2 .text 00baa000 0000000000005000 0000000000005000 00005000 2**4
> CONTENTS, ALLOC, LOAD, READONLY, CODE
> 3 .data 00001200 0000000000baf000 0000000000baf000 00baf000 2**4
> CONTENTS, ALLOC, LOAD, DATA
> $ objdump -h vmlinuz-6.7.3-zabbly+
>
> vmlinuz-6.7.3-zabbly+: file format pei-x86-64
>
> Sections:
> Idx Name Size VMA LMA File off Algn
> 0 .setup 00003000 0000000000001000 0000000000001000 00001000 2**2
> CONTENTS, ALLOC, LOAD, READONLY, DATA
> 1 .compat 00000008 0000000000df0000 0000000000df0000 00004000 2**2
> CONTENTS, ALLOC, LOAD, READONLY, DATA
> 2 .text 00d84000 0000000000005000 0000000000005000 00005000 2**4
> CONTENTS, ALLOC, LOAD, READONLY, CODE
> 3 .data 00001200 0000000000d89000 0000000000d89000 00d89000 2**4
> CONTENTS, ALLOC, LOAD, DATA
> $ objdump -h vmlinuz-6.8.0-0.rc3.225.vanilla.fc39.x86_64
>
> vmlinuz-6.8.0-0.rc3.225.vanilla.fc39.x86_64: file format pei-x86-64
>
> Sections:
> Idx Name Size VMA LMA File off Algn
> 0 .setup 00003000 0000000000001000 0000000000001000 00001000 2**2
> CONTENTS, ALLOC, LOAD, READONLY, DATA
> 1 .compat 00000008 0000000000e8b000 0000000000e8b000 00004000 2**2
> CONTENTS, ALLOC, LOAD, READONLY, DATA
> 2 .text 00e1f000 0000000000005000 0000000000005000 00005000 2**4
> CONTENTS, ALLOC, LOAD, READONLY, CODE
> 3 .data 00001200 0000000000e24000 0000000000e24000 00e24000 2**4
> CONTENTS, ALLOC, LOAD, DATA
> $

So v6.7 onwards misses .reloc section, right?

Confused...

--
An old man doll... just what I always wanted! - Clara


Attachments:
(No filename) (4.55 kB)
signature.asc (235.00 B)
Download all attachments

2024-02-05 07:47:23

by Mike Beaton

[permalink] [raw]
Subject: Re: Broken section alignment in 6.7 and 6.8rc EFI stub

On Mon, 5 Feb 2024 at 02:06, Bagas Sanjaya <[email protected]> wrote:
>
> So v6.7 onwards misses .reloc section, right?
>
> Confused...

Reloc info is still present as normal in data directories, e.g.
`llvm-objdump -p` shows NumberOfRvaAndSizes = 6. Reloc info is taken
from index 5 https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/PeImage.h#L128
(I've been told a dummy .reloc section was dumped recently?)

2024-02-05 07:54:38

by Ard Biesheuvel

[permalink] [raw]
Subject: Re: Broken section alignment in 6.7 and 6.8rc EFI stub

On Mon, 5 Feb 2024 at 08:37, Mike Beaton <[email protected]> wrote:
>
> On Mon, 5 Feb 2024 at 02:06, Bagas Sanjaya <[email protected]> wrote:
> >
> > So v6.7 onwards misses .reloc section, right?
> >
> > Confused...
>
> Reloc info is still present as normal in data directories, e.g.
> `llvm-objdump -p` shows NumberOfRvaAndSizes = 6. Reloc info is taken
> from index 5 https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/PeImage.h#L128
> . (I've been told a dummy .reloc section was dumped recently?)
>

So there are a couple of things going on here:
- the .reloc section was indeed dropped because we could not find any
evidence anywhere that the reason it was added is still valid;
- the .compat section uses a non-1:1 RVA mapping, to avoid padding,
but reading the PE/COFF spec again, I suppose this is not compliant.

Note that objdump looks broken too, on an image I have locally, I get

(llvm-readelf -a)

Section {
Number: 2
Name: .compat (2E 63 6F 6D 70 61 74 00)
VirtualSize: 0x8
VirtualAddress: 0xB82000
RawDataSize: 4096
PointerToRawData: 0x4000

(objdump -h)

1 .compat 00000008 0000000000b82000 0000000000b82000 00004000 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA

So the .compat section is in the correct spot in the file view but not
in the memory view.

Given that the .setup section is not relevant to EFI boot anyway, we
could try to use the same file mapping as the virtual mapping, and
just split the content preceding .text across the .setup and .compat
sections arbitrarily.

Could you try the below?


diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index b2771710ed98..f8b48ff86dd9 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -106,8 +106,7 @@ extra_header_fields:
.word 0 # MinorSubsystemVersion
.long 0 # Win32VersionValue

- .long setup_size + ZO__end + pecompat_vsize
- # SizeOfImage
+ .long setup_size + ZO__end # SizeOfImage

.long salign # SizeOfHeaders
.long 0 # CheckSum
@@ -143,7 +142,7 @@ section_table:
.ascii ".setup"
.byte 0
.byte 0
- .long setup_size - salign # VirtualSize
+ .long pecompat_fstart - salign # VirtualSize
.long salign # VirtualAddress
.long pecompat_fstart - salign # SizeOfRawData
.long salign # PointerToRawData
@@ -157,7 +156,7 @@ section_table:
.asciz ".compat"

.long 8 # VirtualSize
- .long setup_size + ZO__end # VirtualAddress
+ .long pecompat_fstart # VirtualAddress
.long pecompat_fsize # SizeOfRawData
.long pecompat_fstart # PointerToRawData

@@ -173,7 +172,6 @@ section_table:
*/
.pushsection ".pecompat", "a", @progbits
.balign falign
- .set pecompat_vsize, salign
.globl pecompat_fstart
pecompat_fstart:
.byte 0x1 # Version
@@ -182,7 +180,6 @@ pecompat_fstart:
.long setup_size + ZO_efi32_pe_entry # Entrypoint
.popsection
#else
- .set pecompat_vsize, 0
.set pecompat_fstart, setup_size
#endif
.ascii ".text"

2024-02-05 07:59:25

by Ard Biesheuvel

[permalink] [raw]
Subject: Re: Broken section alignment in 6.7 and 6.8rc EFI stub

On Mon, 5 Feb 2024 at 08:47, Ard Biesheuvel <[email protected]> wrote:
>
> On Mon, 5 Feb 2024 at 08:37, Mike Beaton <[email protected]> wrote:
> >
> > On Mon, 5 Feb 2024 at 02:06, Bagas Sanjaya <[email protected]> wrote:
> > >
> > > So v6.7 onwards misses .reloc section, right?
> > >
> > > Confused...
> >
> > Reloc info is still present as normal in data directories, e.g.
> > `llvm-objdump -p` shows NumberOfRvaAndSizes = 6. Reloc info is taken
> > from index 5 https://github.com/tianocore/edk2/blob/master/MdePkg/Include/IndustryStandard/PeImage.h#L128
> > . (I've been told a dummy .reloc section was dumped recently?)
> >
>
> So there are a couple of things going on here:
> - the .reloc section was indeed dropped because we could not find any
> evidence anywhere that the reason it was added is still valid;
> - the .compat section uses a non-1:1 RVA mapping, to avoid padding,
> but reading the PE/COFF spec again, I suppose this is not compliant.
>
> Note that objdump looks broken too, on an image I have locally, I get
>
> (llvm-readelf -a)
>
> Section {
> Number: 2
> Name: .compat (2E 63 6F 6D 70 61 74 00)
> VirtualSize: 0x8
> VirtualAddress: 0xB82000
> RawDataSize: 4096
> PointerToRawData: 0x4000
>
> (objdump -h)
>
> 1 .compat 00000008 0000000000b82000 0000000000b82000 00004000 2**2
> CONTENTS, ALLOC, LOAD, READONLY, DATA
>
> So the .compat section is in the correct spot in the file view but not
> in the memory view.
>
> Given that the .setup section is not relevant to EFI boot anyway, we
> could try to use the same file mapping as the virtual mapping, and
> just split the content preceding .text across the .setup and .compat
> sections arbitrarily.
>
> Could you try the below?
>

OK, never mind - that violates the section alignment.