* [PATCH v3 0/8] x86/boot: Rework PE header generation
@ 2023-09-15 17:16 Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 1/8] x86/boot: Grab kernel_info offset from zoffset header directly Ard Biesheuvel
` (8 more replies)
0 siblings, 9 replies; 10+ messages in thread
From: Ard Biesheuvel @ 2023-09-15 17:16 UTC (permalink / raw)
To: linux-efi
Cc: linux-kernel, Ard Biesheuvel, Evgeniy Baskov, Borislav Petkov,
Dave Hansen, Ingo Molnar, Thomas Gleixner, Peter Jones,
Matthew Garrett, Gerd Hoffmann, Kees Cook, H. Peter Anvin
From: Ard Biesheuvel <ardb@kernel.org>
Now that the EFI stub boot flow no longer relies on memory that is
executable and writable at the same time, we can reorganize the PE/COFF
view of the kernel image and expose the decompressor binary's code and
r/o data as a .text section and data/bss as a .data section, using 4k
alignment and limited permissions.
Doing so is necessary for compatibility with hardening measures that are
being rolled out on x86 PCs built to run Windows (i.e., the majority of
them). The EFI boot environment that the Linux EFI stub executes in is
especially sensitive to safety issues, given that a vulnerability in the
loader of one OS can be abused to attack another.
In true x86 fashion, this is a lot more complicated than on other
architectures, which have implemented this code/data split with 4k
alignment from the beginning. The complicating factor here is that the
boot image consists of two different parts, which are stitched together
and fixed up using a special build tool.
After this series is applied, the only remaining task performed by the
build tool is generating the CRC-32. Even though this checksum is
usually wrong (given that distro kernels are signed for secure boot in a
way that corrupts the CRC), this feature is retained as we cannot be
sure that nobody is relying on this.
This supersedes the work proposed by Evgeniy last year, which did a
major rewrite of the build tool in order to clean it up, before updating
it to generate the new 4k aligned image layout. As this series proves,
the build tool is mostly unnecessary, and we have too many of those
already.
Changes since v2:
- rebase onto tip/master
- drop patches that have been picked up already
- fix issue in the linker script that resulted in a bogus setup_size in
some cases when using ld.bfd
- fix comment capitalization
Changes since v1:
- drop patch that removed the CRC and the build tool
- do not use fixed setup_size but derive it in the setup.ld linker
script
- reorganize the PE header so the .compat section only covers its
payload and the padding that follows it
- add hpa's ack to patch #4
Cc: Evgeniy Baskov <baskov@ispras.ru>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Jones <pjones@redhat.com>
Cc: Matthew Garrett <mjg59@srcf.ucam.org>
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Ard Biesheuvel (8):
x86/boot: Grab kernel_info offset from zoffset header directly
x86/boot: Set EFI handover offset directly in header asm
x86/boot: Define setup size in linker script
x86/boot: Derive file size from _edata symbol
x86/boot: Construct PE/COFF .text section from assembler
x86/boot: Drop PE/COFF .reloc section
x86/boot: Split off PE/COFF .data section
x86/boot: Increase section and file alignment to 4k/512
arch/x86/boot/Makefile | 2 +-
arch/x86/boot/compressed/vmlinux.lds.S | 5 +-
arch/x86/boot/header.S | 146 +++++++------
arch/x86/boot/setup.ld | 7 +-
arch/x86/boot/tools/build.c | 223 +-------------------
5 files changed, 97 insertions(+), 286 deletions(-)
--
2.42.0.459.ge4e396fd5e-goog
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 1/8] x86/boot: Grab kernel_info offset from zoffset header directly
2023-09-15 17:16 [PATCH v3 0/8] x86/boot: Rework PE header generation Ard Biesheuvel
@ 2023-09-15 17:16 ` Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 2/8] x86/boot: Set EFI handover offset directly in header asm Ard Biesheuvel
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ard Biesheuvel @ 2023-09-15 17:16 UTC (permalink / raw)
To: linux-efi
Cc: linux-kernel, Ard Biesheuvel, Evgeniy Baskov, Borislav Petkov,
Dave Hansen, Ingo Molnar, Thomas Gleixner, Peter Jones,
Matthew Garrett, Gerd Hoffmann, Kees Cook, H. Peter Anvin
From: Ard Biesheuvel <ardb@kernel.org>
Instead of parsing zoffset.h and poking the kernel_info offset value
into the header from the build tool, just grab the value directly in the
asm file that describes this header.
This change has no impact on the resulting bzImage binary.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
| 2 +-
arch/x86/boot/tools/build.c | 4 ----
2 files changed, 1 insertion(+), 5 deletions(-)
--git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 6059f87b159d..5575d0f06bab 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -526,7 +526,7 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr
init_size: .long INIT_SIZE # kernel initialization size
handover_offset: .long 0 # Filled in by build.c
-kernel_info_offset: .long 0 # Filled in by build.c
+kernel_info_offset: .long ZO_kernel_info
# End of setup header #####################################################
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index 10b0207a6b18..14ef13fe7ab0 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -59,7 +59,6 @@ static unsigned long efi32_stub_entry;
static unsigned long efi64_stub_entry;
static unsigned long efi_pe_entry;
static unsigned long efi32_pe_entry;
-static unsigned long kernel_info;
static unsigned long _end;
/*----------------------------------------------------------------------*/
@@ -337,7 +336,6 @@ static void parse_zoffset(char *fname)
PARSE_ZOFS(p, efi64_stub_entry);
PARSE_ZOFS(p, efi_pe_entry);
PARSE_ZOFS(p, efi32_pe_entry);
- PARSE_ZOFS(p, kernel_info);
PARSE_ZOFS(p, _end);
p = strchr(p, '\n');
@@ -419,8 +417,6 @@ int main(int argc, char ** argv)
update_pecoff_text(setup_sectors * 512, i + (sys_size * 16));
efi_stub_entry_update();
- /* Update kernel_info offset. */
- put_unaligned_le32(kernel_info, &buf[0x268]);
crc = partial_crc32(buf, i, crc);
if (fwrite(buf, 1, i, dest) != i)
--
2.42.0.459.ge4e396fd5e-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 2/8] x86/boot: Set EFI handover offset directly in header asm
2023-09-15 17:16 [PATCH v3 0/8] x86/boot: Rework PE header generation Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 1/8] x86/boot: Grab kernel_info offset from zoffset header directly Ard Biesheuvel
@ 2023-09-15 17:16 ` Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 3/8] x86/boot: Define setup size in linker script Ard Biesheuvel
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ard Biesheuvel @ 2023-09-15 17:16 UTC (permalink / raw)
To: linux-efi
Cc: linux-kernel, Ard Biesheuvel, Evgeniy Baskov, Borislav Petkov,
Dave Hansen, Ingo Molnar, Thomas Gleixner, Peter Jones,
Matthew Garrett, Gerd Hoffmann, Kees Cook, H. Peter Anvin
From: Ard Biesheuvel <ardb@kernel.org>
The offsets of the EFI handover entrypoints are available to the
assembler when constructing the header, so there is no need to set them
from the build tool afterwards.
This change has no impact on the resulting bzImage binary.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
| 18 ++++++++++++++-
arch/x86/boot/tools/build.c | 24 --------------------
2 files changed, 17 insertions(+), 25 deletions(-)
--git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 5575d0f06bab..72744ba440f6 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -524,8 +524,24 @@ pref_address: .quad LOAD_PHYSICAL_ADDR # preferred load addr
# define INIT_SIZE VO_INIT_SIZE
#endif
+ .macro __handover_offset
+#ifndef CONFIG_EFI_HANDOVER_PROTOCOL
+ .long 0
+#elif !defined(CONFIG_X86_64)
+ .long ZO_efi32_stub_entry
+#else
+ /* Yes, this is really how we defined it :( */
+ .long ZO_efi64_stub_entry - 0x200
+#ifdef CONFIG_EFI_MIXED
+ .if ZO_efi32_stub_entry != ZO_efi64_stub_entry - 0x200
+ .error "32-bit and 64-bit EFI entry points do not match"
+ .endif
+#endif
+#endif
+ .endm
+
init_size: .long INIT_SIZE # kernel initialization size
-handover_offset: .long 0 # Filled in by build.c
+handover_offset: __handover_offset
kernel_info_offset: .long ZO_kernel_info
# End of setup header #####################################################
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index 14ef13fe7ab0..069497543164 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -55,8 +55,6 @@ u8 buf[SETUP_SECT_MAX*512];
#define PECOFF_COMPAT_RESERVE 0x0
#endif
-static unsigned long efi32_stub_entry;
-static unsigned long efi64_stub_entry;
static unsigned long efi_pe_entry;
static unsigned long efi32_pe_entry;
static unsigned long _end;
@@ -265,31 +263,12 @@ static void efi_stub_defaults(void)
#endif
}
-static void efi_stub_entry_update(void)
-{
- unsigned long addr = efi32_stub_entry;
-
-#ifdef CONFIG_EFI_HANDOVER_PROTOCOL
-#ifdef CONFIG_X86_64
- /* Yes, this is really how we defined it :( */
- addr = efi64_stub_entry - 0x200;
-#endif
-
-#ifdef CONFIG_EFI_MIXED
- if (efi32_stub_entry != addr)
- die("32-bit and 64-bit EFI entry points do not match\n");
-#endif
-#endif
- put_unaligned_le32(addr, &buf[0x264]);
-}
-
#else
static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
static inline void update_pecoff_text(unsigned int text_start,
unsigned int file_sz) {}
static inline void efi_stub_defaults(void) {}
-static inline void efi_stub_entry_update(void) {}
static inline int reserve_pecoff_reloc_section(int c)
{
@@ -332,8 +311,6 @@ static void parse_zoffset(char *fname)
p = (char *)buf;
while (p && *p) {
- PARSE_ZOFS(p, efi32_stub_entry);
- PARSE_ZOFS(p, efi64_stub_entry);
PARSE_ZOFS(p, efi_pe_entry);
PARSE_ZOFS(p, efi32_pe_entry);
PARSE_ZOFS(p, _end);
@@ -416,7 +393,6 @@ int main(int argc, char ** argv)
update_pecoff_text(setup_sectors * 512, i + (sys_size * 16));
- efi_stub_entry_update();
crc = partial_crc32(buf, i, crc);
if (fwrite(buf, 1, i, dest) != i)
--
2.42.0.459.ge4e396fd5e-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 3/8] x86/boot: Define setup size in linker script
2023-09-15 17:16 [PATCH v3 0/8] x86/boot: Rework PE header generation Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 1/8] x86/boot: Grab kernel_info offset from zoffset header directly Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 2/8] x86/boot: Set EFI handover offset directly in header asm Ard Biesheuvel
@ 2023-09-15 17:16 ` Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 4/8] x86/boot: Derive file size from _edata symbol Ard Biesheuvel
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ard Biesheuvel @ 2023-09-15 17:16 UTC (permalink / raw)
To: linux-efi
Cc: linux-kernel, Ard Biesheuvel, Evgeniy Baskov, Borislav Petkov,
Dave Hansen, Ingo Molnar, Thomas Gleixner, Peter Jones,
Matthew Garrett, Gerd Hoffmann, Kees Cook, H. Peter Anvin
From: Ard Biesheuvel <ardb@kernel.org>
The setup block contains the real mode startup code that is used when
booting from a legacy BIOS, along with the boot_params/setup_data that
is used by legacy x86 bootloaders to pass the command line and initial
ramdisk parameters, among other things.
The setup block also contains the PE/COFF header of the entire combined
image, which includes the compressed kernel image, the decompressor and
the EFI stub.
This PE header describes the layout of the executable image in memory,
and currently, the fact that the setup block precedes it makes it rather
fiddly to get the right values into the right place in the final image.
Let's make things a bit easier by defining the setup_size in the linker
script so it can be referenced from the asm code directly, rather than
having to rely on the build tool to calculate it. For the time being,
add 64 bytes of fixed padding for the .reloc and .compat sections - this
will be removed in a subsequent patch after the PE/COFF header has been
reorganized.
This change has no impact on the resulting bzImage binary when
configured with CONFIG_EFI_MIXED=y.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
| 2 +-
arch/x86/boot/setup.ld | 4 ++++
arch/x86/boot/tools/build.c | 6 ------
3 files changed, 5 insertions(+), 7 deletions(-)
--git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 72744ba440f6..06bd72a324c1 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -231,7 +231,7 @@ sentinel: .byte 0xff, 0xff /* Used to detect broken loaders */
.globl hdr
hdr:
-setup_sects: .byte 0 /* Filled in by build.c */
+ .byte setup_sects - 1
root_flags: .word ROOT_RDONLY
syssize: .long 0 /* Filled in by build.c */
ram_size: .word 0 /* Obsolete */
diff --git a/arch/x86/boot/setup.ld b/arch/x86/boot/setup.ld
index b11c45b9e51e..9bd5c1ada599 100644
--- a/arch/x86/boot/setup.ld
+++ b/arch/x86/boot/setup.ld
@@ -39,6 +39,10 @@ SECTIONS
.signature : {
setup_sig = .;
LONG(0x5a5aaa55)
+
+ /* Reserve some extra space for the reloc and compat sections */
+ setup_size = ALIGN(ABSOLUTE(.) + 64, 512);
+ setup_sects = ABSOLUTE(setup_size / 512);
}
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index 069497543164..745d64b6d930 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -48,12 +48,7 @@ typedef unsigned int u32;
u8 buf[SETUP_SECT_MAX*512];
#define PECOFF_RELOC_RESERVE 0x20
-
-#ifdef CONFIG_EFI_MIXED
#define PECOFF_COMPAT_RESERVE 0x20
-#else
-#define PECOFF_COMPAT_RESERVE 0x0
-#endif
static unsigned long efi_pe_entry;
static unsigned long efi32_pe_entry;
@@ -388,7 +383,6 @@ int main(int argc, char ** argv)
#endif
/* Patch the setup code with the appropriate size parameters */
- buf[0x1f1] = setup_sectors-1;
put_unaligned_le32(sys_size, &buf[0x1f4]);
update_pecoff_text(setup_sectors * 512, i + (sys_size * 16));
--
2.42.0.459.ge4e396fd5e-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 4/8] x86/boot: Derive file size from _edata symbol
2023-09-15 17:16 [PATCH v3 0/8] x86/boot: Rework PE header generation Ard Biesheuvel
` (2 preceding siblings ...)
2023-09-15 17:16 ` [PATCH v3 3/8] x86/boot: Define setup size in linker script Ard Biesheuvel
@ 2023-09-15 17:16 ` Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 5/8] x86/boot: Construct PE/COFF .text section from assembler Ard Biesheuvel
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ard Biesheuvel @ 2023-09-15 17:16 UTC (permalink / raw)
To: linux-efi
Cc: linux-kernel, Ard Biesheuvel, Evgeniy Baskov, Borislav Petkov,
Dave Hansen, Ingo Molnar, Thomas Gleixner, Peter Jones,
Matthew Garrett, Gerd Hoffmann, Kees Cook, H. Peter Anvin
From: Ard Biesheuvel <ardb@kernel.org>
Tweak the linker script so that the value of _edata represents the
decompressor binary's file size rounded up to the appropriate alignment.
This removes the need to calculate it in the build tool, and will make
it easier to refer to the file size from the header directly in
subsequent changes to the PE header layout.
While adding _edata to the sed regex that parses the compressed
vmlinux's symbol list, tweak the regex a bit for conciseness.
This change has no impact on the resulting bzImage binary when
configured with CONFIG_EFI_STUB=y.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/boot/Makefile | 2 +-
arch/x86/boot/compressed/vmlinux.lds.S | 3 ++
| 2 +-
arch/x86/boot/tools/build.c | 30 +++++---------------
4 files changed, 12 insertions(+), 25 deletions(-)
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 0e98bc503699..cc04917b1ac6 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -89,7 +89,7 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
-sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|efi32_stub_entry\|efi64_stub_entry\|efi_pe_entry\|efi32_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|z_.*\)$$/\#define ZO_\2 0x\1/p'
+sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|efi.._stub_entry\|efi\(32\)\?_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|_edata\|z_.*\)$$/\#define ZO_\2 0x\1/p'
quiet_cmd_zoffset = ZOFFSET $@
cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S
index 4ff6ab1b67d9..b688598db28e 100644
--- a/arch/x86/boot/compressed/vmlinux.lds.S
+++ b/arch/x86/boot/compressed/vmlinux.lds.S
@@ -47,6 +47,9 @@ SECTIONS
_data = . ;
*(.data)
*(.data.*)
+
+ /* Add 4 bytes of extra space for a CRC-32 checksum */
+ . = ALIGN(. + 4, 0x20);
_edata = . ;
}
. = ALIGN(L1_CACHE_BYTES);
--git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 06bd72a324c1..34e9b35b827c 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -233,7 +233,7 @@ sentinel: .byte 0xff, 0xff /* Used to detect broken loaders */
hdr:
.byte setup_sects - 1
root_flags: .word ROOT_RDONLY
-syssize: .long 0 /* Filled in by build.c */
+syssize: .long ZO__edata / 16
ram_size: .word 0 /* Obsolete */
vid_mode: .word SVGA_MODE
root_dev: .word 0 /* Default to major/minor 0/0 */
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index 745d64b6d930..e792c6c5a634 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -52,6 +52,7 @@ u8 buf[SETUP_SECT_MAX*512];
static unsigned long efi_pe_entry;
static unsigned long efi32_pe_entry;
+static unsigned long _edata;
static unsigned long _end;
/*----------------------------------------------------------------------*/
@@ -308,6 +309,7 @@ static void parse_zoffset(char *fname)
while (p && *p) {
PARSE_ZOFS(p, efi_pe_entry);
PARSE_ZOFS(p, efi32_pe_entry);
+ PARSE_ZOFS(p, _edata);
PARSE_ZOFS(p, _end);
p = strchr(p, '\n');
@@ -320,7 +322,6 @@ int main(int argc, char ** argv)
{
unsigned int i, sz, setup_sectors;
int c;
- u32 sys_size;
struct stat sb;
FILE *file, *dest;
int fd;
@@ -368,24 +369,14 @@ int main(int argc, char ** argv)
die("Unable to open `%s': %m", argv[2]);
if (fstat(fd, &sb))
die("Unable to stat `%s': %m", argv[2]);
- sz = sb.st_size;
+ if (_edata != sb.st_size)
+ die("Unexpected file size `%s': %u != %u", argv[2], _edata,
+ sb.st_size);
+ sz = _edata - 4;
kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
if (kernel == MAP_FAILED)
die("Unable to mmap '%s': %m", argv[2]);
- /* Number of 16-byte paragraphs, including space for a 4-byte CRC */
- sys_size = (sz + 15 + 4) / 16;
-#ifdef CONFIG_EFI_STUB
- /*
- * COFF requires minimum 32-byte alignment of sections, and
- * adding a signature is problematic without that alignment.
- */
- sys_size = (sys_size + 1) & ~1;
-#endif
-
- /* Patch the setup code with the appropriate size parameters */
- put_unaligned_le32(sys_size, &buf[0x1f4]);
-
- update_pecoff_text(setup_sectors * 512, i + (sys_size * 16));
+ update_pecoff_text(setup_sectors * 512, i + _edata);
crc = partial_crc32(buf, i, crc);
@@ -397,13 +388,6 @@ int main(int argc, char ** argv)
if (fwrite(kernel, 1, sz, dest) != sz)
die("Writing kernel failed");
- /* Add padding leaving 4 bytes for the checksum */
- while (sz++ < (sys_size*16) - 4) {
- crc = partial_crc32_one('\0', crc);
- if (fwrite("\0", 1, 1, dest) != 1)
- die("Writing padding failed");
- }
-
/* Write the CRC */
put_unaligned_le32(crc, buf);
if (fwrite(buf, 1, 4, dest) != 4)
--
2.42.0.459.ge4e396fd5e-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 5/8] x86/boot: Construct PE/COFF .text section from assembler
2023-09-15 17:16 [PATCH v3 0/8] x86/boot: Rework PE header generation Ard Biesheuvel
` (3 preceding siblings ...)
2023-09-15 17:16 ` [PATCH v3 4/8] x86/boot: Derive file size from _edata symbol Ard Biesheuvel
@ 2023-09-15 17:16 ` Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 6/8] x86/boot: Drop PE/COFF .reloc section Ard Biesheuvel
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ard Biesheuvel @ 2023-09-15 17:16 UTC (permalink / raw)
To: linux-efi
Cc: linux-kernel, Ard Biesheuvel, Evgeniy Baskov, Borislav Petkov,
Dave Hansen, Ingo Molnar, Thomas Gleixner, Peter Jones,
Matthew Garrett, Gerd Hoffmann, Kees Cook, H. Peter Anvin
From: Ard Biesheuvel <ardb@kernel.org>
Now that the size of the setup block is visible to the assembler, it is
possible to populate the PE/COFF header fields from the asm code
directly, instead of poking the values into the binary using the build
tool. This will make it easier to reorganize the section layout without
having to tweak the build tool in lockstep.
This change has no impact on the resulting bzImage binary.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
| 22 +++------
arch/x86/boot/tools/build.c | 47 --------------------
2 files changed, 7 insertions(+), 62 deletions(-)
--git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 34e9b35b827c..2b07bc596c39 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -75,14 +75,12 @@ optional_header:
.byte 0x02 # MajorLinkerVersion
.byte 0x14 # MinorLinkerVersion
- # Filled in by build.c
- .long 0 # SizeOfCode
+ .long setup_size + ZO__end - 0x200 # SizeOfCode
.long 0 # SizeOfInitializedData
.long 0 # SizeOfUninitializedData
- # Filled in by build.c
- .long 0x0000 # AddressOfEntryPoint
+ .long setup_size + ZO_efi_pe_entry # AddressOfEntryPoint
.long 0x0200 # BaseOfCode
#ifdef CONFIG_X86_32
@@ -105,10 +103,7 @@ extra_header_fields:
.word 0 # MinorSubsystemVersion
.long 0 # Win32VersionValue
- #
- # The size of the bzImage is written in tools/build.c
- #
- .long 0 # SizeOfImage
+ .long setup_size + ZO__end # SizeOfImage
.long 0x200 # SizeOfHeaders
.long 0 # CheckSum
@@ -199,18 +194,15 @@ section_table:
IMAGE_SCN_MEM_DISCARDABLE # Characteristics
#endif
- #
- # The offset & size fields are filled in by build.c.
- #
.ascii ".text"
.byte 0
.byte 0
.byte 0
- .long 0
- .long 0x0 # startup_{32,64}
- .long 0 # Size of initialized data
+ .long ZO__end
+ .long setup_size
+ .long ZO__edata # Size of initialized data
# on disk
- .long 0x0 # startup_{32,64}
+ .long setup_size
.long 0 # PointerToRelocations
.long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index e792c6c5a634..9712f27e32c1 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -50,10 +50,8 @@ u8 buf[SETUP_SECT_MAX*512];
#define PECOFF_RELOC_RESERVE 0x20
#define PECOFF_COMPAT_RESERVE 0x20
-static unsigned long efi_pe_entry;
static unsigned long efi32_pe_entry;
static unsigned long _edata;
-static unsigned long _end;
/*----------------------------------------------------------------------*/
@@ -216,32 +214,6 @@ static void update_pecoff_setup_and_reloc(unsigned int size)
#endif
}
-static void update_pecoff_text(unsigned int text_start, unsigned int file_sz)
-{
- unsigned int pe_header;
- unsigned int text_sz = file_sz - text_start;
- unsigned int bss_sz = _end - text_sz;
-
- pe_header = get_unaligned_le32(&buf[0x3c]);
-
- /*
- * Size of code: Subtract the size of the first sector (512 bytes)
- * which includes the header.
- */
- put_unaligned_le32(file_sz - 512 + bss_sz, &buf[pe_header + 0x1c]);
-
- /* Size of image */
- put_unaligned_le32(file_sz + bss_sz, &buf[pe_header + 0x50]);
-
- /*
- * Address of entry point for PE/COFF executable
- */
- put_unaligned_le32(text_start + efi_pe_entry, &buf[pe_header + 0x28]);
-
- update_pecoff_section_header_fields(".text", text_start, text_sz + bss_sz,
- text_sz, text_start);
-}
-
static int reserve_pecoff_reloc_section(int c)
{
/* Reserve 0x20 bytes for .reloc section */
@@ -249,22 +221,9 @@ static int reserve_pecoff_reloc_section(int c)
return PECOFF_RELOC_RESERVE;
}
-static void efi_stub_defaults(void)
-{
- /* Defaults for old kernel */
-#ifdef CONFIG_X86_32
- efi_pe_entry = 0x10;
-#else
- efi_pe_entry = 0x210;
-#endif
-}
-
#else
static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
-static inline void update_pecoff_text(unsigned int text_start,
- unsigned int file_sz) {}
-static inline void efi_stub_defaults(void) {}
static inline int reserve_pecoff_reloc_section(int c)
{
@@ -307,10 +266,8 @@ static void parse_zoffset(char *fname)
p = (char *)buf;
while (p && *p) {
- PARSE_ZOFS(p, efi_pe_entry);
PARSE_ZOFS(p, efi32_pe_entry);
PARSE_ZOFS(p, _edata);
- PARSE_ZOFS(p, _end);
p = strchr(p, '\n');
while (p && (*p == '\r' || *p == '\n'))
@@ -328,8 +285,6 @@ int main(int argc, char ** argv)
void *kernel;
u32 crc = 0xffffffffUL;
- efi_stub_defaults();
-
if (argc != 5)
usage();
parse_zoffset(argv[3]);
@@ -376,8 +331,6 @@ int main(int argc, char ** argv)
kernel = mmap(NULL, sz, PROT_READ, MAP_SHARED, fd, 0);
if (kernel == MAP_FAILED)
die("Unable to mmap '%s': %m", argv[2]);
- update_pecoff_text(setup_sectors * 512, i + _edata);
-
crc = partial_crc32(buf, i, crc);
if (fwrite(buf, 1, i, dest) != i)
--
2.42.0.459.ge4e396fd5e-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 6/8] x86/boot: Drop PE/COFF .reloc section
2023-09-15 17:16 [PATCH v3 0/8] x86/boot: Rework PE header generation Ard Biesheuvel
` (4 preceding siblings ...)
2023-09-15 17:16 ` [PATCH v3 5/8] x86/boot: Construct PE/COFF .text section from assembler Ard Biesheuvel
@ 2023-09-15 17:16 ` Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 7/8] x86/boot: Split off PE/COFF .data section Ard Biesheuvel
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ard Biesheuvel @ 2023-09-15 17:16 UTC (permalink / raw)
To: linux-efi
Cc: linux-kernel, Ard Biesheuvel, Evgeniy Baskov, Borislav Petkov,
Dave Hansen, Ingo Molnar, Thomas Gleixner, Peter Jones,
Matthew Garrett, Gerd Hoffmann, Kees Cook, H. Peter Anvin
From: Ard Biesheuvel <ardb@kernel.org>
Ancient buggy EFI loaders may have required a .reloc section to be
present at some point in time, but this has not been true for a long
time so the .reloc section can just be dropped.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
| 20 ------------
arch/x86/boot/setup.ld | 4 +--
arch/x86/boot/tools/build.c | 34 +++-----------------
3 files changed, 7 insertions(+), 51 deletions(-)
--git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 2b07bc596c39..9e9641e220a7 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -155,26 +155,6 @@ section_table:
IMAGE_SCN_MEM_READ | \
IMAGE_SCN_MEM_EXECUTE # Characteristics
- #
- # The EFI application loader requires a relocation section
- # because EFI applications must be relocatable. The .reloc
- # offset & size fields are filled in by build.c.
- #
- .ascii ".reloc"
- .byte 0
- .byte 0
- .long 0
- .long 0
- .long 0 # SizeOfRawData
- .long 0 # PointerToRawData
- .long 0 # PointerToRelocations
- .long 0 # PointerToLineNumbers
- .word 0 # NumberOfRelocations
- .word 0 # NumberOfLineNumbers
- .long IMAGE_SCN_CNT_INITIALIZED_DATA | \
- IMAGE_SCN_MEM_READ | \
- IMAGE_SCN_MEM_DISCARDABLE # Characteristics
-
#ifdef CONFIG_EFI_MIXED
#
# The offset & size fields are filled in by build.c.
diff --git a/arch/x86/boot/setup.ld b/arch/x86/boot/setup.ld
index 9bd5c1ada599..6d389499565c 100644
--- a/arch/x86/boot/setup.ld
+++ b/arch/x86/boot/setup.ld
@@ -40,8 +40,8 @@ SECTIONS
setup_sig = .;
LONG(0x5a5aaa55)
- /* Reserve some extra space for the reloc and compat sections */
- setup_size = ALIGN(ABSOLUTE(.) + 64, 512);
+ /* Reserve some extra space for the compat section */
+ setup_size = ALIGN(ABSOLUTE(.) + 32, 512);
setup_sects = ABSOLUTE(setup_size / 512);
}
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index 9712f27e32c1..faccff9743a3 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -47,7 +47,6 @@ typedef unsigned int u32;
/* This must be large enough to hold the entire setup */
u8 buf[SETUP_SECT_MAX*512];
-#define PECOFF_RELOC_RESERVE 0x20
#define PECOFF_COMPAT_RESERVE 0x20
static unsigned long efi32_pe_entry;
@@ -180,24 +179,13 @@ static void update_pecoff_section_header(char *section_name, u32 offset, u32 siz
update_pecoff_section_header_fields(section_name, offset, size, size, offset);
}
-static void update_pecoff_setup_and_reloc(unsigned int size)
+static void update_pecoff_setup(unsigned int size)
{
u32 setup_offset = 0x200;
- u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE;
-#ifdef CONFIG_EFI_MIXED
- u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE;
-#endif
- u32 setup_size = reloc_offset - setup_offset;
+ u32 compat_offset = size - PECOFF_COMPAT_RESERVE;
+ u32 setup_size = compat_offset - setup_offset;
update_pecoff_section_header(".setup", setup_offset, setup_size);
- update_pecoff_section_header(".reloc", reloc_offset, PECOFF_RELOC_RESERVE);
-
- /*
- * Modify .reloc section contents with a single entry. The
- * relocation is applied to offset 10 of the relocation section.
- */
- put_unaligned_le32(reloc_offset + 10, &buf[reloc_offset]);
- put_unaligned_le32(10, &buf[reloc_offset + 4]);
#ifdef CONFIG_EFI_MIXED
update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE);
@@ -214,21 +202,10 @@ static void update_pecoff_setup_and_reloc(unsigned int size)
#endif
}
-static int reserve_pecoff_reloc_section(int c)
-{
- /* Reserve 0x20 bytes for .reloc section */
- memset(buf+c, 0, PECOFF_RELOC_RESERVE);
- return PECOFF_RELOC_RESERVE;
-}
-
#else
-static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
+static inline void update_pecoff_setup(unsigned int size) {}
-static inline int reserve_pecoff_reloc_section(int c)
-{
- return 0;
-}
#endif /* CONFIG_EFI_STUB */
static int reserve_pecoff_compat_section(int c)
@@ -307,7 +284,6 @@ int main(int argc, char ** argv)
fclose(file);
c += reserve_pecoff_compat_section(c);
- c += reserve_pecoff_reloc_section(c);
/* Pad unused space with zeros */
setup_sectors = (c + 511) / 512;
@@ -316,7 +292,7 @@ int main(int argc, char ** argv)
i = setup_sectors*512;
memset(buf+c, 0, i-c);
- update_pecoff_setup_and_reloc(i);
+ update_pecoff_setup(i);
/* Open and stat the kernel file */
fd = open(argv[2], O_RDONLY);
--
2.42.0.459.ge4e396fd5e-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 7/8] x86/boot: Split off PE/COFF .data section
2023-09-15 17:16 [PATCH v3 0/8] x86/boot: Rework PE header generation Ard Biesheuvel
` (5 preceding siblings ...)
2023-09-15 17:16 ` [PATCH v3 6/8] x86/boot: Drop PE/COFF .reloc section Ard Biesheuvel
@ 2023-09-15 17:16 ` Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 8/8] x86/boot: Increase section and file alignment to 4k/512 Ard Biesheuvel
2023-09-17 17:50 ` [PATCH v3 0/8] x86/boot: Rework PE header generation Ingo Molnar
8 siblings, 0 replies; 10+ messages in thread
From: Ard Biesheuvel @ 2023-09-15 17:16 UTC (permalink / raw)
To: linux-efi
Cc: linux-kernel, Ard Biesheuvel, Evgeniy Baskov, Borislav Petkov,
Dave Hansen, Ingo Molnar, Thomas Gleixner, Peter Jones,
Matthew Garrett, Gerd Hoffmann, Kees Cook, H. Peter Anvin
From: Ard Biesheuvel <ardb@kernel.org>
Describe the code and data of the decompressor binary using separate
.text and .data PE/COFF sections, so that we will be able to map them
using restricted permissions once we increase the section and file
alignment sufficiently. This avoids the need for memory mappings that
are writable and executable at the same time, which is something that
is best avoided for security reasons.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/boot/Makefile | 2 +-
| 19 +++++++++++++++----
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index cc04917b1ac6..3cece19b7473 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -89,7 +89,7 @@ $(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE
SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
-sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|efi.._stub_entry\|efi\(32\)\?_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|_edata\|z_.*\)$$/\#define ZO_\2 0x\1/p'
+sed-zoffset := -e 's/^\([0-9a-fA-F]*\) [a-zA-Z] \(startup_32\|efi.._stub_entry\|efi\(32\)\?_pe_entry\|input_data\|kernel_info\|_end\|_ehead\|_text\|_e\?data\|z_.*\)$$/\#define ZO_\2 0x\1/p'
quiet_cmd_zoffset = ZOFFSET $@
cmd_zoffset = $(NM) $< | sed -n $(sed-zoffset) > $@
--git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index 9e9641e220a7..a1f986105f00 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -75,9 +75,9 @@ optional_header:
.byte 0x02 # MajorLinkerVersion
.byte 0x14 # MinorLinkerVersion
- .long setup_size + ZO__end - 0x200 # SizeOfCode
+ .long ZO__data # SizeOfCode
- .long 0 # SizeOfInitializedData
+ .long ZO__end - ZO__data # SizeOfInitializedData
.long 0 # SizeOfUninitializedData
.long setup_size + ZO_efi_pe_entry # AddressOfEntryPoint
@@ -178,9 +178,9 @@ section_table:
.byte 0
.byte 0
.byte 0
- .long ZO__end
+ .long ZO__data
.long setup_size
- .long ZO__edata # Size of initialized data
+ .long ZO__data # Size of initialized data
# on disk
.long setup_size
.long 0 # PointerToRelocations
@@ -191,6 +191,17 @@ section_table:
IMAGE_SCN_MEM_READ | \
IMAGE_SCN_MEM_EXECUTE # Characteristics
+ .ascii ".data\0\0\0"
+ .long ZO__end - ZO__data # VirtualSize
+ .long setup_size + ZO__data # VirtualAddress
+ .long ZO__edata - ZO__data # SizeOfRawData
+ .long setup_size + ZO__data # PointerToRawData
+
+ .long 0, 0, 0
+ .long IMAGE_SCN_CNT_INITIALIZED_DATA | \
+ IMAGE_SCN_MEM_READ | \
+ IMAGE_SCN_MEM_WRITE # Characteristics
+
.set section_count, (. - section_table) / 40
#endif /* CONFIG_EFI_STUB */
--
2.42.0.459.ge4e396fd5e-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 8/8] x86/boot: Increase section and file alignment to 4k/512
2023-09-15 17:16 [PATCH v3 0/8] x86/boot: Rework PE header generation Ard Biesheuvel
` (6 preceding siblings ...)
2023-09-15 17:16 ` [PATCH v3 7/8] x86/boot: Split off PE/COFF .data section Ard Biesheuvel
@ 2023-09-15 17:16 ` Ard Biesheuvel
2023-09-17 17:50 ` [PATCH v3 0/8] x86/boot: Rework PE header generation Ingo Molnar
8 siblings, 0 replies; 10+ messages in thread
From: Ard Biesheuvel @ 2023-09-15 17:16 UTC (permalink / raw)
To: linux-efi
Cc: linux-kernel, Ard Biesheuvel, Evgeniy Baskov, Borislav Petkov,
Dave Hansen, Ingo Molnar, Thomas Gleixner, Peter Jones,
Matthew Garrett, Gerd Hoffmann, Kees Cook, H. Peter Anvin
From: Ard Biesheuvel <ardb@kernel.org>
Align x86 with other EFI architectures, and increase the section
alignment to the EFI page size (4k), so that firmware is able to honour
the section permission attributes and map code read-only and data
non-executable.
There are a number of requirements that have to be taken into account:
- the sign tools get cranky when there are gaps between sections in the
file view of the image
- the virtual offset of each section must be aligned to the image's
section alignment
- the file offset *and size* of each section must be aligned to the
image's file alignment
- the image size must be aligned to the section alignment
- each section's virtual offset must be greater than or equal to the
size of the headers.
In order to meet all these requirements, while avoiding the need for
lots of padding to accommodate the .compat section, the latter is placed
at an arbitrary offset towards the end of the image, but aligned to the
minimum file alignment (512 bytes). The space before the .text section
is therefore distributed between the PE header, the .setup section and
the .compat section, leaving no gaps in the file coverage, making the
signing tools happy.
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
arch/x86/boot/compressed/vmlinux.lds.S | 4 +-
| 75 +++++++++-------
arch/x86/boot/setup.ld | 7 +-
arch/x86/boot/tools/build.c | 90 +-------------------
4 files changed, 51 insertions(+), 125 deletions(-)
diff --git a/arch/x86/boot/compressed/vmlinux.lds.S b/arch/x86/boot/compressed/vmlinux.lds.S
index b688598db28e..083ec6d7722a 100644
--- a/arch/x86/boot/compressed/vmlinux.lds.S
+++ b/arch/x86/boot/compressed/vmlinux.lds.S
@@ -43,13 +43,13 @@ SECTIONS
*(.rodata.*)
_erodata = . ;
}
- .data : {
+ .data : ALIGN(0x1000) {
_data = . ;
*(.data)
*(.data.*)
/* Add 4 bytes of extra space for a CRC-32 checksum */
- . = ALIGN(. + 4, 0x20);
+ . = ALIGN(. + 4, 0x200);
_edata = . ;
}
. = ALIGN(L1_CACHE_BYTES);
--git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index a1f986105f00..b2771710ed98 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -36,6 +36,9 @@ SYSSEG = 0x1000 /* historical load address >> 4 */
#define ROOT_RDONLY 1
#endif
+ .set salign, 0x1000
+ .set falign, 0x200
+
.code16
.section ".bstext", "ax"
#ifdef CONFIG_EFI_STUB
@@ -82,7 +85,7 @@ optional_header:
.long setup_size + ZO_efi_pe_entry # AddressOfEntryPoint
- .long 0x0200 # BaseOfCode
+ .long setup_size # BaseOfCode
#ifdef CONFIG_X86_32
.long 0 # data
#endif
@@ -93,8 +96,8 @@ extra_header_fields:
#else
.quad 0 # ImageBase
#endif
- .long 0x20 # SectionAlignment
- .long 0x20 # FileAlignment
+ .long salign # SectionAlignment
+ .long falign # FileAlignment
.word 0 # MajorOperatingSystemVersion
.word 0 # MinorOperatingSystemVersion
.word LINUX_EFISTUB_MAJOR_VERSION # MajorImageVersion
@@ -103,9 +106,10 @@ extra_header_fields:
.word 0 # MinorSubsystemVersion
.long 0 # Win32VersionValue
- .long setup_size + ZO__end # SizeOfImage
+ .long setup_size + ZO__end + pecompat_vsize
+ # SizeOfImage
- .long 0x200 # SizeOfHeaders
+ .long salign # SizeOfHeaders
.long 0 # CheckSum
.word IMAGE_SUBSYSTEM_EFI_APPLICATION # Subsystem (EFI application)
#ifdef CONFIG_EFI_DXE_MEM_ATTRIBUTES
@@ -136,44 +140,51 @@ extra_header_fields:
# Section table
section_table:
- #
- # The offset & size fields are filled in by build.c.
- #
.ascii ".setup"
.byte 0
.byte 0
- .long 0
- .long 0x0 # startup_{32,64}
- .long 0 # Size of initialized data
- # on disk
- .long 0x0 # startup_{32,64}
- .long 0 # PointerToRelocations
- .long 0 # PointerToLineNumbers
- .word 0 # NumberOfRelocations
- .word 0 # NumberOfLineNumbers
- .long IMAGE_SCN_CNT_CODE | \
+ .long setup_size - salign # VirtualSize
+ .long salign # VirtualAddress
+ .long pecompat_fstart - salign # SizeOfRawData
+ .long salign # PointerToRawData
+
+ .long 0, 0, 0
+ .long IMAGE_SCN_CNT_INITIALIZED_DATA | \
IMAGE_SCN_MEM_READ | \
- IMAGE_SCN_MEM_EXECUTE # Characteristics
+ IMAGE_SCN_MEM_DISCARDABLE # Characteristics
#ifdef CONFIG_EFI_MIXED
- #
- # The offset & size fields are filled in by build.c.
- #
.asciz ".compat"
- .long 0
- .long 0x0
- .long 0 # Size of initialized data
- # on disk
- .long 0x0
- .long 0 # PointerToRelocations
- .long 0 # PointerToLineNumbers
- .word 0 # NumberOfRelocations
- .word 0 # NumberOfLineNumbers
+
+ .long 8 # VirtualSize
+ .long setup_size + ZO__end # VirtualAddress
+ .long pecompat_fsize # SizeOfRawData
+ .long pecompat_fstart # PointerToRawData
+
+ .long 0, 0, 0
.long IMAGE_SCN_CNT_INITIALIZED_DATA | \
IMAGE_SCN_MEM_READ | \
IMAGE_SCN_MEM_DISCARDABLE # Characteristics
-#endif
+ /*
+ * Put the IA-32 machine type and the associated entry point address in
+ * the .compat section, so loaders can figure out which other execution
+ * modes this image supports.
+ */
+ .pushsection ".pecompat", "a", @progbits
+ .balign falign
+ .set pecompat_vsize, salign
+ .globl pecompat_fstart
+pecompat_fstart:
+ .byte 0x1 # Version
+ .byte 8 # Size
+ .word IMAGE_FILE_MACHINE_I386 # PE machine type
+ .long setup_size + ZO_efi32_pe_entry # Entrypoint
+ .popsection
+#else
+ .set pecompat_vsize, 0
+ .set pecompat_fstart, setup_size
+#endif
.ascii ".text"
.byte 0
.byte 0
diff --git a/arch/x86/boot/setup.ld b/arch/x86/boot/setup.ld
index 6d389499565c..83bb7efad8ae 100644
--- a/arch/x86/boot/setup.ld
+++ b/arch/x86/boot/setup.ld
@@ -36,16 +36,17 @@ SECTIONS
. = ALIGN(16);
.data : { *(.data*) }
+ .pecompat : { *(.pecompat) }
+ PROVIDE(pecompat_fsize = setup_size - pecompat_fstart);
+
.signature : {
setup_sig = .;
LONG(0x5a5aaa55)
- /* Reserve some extra space for the compat section */
- setup_size = ALIGN(ABSOLUTE(.) + 32, 512);
+ setup_size = ALIGN(ABSOLUTE(.), 4096);
setup_sects = ABSOLUTE(setup_size / 512);
}
-
. = ALIGN(16);
.bss :
{
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index faccff9743a3..10311d77c67f 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -47,9 +47,6 @@ typedef unsigned int u32;
/* This must be large enough to hold the entire setup */
u8 buf[SETUP_SECT_MAX*512];
-#define PECOFF_COMPAT_RESERVE 0x20
-
-static unsigned long efi32_pe_entry;
static unsigned long _edata;
/*----------------------------------------------------------------------*/
@@ -136,85 +133,6 @@ static void usage(void)
die("Usage: build setup system zoffset.h image");
}
-#ifdef CONFIG_EFI_STUB
-
-static void update_pecoff_section_header_fields(char *section_name, u32 vma, u32 size, u32 datasz, u32 offset)
-{
- unsigned int pe_header;
- unsigned short num_sections;
- u8 *section;
-
- pe_header = get_unaligned_le32(&buf[0x3c]);
- num_sections = get_unaligned_le16(&buf[pe_header + 6]);
-
-#ifdef CONFIG_X86_32
- section = &buf[pe_header + 0xa8];
-#else
- section = &buf[pe_header + 0xb8];
-#endif
-
- while (num_sections > 0) {
- if (strncmp((char*)section, section_name, 8) == 0) {
- /* section header size field */
- put_unaligned_le32(size, section + 0x8);
-
- /* section header vma field */
- put_unaligned_le32(vma, section + 0xc);
-
- /* section header 'size of initialised data' field */
- put_unaligned_le32(datasz, section + 0x10);
-
- /* section header 'file offset' field */
- put_unaligned_le32(offset, section + 0x14);
-
- break;
- }
- section += 0x28;
- num_sections--;
- }
-}
-
-static void update_pecoff_section_header(char *section_name, u32 offset, u32 size)
-{
- update_pecoff_section_header_fields(section_name, offset, size, size, offset);
-}
-
-static void update_pecoff_setup(unsigned int size)
-{
- u32 setup_offset = 0x200;
- u32 compat_offset = size - PECOFF_COMPAT_RESERVE;
- u32 setup_size = compat_offset - setup_offset;
-
- update_pecoff_section_header(".setup", setup_offset, setup_size);
-
-#ifdef CONFIG_EFI_MIXED
- update_pecoff_section_header(".compat", compat_offset, PECOFF_COMPAT_RESERVE);
-
- /*
- * Put the IA-32 machine type (0x14c) and the associated entry point
- * address in the .compat section, so loaders can figure out which other
- * execution modes this image supports.
- */
- buf[compat_offset] = 0x1;
- buf[compat_offset + 1] = 0x8;
- put_unaligned_le16(0x14c, &buf[compat_offset + 2]);
- put_unaligned_le32(efi32_pe_entry + size, &buf[compat_offset + 4]);
-#endif
-}
-
-#else
-
-static inline void update_pecoff_setup(unsigned int size) {}
-
-#endif /* CONFIG_EFI_STUB */
-
-static int reserve_pecoff_compat_section(int c)
-{
- /* Reserve 0x20 bytes for .compat section */
- memset(buf+c, 0, PECOFF_COMPAT_RESERVE);
- return PECOFF_COMPAT_RESERVE;
-}
-
/*
* Parse zoffset.h and find the entry points. We could just #include zoffset.h
* but that would mean tools/build would have to be rebuilt every time. It's
@@ -243,7 +161,6 @@ static void parse_zoffset(char *fname)
p = (char *)buf;
while (p && *p) {
- PARSE_ZOFS(p, efi32_pe_entry);
PARSE_ZOFS(p, _edata);
p = strchr(p, '\n');
@@ -283,17 +200,14 @@ int main(int argc, char ** argv)
die("Boot block hasn't got boot flag (0xAA55)");
fclose(file);
- c += reserve_pecoff_compat_section(c);
-
/* Pad unused space with zeros */
- setup_sectors = (c + 511) / 512;
+ setup_sectors = (c + 4095) / 4096;
+ setup_sectors *= 8;
if (setup_sectors < SETUP_SECT_MIN)
setup_sectors = SETUP_SECT_MIN;
i = setup_sectors*512;
memset(buf+c, 0, i-c);
- update_pecoff_setup(i);
-
/* Open and stat the kernel file */
fd = open(argv[2], O_RDONLY);
if (fd < 0)
--
2.42.0.459.ge4e396fd5e-goog
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v3 0/8] x86/boot: Rework PE header generation
2023-09-15 17:16 [PATCH v3 0/8] x86/boot: Rework PE header generation Ard Biesheuvel
` (7 preceding siblings ...)
2023-09-15 17:16 ` [PATCH v3 8/8] x86/boot: Increase section and file alignment to 4k/512 Ard Biesheuvel
@ 2023-09-17 17:50 ` Ingo Molnar
8 siblings, 0 replies; 10+ messages in thread
From: Ingo Molnar @ 2023-09-17 17:50 UTC (permalink / raw)
To: Ard Biesheuvel
Cc: linux-efi, linux-kernel, Ard Biesheuvel, Evgeniy Baskov,
Borislav Petkov, Dave Hansen, Ingo Molnar, Thomas Gleixner,
Peter Jones, Matthew Garrett, Gerd Hoffmann, Kees Cook,
H. Peter Anvin
* Ard Biesheuvel <ardb@google.com> wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> Now that the EFI stub boot flow no longer relies on memory that is
> executable and writable at the same time, we can reorganize the PE/COFF
> view of the kernel image and expose the decompressor binary's code and
> r/o data as a .text section and data/bss as a .data section, using 4k
> alignment and limited permissions.
>
> Doing so is necessary for compatibility with hardening measures that are
> being rolled out on x86 PCs built to run Windows (i.e., the majority of
> them). The EFI boot environment that the Linux EFI stub executes in is
> especially sensitive to safety issues, given that a vulnerability in the
> loader of one OS can be abused to attack another.
>
> In true x86 fashion, this is a lot more complicated than on other
> architectures, which have implemented this code/data split with 4k
> alignment from the beginning. The complicating factor here is that the
> boot image consists of two different parts, which are stitched together
> and fixed up using a special build tool.
>
> After this series is applied, the only remaining task performed by the
> build tool is generating the CRC-32. Even though this checksum is
> usually wrong (given that distro kernels are signed for secure boot in a
> way that corrupts the CRC), this feature is retained as we cannot be
> sure that nobody is relying on this.
>
> This supersedes the work proposed by Evgeniy last year, which did a
> major rewrite of the build tool in order to clean it up, before updating
> it to generate the new 4k aligned image layout. As this series proves,
> the build tool is mostly unnecessary, and we have too many of those
> already.
>
> Changes since v2:
> - rebase onto tip/master
> - drop patches that have been picked up already
> - fix issue in the linker script that resulted in a bogus setup_size in
> some cases when using ld.bfd
> - fix comment capitalization
>
> Changes since v1:
> - drop patch that removed the CRC and the build tool
> - do not use fixed setup_size but derive it in the setup.ld linker
> script
> - reorganize the PE header so the .compat section only covers its
> payload and the padding that follows it
> - add hpa's ack to patch #4
>
> Cc: Evgeniy Baskov <baskov@ispras.ru>
> Cc: Borislav Petkov <bp@alien8.de>
> Cc: Dave Hansen <dave.hansen@linux.intel.com>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Cc: Peter Jones <pjones@redhat.com>
> Cc: Matthew Garrett <mjg59@srcf.ucam.org>
> Cc: Gerd Hoffmann <kraxel@redhat.com>
> Cc: Kees Cook <keescook@chromium.org>
> Cc: "H. Peter Anvin" <hpa@zytor.com>
>
>
> Ard Biesheuvel (8):
> x86/boot: Grab kernel_info offset from zoffset header directly
> x86/boot: Set EFI handover offset directly in header asm
> x86/boot: Define setup size in linker script
> x86/boot: Derive file size from _edata symbol
> x86/boot: Construct PE/COFF .text section from assembler
> x86/boot: Drop PE/COFF .reloc section
> x86/boot: Split off PE/COFF .data section
> x86/boot: Increase section and file alignment to 4k/512
>
> arch/x86/boot/Makefile | 2 +-
> arch/x86/boot/compressed/vmlinux.lds.S | 5 +-
> arch/x86/boot/header.S | 146 +++++++------
> arch/x86/boot/setup.ld | 7 +-
> arch/x86/boot/tools/build.c | 223 +-------------------
> 5 files changed, 97 insertions(+), 286 deletions(-)
Applied to tip:x86/boot, thanks!
Ingo
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2023-09-17 17:51 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-09-15 17:16 [PATCH v3 0/8] x86/boot: Rework PE header generation Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 1/8] x86/boot: Grab kernel_info offset from zoffset header directly Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 2/8] x86/boot: Set EFI handover offset directly in header asm Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 3/8] x86/boot: Define setup size in linker script Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 4/8] x86/boot: Derive file size from _edata symbol Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 5/8] x86/boot: Construct PE/COFF .text section from assembler Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 6/8] x86/boot: Drop PE/COFF .reloc section Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 7/8] x86/boot: Split off PE/COFF .data section Ard Biesheuvel
2023-09-15 17:16 ` [PATCH v3 8/8] x86/boot: Increase section and file alignment to 4k/512 Ard Biesheuvel
2023-09-17 17:50 ` [PATCH v3 0/8] x86/boot: Rework PE header generation Ingo Molnar
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).