Blame SOURCES/0060-Generate-a-sane-PE-header-on-shim-fallback-and-MokMa.patch

4210fa
From 0e7ba5947eb38b79de2051ecf3b95055e620475c Mon Sep 17 00:00:00 2001
4210fa
From: Peter Jones <pjones@redhat.com>
4210fa
Date: Sat, 20 Sep 2014 14:03:03 -0400
4210fa
Subject: [PATCH 60/74] Generate a sane PE header on shim, fallback, and
4210fa
 MokManager.
4210fa
4210fa
It turns out a7249a65 was masking a second problem - on some binaries,
4210fa
when we actually don't have any base relocations at all, binutils'
4210fa
"objcopy --target efi-app-x86_64" is generating a PE header with a base
4210fa
relocations pointer that happily points into the middle of our text
4210fa
section.  So with shim processing base relocations correctly, it refuses
4210fa
to load those binaries.
4210fa
4210fa
For example, on one binary I just built:
4210fa
4210fa
00000130  00 a0 00 00 0a 00 00 00  00 00 00 00 00 00 00 00 |................|
4210fa
4210fa
which says there's a Base Relocation Table at 0xa000 that's 0xa bytes long.
4210fa
That's here:
4210fa
4210fa
0000a000  58 00 29 00 00 00 00 00  48 00 44 00 28 00 50 00 |X.).....H.D.(.P.|
4210fa
0000a010  61 00 72 00 74 00 25 00  64 00 2c 00 53 00 69 00 |a.r.t.%.d.,.S.i.|
4210fa
0000a020  67 00 25 00 67 00 29 00  00 00 00 00 00 00 00 00 |g.%.g.).........|
4210fa
0000a030  48 00 44 00 28 00 50 00  61 00 72 00 74 00 25 00 |H.D.(.P.a.r.t.%.|
4210fa
4210fa
So the table is:
4210fa
4210fa
0000a000  58 00 29 00 00 00 00 00  48 00                   |X.).....H.      |
4210fa
4210fa
That wouldn't be so bad, except those binaries are MokManager.efi,
4210fa
fallback.efi, and shim.efi, and sometimes they're .reloc, which we're
4210fa
actually trying to handle correctly now because grub builds with a real
4210fa
and valid .reloc table.  So though I didn't think there was any hair
4210fa
left on this yak, more shaving ensues.
4210fa
4210fa
With this change, instead of letting objcopy do whatever it likes, we
4210fa
switch to "-O binary" and merely link in a header that's appropriate for
4210fa
our binaries.  This is the same method Ard wrote for aarch64, and it
4210fa
seems to work fine in either place (modulo some minor changes.)
4210fa
4210fa
At some point this should be merged into gnu-efi instead of carrying our
4210fa
own crt0-efi-x86_64.S, but that's a less immediate problem.
4210fa
4210fa
I did not need this problem.
4210fa
4210fa
Signed-off-by: Peter Jones <pjones@redhat.com>
4210fa
---
4210fa
 Makefile           |  24 ++++++--
4210fa
 crt0-efi-x86_64.S  | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++++
4210fa
 elf_x86_64_efi.lds |  85 +++++++++++++------------
4210fa
 3 files changed, 236 insertions(+), 50 deletions(-)
4210fa
 create mode 100644 crt0-efi-x86_64.S
4210fa
4210fa
diff --git a/Makefile b/Makefile
4210fa
index 5bc513c..d5fd55b 100644
4210fa
--- a/Makefile
4210fa
+++ b/Makefile
4210fa
@@ -15,7 +15,10 @@ EFI_PATH	:= /usr/lib64/gnuefi
4210fa
 LIB_GCC		= $(shell $(CC) -print-libgcc-file-name)
4210fa
 EFI_LIBS	= -lefi -lgnuefi --start-group Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a --end-group $(LIB_GCC) 
4210fa
 
4210fa
-EFI_CRT_OBJS 	= $(EFI_PATH)/crt0-efi-$(ARCH).o
4210fa
+ifeq ($(ARCH),x86_64)
4210fa
+EFI_CRT_OBJS	:= crt0-efi-$(ARCH).o
4210fa
+endif
4210fa
+EFI_CRT_OBJS 	?= $(EFI_PATH)/crt0-efi-$(ARCH).o
4210fa
 EFI_LDS		= elf_$(ARCH)_efi.lds
4210fa
 
4210fa
 DEFAULT_LOADER	:= \\\\grub.efi
4210fa
@@ -52,11 +55,11 @@ ifneq ($(origin VENDOR_DBX_FILE), undefined)
4210fa
 	CFLAGS += -DVENDOR_DBX_FILE=\"$(VENDOR_DBX_FILE)\"
4210fa
 endif
4210fa
 
4210fa
-LDFLAGS		= -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L$(EFI_PATH) -L$(LIB_PATH) -LCryptlib -LCryptlib/OpenSSL $(EFI_CRT_OBJS)
4210fa
+LDFLAGS		= -nostdlib -znocombreloc -T $(EFI_LDS) -shared -Bsymbolic -L$(EFI_PATH) -L$(LIB_PATH) -LCryptlib -LCryptlib/OpenSSL
4210fa
 
4210fa
 VERSION		= 0.7
4210fa
 
4210fa
-TARGET	= shim.efi MokManager.efi.signed fallback.efi.signed
4210fa
+TARGET	+= shim.efi MokManager.efi.signed fallback.efi.signed
4210fa
 OBJS	= shim.o netboot.o cert.o replacements.o version.o
4210fa
 KEYS	= shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer
4210fa
 SOURCES	= shim.c shim.h netboot.c include/PeImage.h include/wincert.h include/console.h replacements.c replacements.h version.c version.h
4210fa
@@ -94,17 +97,17 @@ shim.o: $(SOURCES) shim_cert.h
4210fa
 cert.o : cert.S
4210fa
 	$(CC) $(CFLAGS) -c -o $@ $<
4210fa
 
4210fa
-shim.so: $(OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
4210fa
+shim.so: $(OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a $(EFI_CRT_OBJS)
4210fa
 	$(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS)
4210fa
 
4210fa
 fallback.o: $(FALLBACK_SRCS)
4210fa
 
4210fa
-fallback.so: $(FALLBACK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
4210fa
+fallback.so: $(FALLBACK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a $(EFI_CRT_OBJS)
4210fa
 	$(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS)
4210fa
 
4210fa
 MokManager.o: $(MOK_SOURCES)
4210fa
 
4210fa
-MokManager.so: $(MOK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a
4210fa
+MokManager.so: $(MOK_OBJS) Cryptlib/libcryptlib.a Cryptlib/OpenSSL/libopenssl.a lib/lib.a $(EFI_CRT_OBJS)
4210fa
 	$(LD) -o $@ $(LDFLAGS) $^ $(EFI_LIBS) lib/lib.a
4210fa
 
4210fa
 Cryptlib/libcryptlib.a:
4210fa
@@ -128,8 +131,17 @@ SUBSYSTEM	:= 0xa
4210fa
 LDFLAGS		+= --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
4210fa
 endif
4210fa
 
4210fa
+ifeq ($(ARCH),x86_64)
4210fa
+FORMAT		:= -O binary
4210fa
+SUBSYSTEM	:= 0xa
4210fa
+LDFLAGS		+= --defsym=EFI_SUBSYSTEM=$(SUBSYSTEM)
4210fa
+endif
4210fa
+
4210fa
 FORMAT		?= --target efi-app-$(ARCH)
4210fa
 
4210fa
+crt0-efi-x86_64.o : crt0-efi-x86_64.S
4210fa
+	$(CC) $(CFLAGS) -DEFI_SUBSYSTEM=$(SUBSYSTEM) -c -o $@ $<
4210fa
+
4210fa
 %.efi: %.so
4210fa
 	$(OBJCOPY) -j .text -j .sdata -j .data \
4210fa
 		-j .dynamic -j .dynsym  -j .rel* \
4210fa
diff --git a/crt0-efi-x86_64.S b/crt0-efi-x86_64.S
4210fa
new file mode 100644
4210fa
index 0000000..f334a63
4210fa
--- /dev/null
4210fa
+++ b/crt0-efi-x86_64.S
4210fa
@@ -0,0 +1,177 @@
4210fa
+/* crt0-efi-x86_64.S - x86_64 EFI startup code.
4210fa
+ *
4210fa
+ * Copyright 2014 Red Hat, Inc. <pjones@redhat.com>
4210fa
+ * Redistribution and use in source and binary forms, with or without
4210fa
+ * modification, are permitted provided that the following conditions
4210fa
+ * are met:
4210fa
+ *
4210fa
+ * Redistributions of source code must retain the above copyright
4210fa
+ * notice, this list of conditions and the following disclaimer.
4210fa
+ *
4210fa
+ * Redistributions in binary form must reproduce the above copyright
4210fa
+ * notice, this list of conditions and the following disclaimer in the
4210fa
+ * documentation and/or other materials provided with the
4210fa
+ * distribution.
4210fa
+ *
4210fa
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4210fa
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
4210fa
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
4210fa
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
4210fa
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
4210fa
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
4210fa
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
4210fa
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4210fa
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4210fa
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
4210fa
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
4210fa
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
4210fa
+ */
4210fa
+	.section	.text.head
4210fa
+
4210fa
+	/*
4210fa
+	 * Magic "MZ" signature for PE/COFF
4210fa
+	 */
4210fa
+	.globl	ImageBase
4210fa
+ImageBase:
4210fa
+	.ascii	"MZ"
4210fa
+	.skip	58				// 'MZ' + pad + offset == 64
4210fa
+	.long	pe_header - ImageBase		// Offset to the PE header.
4210fa
+	.long	0x0eba1f0e			/* terrifying code */
4210fa
+	.long	0xcd09b400			/* terrifying code */
4210fa
+	.long	0x4c01b821			/* terrifying code */
4210fa
+	.short	0x21cd				/* terrfiying code */
4210fa
+	.ascii	"The only winning move is not to play.\r\r\n$" /* DOS text */
4210fa
+	.skip	9
4210fa
+pe_header:
4210fa
+	.ascii	"PE"
4210fa
+	.short 	0
4210fa
+coff_header:
4210fa
+	.short	0x8664				// x86_64
4210fa
+	.short	1				// nr_sections
4210fa
+	.long	0 				// TimeDateStamp
4210fa
+	.long	0				// PointerToSymbolTable
4210fa
+	.long	0				// NumberOfSymbols
4210fa
+	.short	section_table - optional_header	// SizeOfOptionalHeader
4210fa
+	.short	0x206				// Characteristics.
4210fa
+						// IMAGE_FILE_DEBUG_STRIPPED |
4210fa
+						// IMAGE_FILE_EXECUTABLE_IMAGE |
4210fa
+						// IMAGE_FILE_LINE_NUMS_STRIPPED
4210fa
+optional_header:
4210fa
+	.short	0x20b				// PE32+ format
4210fa
+	.byte	0x02				// MajorLinkerVersion
4210fa
+	.byte	0x18				// MinorLinkerVersion
4210fa
+	.long	_edata - _start			// SizeOfCode
4210fa
+	.long	0				// SizeOfInitializedData
4210fa
+	.long	0				// SizeOfUninitializedData
4210fa
+	.long	_start - ImageBase		// AddressOfEntryPoint
4210fa
+	.long	_start - ImageBase		// BaseOfCode
4210fa
+
4210fa
+extra_header_fields:
4210fa
+	.quad	0				// ImageBase
4210fa
+	.long	0x20				// SectionAlignment
4210fa
+	.long	0x8				// FileAlignment
4210fa
+	.short	0				// MajorOperatingSystemVersion
4210fa
+	.short	0				// MinorOperatingSystemVersion
4210fa
+	.short	0				// MajorImageVersion
4210fa
+	.short	0				// MinorImageVersion
4210fa
+	.short	0				// MajorSubsystemVersion
4210fa
+	.short	0				// MinorSubsystemVersion
4210fa
+	.long	0				// Win32VersionValue
4210fa
+
4210fa
+	.long	_edata - ImageBase		// SizeOfImage
4210fa
+
4210fa
+	// Everything before the kernel image is considered part of the header
4210fa
+	.long	_start - ImageBase		// SizeOfHeaders
4210fa
+	.long	0				// CheckSum
4210fa
+	.short	EFI_SUBSYSTEM			// Subsystem
4210fa
+	.short	0				// DllCharacteristics
4210fa
+	.quad	0				// SizeOfStackReserve
4210fa
+	.quad	0				// SizeOfStackCommit
4210fa
+	.quad	0				// SizeOfHeapReserve
4210fa
+	.quad	0				// SizeOfHeapCommit
4210fa
+	.long	0				// LoaderFlags
4210fa
+	.long	0x10				// NumberOfRvaAndSizes
4210fa
+
4210fa
+	.quad	0				// ExportTable
4210fa
+	.quad	0				// ImportTable
4210fa
+	.quad	0				// ResourceTable
4210fa
+	.quad	0				// ExceptionTable
4210fa
+	.quad	0				// CertificationTable
4210fa
+	.quad	0				// BaseRelocationTable
4210fa
+	.quad	0				// DebugTable
4210fa
+	.quad	0				// ArchTable
4210fa
+	.quad	0				// GlobalPointerTable
4210fa
+	.quad	0				// .tls
4210fa
+	.quad	0				// LoadConfigTable
4210fa
+	.quad	0				// BoundImportsTable
4210fa
+	.quad	0				// ImportAddressTable
4210fa
+	.quad	0				// DelayLoadImportTable
4210fa
+	.quad	0				// ClrRuntimeHeader (.cor)
4210fa
+	.quad	0				// Reserved
4210fa
+
4210fa
+	// Section table
4210fa
+section_table:
4210fa
+	.ascii	".text"
4210fa
+	.byte	0
4210fa
+	.byte	0
4210fa
+	.byte	0			// end of 0 padding of section name
4210fa
+
4210fa
+	.long	_edata - _start		// VirtualSize
4210fa
+	.long	_start - ImageBase	// VirtualAddress
4210fa
+	.long	_edata - _start		// SizeOfRawData
4210fa
+	.long	_start - ImageBase	// PointerToRawData
4210fa
+	.long	0		// PointerToRelocations (0 for executables)
4210fa
+	.long	0		// PointerToLineNumbers (0 for executables)
4210fa
+	.short	0		// NumberOfRelocations  (0 for executables)
4210fa
+	.short	0		// NumberOfLineNumbers  (0 for executables)
4210fa
+	.long	0x60500020	// Characteristics (section flags)
4210fa
+
4210fa
+	/*
4210fa
+	 * The EFI application loader requires a relocation section
4210fa
+	 * because EFI applications must be relocatable.  This is a
4210fa
+	 * dummy section as far as we are concerned.
4210fa
+	 */
4210fa
+	.ascii	".reloc"
4210fa
+	.byte	0
4210fa
+	.byte	0			// end of 0 padding of section name
4210fa
+
4210fa
+	.long	0			// VirtualSize
4210fa
+	.long	0			// VirtualAddress
4210fa
+	.long	0			// SizeOfRawData
4210fa
+	.long	0			// PointerToRawData
4210fa
+	.long	0			// PointerToRelocations
4210fa
+	.long	0			// PointerToLineNumbers
4210fa
+	.short	0			// NumberOfRelocations
4210fa
+	.short	0			// NumberOfLineNumbers
4210fa
+	.long	0x42100040		// Characteristics (section flags)
4210fa
+
4210fa
+	/* x86-64 needs this padding here; without it, some machines simply
4210fa
+	 * refuse to admit this is an EFI binary.  I'm not really sure why;
4210fa
+	 * reading the spec, it's unclear, but you'd expect it would need to
4210fa
+	 * be aligned to (1 << FileAlignment), which would mean not having
4210fa
+	 * the spacing.
4210fa
+	 */
4210fa
+	.quad	0
4210fa
+_start:
4210fa
+	subq $8, %rsp
4210fa
+	pushq %rcx
4210fa
+	pushq %rdx
4210fa
+
4210fa
+0:
4210fa
+	lea ImageBase(%rip), %rdi
4210fa
+	lea _DYNAMIC(%rip), %rsi
4210fa
+
4210fa
+	popq %rcx
4210fa
+	popq %rdx
4210fa
+	pushq %rcx
4210fa
+	pushq %rdx
4210fa
+	call _relocate
4210fa
+
4210fa
+	popq %rdi
4210fa
+	popq %rsi
4210fa
+
4210fa
+	call efi_main
4210fa
+	addq $8, %rsp
4210fa
+
4210fa
+.exit:	
4210fa
+  	ret
4210fa
diff --git a/elf_x86_64_efi.lds b/elf_x86_64_efi.lds
4210fa
index f981102..091187b 100644
4210fa
--- a/elf_x86_64_efi.lds
4210fa
+++ b/elf_x86_64_efi.lds
4210fa
@@ -4,63 +4,60 @@ OUTPUT_ARCH(i386:x86-64)
4210fa
 ENTRY(_start)
4210fa
 SECTIONS
4210fa
 {
4210fa
-  . = 0;
4210fa
-  ImageBase = .;
4210fa
-  .hash : { *(.hash) }	/* this MUST come first! */
4210fa
-  . = ALIGN(4096);
4210fa
-  .eh_frame : 
4210fa
-  { 
4210fa
-    *(.eh_frame)
4210fa
-  }
4210fa
-  . = ALIGN(4096);
4210fa
-  .text :
4210fa
-  {
4210fa
-   *(.text)
4210fa
-  }
4210fa
-  . = ALIGN(4096);
4210fa
-  .reloc :
4210fa
-  {
4210fa
-   *(.reloc)
4210fa
+  .text 0x0 : {
4210fa
+    *(.text.head)
4210fa
+    *(.text)
4210fa
+    *(.text.*)
4210fa
+    *(.gnu.linkonce.t.*)
4210fa
+    *(.srodata)
4210fa
+    *(.rodata*)
4210fa
+    . = ALIGN(16);
4210fa
+    _etext = .;
4210fa
   }
4210fa
-  . = ALIGN(4096);
4210fa
+  .dynamic : { *(.dynamic) }
4210fa
   .data :
4210fa
   {
4210fa
-   *(.rodata*)
4210fa
-   *(.got.plt)
4210fa
-   *(.got)
4210fa
-   *(.data*)
4210fa
-   *(.sdata)
4210fa
-   /* the EFI loader doesn't seem to like a .bss section, so we stick
4210fa
-      it all into .data: */
4210fa
-   *(.sbss)
4210fa
-   *(.scommon)
4210fa
-   *(.dynbss)
4210fa
-   *(.bss)
4210fa
-   *(COMMON)
4210fa
-   *(.rel.local)
4210fa
+    *(.sdata)
4210fa
+    *(.data)
4210fa
+    *(.data1)
4210fa
+    *(.data.*)
4210fa
+    *(.got.plt)
4210fa
+    *(.got)
4210fa
+
4210fa
+    /* the EFI loader doesn't seem to like a .bss section, so we stick
4210fa
+     * it all into .data: */
4210fa
+    . = ALIGN(16);
4210fa
+    _bss = .;
4210fa
+    *(.sbss)
4210fa
+    *(.scommon)
4210fa
+    *(.dynbss)
4210fa
+    *(.bss)
4210fa
+    *(COMMON)
4210fa
+    . = ALIGN(16);
4210fa
+    _bss_end = .;
4210fa
   }
4210fa
   . = ALIGN(4096);
4210fa
   .vendor_cert :
4210fa
   {
4210fa
-   *(.vendor_cert)
4210fa
+    *(.vendor_cert)
4210fa
   }
4210fa
+
4210fa
   . = ALIGN(4096);
4210fa
-  .dynamic  : { *(.dynamic) }
4210fa
-  . = ALIGN(4096);
4210fa
-  .rela :
4210fa
-  {
4210fa
-    *(.rela.data*)
4210fa
-    *(.rela.got)
4210fa
-    *(.rela.stab)
4210fa
-  }
4210fa
+  .rela.dyn : { *(.rela.dyn) }
4210fa
+  .rela.plt : { *(.rela.plt) }
4210fa
+  .rela.got : { *(.rela.got) }
4210fa
+  .rela.data : { *(.rela.data) *(.rela.data*) }
4210fa
+  _edata = .;
4210fa
+  _data_size = . - _etext;
4210fa
+
4210fa
   . = ALIGN(4096);
4210fa
-  .dynsym   : { *(.dynsym) }
4210fa
+  .dynsym : { *(.dynsym) }
4210fa
   . = ALIGN(4096);
4210fa
-  .dynstr   : { *(.dynstr) }
4210fa
+  .dynstr : { *(.dynstr) }
4210fa
   . = ALIGN(4096);
4210fa
-  .ignored.reloc :
4210fa
+  /DISCARD/ :
4210fa
   {
4210fa
-    *(.rela.reloc)
4210fa
+    *(.rel.reloc)
4210fa
     *(.eh_frame)
4210fa
     *(.note.GNU-stack)
4210fa
   }
4210fa
-- 
4210fa
1.9.3
4210fa