From 5dffa283ee51ed05c6d173ce63237ed97cf078f6 Mon Sep 17 00:00:00 2001 From: Dorian Stoll Date: Sat, 13 May 2023 20:46:57 +0200 Subject: [PATCH] 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. --- pkg/fedora/kernel-surface/.gitignore | 6 +- pkg/fedora/kernel-surface/build-ark.py | 171 ++++++++++++++++++ .../kernel-surface/build-linux-surface.py | 111 ++++++++++++ pkg/fedora/kernel-surface/configs/.gitkeep | 0 .../kernel-surface/configs/fedora.config | 7 + pkg/fedora/kernel-surface/files/.gitkeep | 0 pkg/fedora/kernel-surface/patches/.gitkeep | 0 .../secureboot/0001-secureboot.patch | 60 ++++++ 8 files changed, 353 insertions(+), 2 deletions(-) create mode 100755 pkg/fedora/kernel-surface/build-ark.py create mode 100755 pkg/fedora/kernel-surface/build-linux-surface.py create mode 100644 pkg/fedora/kernel-surface/configs/.gitkeep create mode 100644 pkg/fedora/kernel-surface/configs/fedora.config create mode 100644 pkg/fedora/kernel-surface/files/.gitkeep create mode 100644 pkg/fedora/kernel-surface/patches/.gitkeep create mode 100644 pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch diff --git a/pkg/fedora/kernel-surface/.gitignore b/pkg/fedora/kernel-surface/.gitignore index 93ce722d5..e20d2e79f 100644 --- a/pkg/fedora/kernel-surface/.gitignore +++ b/pkg/fedora/kernel-surface/.gitignore @@ -1,2 +1,4 @@ -surface.key -surface.crt +secureboot/MOK.key +secureboot/MOK.crt +kernel-ark +out diff --git a/pkg/fedora/kernel-surface/build-ark.py b/pkg/fedora/kernel-surface/build-ark.py new file mode 100755 index 000000000..347b46041 --- /dev/null +++ b/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) diff --git a/pkg/fedora/kernel-surface/build-linux-surface.py b/pkg/fedora/kernel-surface/build-linux-surface.py new file mode 100755 index 000000000..9072c69d7 --- /dev/null +++ b/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) diff --git a/pkg/fedora/kernel-surface/configs/.gitkeep b/pkg/fedora/kernel-surface/configs/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/pkg/fedora/kernel-surface/configs/fedora.config b/pkg/fedora/kernel-surface/configs/fedora.config new file mode 100644 index 000000000..ee8cc1e7e --- /dev/null +++ b/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 diff --git a/pkg/fedora/kernel-surface/files/.gitkeep b/pkg/fedora/kernel-surface/files/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/pkg/fedora/kernel-surface/patches/.gitkeep b/pkg/fedora/kernel-surface/patches/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch b/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch new file mode 100644 index 000000000..1f8ca29f7 --- /dev/null +++ b/pkg/fedora/kernel-surface/secureboot/0001-secureboot.patch @@ -0,0 +1,60 @@ +From 67f8052f553191686b1224b5598d00ff33d38608 Mon Sep 17 00:00:00 2001 +From: Dorian Stoll +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 +--- + 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 +