From: kernel.org@andraxin.se
To: Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
linux-kernel@vger.kernel.org
Subject: SBAT support in EFI stub?
Date: Sun, 12 Jan 2025 16:11:25 +0100 [thread overview]
Message-ID: <Z4PbnY6ivJfVW64p@meta> (raw)
[-- Attachment #1: Type: text/plain, Size: 3078 bytes --]
Folks,
The problem: *secure boot* directly via EFI stub on a system,
where the necessary key management options are not present
(disabled by the OEM) in the BIOS.
Unless one is prepared to hack that BIOS, following, say
https://lukegb.com/posts/2016-11-11-secure-boot-shenanigans/
the standard approach would be to use SHIM (and MOK):
https://github.com/rhboot/shim
A few years back, CVE-2020-10713 ("BootHole") prompted
what one might call a lightweight revocation solution:
Secure Boot Advanced Targeting (SBAT).
https://github.com/rhboot/shim/blob/main/SBAT.md
As a result, SHIM flatly refuses to load an EFI binary without
an embedded SBAT section.
Adding SBAT to a "plain" kernel, as described, for instance here:
https://www.rodsbooks.com/efi-bootloaders/secureboot.html#sbat
works fine, but doing the same for a kernel with EFI stub
messes up the binary and results in a boot loop. That's,
perhaps, not surprising considering that the intervention
also changes the file's signature:
```
$ file bzImage-6.12.9-gentoo
bzImage-6.12.9-gentoo: Linux kernel x86 boot executable bzImage, version 6.12.9-gentoo ...
$ objcopy --set-section-alignment '.sbat=512' --add-section .sbat=sbat.csv --adjust-section-vma .sbat+10000000 bzImage-6.12.9-gentoo
$ file bzImage-6.12.9-gentoo
bzImage-6.12.9-gentoo: PE32+ executable (EFI application) x86-64 (stripped to external PDB), for MS Windows, 4 sections
$
```
NB: I have NOT tried the `pe-add-sections.py` script linked from
https://github.com/rhboot/shim/issues/376#issuecomment-1628004034
but I'd expect similar results to the `objcopy` case above, since
the EFI stub is a bit "special" in its construction.
BTW, workarounds for secure boot on such a system via OTHER MEANS
than EFI stub do exist. One could simply employ a bootloader,
or build a Unified Kernel Image using `ukify` that will add both
its own "EFIStub" and an SBAT section to a "plain" kernel.
https://manpages.debian.org/bookworm-backports/systemd/ukify.1.en.html
https://wiki.gentoo.org/wiki/Unified_kernel_image#EFI_stub
I realize that wanting to stick with the kernel's built-in EFI stub
may be a bit of a niche issue, and I do have a WORKSFORME-level hack
to address this for myself (attached, since it's not a proper patch
for review, only a conversation starter); so, this isn't high priority.
I'm only checking if adding SBAT support may be of general interest.
Best,
--andrás
PS
BTW, I wasn't kidding. My current approach_is_ a hack.
The included `sbat.csv` is for Gentoo (although simple to adapt).
The code blindly uses a fixed (overly large) size for SBAT.
The final binary MUST be renamed to `grubx64.efi` (or similar,
for 32-bit systems); AND, it MUST be enrolled by hash, since
I haven't added any code that might satisfy the "participating
bootloader" requirements.
https://github.com/rhboot/shim/commit/39df41ceb5a793f7db9233a2741d30c55b6a8861
Interestingly, MOK Manager cannot (or doesn't want to?) extract
the hash from a signed binary; so, either the hash must be
enrolled via `mokutil`, or the kernel can be left unsigned...
[-- Attachment #2: sbat.patch --]
[-- Type: text/plain, Size: 6569 bytes --]
diff '--color=auto' -ruN linux-6.12.1-gentoo/arch/x86/boot/Makefile linux-6.12.1-gentoo.sbat/arch/x86/boot/Makefile
--- linux-6.12.1-gentoo/arch/x86/boot/Makefile 2024-11-22 22:47:28.288743052 +0100
+++ linux-6.12.1-gentoo.sbat/arch/x86/boot/Makefile 2024-11-23 13:39:34.930313632 +0100
@@ -63,9 +63,9 @@
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 $(obj)/sbat.csv $@ $($(quiet)redirect_image)
-$(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
+$(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/sbat.csv $(obj)/tools/build FORCE
$(call if_changed,image)
@$(kecho) 'Kernel: $@ is ready' ' (#'$(or $(KBUILD_BUILD_VERSION),`cat .version`)')'
@@ -75,6 +75,16 @@
SETUP_OBJS = $(addprefix $(obj)/,$(setup-y))
+
+quiet_cmd_sbat = SBAT $@
+ cmd_sbat = sed s@%KERNELVERSION%@$(KERNELVERSION)@ $(srctree)/$@ > $@
+
+
+targets += sbat.csv
+$(obj)/sbat.csv: $(srctree)/$@ FORCE
+ $(call if_changed,sbat)
+
+
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 $@
diff '--color=auto' -ruN linux-6.12.1-gentoo/arch/x86/boot/header.S linux-6.12.1-gentoo.sbat/arch/x86/boot/header.S
--- linux-6.12.1-gentoo/arch/x86/boot/header.S 2024-11-22 22:47:28.291743064 +0100
+++ linux-6.12.1-gentoo.sbat/arch/x86/boot/header.S 2024-11-30 15:33:33.427367030 +0100
@@ -83,9 +83,9 @@
.long ZO__end - ZO__data # SizeOfInitializedData
.long 0 # SizeOfUninitializedData
- .long setup_size + ZO_efi_pe_entry # AddressOfEntryPoint
+ .long setup_size + salign + ZO_efi_pe_entry # AddressOfEntryPoint
- .long setup_size # BaseOfCode
+ .long setup_size + salign # BaseOfCode
#ifdef CONFIG_X86_32
.long 0 # data
#endif
@@ -106,7 +106,7 @@
.word 0 # MinorSubsystemVersion
.long 0 # Win32VersionValue
- .long setup_size + ZO__end # SizeOfImage
+ .long setup_size + salign + ZO__end # SizeOfImage
.long salign # SizeOfHeaders
.long 0 # CheckSum
@@ -179,15 +179,25 @@
#else
.set pecompat_fstart, setup_size
#endif
+
+ .ascii ".sbat\0\0\0"
+ .long salign # SizeOfRawData
+ .long setup_size # VirtualAddress
+ .long salign # SizeOfRawData
+ .long setup_size # PointerToRawData
+
+ .long 0, 0, 0
+ .long IMAGE_SCN_ALIGN_512BYTES
+
.ascii ".text"
.byte 0
.byte 0
.byte 0
.long ZO__data
- .long setup_size
+ .long setup_size + salign
.long ZO__data # Size of initialized data
# on disk
- .long setup_size
+ .long setup_size + salign
.long 0 # PointerToRelocations
.long 0 # PointerToLineNumbers
.word 0 # NumberOfRelocations
@@ -198,9 +208,9 @@
.ascii ".data\0\0\0"
.long ZO__end - ZO__data # VirtualSize
- .long setup_size + ZO__data # VirtualAddress
+ .long setup_size + salign + ZO__data # VirtualAddress
.long ZO__edata - ZO__data # SizeOfRawData
- .long setup_size + ZO__data # PointerToRawData
+ .long setup_size + salign + ZO__data # PointerToRawData
.long 0, 0, 0
.long IMAGE_SCN_CNT_INITIALIZED_DATA | \
diff '--color=auto' -ruN linux-6.12.1-gentoo/arch/x86/boot/sbat.csv linux-6.12.1-gentoo.sbat/arch/x86/boot/sbat.csv
--- linux-6.12.1-gentoo/arch/x86/boot/sbat.csv 1970-01-01 01:00:00.000000000 +0100
+++ linux-6.12.1-gentoo.sbat/arch/x86/boot/sbat.csv 2024-11-23 13:39:34.930313632 +0100
@@ -0,0 +1,2 @@
+sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
+kernel,1,Gentoo Linux,gentoo-sources,%KERNELVERSION%,https://www.gentoo.org
diff '--color=auto' -ruN linux-6.12.1-gentoo/arch/x86/boot/tools/build.c linux-6.12.1-gentoo.sbat/arch/x86/boot/tools/build.c
--- linux-6.12.1-gentoo/arch/x86/boot/tools/build.c 2024-11-22 22:47:28.292743068 +0100
+++ linux-6.12.1-gentoo.sbat/arch/x86/boot/tools/build.c 2024-11-30 15:27:50.721048086 +0100
@@ -6,11 +6,15 @@
*/
/*
- * This file builds a disk-image from three different files:
+ * This file builds a disk-image from 4 different files:
*
* - setup: 8086 machine code, sets up system parm
* - system: 80386 code for actual system
* - zoffset.h: header with ZO_* defines
+ * - sbat.csv: policy specification for Secure Boot Advanced Targeting
+ * only needed when CONFIG_EFI_STUB is selected,
+ * and secure boot is enabled, but does no harm
+ * to include SBAT in either case
*
* It does some checking that all files are of the correct type, and writes
* the result to the specified destination, removing headers and padding to
@@ -43,6 +47,7 @@
/* Minimal number of setup sectors */
#define SETUP_SECT_MIN 5
#define SETUP_SECT_MAX 64
+#define SBAT_SIZE 4096
/* This must be large enough to hold the entire setup */
u8 buf[SETUP_SECT_MAX*512];
@@ -130,7 +135,7 @@
static void usage(void)
{
- die("Usage: build setup system zoffset.h image");
+ die("Usage: build setup system zoffset.h sbat.csv image");
}
/*
@@ -179,13 +184,13 @@
void *kernel;
u32 crc = 0xffffffffUL;
- if (argc != 5)
+ if (argc != 6)
usage();
parse_zoffset(argv[3]);
- dest = fopen(argv[4], "w");
+ dest = fopen(argv[5], "w");
if (!dest)
- die("Unable to write `%s': %m", argv[4]);
+ die("Unable to write `%s': %m", argv[5]);
/* Copy the setup code */
file = fopen(argv[1], "r");
@@ -215,8 +220,7 @@
if (fstat(fd, &sb))
die("Unable to stat `%s': %m", argv[2]);
if (_edata != sb.st_size)
- die("Unexpected file size `%s': %u != %u", argv[2], _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)
@@ -226,6 +230,22 @@
if (fwrite(buf, 1, i, dest) != i)
die("Writing setup failed");
+ /* Copy CSV for Secure Boot Advanced Targeting (SBAT) */
+ file = fopen(argv[4], "r");
+ if (!file)
+ die("Unable to open `%s': %m", argv[4]);
+ c = fread(buf, 1, sizeof(buf), file);
+ if (ferror(file))
+ die("read-error on SBAT");
+ fclose(file);
+ if (c > SBAT_SIZE)
+ die("SBAT must be at most %u bytes", SBAT_SIZE);
+ if (c < SBAT_SIZE)
+ memset(buf+c, 0, SBAT_SIZE-c);
+ crc = partial_crc32(buf, SBAT_SIZE, crc);
+ if (fwrite(buf, 1, SBAT_SIZE, dest) != SBAT_SIZE)
+ die("Writing SBAT failed");
+
/* Copy the kernel code */
crc = partial_crc32(kernel, sz, crc);
if (fwrite(kernel, 1, sz, dest) != sz)
reply other threads:[~2025-01-12 15:51 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Z4PbnY6ivJfVW64p@meta \
--to=kernel.org@andraxin.se \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=tglx@linutronix.de \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.