From: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx> redhat: Add SBAT information to Linux kernel Recent versions of shim (e.g. 15.8) refuses to boot UEFI binaries with no SBAT information issuing "Security Policy Violation" error. While this does not yet affect tradition 'shim -> grub -> kernel' and 'shim -> UKI(sd-boot) -> kernel' chains (as both shim and sd-stub have SBAT), direct loading of kernel from shim may also come handy in certain cases. Also, grub may also refuse to boot Linux kernel without SBAT at some point. Note: UKI's SBAT combines .sbat sections from sd-stub and linux kernel so if we add 'linux' and 'linux.{fedora,centos,rhel}' components to the kernel, they have to be removed from UKI so the result stays unchanged. Note: we don't currently define any policy for bumping SBAT version but we already add 'linux' and 'linux.{fedora,centos,rhel}' to the UKI. The decision on when to bump will likely be made when the first candidate for a bug requiring it is discovered. Signed-off-by: Vitaly Kuznetsov <vkuznets@xxxxxxxxxx> diff --git a/redhat/Makefile b/redhat/Makefile index blahblah..blahblah 100644 --- a/redhat/Makefile +++ b/redhat/Makefile @@ -716,6 +716,7 @@ sources-rh: $(TARBALL) $(KABI_TARBALL) $(KABIDW_TARBALL) generate-testpatch-tmp scripts/mod/mod-sign.sh \ scripts/uki_addons/uki_create_addons.py \ scripts/uki_addons/uki_addons.json \ + scripts/pe-add-sbat.py \ configs/flavors \ configs/generate_all_configs.sh \ configs/merge.py \ diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template index blahblah..blahblah 100644 --- a/redhat/kernel.spec.template +++ b/redhat/kernel.spec.template @@ -990,6 +990,7 @@ Source87: flavors Source151: uki_create_addons.py Source152: uki_addons.json +Source153: pe-add-sbat.py Source100: rheldup3.x509 Source101: rhelkpatch1.x509 @@ -2282,6 +2283,15 @@ BuildKernel() { cp arch/$Arch/boot/zImage.stub $RPM_BUILD_ROOT/lib/modules/$KernelVer/zImage.stub-$KernelVer || : fi +%ifarch x86_64 aarch64 + # Add SBAT (https://github.com/rhboot/shim/blob/main/SBAT.md) information + python3 %{SOURCE153} $KernelImage <<- EOF +sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md +linux,1,Red Hat,linux,$KernelVer,mailto:secalert@xxxxxxxxxx +linux.%{sbat_suffix},1,Red Hat,linux,$KernelVer,mailto:secalert@xxxxxxxxxx +EOF +%endif + %if %{signkernel} %{log_msg "Copy kernel for signing"} if [ "$KernelImage" = vmlinux ]; then @@ -2696,8 +2706,6 @@ BuildKernel() { SBATsuffix="rhel" %endif SBAT=$(cat <<- EOF - linux,1,Red Hat,linux,$KernelVer,mailto:secalert@xxxxxxxxxx - linux.$SBATsuffix,1,Red Hat,linux,$KernelVer,mailto:secalert@xxxxxxxxxx kernel-uki-virt.$SBATsuffix,1,Red Hat,kernel-uki-virt,$KernelVer,mailto:secalert@xxxxxxxxxx EOF ) diff --git a/redhat/scripts/pe-add-sbat.py b/redhat/scripts/pe-add-sbat.py new file mode 100755 index blahblah..blahblah 100755 --- /dev/null +++ b/redhat/scripts/pe-add-sbat.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 + +# SPDX-License-Identifier: LGPL-2.1-or-later +# Mostly based on https://github.com/chenxiaolong/random-scripts/blob/master/pe-add-sections.py +# which is based on systemd's ukify logic + +import sys +import pefile + +def align_to(value, page_size): + if bin(page_size).count("1") != 1: + raise ValueError(f'Page size is not a power of 2: {page_size}') + + return (value + page_size - 1) // page_size * page_size + +def pe_add_sections(input: str, output: str, sections: dict[str, bytes]): + pe = pefile.PE(input, fast_load=True) + + for s in pe.sections: + if (name := s.Name.rstrip(b"\x00").decode('ascii')) in sections.keys(): + raise ValueError(f'Section {name} already exists') + + security = pe.OPTIONAL_HEADER.DATA_DIRECTORY[ + pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_SECURITY']] + if security.VirtualAddress != 0: + raise ValueError('Cannot modify signed file') + + # Try to make room for the new headers by eating into the existing padding + pe.OPTIONAL_HEADER.SizeOfHeaders = align_to( + pe.OPTIONAL_HEADER.SizeOfHeaders, + pe.OPTIONAL_HEADER.FileAlignment, + ) + pe = pefile.PE(data=pe.write(), fast_load=True) + + warnings = pe.get_warnings() + if warnings: + raise Exception(f'Warnings when adjusting size of headers: {warnings}') + + for name, data in sections.items(): + new_section = pefile.SectionStructure( + pe.__IMAGE_SECTION_HEADER_format__, pe=pe) + new_section.__unpack__(b'\0' * new_section.sizeof()) + + offset = pe.sections[-1].get_file_offset() + pe.sections[-1].sizeof() + if offset + new_section.sizeof() > pe.OPTIONAL_HEADER.SizeOfHeaders: + raise Exception(f'Not enough header space for {name}') + + new_section.set_file_offset(offset) + new_section.Name = name.encode('ascii') + new_section.Misc_VirtualSize = len(data) + # Start at previous EOF + padding for alignment + new_section.PointerToRawData = align_to( + len(pe.__data__), + pe.OPTIONAL_HEADER.FileAlignment, + ) + new_section.SizeOfRawData = align_to( + len(data), + pe.OPTIONAL_HEADER.FileAlignment, + ) + new_section.VirtualAddress = align_to( + pe.sections[-1].VirtualAddress + pe.sections[-1].Misc_VirtualSize, + pe.OPTIONAL_HEADER.SectionAlignment, + ) + + new_section.IMAGE_SCN_MEM_READ = True + new_section.IMAGE_SCN_CNT_INITIALIZED_DATA = True + + # Append: + # - Padding from previous EOF to new aligned section + # - New section data + # - Padding from end of section to EOF + pe.__data__ = pe.__data__[:] \ + + bytes(new_section.PointerToRawData - len(pe.__data__)) \ + + data \ + + bytes(new_section.SizeOfRawData - len(data)) + + pe.FILE_HEADER.NumberOfSections += 1 + pe.OPTIONAL_HEADER.SizeOfInitializedData += \ + new_section.Misc_VirtualSize + pe.__structures__.append(new_section) + pe.sections.append(new_section) + + pe.OPTIONAL_HEADER.CheckSum = 0 + pe.OPTIONAL_HEADER.SizeOfImage = align_to( + pe.sections[-1].VirtualAddress + pe.sections[-1].Misc_VirtualSize, + pe.OPTIONAL_HEADER.SectionAlignment, + ) + + pe.write(output) + +def main(): + if len(sys.argv) != 2: + print("Usage: %s <filename>.efi") + + sections = {'.sbat': sys.stdin.read().encode('ascii')+b'\0'} + + pe_add_sections(sys.argv[1], sys.argv[1], sections) + +if __name__ == '__main__': + main() -- https://gitlab.com/cki-project/kernel-ark/-/merge_requests/3581 -- _______________________________________________ kernel mailing list -- kernel@xxxxxxxxxxxxxxxxxxxxxxx To unsubscribe send an email to kernel-leave@xxxxxxxxxxxxxxxxxxxxxxx Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedoraproject.org/archives/list/kernel@xxxxxxxxxxxxxxxxxxxxxxx Do not reply to spam, report it: https://pagure.io/fedora-infrastructure/new_issue