rhboot / shim

UEFI shim loader
Other
848 stars 290 forks source link

objcopy for SBAT doesn't work? #376

Closed TBOpen closed 3 years ago

TBOpen commented 3 years ago

I'm now building the GRUB2 versions and when I use:

objcopy --set-section-alignment '.sbat=512' --add-section .sbat=sbat.csv foo.efi

the resulting GRUB cannot be booted by shim because it says:

Section 0 is inside image headers Malformed section header Failed to load image: Unsupported start_image() returned Unsupported

Is there a particular version of objcopy needed? I noticed it puts the section in the beginning instead of end of the PE like shim itself.

Is there something else needed?

Update:

It appears because the .sbat virtual address is created as 0.

TBOpen commented 3 years ago

I see shim used a different command line which I tried same issue either way. I was able to hack around it via:

objcopy --add-section .sbat=mycsvfile.csv --set-section-flags .sbat=contents,alloc,load,readonly,data grubx64.efi objcopy --adjust-vma 4096 grubx64.efi

However, it won't load, it just hangs the system when attempting to boot. If I don't touch grubx64.efi with the objcopy then it works fine.

This one works fine:

Dump of file: grubx64.efi, type: COFF64
Dump of PE/COFF file grubx64.efi
-----------------------------------------------
File size: 1062664
File header:
Machine: x86-64
TimeDate: 0x54A48E00 - Wed Dec 31 16:00:00 2014

Number of sections:  4
Number of symbols:   0
Optional header size: 240
Flags: 0x020E
Symbol table offset: 0x0
String table offset: 0x0
Section headers offset: 0x104

Optional header:
Magic number: 0x20B
Size of code: 0xB000
Size of uninitialized data: 0xF6000
Address of entry point: 0x1000
Base of code: 0x1000
Image base: 0x0000000000000000
Section alignment: 0x1000
File alignment: 0x1000
Size of image: 0x103000
Size of headers: 0x1000
Dll characteristics: 0x0
Size of stack reserve: 0x0000000000010000
Size of stack commit: 0x0000000000010000
Size of heap reserve: 0x0000000000010000
Size of heap commit: 0x0000000000010000
Directory  5, Base_relocation_table:
  Address 0x102000, Size 0x1000, Section 4, Offset 0x0000

 1 Section .text
Virtual size: 0xB000
Virtual address: 0x1000
Size of raw data: 0xB000
Raw data pointer: 0x1000
Characteristics: Text, Executable, Readable

 2 Section .data
Virtual size: 0x10000
Virtual address: 0xC000
Size of raw data: 0x10000
Raw data pointer: 0xC000
Characteristics: Data, Readable, Writeable

 3 Section mods
Virtual size: 0xE6000
Virtual address: 0x1C000
Size of raw data: 0xE6000
Raw data pointer: 0x1C000
Characteristics: Data, Readable, Writeable

 4 Section .reloc
Virtual size: 0x1000
Virtual address: 0x102000
Size of raw data: 0x1000
Raw data pointer: 0x102000
Characteristics: Data, Discardable, Readable

This one doesn't:

Dump of file: grubx64.efi, type: COFF64
Dump of PE/COFF file grubx64.efi
-----------------------------------------------
File size: 1066760
File header:
Machine: x86-64
TimeDate: 0x00000000 - Wed Dec 31 16:00:00 1969

Number of sections:  5
Number of symbols:   0
Optional header size: 240
Flags: 0x020E
Symbol table offset: 0x0
String table offset: 0x0
Section headers offset: 0x104

Optional header:
Magic number: 0x20B
Size of code: 0xB000
Size of uninitialized data: 0xF8000
Address of entry point: 0x2000
Base of code: 0x2000
Image base: 0x0000000000000000
Section alignment: 0x1000
File alignment: 0x1000
Size of image: 0x104000
Size of headers: 0x1000
Dll characteristics: 0x0
Size of stack reserve: 0x0000000000010000
Size of stack commit: 0x0000000000010000
Size of heap reserve: 0x0000000000010000
Size of heap commit: 0x0000000000010000
Directory  5, Base_relocation_table:
  Address 0x103000, Size 0x1000, Section 5, Offset 0x0000

 1 Section .sbat
Virtual size: 0x130
Virtual address: 0x1000
Size of raw data: 0x1000
Raw data pointer: 0x1000
Characteristics: Data, Readable, Align by 0x4

 2 Section .text
Virtual size: 0xB000
Virtual address: 0x2000
Size of raw data: 0xB000
Raw data pointer: 0x2000
Characteristics: Text, Executable, Readable, Align by 0x10

 3 Section .data
Virtual size: 0x10000
Virtual address: 0xD000
Size of raw data: 0x10000
Raw data pointer: 0xD000
Characteristics: Data, Readable, Writeable, Align by 0x10

 4 Section mods
Virtual size: 0xE6000
Virtual address: 0x1D000
Size of raw data: 0xE6000
Raw data pointer: 0x1D000
Characteristics: Data, Readable, Writeable, Align by 0x4

 5 Section .reloc
Virtual size: 0x1000
Virtual address: 0x103000
Size of raw data: 0x1000
Raw data pointer: 0x103000
Characteristics: Data, Discardable, Readable, Align by 0x4

Those are dumps using objconv in windows. Maybe if I can push the .sbat at the end if objcopy has an option for that?

TBOpen commented 3 years ago

So yes, objcopy isn't going to work unless it added a section to the end instead of beginning. I ran a disassembly of grub and there are no fix-up for things like:

48 BF BE C1 00 00 00 00 00 00 mov rdi, offset word_C1BE

Which should now be:

48 BF BE D1 00 00 00 00 00 00 mov rdi, offset word_D1BE

So unless objcopy has an option I can't find to add to end and nothing else exists to update existing PE/PE64 binaries, I guess I'll have to roll my own or see if I can make heads-or-tails out of the binutils objcopy / bfd code. I was going to use the __attribute__ ((section(".sbat"))) for a variable but due to the way those grubs are built (mk-image) it's not bringing in a section .sbat, but just adding the csv data in .data.

How is shim getting it further down, I'll have to see if I see it in the build?

TBOpen commented 3 years ago

I basically had to roll my own pe modifier and now it works.

hallyn commented 3 years ago

@TBOpen have you posted your pe modifier anywhere?

steadfasterX commented 2 years ago

I basically had to roll my own pe modifier and now it works.

could you pls describe what you did to solve that issue?

steadfasterX commented 2 years ago

ok so.. the hint that the .sbat section gets added to the beginning instead of getting appended was a life saver. I wouldn't had any idea where to start otherwise. so thx @TBOpen ! :)

TBOpen tried to use --adjust-vma but this will re-locate ALL sections having no effect at all (afaiu from the manpage).

My solution might be dirty/a hack/workaround only but "it works for me" and ensures that the .sbat section gets added at the end (or at least not at the start):

objcopy --set-section-alignment '.sbat=512' --add-section .sbat=refind_x64.csv --adjust-section-vma .sbat+10000000 /path/to/grubx64.efi

(note: my grubx64.efi is rEFInd so thats why I named my sbat CSV that way)

so the important part here is: --adjust-section-vma .sbat+10000000 which moves the address of the .sbat section to the end. Again this might be not ideal in all cases and maybe there are better ways to achieve this but.. as said.. it works for me.

for completeness: the content of my self-created refind_x64.csv:

sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
grubx64,1,Roderick W. Smith,rEFInd,0.13.2,https://www.rodsbooks.com/refind

maybe someone else find this useful and saves some hours of troubleshooting ;)

project0 commented 2 years ago

@steadfasterX I just tried your example with --adjust-section-vma .sbat+10000000, but unfortunately i end up with another error which only shows up when SecureBoot is enabled.

Malformed section header Failed to load image: Invalid Parameter start_image() returned Invalid Parameter

Looks like there is now an issue with the pointer/size calculation, at least these lines seems to be related to the issue i am facing: https://github.com/rhboot/shim/blob/shim-15.4/pe.c#L28-L40 https://github.com/rhboot/shim/blob/shim-15.4/pe.c#L494-L499

Any ideas how to fix it?

jonathan-conder commented 2 years ago

Did you sign the binary after adding the section?

project0 commented 2 years ago

Yeah of course, signed it after modifying. When using objcopy the signature table seemed to be removed anyway (checked with sbverify).

Not sure what i am missing.

steadfasterX commented 2 years ago

Yeah of course, signed it after modifying. When using objcopy the signature table seemed to be removed anyway (checked with sbverify).

Not sure what i am missing.

Could you share the header dump from before and after adding sbat?!

project0 commented 2 years ago

False positive from my side. I dont know what i was doing wrong, but i assume i just messed up the original files. After a fresh setup it is now working as expected :tada:.

5p4k commented 1 year ago

I am trying to add a .sbat section to a vmlinuz bootable kernel image, but it seems even --adjust-section-vma is not sufficient. I had to increase the offset to .sbat+100000000 (one more zero) because the image is 12MB in size. Here's my sbat.csv:

sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
linuxmint-5.15.0-56-generic,1,auto-efi-kernel,linuxmint,21.1,https://kernel.org

I then ran

$ objcopy --add-section .sbat=sbat.csv --adjust-section-vma .sbat+1000000000 vmlinuz-5.15.0-56-generic vmlinuz-with-sbat.efi
$ sbsign --key mok.key --cert mok.crt vmlinuz-with-sbat.efi
warning: checksum areas are greater than image size. Invalid section table?
Signing Unsigned original image

The warning is already indicating that something did not work, and indeed if I try to boot I get the message above,

Section 0 is inside image headers
Malformed section header
Failed to load image: Unsupported
start_image() returned Unsupported

I am using shim 15.4 shipped with Mint (Ubuntu). I am not sure how exactly it happens that Section 0 can be in the image headers, I do not know much about how binaries are arranged internally, but here's a diff of the output of objdump -x vmlinuz-5.15.0-56-generic and objdump -x vmlinuz-with-sbat.efi.signed:

diff --git a/vmlinuz-5.15.0-56-generic.dump b/vmlinuz-with-sbat.efi.signed.dump
index 1f932c9..302c10a 100644
--- a/vmlinuz-5.15.0-56-generic.dump
+++ b/vmlinuz-with-sbat.efi.signed.dump
@@ -1,6 +1,6 @@

-vmlinuz-5.15.0-56-generic:     file format pei-x86-64
-vmlinuz-5.15.0-56-generic
+vmlinuz-with-sbat.efi.signed:     file format pei-x86-64
+vmlinuz-with-sbat.efi.signed
 architecture: i386:x86-64, flags 0x00000103:
 HAS_RELOC, EXEC_P, D_PAGED
 start address 0x0000000001afc2dc
@@ -14,12 +14,12 @@ Characteristics 0x20e
 Time/Date      Thu Jan  1 01:00:00 1970
 Magic          020b    (PE32+)
 MajorLinkerVersion 2
-MinorLinkerVersion 20
-SizeOfCode     0000000003a2fe00
-SizeOfInitializedData  0000000000000000
+MinorLinkerVersion 38
+SizeOfCode     0000000000b038e0
+SizeOfInitializedData  00000000000000e0
 SizeOfUninitializedData    0000000000000000
 AddressOfEntryPoint    0000000000afc2dc
-BaseOfCode     0000000000000200
+BaseOfCode     0000000000003e00
 ImageBase      0000000001000000
 SectionAlignment   00000020
 FileAlignment      00000020
@@ -30,9 +30,9 @@ MinorImageVersion 0
 MajorSubsystemVersion  0
 MinorSubsystemVersion  0
 Win32Version       00000000
-SizeOfImage        03a30000
-SizeOfHeaders      00000200
-CheckSum       00b0d39f
+SizeOfImage        3a9acaa0
+SizeOfHeaders      00000250
+CheckSum       00b13af2
 Subsystem      0000000a    (EFI application)
 DllCharacteristics 00000000
 SizeOfStackReserve 0000000000000000
@@ -40,15 +40,15 @@ SizeOfStackCommit   0000000000000000
 SizeOfHeapReserve  0000000000000000
 SizeOfHeapCommit   0000000000000000
 LoaderFlags        00000000
-NumberOfRvaAndSizes    00000006
+NumberOfRvaAndSizes    00000010

 The Data Directory
 Entry 0 0000000000000000 00000000 Export Directory [.edata (or where ever we found it)]
 Entry 1 0000000000000000 00000000 Import Directory [parts of .idata]
 Entry 2 0000000000000000 00000000 Resource Directory [.rsrc]
 Entry 3 0000000000000000 00000000 Exception Directory [.pdata]
-Entry 4 0000000000b03b20 00000780 Security Directory
-Entry 5 0000000000000000 00000000 Base Relocation Directory [.reloc]
+Entry 4 0000000000b03c10 00000628 Security Directory
+Entry 5 0000000000003dc0 00000020 Base Relocation Directory [.reloc]
 Entry 6 0000000000000000 00000000 Debug Directory
 Entry 7 0000000000000000 00000000 Description Directory
 Entry 8 0000000000000000 00000000 Special Directory
@@ -68,14 +68,16 @@ Virtual Address: 00003dca Chunk size 10 (0xa) Number of fixups 1

 Sections:
 Idx Name          Size      VMA               LMA               File off  Algn
-  0 .setup        00003bc0  0000000001000200  0000000001000200  00000200  2**4
+  0 .setup        00003bc0  0000000001000200  0000000001000200  00000250  2**2
                   CONTENTS, ALLOC, LOAD, READONLY, CODE
-  1 .reloc        00000020  0000000001003dc0  0000000001003dc0  00003dc0  2**0
+  1 .reloc        00000020  0000000001003dc0  0000000001003dc0  00003e10  2**2
                   CONTENTS, ALLOC, LOAD, READONLY, DATA
-  2 .compat       00000020  0000000001003de0  0000000001003de0  00003de0  2**0
+  2 .compat       00000020  0000000001003de0  0000000001003de0  00003e30  2**2
                   CONTENTS, ALLOC, LOAD, READONLY, DATA
-  3 .text         00affd20  0000000001003e00  0000000001003e00  00003e00  2**4
+  3 .text         00affd20  0000000001003e00  0000000001003e00  00003e50  2**4
                   CONTENTS, ALLOC, LOAD, READONLY, CODE
+  4 .sbat         0000009d  000000003b9aca00  000000003b9aca00  00b03b70  2**2
+                  CONTENTS, ALLOC, LOAD, READONLY, DATA
 SYMBOL TABLE:
 no symbols

Aside from the Algn field, which changes, all section seem to shift down by 0x50, which is the difference in SizeOfHeaders. But then, SizeOfCode, SizeOfInitializedData, BaseOfCode, SizeOfImage change in a way that I cannot make sense of.

chenxiaolong commented 1 year ago

I made a script for appending arbitrary sections to the end of a PE file: https://github.com/chenxiaolong/random-scripts/blob/master/pe-add-sections.py. It can be used to add .sbat while keeping the file bootable.

It uses the pefile Python library to modify the PE executable (based on systemd ukify's logic). Only appending (not overwriting) sections in unsigned files is supported, but that should be sufficient for most use cases.

# `-z .sbat` to automatically NULL-terminate the data since that's what shim expects
./pe-add-sections.py -s .sbat <sbat csv file> -z .sbat -i <input file> -o <output file>

EDIT: Permalink at the current commit, in case I rename/remove the file in the future: https://github.com/chenxiaolong/random-scripts/blob/e752bf07bcfb0aa19a9d7dafa139cca74ecca4b7/pe-add-sections.py