Pull request #107: feat(efibootguard): single image with automatic partition switch

Merge in ICO/coreos from feat/single-uki to master

* commit '04e0adf97af475345f14d25de03985be599e4965':
  feat(efibootguard): single image with automatic partition switch
This commit is contained in:
Samuel Dolt 2023-07-05 10:36:36 +02:00
commit 0001e685fa
10 changed files with 135 additions and 72 deletions

@ -1 +1 @@
Subproject commit c65743e5dcaecce38383b23782c063bdbc73c404 Subproject commit e3581b11d30d91d0363acb48a6aee47043b7e0bc

View File

@ -2,8 +2,8 @@
# Variable used in WKS file # Variable used in WKS file
WKS_PART_EFI ??= 'part --source efibootguard-efi --label efi --part-type=EF00' WKS_PART_EFI ??= 'part --source efibootguard-efi --label efi --part-type=EF00'
WKS_PART_EFIBOOTGUARD_A ??= 'part --source efibootguard-boot --label ebg0 --part-type=0700 --sourceparams "watchdog=${EFIBOOTGUARD_TIMEOUT},revision=2,kernel=kernel0-${MACHINE}.efi;KERNEL.EFI"' WKS_PART_EFIBOOTGUARD_A ??= 'part --source efibootguard-boot --label ebg0 --part-type=0700 --sourceparams "args=coreos.root=rootfs0,watchdog=${EFIBOOTGUARD_TIMEOUT},revision=2,kernel=kernel-${MACHINE}.efi;KERNEL.EFI"'
WKS_PART_EFIBOOTGUARD_B ??= 'part --source efibootguard-boot --label ebg1 --part-type=0700 --sourceparams "watchdog=${EFIBOOTGUARD_TIMEOUT},revision=1,kernel=kernel1-${MACHINE}.efi;KERNEL.EFI"' WKS_PART_EFIBOOTGUARD_B ??= 'part --source efibootguard-boot --label ebg1 --part-type=0700 --sourceparams "args=coreos.root=rootfs1,watchdog=${EFIBOOTGUARD_TIMEOUT},revision=1,kernel=kernel-${MACHINE}.efi;KERNEL.EFI"'
WKS_PART_ROOT_A ??= 'part / --source rootfs --fstype=ext4 --label rootfs0' WKS_PART_ROOT_A ??= 'part / --source rootfs --fstype=ext4 --label rootfs0'
WKS_PART_ROOT_B ??= 'part --fstype=ext4 --label rootfs1' WKS_PART_ROOT_B ??= 'part --fstype=ext4 --label rootfs1'
WKS_PART_ROOT_SIZE ??= '2G' WKS_PART_ROOT_SIZE ??= '2G'

View File

@ -46,8 +46,7 @@ def get_coreos_ci_artifacts(d):
artifacts.append(kernel_imagetype + '-' + machine + kernel_image_bin_ext) artifacts.append(kernel_imagetype + '-' + machine + kernel_image_bin_ext)
if d.getVar('COREOS_IMAGE_GENERATE_UKI') == '1': if d.getVar('COREOS_IMAGE_GENERATE_UKI') == '1':
artifacts.append(d.getVar('COREOS_KERNEL0_FILENAME')) artifacts.append(d.getVar('COREOS_KERNEL_FILENAME'))
artifacts.append(d.getVar('COREOS_KERNEL1_FILENAME'))
# Bootloaders # Bootloaders
# ========================================================================== # ==========================================================================

View File

@ -16,21 +16,19 @@ python () {
inherit swupdate-image inherit swupdate-image
# Ensure than variable used in the sw-description files are watched for change # Ensure than variable used in the sw-description files are watched for change
do_swuimage[vardeps] += "COREOS_KERNEL0_FILENAME COREOS_KERNEL1_FILENAME EFIBOOTGUARD_TIMEOUT EFIDIR EFI_BOOT_IMAGE COREOS_EFIBOOTGUARD_FILENAME" do_swuimage[vardeps] += "COREOS_KERNEL_FILENAME EFIBOOTGUARD_TIMEOUT EFIDIR EFI_BOOT_IMAGE COREOS_EFIBOOTGUARD_FILENAME"
do_swuimage[deptask] += "do_bundle_uki" do_swuimage[deptask] += "do_bundle_uki"
COREOS_EFIBOOTGUARD_NAME ?= "efibootguard${EFI_ARCH}" COREOS_EFIBOOTGUARD_NAME ?= "efibootguard${EFI_ARCH}"
COREOS_EFIBOOTGUARD_EXT ?= ".efi" COREOS_EFIBOOTGUARD_EXT ?= ".efi"
COREOS_EFIBOOTGUARD_FILENAME = "${COREOS_EFIBOOTGUARD_NAME}${COREOS_EFIBOOTGUARD_EXT}" COREOS_EFIBOOTGUARD_FILENAME = "${COREOS_EFIBOOTGUARD_NAME}${COREOS_EFIBOOTGUARD_EXT}"
SWUPDATE_IMAGES += "${COREOS_KERNEL0_NAME} ${COREOS_KERNEL1_NAME} ${COREOS_EFIBOOTGUARD_NAME}" SWUPDATE_IMAGES += "${COREOS_KERNEL_NAME} ${COREOS_EFIBOOTGUARD_NAME}"
python () { python () {
kernel0 = d.getVar('COREOS_KERNEL0_NAME') kernel = d.getVar('COREOS_KERNEL_NAME')
kernel1 = d.getVar('COREOS_KERNEL1_NAME')
kernelext = d.getVar('COREOS_KERNEL_EXT') kernelext = d.getVar('COREOS_KERNEL_EXT')
d.setVarFlag("SWUPDATE_IMAGES_FSTYPES", kernel0, kernelext) d.setVarFlag("SWUPDATE_IMAGES_FSTYPES", kernel, kernelext)
d.setVarFlag("SWUPDATE_IMAGES_FSTYPES", kernel1, kernelext)
efibootguard = d.getVar('COREOS_EFIBOOTGUARD_NAME') efibootguard = d.getVar('COREOS_EFIBOOTGUARD_NAME')
efibootguardext = d.getVar('COREOS_EFIBOOTGUARD_EXT') efibootguardext = d.getVar('COREOS_EFIBOOTGUARD_EXT')

View File

@ -10,20 +10,17 @@ inherit coreos-efi-sbsign
# ============================================================================== # ==============================================================================
COREOS_KERNEL_EXT ??= ".efi" COREOS_KERNEL_EXT ??= ".efi"
COREOS_KERNEL0_NAME ??= "kernel0-${MACHINE}" COREOS_KERNEL_NAME ??= "kernel-${MACHINE}"
COREOS_KERNEL1_NAME ??= "kernel1-${MACHINE}" COREOS_KERNEL_FILENAME ??= "${COREOS_KERNEL_NAME}${COREOS_KERNEL_EXT}"
COREOS_KERNEL0_FILENAME ??= "${COREOS_KERNEL0_NAME}${COREOS_KERNEL_EXT}" COREOS_KERNEL ??= "${DEPLOY_DIR_IMAGE}/${COREOS_KERNEL_FILENAME}"
COREOS_KERNEL0 ??= "${DEPLOY_DIR_IMAGE}/${COREOS_KERNEL0_FILENAME}"
COREOS_KERNEL1_FILENAME ??= "${COREOS_KERNEL1_NAME}${COREOS_KERNEL_EXT}"
COREOS_KERNEL1 ??= "${DEPLOY_DIR_IMAGE}/${COREOS_KERNEL1_FILENAME}"
# Kernel command line # Kernel command line
# ============================================================================== # ==============================================================================
COREOS_ROOTFS0_ROOT ??= "PARTLABEL=rootfs0" # AUTOLABEL will be replaced by the right PARTLABEL (rootfs0 or rootfs1) at
COREOS_ROOTFS1_ROOT ??= "PARTLABEL=rootfs1" # runtime in the efibootguard UKI stub
COREOS_KERNEL0_CMDLINE ??= "root=${COREOS_ROOTFS0_ROOT} ${APPEND} rootwait" COREOS_ROOTFS_ROOT ??= "PARTLABEL=AUTOLABEL"
COREOS_KERNEL1_CMDLINE ??= "root=${COREOS_ROOTFS1_ROOT} ${APPEND} rootwait" COREOS_KERNEL_CMDLINE ??= "root=${COREOS_ROOTFS_ROOT} ${APPEND} rootwait"
COREOS_UKI_PART_KERNEL_FILENAME ??= "${KERNEL_IMAGETYPE}-${MACHINE}${KERNEL_IMAGE_BIN_EXT}" COREOS_UKI_PART_KERNEL_FILENAME ??= "${KERNEL_IMAGETYPE}-${MACHINE}${KERNEL_IMAGE_BIN_EXT}"
COREOS_UKI_PART_KERNEL ??= "${DEPLOY_DIR_IMAGE}/${COREOS_UKI_PART_KERNEL_FILENAME}" COREOS_UKI_PART_KERNEL ??= "${DEPLOY_DIR_IMAGE}/${COREOS_UKI_PART_KERNEL_FILENAME}"
@ -48,8 +45,7 @@ do_image_uki() {
echo "kernel: ${COREOS_UKI_PART_KERNEL_FILENAME}" echo "kernel: ${COREOS_UKI_PART_KERNEL_FILENAME}"
echo "dtb: ${DTB_PARAMS}" echo "dtb: ${DTB_PARAMS}"
echo "cmdline0: ${COREOS_KERNEL0_CMDLINE}" echo "cmdline: ${COREOS_KERNEL_CMDLINE}"
echo "cmdline1: ${COREOS_KERNEL1_CMDLINE}"
echo "initramfs: ${COREOS_UKI_PART_INITRAMFS}" echo "initramfs: ${COREOS_UKI_PART_INITRAMFS}"
if [ ! -z "${COREOS_UKI_PART_INITRAMFS}" ]; then if [ ! -z "${COREOS_UKI_PART_INITRAMFS}" ]; then
@ -61,19 +57,11 @@ do_image_uki() {
bg_gen_unified_kernel \ bg_gen_unified_kernel \
"${COREOS_UKI_PART_STUB}" \ "${COREOS_UKI_PART_STUB}" \
"${COREOS_UKI_PART_KERNEL}" \ "${COREOS_UKI_PART_KERNEL}" \
"${COREOS_KERNEL0}" \ "${COREOS_KERNEL}" \
--cmdline "${COREOS_KERNEL0_CMDLINE}" \ --cmdline "${COREOS_KERNEL_CMDLINE}" \
${DTB_PARAMS} ${DTB_PARAMS}
bg_gen_unified_kernel \ coreos_efi_secureboot_sign_app "${deployDir}/${COREOS_KERNEL_FILENAME}"
"${COREOS_UKI_PART_STUB}" \
"${COREOS_UKI_PART_KERNEL}" \
"${COREOS_KERNEL1}" \
--cmdline "${COREOS_KERNEL1_CMDLINE}" \
${DTB_PARAMS}
coreos_efi_secureboot_sign_app "${deployDir}/${COREOS_KERNEL0_FILENAME}"
coreos_efi_secureboot_sign_app "${deployDir}/${COREOS_KERNEL1_FILENAME}"
} }
do_image_uki[depends] += "virtual/kernel:do_deploy efibootguard-native:do_populate_sysroot efibootguard:do_populate_sysroot" do_image_uki[depends] += "virtual/kernel:do_deploy efibootguard-native:do_populate_sysroot efibootguard:do_populate_sysroot"

View File

@ -23,11 +23,11 @@ software =
files: ( files: (
{ {
filename = "@@COREOS_KERNEL0_FILENAME@@"; filename = "@@COREOS_KERNEL_FILENAME@@";
path = "/KERNEL.EFI"; path = "/KERNEL.EFI";
device = "/dev/disk/by-partlabel/ebg0"; device = "/dev/disk/by-partlabel/ebg0";
filesystem = "vfat"; filesystem = "vfat";
sha256 = "$swupdate_get_sha256(@@COREOS_KERNEL0_FILENAME@@)"; sha256 = "$swupdate_get_sha256(@@COREOS_KERNEL_FILENAME@@)";
}, },
{ {
filename = "@@COREOS_EFIBOOTGUARD_FILENAME@@"; filename = "@@COREOS_EFIBOOTGUARD_FILENAME@@";
@ -44,7 +44,7 @@ software =
bootenv: ( bootenv: (
{ {
name = "kernelparams"; name = "kernelparams";
value = ""; value = "coreos.root=rootfs0";
}, },
{ {
name = "watchdog_timeout_sec"; name = "watchdog_timeout_sec";
@ -80,11 +80,11 @@ software =
files: ( files: (
{ {
filename = "@@COREOS_KERNEL1_FILENAME@@"; filename = "@@COREOS_KERNEL_FILENAME@@";
path = "/KERNEL.EFI"; path = "/KERNEL.EFI";
device = "/dev/disk/by-partlabel/ebg1"; device = "/dev/disk/by-partlabel/ebg1";
filesystem = "vfat"; filesystem = "vfat";
sha256 = "$swupdate_get_sha256(@@COREOS_KERNEL1_FILENAME@@)"; sha256 = "$swupdate_get_sha256(@@COREOS_KERNEL_FILENAME@@)";
}, },
{ {
filename = "@@COREOS_EFIBOOTGUARD_FILENAME@@"; filename = "@@COREOS_EFIBOOTGUARD_FILENAME@@";
@ -100,7 +100,7 @@ software =
bootenv: ( bootenv: (
{ {
name = "kernelparams"; name = "kernelparams";
value = ""; value = "coreos.root=rootfs1";
}, },
{ {
name = "watchdog_timeout_sec"; name = "watchdog_timeout_sec";

View File

@ -272,40 +272,24 @@ def efibootguard_generate_uki(args, config, basepath, workspace):
keydir = os.path.relpath(rd.getVar("COREOS_EFI_SECUREBOOT_KEYDIR")) keydir = os.path.relpath(rd.getVar("COREOS_EFI_SECUREBOOT_KEYDIR"))
uki0 = UKIGeneratorArgs( uki = UKIGeneratorArgs(
kernel=kernel, kernel=kernel,
output=os.path.relpath(rd.getVar("COREOS_KERNEL0")), output=os.path.relpath(rd.getVar("COREOS_KERNEL")),
cmdline=rd.getVar("COREOS_KERNEL0_CMDLINE"), cmdline=rd.getVar("COREOS_KERNEL_CMDLINE"),
dtb=dtb, dtb=dtb,
stub=stub, stub=stub,
root=rd.getVar("COREOS_ROOTFS0_ROOT"), root=rd.getVar("COREOS_ROOTFS_ROOT"),
build_binary=build_binary,
keydir=keydir,
)
uki1 = UKIGeneratorArgs(
kernel=kernel,
output=os.path.relpath(rd.getVar("COREOS_KERNEL1")),
cmdline=rd.getVar("COREOS_KERNEL1_CMDLINE"),
dtb=dtb,
stub=stub,
root=rd.getVar("COREOS_ROOTFS1_ROOT"),
build_binary=build_binary, build_binary=build_binary,
keydir=keydir, keydir=keydir,
) )
print(f"Applying passed parameters...") print(f"Applying passed parameters...")
uki0.process_args(args) uki.process_args(args)
uki1.process_args(args)
print(f"KERNEL0 image will be generated with the following settings:") print(f"KERNEL image will be generated with the following settings:")
printi(f"{uki0}", 1) printi(f"{uki}", 1)
print()
print(f"KERNEL1 image will be generated with the following settings:")
printi(f"{uki1}", 1)
print() print()
print(f"Generating the files...") print(f"Generating the files...")
r = uki0.build_and_sign() return uki0.build_and_sign()
r += uki1.build_and_sign()
return r

View File

@ -0,0 +1,93 @@
From 2e8b73826c6ecaf5168002a18282ba7e4ac95e76 Mon Sep 17 00:00:00 2001
From: Samuel Dolt <samuel.dolt@netmodule.com>
Date: Mon, 12 Jun 2023 16:29:49 +0200
Subject: [PATCH] coreos: add a coreos specific rootfs switch to the UKI stub
The unified kernel stub can now replace the substring "AUTOLABEL"
in the built-in kernel command line by either rootfs0 and rootfs1
by looking the LoadOption string passed by ther firmware:
- LoadOptions contain "coreos.root=rootfs0", all occurences of
"AUTOLABEL" are replaced by "rootfs0"
- LoadOptions contain "coreos.root=rootfs1", all occurences of
"AUTOLABEL" are replaced by "rootfs1".
- LoadOptions is empty, the kernel command line will be used as is.
In all other case, the stub will exist without booting the kernel
with a INVALID PARAMETER error.
---
kernel-stub/main.c | 55 +++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 50 insertions(+), 5 deletions(-)
diff --git a/kernel-stub/main.c b/kernel-stub/main.c
index c0be1f6..6f456d3 100644
--- a/kernel-stub/main.c
+++ b/kernel-stub/main.c
@@ -128,11 +128,6 @@ EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
error_exit(L"Error getting LoadedImageProtocol", status);
}
- /* consider zero-termination for string length */
- if (stub_image->LoadOptionsSize > sizeof(CHAR16)) {
- info(L"WARNING: Passed command line options ignored, only built-in used");
- }
-
pe_header = get_pe_header(stub_image->ImageBase);
for (n = 0, section = get_sections(pe_header);
n < pe_header->Coff.NumberOfSections;
@@ -161,6 +156,56 @@ EFI_STATUS efi_main(EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *system_table)
kernel_image.LoadOptions = (UINT8 *) stub_image->ImageBase +
cmdline_section->VirtualAddress;
kernel_image.LoadOptionsSize = cmdline_section->VirtualSize;
+
+ /* CoreOS utilize the option passed from efibootguard to customize the kernel
+ * command line.
+ *
+ * Allowed option are:
+ * 'coreos.root=rootfs0' => replace "AUTOLABEL" with "rootfs0 " in place in the kernel CLI
+ * 'coreos.root=rootfs1' => replace "AUTOLABEL" with "rootfs1 " in place in the kernel CLI
+ * '' => no option passed
+ *
+ * Using another option string will return without booting the kernel
+ *
+ * hint: LoadOptions is a null-terminated wide string
+ * hint: sizeof return the number of byte. StrLen the number of characters
+ */
+ if (stub_image->LoadOptionsSize > sizeof(CHAR16)) {
+
+ // !!! symbol and rootfs must have the same length !!!
+ const CHAR16 symbol[] = L"AUTOLABEL";
+ CHAR16 rootfs[] = L"rootfsX ";
+
+ if (StrnCmp(L"coreos.root=rootfs0", stub_image->LoadOptions, stub_image->LoadOptionsSize) == 0) {
+ rootfs[6] = L'0';
+ } else if (StrnCmp(L"coreos.root=rootfs1", stub_image->LoadOptions, stub_image->LoadOptionsSize) == 0) {
+ rootfs[6] = L'1';
+ } else {
+ error_exit(L"LoadOptions is not valid", EFI_INVALID_PARAMETER);
+ }
+
+ /* Replace symbol by rootfs (AUTOLABEL by either rootfs0 or rootfs1) */
+ CHAR16 * str = kernel_image.LoadOptions;
+ UINTN len = kernel_image.LoadOptionsSize;
+ while (*str && len) {
+
+ /* Ensure that the string still contains enough char for the symbol */
+ if(len < sizeof(symbol)) {
+ break;
+ }
+
+ if(StrnCmp(str, &symbol, StrLen(symbol)) == 0) {
+ /* Replace symbol by rootfs, works because symbole and rootfs has the same length */
+ StrnCpy(str, rootfs, StrLen(rootfs));
+ }
+
+ str += 1;
+ len -= sizeof(CHAR16);
+ }
+
+ }
+
+ Print(L"Unified kernel stub: Kernel Options: %s\n", kernel_image.LoadOptions);
}
if (initrd_section) {

View File

@ -0,0 +1,4 @@
FILESEXTRAPATHS:prepend := "${THISDIR}/${PN}:"
SRC_URI += "file://0001-coreos-add-a-coreos-specific-rootfs-switch-to-the-UK.patch"

View File

@ -17,7 +17,7 @@ IMAGE_FSTYPES = "cpio.gz"
COREOS_INSTALLER_WKS_FILE ??= "" COREOS_INSTALLER_WKS_FILE ??= ""
WKS_FILE = "${COREOS_INSTALLER_WKS_FILE}" WKS_FILE = "${COREOS_INSTALLER_WKS_FILE}"
IMAGE_FSTYPES += "${@'wic.xz wic.bmap' if d.getVar('COREOS_INSTALLER_WKS_FILE') else ''}" IMAGE_FSTYPES += "${@'wic.xz wic.bmap' if d.getVar('COREOS_INSTALLER_WKS_FILE') else ''}"
IMAGE_BOOT_FILES = "${COREOS_KERNEL0_FILENAME};EFI/BOOT/${EFI_BOOT_IMAGE}" IMAGE_BOOT_FILES = "${COREOS_KERNEL_FILENAME};EFI/BOOT/${EFI_BOOT_IMAGE}"
COREOS_IMAGE_GENERATE_UKI = "1" COREOS_IMAGE_GENERATE_UKI = "1"
@ -30,13 +30,10 @@ COREOS_IMAGE_GENERATE_INSTALLER = "0"
COREOS_UKI_PART_INITRAMFS = "${IMGDEPLOYDIR}/${IMAGE_BASENAME}-${MACHINE}.cpio.gz" COREOS_UKI_PART_INITRAMFS = "${IMGDEPLOYDIR}/${IMAGE_BASENAME}-${MACHINE}.cpio.gz"
COREOS_IMAGE_GENERATE_SWU = "0" COREOS_IMAGE_GENERATE_SWU = "0"
# Change generated UKI filename and bundled command line # Change generated UKI filename and reset the bundled command line to "APPEND"
# Having the same name to KERNEL0 and KERNEL1 means that KERNEL1 will overwrite # to ensure that root is not set in the kernel command line
# KERNEL0. COREOS_KERNEL_NAME ?= "coreos-installer-${MACHINE}"
COREOS_KERNEL0_NAME ?= "coreos-installer-${MACHINE}" COREOS_KERNEL_CMDLINE ?= "${APPEND}"
COREOS_KERNEL1_NAME ?= "coreos-installer-${MACHINE}"
COREOS_KERNEL0_CMDLINE ?= "${APPEND}"
COREOS_KERNEL1_CMDLINE ?= "${APPEND}"
inherit coreos-image inherit coreos-image