linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/6] arm64/efi/zboot: Clean up and enable BTI annotation
@ 2023-04-18 13:49 Ard Biesheuvel
  2023-04-18 13:49 ` [PATCH v2 1/6] efi/pe: Import new BTI/IBT header flags from the spec Ard Biesheuvel
                   ` (5 more replies)
  0 siblings, 6 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2023-04-18 13:49 UTC (permalink / raw)
  To: linux-efi
  Cc: linux-arm-kernel, mark.rutland, broonie, will, catalin.marinas,
	Ard Biesheuvel

Some tweaks for the arm64 EFI header and the zboot version, to add the
annotation that informs the loader that the code regions may be mapped
with BTI enforcement enabled.

As a related cleanup, add the combined codesize (text+rodata+inittext)
to the arm64 Image header, so the EFI zboot loader can grab it from the
image after decompressing it.

Changes since v1:
- instead of adding a proper header field, only pass the code size via
  the image header when generating the zboot image, using the
  text_offset field which still has meaning in the bare metal ABI (which
  means bare metal loaders must honour it) but is actually no longer in
  use.

Ard Biesheuvel (6):
  efi/pe: Import new BTI/IBT header flags from the spec
  arm64: efi: Enable BTI codegen and add PE/COFF annotation
  efi/zboot: arm64: Poke kernel code size into the zboot payload image
    header
  efi/zboot: Add BSS padding before compression
  efi/zboot: Set forward edge CFI compat header flag if supported
  efi/zboot: arm64: Grab code size from image header

 arch/arm64/boot/Makefile                    | 24 ++++++-
 arch/arm64/kernel/efi-header.S              | 71 ++++++++++++--------
 arch/arm64/kernel/image-vars.h              |  4 ++
 drivers/firmware/efi/libstub/Makefile       |  3 +-
 drivers/firmware/efi/libstub/Makefile.zboot | 41 +++++++----
 drivers/firmware/efi/libstub/arm64.c        | 26 +++++--
 drivers/firmware/efi/libstub/efistub.h      |  3 +-
 drivers/firmware/efi/libstub/zboot-header.S | 51 +++++++++-----
 drivers/firmware/efi/libstub/zboot.c        | 13 +---
 include/linux/pe.h                          |  4 ++
 10 files changed, 160 insertions(+), 80 deletions(-)

-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v2 1/6] efi/pe: Import new BTI/IBT header flags from the spec
  2023-04-18 13:49 [PATCH v2 0/6] arm64/efi/zboot: Clean up and enable BTI annotation Ard Biesheuvel
@ 2023-04-18 13:49 ` Ard Biesheuvel
  2023-04-18 13:49 ` [PATCH v2 2/6] arm64: efi: Enable BTI codegen and add PE/COFF annotation Ard Biesheuvel
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2023-04-18 13:49 UTC (permalink / raw)
  To: linux-efi
  Cc: linux-arm-kernel, mark.rutland, broonie, will, catalin.marinas,
	Ard Biesheuvel

The latest version of your favorite fork of the PE/COFF spec includes a
new type of header flag that is intended to be used in the context of
EFI firmware to indicate to the image loader that the executable regions
of an image can be mapped with BTI/IBT enforcement enabled.

So let's import these definitions so we can use them in subsequent
patches.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 include/linux/pe.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/include/linux/pe.h b/include/linux/pe.h
index 6ffabf1e6d039e67..5e1e115408702c77 100644
--- a/include/linux/pe.h
+++ b/include/linux/pe.h
@@ -118,6 +118,9 @@
 #define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER             0x2000
 #define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE  0x8000
 
+#define IMAGE_DLLCHARACTERISTICS_EX_CET_COMPAT		0x0001
+#define IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT	0x0040
+
 /* they actually defined 0x00000000 as well, but I think we'll skip that one. */
 #define IMAGE_SCN_RESERVED_0	0x00000001
 #define IMAGE_SCN_RESERVED_1	0x00000002
@@ -165,6 +168,7 @@
 #define IMAGE_SCN_MEM_WRITE	0x80000000 /* writeable */
 
 #define IMAGE_DEBUG_TYPE_CODEVIEW	2
+#define IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS	20
 
 #ifndef __ASSEMBLY__
 
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 2/6] arm64: efi: Enable BTI codegen and add PE/COFF annotation
  2023-04-18 13:49 [PATCH v2 0/6] arm64/efi/zboot: Clean up and enable BTI annotation Ard Biesheuvel
  2023-04-18 13:49 ` [PATCH v2 1/6] efi/pe: Import new BTI/IBT header flags from the spec Ard Biesheuvel
@ 2023-04-18 13:49 ` Ard Biesheuvel
  2023-04-18 13:49 ` [PATCH v2 3/6] efi/zboot: arm64: Poke kernel code size into the zboot payload image header Ard Biesheuvel
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2023-04-18 13:49 UTC (permalink / raw)
  To: linux-efi
  Cc: linux-arm-kernel, mark.rutland, broonie, will, catalin.marinas,
	Ard Biesheuvel

UEFI heavily relies on so-called protocols, which are essentially
tables populated with pointers to executable code, and these are invoked
indirectly using BR or BLR instructions.

This makes the EFI execution context vulnerable to attacks on forward
edge control flow, and so it would help if we could enable hardware
enforcement (BTI) on CPUs that implement it.

So let's no longer disable BTI codegen for the EFI stub, and set the
newly introduced PE/COFF header flag when the kernel is built with BTI
landing pads.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Reviewed-by: Mark Brown <broonie@kernel.org>
---
 arch/arm64/kernel/efi-header.S        | 71 ++++++++++++--------
 drivers/firmware/efi/libstub/Makefile |  3 +-
 2 files changed, 44 insertions(+), 30 deletions(-)

diff --git a/arch/arm64/kernel/efi-header.S b/arch/arm64/kernel/efi-header.S
index d731b4655df8eb27..11d7f7de202d0ed2 100644
--- a/arch/arm64/kernel/efi-header.S
+++ b/arch/arm64/kernel/efi-header.S
@@ -81,9 +81,47 @@
 	.quad	0					// CertificationTable
 	.quad	0					// BaseRelocationTable
 
-#ifdef CONFIG_DEBUG_EFI
+#if defined(CONFIG_DEBUG_EFI) || defined(CONFIG_ARM64_BTI_KERNEL)
 	.long	.Lefi_debug_table - .L_head		// DebugTable
 	.long	.Lefi_debug_table_size
+
+	/*
+	 * The debug table is referenced via its Relative Virtual Address (RVA),
+	 * which is only defined for those parts of the image that are covered
+	 * by a section declaration. Since this header is not covered by any
+	 * section, the debug table must be emitted elsewhere. So stick it in
+	 * the .init.rodata section instead.
+	 *
+	 * Note that the payloads themselves are permitted to have zero RVAs,
+	 * which means we can simply put those right after the section headers.
+	 */
+	__INITRODATA
+
+	.align	2
+.Lefi_debug_table:
+#ifdef CONFIG_DEBUG_EFI
+	// EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
+	.long	0					// Characteristics
+	.long	0					// TimeDateStamp
+	.short	0					// MajorVersion
+	.short	0					// MinorVersion
+	.long	IMAGE_DEBUG_TYPE_CODEVIEW		// Type
+	.long	.Lefi_debug_entry_size			// SizeOfData
+	.long	0					// RVA
+	.long	.Lefi_debug_entry - .L_head		// FileOffset
+#endif
+#ifdef CONFIG_ARM64_BTI_KERNEL
+	.long	0					// Characteristics
+	.long	0					// TimeDateStamp
+	.short	0					// MajorVersion
+	.short	0					// MinorVersion
+	.long	IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS	// Type
+	.long	4					// SizeOfData
+	.long	0					// RVA
+	.long	.Lefi_dll_characteristics_ex - .L_head	// FileOffset
+#endif
+	.set	.Lefi_debug_table_size, . - .Lefi_debug_table
+	.previous
 #endif
 
 	// Section table
@@ -119,33 +157,6 @@
 	.set	.Lsection_count, (. - .Lsection_table) / 40
 
 #ifdef CONFIG_DEBUG_EFI
-	/*
-	 * The debug table is referenced via its Relative Virtual Address (RVA),
-	 * which is only defined for those parts of the image that are covered
-	 * by a section declaration. Since this header is not covered by any
-	 * section, the debug table must be emitted elsewhere. So stick it in
-	 * the .init.rodata section instead.
-	 *
-	 * Note that the EFI debug entry itself may legally have a zero RVA,
-	 * which means we can simply put it right after the section headers.
-	 */
-	__INITRODATA
-
-	.align	2
-.Lefi_debug_table:
-	// EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
-	.long	0					// Characteristics
-	.long	0					// TimeDateStamp
-	.short	0					// MajorVersion
-	.short	0					// MinorVersion
-	.long	IMAGE_DEBUG_TYPE_CODEVIEW		// Type
-	.long	.Lefi_debug_entry_size			// SizeOfData
-	.long	0					// RVA
-	.long	.Lefi_debug_entry - .L_head		// FileOffset
-
-	.set	.Lefi_debug_table_size, . - .Lefi_debug_table
-	.previous
-
 .Lefi_debug_entry:
 	// EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
 	.ascii	"NB10"					// Signature
@@ -157,6 +168,10 @@
 
 	.set	.Lefi_debug_entry_size, . - .Lefi_debug_entry
 #endif
+#ifdef CONFIG_ARM64_BTI_KERNEL
+.Lefi_dll_characteristics_ex:
+	.long	IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT
+#endif
 
 	.balign	SEGMENT_ALIGN
 .Lefi_header_end:
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 80d85a5169fb2c72..3abb2b357482a416 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -23,8 +23,7 @@ cflags-$(CONFIG_X86)		+= -m$(BITS) -D__KERNEL__ \
 # arm64 uses the full KBUILD_CFLAGS so it's necessary to explicitly
 # disable the stackleak plugin
 cflags-$(CONFIG_ARM64)		+= -fpie $(DISABLE_STACKLEAK_PLUGIN) \
-				   -fno-unwind-tables -fno-asynchronous-unwind-tables \
-				   $(call cc-option,-mbranch-protection=none)
+				   -fno-unwind-tables -fno-asynchronous-unwind-tables
 cflags-$(CONFIG_ARM)		+= -DEFI_HAVE_STRLEN -DEFI_HAVE_STRNLEN \
 				   -DEFI_HAVE_MEMCHR -DEFI_HAVE_STRRCHR \
 				   -DEFI_HAVE_STRCMP -fno-builtin -fpic \
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 3/6] efi/zboot: arm64: Poke kernel code size into the zboot payload image header
  2023-04-18 13:49 [PATCH v2 0/6] arm64/efi/zboot: Clean up and enable BTI annotation Ard Biesheuvel
  2023-04-18 13:49 ` [PATCH v2 1/6] efi/pe: Import new BTI/IBT header flags from the spec Ard Biesheuvel
  2023-04-18 13:49 ` [PATCH v2 2/6] arm64: efi: Enable BTI codegen and add PE/COFF annotation Ard Biesheuvel
@ 2023-04-18 13:49 ` Ard Biesheuvel
  2023-04-18 13:49 ` [PATCH v2 4/6] efi/zboot: Add BSS padding before compression Ard Biesheuvel
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2023-04-18 13:49 UTC (permalink / raw)
  To: linux-efi
  Cc: linux-arm-kernel, mark.rutland, broonie, will, catalin.marinas,
	Ard Biesheuvel

The EFI zboot code is not built as part of the kernel proper, like the
ordinary EFI stub, but still needs access to symbols that are defined
only internally in the kernel, and are left unexposed deliberately to
avoid creating ABI inadvertently that we're stuck with later.

So instead of passing the ordinary Image file to the zboot make rules,
create an alternate version Image.zboot that has the code size copied
into the header into a field that has meaning in the bare metal boot
ABI, but is actually not used anymore, and is always set to 0x0.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/arm64/boot/Makefile       | 23 +++++++++++++++++++-
 arch/arm64/kernel/image-vars.h |  4 ++++
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile
index c65aee0884103c6f..5d73229604b11061 100644
--- a/arch/arm64/boot/Makefile
+++ b/arch/arm64/boot/Makefile
@@ -39,8 +39,29 @@ $(obj)/Image.lzo: $(obj)/Image FORCE
 $(obj)/Image.zst: $(obj)/Image FORCE
 	$(call if_changed,zstd)
 
-EFI_ZBOOT_PAYLOAD	:= Image
+EFI_ZBOOT_PAYLOAD	:= Image.zboot
 EFI_ZBOOT_BFD_TARGET	:= elf64-littleaarch64
 EFI_ZBOOT_MACH_TYPE	:= ARM64
 
+#
+# The EFI zboot logic needs to know the size of the executable region in the
+# image, so let's poke that into the text_offset field of the image header of
+# the zboot payload, as that field is no longer used and can thus be repurposed
+# for other, purely internal uses.
+#
+quiet_cmd_copy_and_poke = $(quiet_cmd_objcopy)
+      cmd_copy_and_poke = $(cmd_objcopy) && /bin/echo -ne "$(POKE_DATA)" | dd bs=1 \
+				status=none conv=notrunc seek=$(POKE_OFFSET) of=$@
+
+# grab the code size and convert it into something we can echo
+$(obj)/$(EFI_ZBOOT_PAYLOAD): POKE_DATA = $(shell $(NM) $<|grep _kernel_codesize|\
+				sed -E 's/0+(..)(..)(..)(..) .+/\\x\4\\x\3\\x\2\\x\1/')
+$(obj)/$(EFI_ZBOOT_PAYLOAD): POKE_OFFSET := 8
+$(obj)/$(EFI_ZBOOT_PAYLOAD): vmlinux FORCE
+	$(call if_changed,copy_and_poke)
+
+OBJCOPYFLAGS_$(EFI_ZBOOT_PAYLOAD) := $(OBJCOPYFLAGS_Image)
+
+targets += $(EFI_ZBOOT_PAYLOAD)
+
 include $(srctree)/drivers/firmware/efi/libstub/Makefile.zboot
diff --git a/arch/arm64/kernel/image-vars.h b/arch/arm64/kernel/image-vars.h
index 8309197c0ebd4a8e..35f3c79595137354 100644
--- a/arch/arm64/kernel/image-vars.h
+++ b/arch/arm64/kernel/image-vars.h
@@ -108,4 +108,8 @@ KVM_NVHE_ALIAS(kvm_protected_mode_initialized);
 
 #endif /* CONFIG_KVM */
 
+#ifdef CONFIG_EFI_ZBOOT
+_kernel_codesize = ABSOLUTE(__inittext_end - _text);
+#endif
+
 #endif /* __ARM64_KERNEL_IMAGE_VARS_H */
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 4/6] efi/zboot: Add BSS padding before compression
  2023-04-18 13:49 [PATCH v2 0/6] arm64/efi/zboot: Clean up and enable BTI annotation Ard Biesheuvel
                   ` (2 preceding siblings ...)
  2023-04-18 13:49 ` [PATCH v2 3/6] efi/zboot: arm64: Poke kernel code size into the zboot payload image header Ard Biesheuvel
@ 2023-04-18 13:49 ` Ard Biesheuvel
  2023-04-18 13:49 ` [PATCH v2 5/6] efi/zboot: Set forward edge CFI compat header flag if supported Ard Biesheuvel
  2023-04-18 13:49 ` [PATCH v2 6/6] efi/zboot: arm64: Grab code size from image header Ard Biesheuvel
  5 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2023-04-18 13:49 UTC (permalink / raw)
  To: linux-efi
  Cc: linux-arm-kernel, mark.rutland, broonie, will, catalin.marinas,
	Ard Biesheuvel

We don't really care about the size of the decompressed image - what
matters is how much space needs to be allocated for the image to
execute, and this includes space for BSS that is not part of the
loadable image and so it is not accounted for in the decompressed size.

So let's add some zero padding to the end of the image: this compresses
well, and it ensures that BSS is accounted for, and as a bonus, it will
be zeroed before launching the image.

Since all architectures that implement support for EFI zboot carry this
value in the header in the same location, we can just grab it from the
binary that is being compressed.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 drivers/firmware/efi/libstub/Makefile.zboot | 36 +++++++++++++++-----
 drivers/firmware/efi/libstub/zboot-header.S |  2 +-
 drivers/firmware/efi/libstub/zboot.c        |  6 ++--
 3 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/drivers/firmware/efi/libstub/Makefile.zboot b/drivers/firmware/efi/libstub/Makefile.zboot
index ccdd6a130d98618e..2d78770236049b21 100644
--- a/drivers/firmware/efi/libstub/Makefile.zboot
+++ b/drivers/firmware/efi/libstub/Makefile.zboot
@@ -3,6 +3,14 @@
 # to be include'd by arch/$(ARCH)/boot/Makefile after setting
 # EFI_ZBOOT_PAYLOAD, EFI_ZBOOT_BFD_TARGET and EFI_ZBOOT_MACH_TYPE
 
+quiet_cmd_copy_and_pad = PAD     $@
+      cmd_copy_and_pad = cp $< $@ && \
+			 truncate -s $(shell hexdump -s16 -n4 -e '"%u"' $<) $@
+
+# Pad the file to the size of the uncompressed image in memory, including BSS
+$(obj)/vmlinux.bin: $(obj)/$(EFI_ZBOOT_PAYLOAD) FORCE
+	$(call if_changed,copy_and_pad)
+
 comp-type-$(CONFIG_KERNEL_GZIP)		:= gzip
 comp-type-$(CONFIG_KERNEL_LZ4)		:= lz4
 comp-type-$(CONFIG_KERNEL_LZMA)		:= lzma
@@ -10,16 +18,25 @@ comp-type-$(CONFIG_KERNEL_LZO)		:= lzo
 comp-type-$(CONFIG_KERNEL_XZ)		:= xzkern
 comp-type-$(CONFIG_KERNEL_ZSTD)		:= zstd22
 
-# Copy the SizeOfHeaders, SizeOfCode and SizeOfImage fields from the payload to
-# the end of the compressed image. Note that this presupposes a PE header
-# offset of 64 bytes, which is what arm64, RISC-V and LoongArch use.
-quiet_cmd_compwithsize = $(quiet_cmd_$(comp-type-y))
-      cmd_compwithsize = $(cmd_$(comp-type-y)) && ( \
+# in GZIP, the appended le32 carrying the uncompressed size is part of the
+# format, but in other cases, we just append it at the end for convenience,
+# causing the original tools to complain when checking image integrity.
+# So disregard it when calculating the payload size in the zimage header.
+zboot-method-y                         := $(comp-type-y)_with_size
+zboot-size-len-y                       := 12
+
+zboot-method-$(CONFIG_KERNEL_GZIP)     := gzip
+zboot-size-len-$(CONFIG_KERNEL_GZIP)   := 8
+
+# Copy the SizeOfHeaders and SizeOfCode fields from the payload to the end of
+# the compressed image. Note that this presupposes a PE header offset of 64
+# bytes, which is what arm64, RISC-V and LoongArch use.
+quiet_cmd_compwithsize = $(quiet_cmd_$(zboot-method-y))
+      cmd_compwithsize = $(cmd_$(zboot-method-y)) && ( \
 			   dd status=none if=$< bs=4 count=1 skip=37 ; \
-			   dd status=none if=$< bs=4 count=1 skip=23 ; \
-			   dd status=none if=$< bs=4 count=1 skip=36 ) >> $@
+			   dd status=none if=$< bs=4 count=1 skip=23 ) >> $@
 
-$(obj)/vmlinuz: $(obj)/$(EFI_ZBOOT_PAYLOAD) FORCE
+$(obj)/vmlinuz: $(obj)/vmlinux.bin FORCE
 	$(call if_changed,compwithsize)
 
 OBJCOPYFLAGS_vmlinuz.o := -I binary -O $(EFI_ZBOOT_BFD_TARGET) \
@@ -29,6 +46,7 @@ $(obj)/vmlinuz.o: $(obj)/vmlinuz FORCE
 
 AFLAGS_zboot-header.o += -DMACHINE_TYPE=IMAGE_FILE_MACHINE_$(EFI_ZBOOT_MACH_TYPE) \
 			 -DZBOOT_EFI_PATH="\"$(realpath $(obj)/vmlinuz.efi.elf)\"" \
+			 -DZBOOT_SIZE_LEN=$(zboot-size-len-y) \
 			 -DCOMP_TYPE="\"$(comp-type-y)\""
 
 $(obj)/zboot-header.o: $(srctree)/drivers/firmware/efi/libstub/zboot-header.S FORCE
@@ -44,4 +62,4 @@ OBJCOPYFLAGS_vmlinuz.efi := -O binary
 $(obj)/vmlinuz.efi: $(obj)/vmlinuz.efi.elf FORCE
 	$(call if_changed,objcopy)
 
-targets += zboot-header.o vmlinuz vmlinuz.o vmlinuz.efi.elf vmlinuz.efi
+targets += zboot-header.o vmlinux.bin vmlinuz vmlinuz.o vmlinuz.efi.elf vmlinuz.efi
diff --git a/drivers/firmware/efi/libstub/zboot-header.S b/drivers/firmware/efi/libstub/zboot-header.S
index 445cb646eaaaf1c6..053aba073594936b 100644
--- a/drivers/firmware/efi/libstub/zboot-header.S
+++ b/drivers/firmware/efi/libstub/zboot-header.S
@@ -17,7 +17,7 @@ __efistub_efi_zboot_header:
 	.long		MZ_MAGIC
 	.ascii		"zimg"					// image type
 	.long		__efistub__gzdata_start - .Ldoshdr	// payload offset
-	.long		__efistub__gzdata_size - 12		// payload size
+	.long		__efistub__gzdata_size - ZBOOT_SIZE_LEN	// payload size
 	.long		0, 0					// reserved
 	.asciz		COMP_TYPE				// compression type
 	.org		.Ldoshdr + 0x38
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
index 6105e5e2eda4612b..63ece480090032c1 100644
--- a/drivers/firmware/efi/libstub/zboot.c
+++ b/drivers/firmware/efi/libstub/zboot.c
@@ -91,12 +91,12 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
 	efi_info("Decompressing Linux Kernel...\n");
 
 	// SizeOfImage from the compressee's PE/COFF header
-	alloc_size = round_up(get_unaligned_le32(_gzdata_end - 4),
+	alloc_size = round_up(get_unaligned_le32(_gzdata_end - 12),
 			      EFI_ALLOC_ALIGN);
 
 	// SizeOfHeaders and SizeOfCode from the compressee's PE/COFF header
-	code_size = get_unaligned_le32(_gzdata_end - 8) +
-		    get_unaligned_le32(_gzdata_end - 12);
+	code_size = get_unaligned_le32(_gzdata_end - 4) +
+		    get_unaligned_le32(_gzdata_end - 8);
 
 	 // If the architecture has a preferred address for the image,
 	 // try that first.
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 5/6] efi/zboot: Set forward edge CFI compat header flag if supported
  2023-04-18 13:49 [PATCH v2 0/6] arm64/efi/zboot: Clean up and enable BTI annotation Ard Biesheuvel
                   ` (3 preceding siblings ...)
  2023-04-18 13:49 ` [PATCH v2 4/6] efi/zboot: Add BSS padding before compression Ard Biesheuvel
@ 2023-04-18 13:49 ` Ard Biesheuvel
  2023-04-18 13:49 ` [PATCH v2 6/6] efi/zboot: arm64: Grab code size from image header Ard Biesheuvel
  5 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2023-04-18 13:49 UTC (permalink / raw)
  To: linux-efi
  Cc: linux-arm-kernel, mark.rutland, broonie, will, catalin.marinas,
	Ard Biesheuvel

Add some plumbing to the zboot EFI header generation to set the newly
introduced DllCharacteristicsEx flag associated with forward edge CFI
enforcement instructions (BTI on arm64, IBT on x86)

x86 does not currently uses the zboot infrastructure, so let's wire it
up only for arm64.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 arch/arm64/boot/Makefile                    |  1 +
 drivers/firmware/efi/libstub/Makefile.zboot |  9 +++-
 drivers/firmware/efi/libstub/zboot-header.S | 49 +++++++++++++-------
 3 files changed, 40 insertions(+), 19 deletions(-)

diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile
index 5d73229604b11061..affbcb0df9db81e5 100644
--- a/arch/arm64/boot/Makefile
+++ b/arch/arm64/boot/Makefile
@@ -42,6 +42,7 @@ $(obj)/Image.zst: $(obj)/Image FORCE
 EFI_ZBOOT_PAYLOAD	:= Image.zboot
 EFI_ZBOOT_BFD_TARGET	:= elf64-littleaarch64
 EFI_ZBOOT_MACH_TYPE	:= ARM64
+EFI_ZBOOT_FORWARD_CFI	:= $(CONFIG_ARM64_BTI_KERNEL)
 
 #
 # The EFI zboot logic needs to know the size of the executable region in the
diff --git a/drivers/firmware/efi/libstub/Makefile.zboot b/drivers/firmware/efi/libstub/Makefile.zboot
index 2d78770236049b21..0a9dcc2b13736519 100644
--- a/drivers/firmware/efi/libstub/Makefile.zboot
+++ b/drivers/firmware/efi/libstub/Makefile.zboot
@@ -1,7 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0
 
 # to be include'd by arch/$(ARCH)/boot/Makefile after setting
-# EFI_ZBOOT_PAYLOAD, EFI_ZBOOT_BFD_TARGET and EFI_ZBOOT_MACH_TYPE
+# EFI_ZBOOT_PAYLOAD, EFI_ZBOOT_BFD_TARGET, EFI_ZBOOT_MACH_TYPE and
+# EFI_ZBOOT_FORWARD_CFI
 
 quiet_cmd_copy_and_pad = PAD     $@
       cmd_copy_and_pad = cp $< $@ && \
@@ -44,10 +45,14 @@ OBJCOPYFLAGS_vmlinuz.o := -I binary -O $(EFI_ZBOOT_BFD_TARGET) \
 $(obj)/vmlinuz.o: $(obj)/vmlinuz FORCE
 	$(call if_changed,objcopy)
 
+aflags-zboot-header-$(EFI_ZBOOT_FORWARD_CFI) := \
+		-DPE_DLL_CHAR_EX=IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT
+
 AFLAGS_zboot-header.o += -DMACHINE_TYPE=IMAGE_FILE_MACHINE_$(EFI_ZBOOT_MACH_TYPE) \
 			 -DZBOOT_EFI_PATH="\"$(realpath $(obj)/vmlinuz.efi.elf)\"" \
 			 -DZBOOT_SIZE_LEN=$(zboot-size-len-y) \
-			 -DCOMP_TYPE="\"$(comp-type-y)\""
+			 -DCOMP_TYPE="\"$(comp-type-y)\"" \
+			 $(aflags-zboot-header-y)
 
 $(obj)/zboot-header.o: $(srctree)/drivers/firmware/efi/libstub/zboot-header.S FORCE
 	$(call if_changed_rule,as_o_S)
diff --git a/drivers/firmware/efi/libstub/zboot-header.S b/drivers/firmware/efi/libstub/zboot-header.S
index 053aba073594936b..fb676ded47fa4341 100644
--- a/drivers/firmware/efi/libstub/zboot-header.S
+++ b/drivers/firmware/efi/libstub/zboot-header.S
@@ -78,9 +78,36 @@ __efistub_efi_zboot_header:
 	.quad		0				// ExceptionTable
 	.quad		0				// CertificationTable
 	.quad		0				// BaseRelocationTable
-#ifdef CONFIG_DEBUG_EFI
+#if defined(PE_DLL_CHAR_EX) || defined(CONFIG_DEBUG_EFI)
 	.long		.Lefi_debug_table - .Ldoshdr	// DebugTable
 	.long		.Lefi_debug_table_size
+
+	.section	".rodata", "a"
+	.p2align	2
+.Lefi_debug_table:
+	// EFI_IMAGE_DEBUG_DIRECTORY_ENTRY[]
+#ifdef PE_DLL_CHAR_EX
+	.long		0					// Characteristics
+	.long		0					// TimeDateStamp
+	.short		0					// MajorVersion
+	.short		0					// MinorVersion
+	.long		IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS	// Type
+	.long		4					// SizeOfData
+	.long		0					// RVA
+	.long		.Lefi_dll_characteristics_ex - .Ldoshdr	// FileOffset
+#endif
+#ifdef CONFIG_DEBUG_EFI
+	.long		0					// Characteristics
+	.long		0					// TimeDateStamp
+	.short		0					// MajorVersion
+	.short		0					// MinorVersion
+	.long		IMAGE_DEBUG_TYPE_CODEVIEW		// Type
+	.long		.Lefi_debug_entry_size			// SizeOfData
+	.long		0					// RVA
+	.long		.Lefi_debug_entry - .Ldoshdr		// FileOffset
+#endif
+	.set		.Lefi_debug_table_size, . - .Lefi_debug_table
+	.previous
 #endif
 
 .Lsection_table:
@@ -110,23 +137,11 @@ __efistub_efi_zboot_header:
 
 	.set		.Lsection_count, (. - .Lsection_table) / 40
 
+#ifdef PE_DLL_CHAR_EX
+.Lefi_dll_characteristics_ex:
+	.long		PE_DLL_CHAR_EX
+#endif
 #ifdef CONFIG_DEBUG_EFI
-	.section	".rodata", "a"
-	.align		2
-.Lefi_debug_table:
-	// EFI_IMAGE_DEBUG_DIRECTORY_ENTRY
-	.long		0				// Characteristics
-	.long		0				// TimeDateStamp
-	.short		0				// MajorVersion
-	.short		0				// MinorVersion
-	.long		IMAGE_DEBUG_TYPE_CODEVIEW	// Type
-	.long		.Lefi_debug_entry_size		// SizeOfData
-	.long		0				// RVA
-	.long		.Lefi_debug_entry - .Ldoshdr	// FileOffset
-
-	.set		.Lefi_debug_table_size, . - .Lefi_debug_table
-	.previous
-
 .Lefi_debug_entry:
 	// EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY
 	.ascii		"NB10"				// Signature
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v2 6/6] efi/zboot: arm64: Grab code size from image header
  2023-04-18 13:49 [PATCH v2 0/6] arm64/efi/zboot: Clean up and enable BTI annotation Ard Biesheuvel
                   ` (4 preceding siblings ...)
  2023-04-18 13:49 ` [PATCH v2 5/6] efi/zboot: Set forward edge CFI compat header flag if supported Ard Biesheuvel
@ 2023-04-18 13:49 ` Ard Biesheuvel
  5 siblings, 0 replies; 7+ messages in thread
From: Ard Biesheuvel @ 2023-04-18 13:49 UTC (permalink / raw)
  To: linux-efi
  Cc: linux-arm-kernel, mark.rutland, broonie, will, catalin.marinas,
	Ard Biesheuvel

Instead of relying on a dodgy dd hack to copy the image code size from
the uncompressed image's PE header to the end of the compressed image,
let's grab the code size from the text_offset field of the arm64 image
header after decompression, which is where the arm64 specific EFI zboot
make rules will poke the code size when generating zboot specific
version of the binary Image payload.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
---
 drivers/firmware/efi/libstub/Makefile.zboot | 14 +++--------
 drivers/firmware/efi/libstub/arm64.c        | 26 +++++++++++++++-----
 drivers/firmware/efi/libstub/efistub.h      |  3 +--
 drivers/firmware/efi/libstub/zboot.c        | 15 +++--------
 4 files changed, 28 insertions(+), 30 deletions(-)

diff --git a/drivers/firmware/efi/libstub/Makefile.zboot b/drivers/firmware/efi/libstub/Makefile.zboot
index 0a9dcc2b13736519..d34d4f0ed33349d5 100644
--- a/drivers/firmware/efi/libstub/Makefile.zboot
+++ b/drivers/firmware/efi/libstub/Makefile.zboot
@@ -24,21 +24,13 @@ comp-type-$(CONFIG_KERNEL_ZSTD)		:= zstd22
 # causing the original tools to complain when checking image integrity.
 # So disregard it when calculating the payload size in the zimage header.
 zboot-method-y                         := $(comp-type-y)_with_size
-zboot-size-len-y                       := 12
+zboot-size-len-y                       := 4
 
 zboot-method-$(CONFIG_KERNEL_GZIP)     := gzip
-zboot-size-len-$(CONFIG_KERNEL_GZIP)   := 8
-
-# Copy the SizeOfHeaders and SizeOfCode fields from the payload to the end of
-# the compressed image. Note that this presupposes a PE header offset of 64
-# bytes, which is what arm64, RISC-V and LoongArch use.
-quiet_cmd_compwithsize = $(quiet_cmd_$(zboot-method-y))
-      cmd_compwithsize = $(cmd_$(zboot-method-y)) && ( \
-			   dd status=none if=$< bs=4 count=1 skip=37 ; \
-			   dd status=none if=$< bs=4 count=1 skip=23 ) >> $@
+zboot-size-len-$(CONFIG_KERNEL_GZIP)   := 0
 
 $(obj)/vmlinuz: $(obj)/vmlinux.bin FORCE
-	$(call if_changed,compwithsize)
+	$(call if_changed,$(zboot-method-y))
 
 OBJCOPYFLAGS_vmlinuz.o := -I binary -O $(EFI_ZBOOT_BFD_TARGET) \
 			  --rename-section .data=.gzdata,load,alloc,readonly,contents
diff --git a/drivers/firmware/efi/libstub/arm64.c b/drivers/firmware/efi/libstub/arm64.c
index 8aad8c49d43f18e0..a75933b3b9f41c38 100644
--- a/drivers/firmware/efi/libstub/arm64.c
+++ b/drivers/firmware/efi/libstub/arm64.c
@@ -9,6 +9,7 @@
 
 #include <linux/efi.h>
 #include <asm/efi.h>
+#include <asm/image.h>
 #include <asm/memory.h>
 #include <asm/sysreg.h>
 
@@ -89,25 +90,38 @@ efi_status_t check_platform_features(void)
 #endif
 
 void efi_cache_sync_image(unsigned long image_base,
-			  unsigned long alloc_size,
-			  unsigned long code_size)
+			  unsigned long alloc_size)
 {
+	struct arm64_image_header *header = (void *)image_base;
+	/*
+	 * In the EFI zboot case, the kernel code size lives in the text_offset
+	 * field of the image header, which is no longer used now that
+	 * TEXT_OFFSET is always 0x0.
+	 */
+	unsigned long code_size = le64_to_cpu(header->text_offset);
 	u32 ctr = read_cpuid_effective_cachetype();
 	u64 lsize = 4 << cpuid_feature_extract_unsigned_field(ctr,
 						CTR_EL0_DminLine_SHIFT);
 
 	/* only perform the cache maintenance if needed for I/D coherency */
 	if (!(ctr & BIT(CTR_EL0_IDC_SHIFT))) {
+		unsigned long base = image_base;
+		unsigned long size = code_size;
+
 		do {
-			asm("dc " DCTYPE ", %0" :: "r"(image_base));
-			image_base += lsize;
-			code_size -= lsize;
-		} while (code_size >= lsize);
+			asm("dc " DCTYPE ", %0" :: "r"(base));
+			base += lsize;
+			size -= lsize;
+		} while (size >= lsize);
 	}
 
 	asm("ic ialluis");
 	dsb(ish);
 	isb();
+
+	header->text_offset = 0x0;
+
+	efi_remap_image(image_base, alloc_size, code_size);
 }
 
 unsigned long __weak primary_entry_offset(void)
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 148013bcb5f89fdd..67d5a20802e0b7c6 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -1066,8 +1066,7 @@ struct screen_info *__alloc_screen_info(void);
 void free_screen_info(struct screen_info *si);
 
 void efi_cache_sync_image(unsigned long image_base,
-			  unsigned long alloc_size,
-			  unsigned long code_size);
+			  unsigned long alloc_size);
 
 struct efi_smbios_record {
 	u8	type;
diff --git a/drivers/firmware/efi/libstub/zboot.c b/drivers/firmware/efi/libstub/zboot.c
index 63ece480090032c1..e5d7fa1f1d8fd160 100644
--- a/drivers/firmware/efi/libstub/zboot.c
+++ b/drivers/firmware/efi/libstub/zboot.c
@@ -50,8 +50,7 @@ static unsigned long alloc_preferred_address(unsigned long alloc_size)
 }
 
 void __weak efi_cache_sync_image(unsigned long image_base,
-				 unsigned long alloc_size,
-				 unsigned long code_size)
+				 unsigned long alloc_size)
 {
 	// Provided by the arch to perform the cache maintenance necessary for
 	// executable code loaded into memory to be safe for execution.
@@ -66,7 +65,7 @@ asmlinkage efi_status_t __efiapi
 efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
 {
 	unsigned long compressed_size = _gzdata_end - _gzdata_start;
-	unsigned long image_base, alloc_size, code_size;
+	unsigned long image_base, alloc_size;
 	efi_loaded_image_t *image;
 	efi_status_t status;
 	char *cmdline_ptr;
@@ -91,13 +90,9 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
 	efi_info("Decompressing Linux Kernel...\n");
 
 	// SizeOfImage from the compressee's PE/COFF header
-	alloc_size = round_up(get_unaligned_le32(_gzdata_end - 12),
+	alloc_size = round_up(get_unaligned_le32(_gzdata_end - 4),
 			      EFI_ALLOC_ALIGN);
 
-	// SizeOfHeaders and SizeOfCode from the compressee's PE/COFF header
-	code_size = get_unaligned_le32(_gzdata_end - 4) +
-		    get_unaligned_le32(_gzdata_end - 8);
-
 	 // If the architecture has a preferred address for the image,
 	 // try that first.
 	image_base = alloc_preferred_address(alloc_size);
@@ -140,9 +135,7 @@ efi_zboot_entry(efi_handle_t handle, efi_system_table_t *systab)
 		goto free_image;
 	}
 
-	efi_cache_sync_image(image_base, alloc_size, code_size);
-
-	efi_remap_image(image_base, alloc_size, code_size);
+	efi_cache_sync_image(image_base, alloc_size);
 
 	status = efi_stub_common(handle, image, image_base, cmdline_ptr);
 
-- 
2.39.2


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2023-04-18 13:51 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-04-18 13:49 [PATCH v2 0/6] arm64/efi/zboot: Clean up and enable BTI annotation Ard Biesheuvel
2023-04-18 13:49 ` [PATCH v2 1/6] efi/pe: Import new BTI/IBT header flags from the spec Ard Biesheuvel
2023-04-18 13:49 ` [PATCH v2 2/6] arm64: efi: Enable BTI codegen and add PE/COFF annotation Ard Biesheuvel
2023-04-18 13:49 ` [PATCH v2 3/6] efi/zboot: arm64: Poke kernel code size into the zboot payload image header Ard Biesheuvel
2023-04-18 13:49 ` [PATCH v2 4/6] efi/zboot: Add BSS padding before compression Ard Biesheuvel
2023-04-18 13:49 ` [PATCH v2 5/6] efi/zboot: Set forward edge CFI compat header flag if supported Ard Biesheuvel
2023-04-18 13:49 ` [PATCH v2 6/6] efi/zboot: arm64: Grab code size from image header Ard Biesheuvel

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).