Message ID | 20250424080950.289864-1-vkuznets@redhat.com |
---|---|
Headers | show |
Series | efi: Add a mechanism for embedding SBAT section | expand |
Hi Vitaly, On Thu, 24 Apr 2025 at 10:10, Vitaly Kuznetsov <vkuznets@redhat.com> wrote: > > SBAT is a mechanism which improves SecureBoot revocations of UEFI binaries > by introducing a generation-based technique. Compromised or vulnerable UEFI > binaries can be prevented from booting by bumping the minimal required > generation for the specific component in the bootloader. More information > on the SBAT can be obtained here: > > https://github.com/rhboot/shim/blob/main/SBAT.md > > Upstream Linux kernel does not currently participate in any way in SBAT as > there's no existing policy in how SBAT generation number should be > defined. Keep the status quo and provide a mechanism for distro vendors and > anyone else who signs their kernel for SecureBoot to include their own SBAT > data. This leaves the decision on the policy to the vendor. Basically, each > distro implementing SecureBoot today, will have an option to inject their > own SBAT data during kernel build and before it gets signed by their > SecureBoot CA. Different distro do not need to agree on the common SBAT > component names or generation numbers as each distro ships its own 'shim' > with their own 'vendor_cert'/'vendor_db' > > Implement support for embedding SBAT data for architectures using > zboot (arm64, loongarch, riscv). Build '.sbat' section along with libstub > so it can be reused by x86 implementation later. > > Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com> > --- > drivers/firmware/efi/Kconfig | 25 +++++++++++++++++++++ > drivers/firmware/efi/libstub/Makefile | 7 ++++++ > drivers/firmware/efi/libstub/Makefile.zboot | 3 ++- > drivers/firmware/efi/libstub/sbat.S | 7 ++++++ > drivers/firmware/efi/libstub/zboot-header.S | 14 ++++++++++++ > drivers/firmware/efi/libstub/zboot.lds | 17 ++++++++++++++ > 6 files changed, 72 insertions(+), 1 deletion(-) > create mode 100644 drivers/firmware/efi/libstub/sbat.S > > diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig > index 5fe61b9ab5f9..2edb0167ba49 100644 > --- a/drivers/firmware/efi/Kconfig > +++ b/drivers/firmware/efi/Kconfig > @@ -281,6 +281,31 @@ config EFI_EMBEDDED_FIRMWARE > bool > select CRYPTO_LIB_SHA256 > > +config EFI_SBAT > + bool "Embed SBAT section in the kernel" > + depends on EFI_ZBOOT > + help > + SBAT section provides a way to improve SecureBoot revocations of UEFI > + binaries by introducing a generation-based mechanism. With SBAT, older > + UEFI binaries can be prevented from booting by bumping the minimal > + required generation for the specific component in the bootloader. > + > + Note: SBAT information is distribution specific, i.e. the owner of the > + signing SecureBoot certificate must define the SBAT policy. Linux > + kernel upstream does not define SBAT components and their generations. > + > + See https://github.com/rhboot/shim/blob/main/SBAT.md for the additional > + details. > + > + If unsure, say N. > + > +config EFI_SBAT_FILE > + string "Embedded SBAT section file path" > + depends on EFI_SBAT > + help > + Specify a file with SBAT data which is going to be embedded as '.sbat' > + section into the kernel. > + Can we simplify this? CONFIG_EFI_SBAT makes no sense if CONFIG_EFI_SBAT_FILE is left empty. If you really need both symbols, set EFI_SBAT automatically based on whether EFI_SBAT_FILE is non-empty. > endmenu > > config UEFI_CPER > diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile > index d23a1b9fed75..5113cbdadf9a 100644 > --- a/drivers/firmware/efi/libstub/Makefile > +++ b/drivers/firmware/efi/libstub/Makefile > @@ -105,6 +105,13 @@ lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o > extra-y := $(lib-y) > lib-y := $(patsubst %.o,%.stub.o,$(lib-y)) > > +extra-$(CONFIG_EFI_SBAT) += sbat.o > +$(obj)/sbat.o: $(obj)/sbat.bin > +targets += sbat.bin > +filechk_sbat.bin = cat $(or $(real-prereqs), /dev/null) > +$(obj)/sbat.bin: $(CONFIG_EFI_SBAT_FILE) FORCE > + $(call filechk,sbat.bin) > + Please get rid of all of this, and move the .incbin into zboot-header.S > # Even when -mbranch-protection=none is set, Clang will generate a > # .note.gnu.property for code-less object files (like lib/ctype.c), > # so work around this by explicitly removing the unwanted section. > diff --git a/drivers/firmware/efi/libstub/Makefile.zboot b/drivers/firmware/efi/libstub/Makefile.zboot > index 48842b5c106b..3d2d0b326f7c 100644 > --- a/drivers/firmware/efi/libstub/Makefile.zboot > +++ b/drivers/firmware/efi/libstub/Makefile.zboot > @@ -44,7 +44,8 @@ AFLAGS_zboot-header.o += -DMACHINE_TYPE=IMAGE_FILE_MACHINE_$(EFI_ZBOOT_MACH_TYPE > $(obj)/zboot-header.o: $(srctree)/drivers/firmware/efi/libstub/zboot-header.S FORCE > $(call if_changed_rule,as_o_S) > > -ZBOOT_DEPS := $(obj)/zboot-header.o $(objtree)/drivers/firmware/efi/libstub/lib.a > +ZBOOT_DEPS := $(obj)/zboot-header.o $(objtree)/drivers/firmware/efi/libstub/lib.a \ > + $(if $(CONFIG_EFI_SBAT),$(objtree)/drivers/firmware/efi/libstub/sbat.o) > Drop this too > LDFLAGS_vmlinuz.efi.elf := -T $(srctree)/drivers/firmware/efi/libstub/zboot.lds > $(obj)/vmlinuz.efi.elf: $(obj)/vmlinuz.o $(ZBOOT_DEPS) FORCE > diff --git a/drivers/firmware/efi/libstub/sbat.S b/drivers/firmware/efi/libstub/sbat.S > new file mode 100644 > index 000000000000..4e99a1bac794 > --- /dev/null > +++ b/drivers/firmware/efi/libstub/sbat.S > @@ -0,0 +1,7 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +/* > + * Embed SBAT data in the kernel. > + */ > + .pushsection ".sbat","a",@progbits > + .incbin "drivers/firmware/efi/libstub/sbat.bin" > + .popsection > diff --git a/drivers/firmware/efi/libstub/zboot-header.S b/drivers/firmware/efi/libstub/zboot-header.S > index fb676ded47fa..f2df24504fc5 100644 > --- a/drivers/firmware/efi/libstub/zboot-header.S > +++ b/drivers/firmware/efi/libstub/zboot-header.S > @@ -135,6 +135,20 @@ __efistub_efi_zboot_header: > IMAGE_SCN_MEM_READ | \ > IMAGE_SCN_MEM_WRITE > > +#ifdef CONFIG_EFI_SBAT > + .ascii ".sbat\0\0\0" > + .long __sbat_size > + .long _edata - .Ldoshdr > + .long __sbat_size > + .long _edata - .Ldoshdr > + > + .long 0, 0 > + .short 0, 0 > + .long IMAGE_SCN_CNT_INITIALIZED_DATA | \ > + IMAGE_SCN_MEM_READ | \ > + IMAGE_SCN_MEM_DISCARDABLE You can put the pushsection/popsection right here. > +#endif > + > .set .Lsection_count, (. - .Lsection_table) / 40 > > #ifdef PE_DLL_CHAR_EX > diff --git a/drivers/firmware/efi/libstub/zboot.lds b/drivers/firmware/efi/libstub/zboot.lds > index 9ecc57ff5b45..2cd5015c70ce 100644 > --- a/drivers/firmware/efi/libstub/zboot.lds > +++ b/drivers/firmware/efi/libstub/zboot.lds > @@ -31,10 +31,24 @@ SECTIONS > > .data : ALIGN(4096) { > *(.data* .init.data*) > +#ifndef CONFIG_EFI_SBAT > _edata = ALIGN(512); > +#else > + /* Avoid gap between '.data' and '.sbat' */ > + _edata = ALIGN(4096); > +#endif Just use 4096 in all cases. > . = _edata; > } > > +#ifdef CONFIG_EFI_SBAT > + .sbat : ALIGN(4096) { > + _sbat = . ; > + *(.sbat) > + _esbat = ALIGN(512); > + . = _esbat; > + } > +#endif > + > .bss : { > *(.bss* .init.bss*) > _end = ALIGN(512); > @@ -52,3 +66,6 @@ PROVIDE(__efistub__gzdata_size = > > PROVIDE(__data_rawsize = ABSOLUTE(_edata - _etext)); > PROVIDE(__data_size = ABSOLUTE(_end - _etext)); > +#ifdef CONFIG_EFI_SBAT > +PROVIDE(__sbat_size = ABSOLUTE(_esbat - _sbat)); > +#endif This can be unconditional - it is only evaluated when a reference to it exists. > -- > 2.49.0 >
On Mon, 28 Apr 2025 at 12:54, Vitaly Kuznetsov <vkuznets@redhat.com> wrote: > > Ard Biesheuvel <ardb@kernel.org> writes: > > > Hi Vitaly, > > > > Ard, thanks for the review! > > > On Thu, 24 Apr 2025 at 10:10, Vitaly Kuznetsov <vkuznets@redhat.com> wrote: > >> > >> SBAT is a mechanism which improves SecureBoot revocations of UEFI binaries > >> by introducing a generation-based technique. Compromised or vulnerable UEFI > >> binaries can be prevented from booting by bumping the minimal required > >> generation for the specific component in the bootloader. More information > >> on the SBAT can be obtained here: > >> > >> https://github.com/rhboot/shim/blob/main/SBAT.md > >> > >> Upstream Linux kernel does not currently participate in any way in SBAT as > >> there's no existing policy in how SBAT generation number should be > >> defined. Keep the status quo and provide a mechanism for distro vendors and > >> anyone else who signs their kernel for SecureBoot to include their own SBAT > >> data. This leaves the decision on the policy to the vendor. Basically, each > >> distro implementing SecureBoot today, will have an option to inject their > >> own SBAT data during kernel build and before it gets signed by their > >> SecureBoot CA. Different distro do not need to agree on the common SBAT > >> component names or generation numbers as each distro ships its own 'shim' > >> with their own 'vendor_cert'/'vendor_db' > >> > >> Implement support for embedding SBAT data for architectures using > >> zboot (arm64, loongarch, riscv). Build '.sbat' section along with libstub > >> so it can be reused by x86 implementation later. > >> > >> Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com> > >> --- > >> drivers/firmware/efi/Kconfig | 25 +++++++++++++++++++++ > >> drivers/firmware/efi/libstub/Makefile | 7 ++++++ > >> drivers/firmware/efi/libstub/Makefile.zboot | 3 ++- > >> drivers/firmware/efi/libstub/sbat.S | 7 ++++++ > >> drivers/firmware/efi/libstub/zboot-header.S | 14 ++++++++++++ > >> drivers/firmware/efi/libstub/zboot.lds | 17 ++++++++++++++ > >> 6 files changed, 72 insertions(+), 1 deletion(-) > >> create mode 100644 drivers/firmware/efi/libstub/sbat.S > >> > >> diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig > >> index 5fe61b9ab5f9..2edb0167ba49 100644 > >> --- a/drivers/firmware/efi/Kconfig > >> +++ b/drivers/firmware/efi/Kconfig > >> @@ -281,6 +281,31 @@ config EFI_EMBEDDED_FIRMWARE > >> bool > >> select CRYPTO_LIB_SHA256 > >> > >> +config EFI_SBAT > >> + bool "Embed SBAT section in the kernel" > >> + depends on EFI_ZBOOT > >> + help > >> + SBAT section provides a way to improve SecureBoot revocations of UEFI > >> + binaries by introducing a generation-based mechanism. With SBAT, older > >> + UEFI binaries can be prevented from booting by bumping the minimal > >> + required generation for the specific component in the bootloader. > >> + > >> + Note: SBAT information is distribution specific, i.e. the owner of the > >> + signing SecureBoot certificate must define the SBAT policy. Linux > >> + kernel upstream does not define SBAT components and their generations. > >> + > >> + See https://github.com/rhboot/shim/blob/main/SBAT.md for the additional > >> + details. > >> + > >> + If unsure, say N. > >> + > >> +config EFI_SBAT_FILE > >> + string "Embedded SBAT section file path" > >> + depends on EFI_SBAT > >> + help > >> + Specify a file with SBAT data which is going to be embedded as '.sbat' > >> + section into the kernel. > >> + > > > > Can we simplify this? CONFIG_EFI_SBAT makes no sense if > > CONFIG_EFI_SBAT_FILE is left empty. If you really need both symbols, > > set EFI_SBAT automatically based on whether EFI_SBAT_FILE is > > non-empty. > > Sure, but FWIW, I modelled this after MODULE_SIG/MODULE_SIG_KEY and > BOOT_CONFIG_EMBED/BOOT_CONFIG_EMBED_FILE where the selection is also > 2-step -- do you think EFI_SBAT/EFI_SBAT_FILE case is different? > Regardless of the other cases,it at the very least should be a config-time error for EFI_SBAT to be y when EFI_SBAT_FILE is empty. We shouldn't have to deal with CONFIG_ options being in an inconsistent state, that's Kconfig's job. > > > >> endmenu > >> > >> config UEFI_CPER > >> diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile > >> index d23a1b9fed75..5113cbdadf9a 100644 > >> --- a/drivers/firmware/efi/libstub/Makefile > >> +++ b/drivers/firmware/efi/libstub/Makefile > >> @@ -105,6 +105,13 @@ lib-$(CONFIG_UNACCEPTED_MEMORY) += unaccepted_memory.o bitmap.o find.o > >> extra-y := $(lib-y) > >> lib-y := $(patsubst %.o,%.stub.o,$(lib-y)) > >> > >> +extra-$(CONFIG_EFI_SBAT) += sbat.o > >> +$(obj)/sbat.o: $(obj)/sbat.bin > >> +targets += sbat.bin > >> +filechk_sbat.bin = cat $(or $(real-prereqs), /dev/null) > >> +$(obj)/sbat.bin: $(CONFIG_EFI_SBAT_FILE) FORCE > >> + $(call filechk,sbat.bin) > >> + > > > > Please get rid of all of this, and move the .incbin into > > zboot-header.S > > The main prupose of this logic is to track possible sbat data > changes. E.g. if the file with SBAT data has changed, then we need to > rebuild the kernel binary. If we just use a raw 'incbin' somewhere and > don't add a specific Makefile dependency, then the logic will be lost. > So why isn't it sufficient to make zboot-header.o depend on $(CONFIG_EFI_SBAT_FILE)? > I think I can drop the dedicated 'sbat.S' and use zboot-header.S but I'd > like to keep at least the 'filechk' part: we compare what's in > EFI_SBAT_FILE with 'sbat.bin' copy and, if things have changed, rebuild. > The filechk is just a copy, and the /dev/null hack should be removed too. So please find another way to track the dependency, and drop all of this.