From 0bd358e4ee0c61355ab057a977fa6f5e311b7f07 Mon Sep 17 00:00:00 2001
From: Alexey Makhalov <amakhalov@vmware.com>
Date: Fri, 22 Sep 2023 12:25:24 -0700
Subject: [PATCH 2/3] Add .sbat section

To be able to revoke previously shipped signed kernel images by SBAT
generation. See https://github.com/rhboot/shim/blob/main/SBAT.md

Signed-off-by: Alexey Makhalov <amakhalov@vmware.com>
---
 arch/x86/boot/Makefile      |  2 +-
 arch/x86/boot/header.S      | 22 ++++++++++++++++++++++
 arch/x86/boot/tools/build.c | 33 ++++++++++++++++++++++++++-------
 security/Kconfig            | 12 ++++++++++++
 4 files changed, 61 insertions(+), 8 deletions(-)

diff --git a/arch/x86/boot/Makefile b/arch/x86/boot/Makefile
index 9e38ffaad..c757ce1fb 100644
--- a/arch/x86/boot/Makefile
+++ b/arch/x86/boot/Makefile
@@ -79,7 +79,7 @@ $(obj)/bzImage: asflags-y  := $(SVGA_MODE)
 quiet_cmd_image = BUILD   $@
 silent_redirect_image = >/dev/null
 cmd_image = $(obj)/tools/build $(obj)/setup.bin $(obj)/vmlinux.bin \
-			       $(obj)/zoffset.h $@ $($(quiet)redirect_image)
+			       $(obj)/zoffset.h $@ $(CONFIG_SECURITY_SBAT) $($(quiet)redirect_image)
 
 $(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
 	$(call if_changed,image)
diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S
index f912d7770..1c0225fbd 100644
--- a/arch/x86/boot/header.S
+++ b/arch/x86/boot/header.S
@@ -232,6 +232,28 @@ section_table:
 		IMAGE_SCN_MEM_DISCARDABLE	| \
 		IMAGE_SCN_ALIGN_1BYTES		# Characteristics
 
+#ifdef CONFIG_SECURITY_SBAT
+	#
+	# The offset & size fields are filled in by build.c.
+	#
+	.ascii	".sbat"
+	.byte	0
+	.byte	0
+	.byte	0
+	.long	0				# VirtualSize
+	.long	0				# VirtualAddress
+	.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	| \
+		IMAGE_SCN_ALIGN_1BYTES		# Characteristics
+#endif
+
 #ifdef CONFIG_EFI_MIXED
 	#
 	# The offset & size fields are filled in by build.c.
diff --git a/arch/x86/boot/tools/build.c b/arch/x86/boot/tools/build.c
index a3725ad46..d0b803d55 100644
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -195,12 +195,12 @@ 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_and_reloc(unsigned int size, unsigned int sbat_size)
 {
 	u32 setup_offset = 0x200;
-	u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE;
+	u32 reloc_offset = size - PECOFF_RELOC_RESERVE - PECOFF_COMPAT_RESERVE - sbat_size;
 #ifdef CONFIG_EFI_MIXED
-	u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE;
+	u32 compat_offset = reloc_offset + PECOFF_RELOC_RESERVE + sbat_size;
 #endif
 	u32 setup_size = reloc_offset - setup_offset;
 
@@ -304,7 +304,8 @@ static void efi_stub_entry_update(void)
 
 #else
 
-static inline void update_pecoff_setup_and_reloc(unsigned int size) {}
+static inline void update_pecoff_setup_and_reloc(unsigned int size,
+						 unsigned int sbat_size) {}
 static inline void update_pecoff_text(unsigned int text_start,
 				      unsigned int file_sz,
 				      unsigned int init_sz) {}
@@ -371,7 +372,7 @@ int main(int argc, char ** argv)
 {
 	unsigned int i, sz, setup_sectors, init_sz;
 	int c;
-	u32 sys_size;
+	u32 sys_size, sbat_size = 0;
 	struct stat sb;
 	FILE *file, *dest;
 	int fd;
@@ -380,7 +381,7 @@ int main(int argc, char ** argv)
 
 	efi_stub_defaults();
 
-	if (argc != 5)
+	if (argc != 5 && argc != 6)
 		usage();
 	parse_zoffset(argv[3]);
 
@@ -401,6 +402,13 @@ int main(int argc, char ** argv)
 		die("Boot block hasn't got boot flag (0xAA55)");
 	fclose(file);
 
+	if (argc == 6) {
+		if (stat(argv[5], &sb))
+			die("Unable to stat `%s': %m", argv[5]);
+		sbat_size = sb.st_size;
+		memset(buf+c, 0, sbat_size);
+		c += sbat_size;
+	}
 	c += reserve_pecoff_compat_section(c);
 	c += reserve_pecoff_reloc_section(c);
 
@@ -411,7 +419,18 @@ 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_and_reloc(i, sbat_size);
+	if (sbat_size) {
+		u32 sbat_offset = i - PECOFF_COMPAT_RESERVE - sbat_size;
+		update_pecoff_section_header(".sbat", sbat_offset, sbat_size);
+		file = fopen(argv[5], "r");
+		if (!file)
+			die("Unable to open `%s': %m", argv[5]);
+		if (fread(&buf[sbat_offset], 1, sizeof(buf) - sbat_offset,
+			  file) != sbat_size)
+			die("Reading sbat failed");
+		fclose(file);
+	}
 
 	/* Set the default root device */
 	put_unaligned_le16(DEFAULT_ROOT_DEV, &buf[508]);
diff --git a/security/Kconfig b/security/Kconfig
index e6db09a77..536689678 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -206,6 +206,18 @@ source "security/loadpin/Kconfig"
 source "security/yama/Kconfig"
 source "security/safesetid/Kconfig"
 source "security/lockdown/Kconfig"
+
+config SECURITY_SBAT
+	string "Add .sbat section to kernel PE image"
+	depends on SECURITY
+	help
+	  If set, this option should be the filename of a CSV-formatted file
+	  containing SBAT data to be included as a .sbat section in PE kernel
+	  image (bzImage).
+
+	  See <https://github.com/rhboot/shim/blob/main/SBAT.md> for more information
+	  about SBAT.
+
 source "security/landlock/Kconfig"
 
 source "security/integrity/Kconfig"
-- 
2.39.0