[OS-BUILD PATCH] redhat: Add SBAT information to Linux kernel

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Fedora General Discussion]     [Older Fedora Users Archive]     [Fedora Advisory Board]     [Fedora Security]     [Fedora Devel Java]     [Fedora Legacy]     [Fedora Desktop]     [ATA RAID]     [Fedora Marketing]     [Fedora Mentors]     [Fedora Package Announce]     [Fedora Package Review]     [Fedora Music]     [Fedora Packaging]     [Centos]     [Fedora SELinux]     [Coolkey]     [Yum Users]     [Tux]     [Yosemite News]     [KDE Users]     [Fedora Art]     [Fedora Docs]     [USB]     [Asterisk PBX]

  Powered by Linux