Closed TBOpen closed 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?
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?
I basically had to roll my own pe modifier and now it works.
@TBOpen have you posted your pe modifier anywhere?
I basically had to roll my own pe modifier and now it works.
could you pls describe what you did to solve that issue?
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 ;)
@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?
Did you sign the binary after adding the section?
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.
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?!
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:.
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.
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
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.