Pārlūkot izejas kodu

pkg: fedora: Add new package build scripts for building patched kernels

These scripts use the kernel-ark repository that upstream Fedora uses too to
build their kernels.
Dorian Stoll 2 gadi atpakaļ
vecāks
revīzija
5dffa283ee

+ 4 - 2
pkg/fedora/kernel-surface/.gitignore

@@ -1,2 +1,4 @@
-surface.key
-surface.crt
+secureboot/MOK.key
+secureboot/MOK.crt
+kernel-ark
+out

+ 171 - 0
pkg/fedora/kernel-surface/build-ark.py

@@ -0,0 +1,171 @@
+#!/usr/bin/env python3
+
+import argparse
+import functools
+import operator
+import os
+import shutil
+import subprocess
+import time
+
+
+def system(cmd: str) -> None:
+    subprocess.run(cmd, shell=True, check=True)
+
+
+parser = argparse.ArgumentParser(usage="Build a patched Fedora kernel")
+
+parser.add_argument(
+    "--package-name",
+    help="The name of the patched package (e.g. foo -> kernel-foo).",
+    required=True,
+)
+
+parser.add_argument(
+    "--package-tag",
+    help="The upstream tag to build.",
+    required=True,
+)
+
+parser.add_argument(
+    "--package-release",
+    help="The release suffix of the modified package.",
+    required=True,
+)
+
+parser.add_argument(
+    "--ark-dir",
+    help="The local path to the kernel-ark repository.",
+    default="kernel-ark",
+)
+
+parser.add_argument(
+    "--ark-url",
+    help="The remote path to the kernel-ark repository.",
+    default="https://gitlab.com/cki-project/kernel-ark",
+)
+
+parser.add_argument(
+    "--patch",
+    help="Applies a patch to the kernel source.",
+    action="append",
+    nargs="+",
+)
+
+parser.add_argument(
+    "--config",
+    help="Applies a KConfig fragment to the kernel source.",
+    action="append",
+    nargs="+",
+)
+
+parser.add_argument(
+    "--file",
+    help="Copy a file into the RPM buildroot.",
+    action="append",
+    nargs="+",
+)
+
+parser.add_argument(
+    "--buildopts",
+    help="Enable or disable options of the kernel spec file.",
+    action="append",
+    nargs="+",
+)
+
+parser.add_argument(
+    "--outdir",
+    help="The directory where the built RPM files will be saved.",
+    default="out",
+)
+
+args = parser.parse_args()
+
+patches = [] if not args.patch else functools.reduce(operator.add, args.patch)
+configs = [] if not args.config else functools.reduce(operator.add, args.config)
+files = [] if not args.file else functools.reduce(operator.add, args.file)
+buildopts = [] if not args.buildopts else functools.reduce(operator.add, args.buildopts)
+
+# Make paths absolute.
+patches = [os.path.realpath(x) for x in patches]
+configs = [os.path.realpath(x) for x in configs]
+files = [os.path.realpath(x) for x in files]
+outdir = os.path.realpath(args.outdir)
+
+# Clone the kernel-ark repository if it doesn't exist.
+if not os.path.exists(args.ark_dir):
+    system("git clone '%s' '%s'" % (args.ark_url, args.ark_dir))
+
+os.chdir(args.ark_dir)
+
+# Check out the requested tag.
+system("git fetch --tags")
+system("git clean -dfx")
+system("git checkout -b 'build/%s'" % time.time())
+system("git reset --hard '%s'" % args.package_tag)
+
+# Apply patches
+for patch in patches:
+    system("git am '%s'" % patch)
+
+# Copy files
+for file in files:
+    shutil.copy(file, "redhat/fedora_files/")
+
+# Apply config options
+#
+# The format that the kernel-ark tree expects is a bit different from
+# a standard kernel config. Every option is split into a single file
+# named after that config.
+#
+# Example:
+#   $ cat redhat/configs/common/generic/CONFIG_PCI
+#   CONFIG_PCI=y
+#
+# This supposedly makes things easier for Red Hat developers,
+# but it also ends up being really annoying for us.
+for config in configs:
+    with open(config) as f:
+        lines = f.readlines()
+
+    # Filter out comments, this means only selecting lines that look like:
+    #   - CONFIG_FOO=b
+    #   - # CONFIG_FOO is not set
+    for line in lines:
+        enable = line.startswith("CONFIG_")
+        disable = line.startswith("# CONFIG_")
+
+        if not enable and not disable:
+            continue
+
+        NAME = ""
+
+        if enable:
+            NAME = line.split("=")[0]
+        elif disable:
+            NAME = line[2:].split(" ")[0]
+
+        print("Applying %s" % line.rstrip("\n"))
+
+        with open("redhat/configs/custom-overrides/generic/%s" % NAME, "w") as f:
+            f.write(line)
+
+system("git add redhat/configs/custom-overrides/generic")
+system("git commit -m 'Merge %s config'" % args.package_name)
+
+cmd = []
+cmd.append("make")
+cmd.append("dist-rpms")
+cmd.append("SPECPACKAGE_NAME='kernel-%s'" % args.package_name)
+cmd.append("DISTLOCALVERSION='.%s'" % args.package_name)
+cmd.append("BUILD='%s'" % args.package_release)
+
+if len(buildopts) > 0:
+    cmd.append("BUILDOPTS='%s'" % " ".join(buildopts))
+
+# Build RPMS
+system(" ".join(cmd))
+
+# Copy built RPMS to output directory
+os.makedirs(outdir, exist_ok=True)
+system("cp -r redhat/rpm/RPMS/* '%s'" % outdir)

+ 111 - 0
pkg/fedora/kernel-surface/build-linux-surface.py

@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+
+import subprocess
+import sys
+from pathlib import Path
+
+#####################################################################
+
+##
+## The name of the modified kernel package.
+##
+PACKAGE_NAME = "surface"
+
+##
+## https://gitlab.com/cki-project/kernel-ark/-/tags
+##
+## Fedora tags: kernel-X.Y.Z
+## Upstream tags: vX.Y.Z
+##
+PACKAGE_TAG = "kernel-6.3.6-0"
+
+##
+## The release number of the modified kernel package.
+## e.g. 300 for kernel-6.3.1-300.fc38.foo
+##
+PACKAGE_RELEASE = "1"
+
+##
+## Build options for configuring which parts of the kernel package are enabled.
+##
+## We disable all userspace components because we only want the kernel + modules.
+## We also don't care too much about debug info or UKI.
+##
+## To list the available options, run make dist-full-help in the kernel-ark tree.
+##
+KERNEL_BUILDOPTS = "+up +baseonly -debuginfo -doc -headers -efiuki"
+
+#####################################################################
+
+# The directory where this script is saved.
+script = Path(sys.argv[0]).resolve().parent
+
+# The root of the linux-surface repository.
+linux_surface = script / ".." / ".." / ".."
+
+# Determine the major version of the kernel.
+kernel_version = PACKAGE_TAG.split("-")[1]
+kernel_major = ".".join(kernel_version.split(".")[:2])
+
+# Determine the patches directory and config file.
+patches = linux_surface / "patches" / kernel_major
+config = linux_surface / "configs" / ("surface-%s.config" % kernel_major)
+
+sb_cert = script / "secureboot" / "MOK.crt"
+sb_key = script / "secureboot" / "MOK.key"
+
+# Check if the major version is supported.
+if not patches.exists() or not config.exists():
+    print("ERROR: Could not find patches / configs for kernel %s!" % kernel_major)
+    sys.exit(1)
+
+# Check if Secure Boot keys are available.
+sb_avail = sb_cert.exists() and sb_key.exists()
+
+# If we are building without secureboot, require user input to continue.
+if not sb_avail:
+    print("")
+    print("Secure Boot keys were not configured! Using Red Hat testkeys.")
+    print("The compiled kernel will not boot with Secure Boot enabled!")
+    print("")
+
+    input("Press any key to continue")
+
+# Expand globs
+surface_patches = list(patches.glob("*.patch"))
+
+cmd = []
+cmd += [script / "build-ark.py"]
+cmd += ["--package-name", PACKAGE_NAME]
+cmd += ["--package-tag", PACKAGE_TAG]
+cmd += ["--package-release", PACKAGE_RELEASE]
+cmd += ["--patch"] + surface_patches
+cmd += ["--config", config]
+cmd += ["--buildopts", KERNEL_BUILDOPTS]
+
+local_patches = list((script / "patches").glob("*.patch"))
+local_configs = list((script / "configs").glob("*.config"))
+local_files = list((script / "files").glob("*"))
+
+if len(local_patches) > 0:
+    cmd += ["--patch"] + local_patches
+
+if len(local_configs) > 0:
+    cmd += ["--config"] + local_configs
+
+if len(local_files) > 0:
+    cmd += ["--file"] + local_files
+
+if sb_avail:
+    sb_patches = list((script / "secureboot").glob("*.patch"))
+    sb_configs = list((script / "secureboot").glob("*.config"))
+
+    if len(sb_patches) > 0:
+        cmd += ["--patch"] + sb_patches
+
+    if len(sb_configs) > 0:
+        cmd += ["--config"] + sb_configs
+
+    cmd += ["--file", sb_cert, sb_key]
+
+subprocess.run(cmd, check=True)

+ 0 - 0
pkg/fedora/kernel-surface/configs/.gitkeep


+ 7 - 0
pkg/fedora/kernel-surface/configs/fedora.config

@@ -0,0 +1,7 @@
+##
+## Config options specific to Fedora
+##
+
+# The build fails because this is not enabled in the config set for RHEL,
+# but enabled automatically by one of our patches.
+CONFIG_VIDEO_V4L2_SUBDEV_API=y

+ 0 - 0
pkg/fedora/kernel-surface/files/.gitkeep


+ 0 - 0
pkg/fedora/kernel-surface/patches/.gitkeep


+ 60 - 0
pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch

@@ -0,0 +1,60 @@
+From 67f8052f553191686b1224b5598d00ff33d38608 Mon Sep 17 00:00:00 2001
+From: Dorian Stoll <dorian.stoll@tmsp.io>
+Date: Sat, 13 May 2023 16:39:50 +0200
+Subject: [PATCH] Use a custom key and certificate for Secure Boot signing
+
+Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io>
+---
+ redhat/kernel.spec.template | 15 +++++++++------
+ 1 file changed, 9 insertions(+), 6 deletions(-)
+
+diff --git a/redhat/kernel.spec.template b/redhat/kernel.spec.template
+index 51f43b21b018..76d1ad8e2818 100644
+--- a/redhat/kernel.spec.template
++++ b/redhat/kernel.spec.template
+@@ -703,6 +703,7 @@ BuildRequires: system-sb-certs
+ %ifarch x86_64 aarch64
+ BuildRequires: nss-tools
+ BuildRequires: pesign >= 0.10-4
++BuildRequires: sbsigntools
+ %endif
+ %endif
+ %endif
+@@ -762,6 +763,13 @@ Source1: Makefile.rhelver
+ %define signing_key_filename kernel-signing-s390.cer
+ %endif
+ 
++%ifarch x86_64 aarch64
++
++Source7001: MOK.key
++Source7002: MOK.crt
++
++%endif
++
+ %if %{?released_kernel}
+ 
+ Source10: redhatsecurebootca5.cer
+@@ -1860,9 +1868,7 @@ BuildKernel() {
+     fi
+ 
+     %ifarch x86_64 aarch64
+-    %pesign -s -i $SignImage -o vmlinuz.tmp -a %{secureboot_ca_0} -c %{secureboot_key_0} -n %{pesign_name_0}
+-    %pesign -s -i vmlinuz.tmp -o vmlinuz.signed -a %{secureboot_ca_1} -c %{secureboot_key_1} -n %{pesign_name_1}
+-    rm vmlinuz.tmp
++    sbsign --key %{SOURCE7001} --cert %{SOURCE7002} --output vmlinuz.signed $SignImage
+     %endif
+     %ifarch s390x ppc64le
+     if [ -x /usr/bin/rpm-sign ]; then
+@@ -2393,9 +2399,6 @@ BuildKernel() {
+     # Red Hat UEFI Secure Boot CA cert, which can be used to authenticate the kernel
+     mkdir -p $RPM_BUILD_ROOT%{_datadir}/doc/kernel-keys/$KernelVer
+     %ifarch x86_64 aarch64
+-       install -m 0644 %{secureboot_ca_0} $RPM_BUILD_ROOT%{_datadir}/doc/kernel-keys/$KernelVer/kernel-signing-ca-20200609.cer
+-       install -m 0644 %{secureboot_ca_1} $RPM_BUILD_ROOT%{_datadir}/doc/kernel-keys/$KernelVer/kernel-signing-ca-20140212.cer
+-       ln -s kernel-signing-ca-20200609.cer $RPM_BUILD_ROOT%{_datadir}/doc/kernel-keys/$KernelVer/kernel-signing-ca.cer
+     %else
+        install -m 0644 %{secureboot_ca_0} $RPM_BUILD_ROOT%{_datadir}/doc/kernel-keys/$KernelVer/kernel-signing-ca.cer
+     %endif
+-- 
+2.40.1
+