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) {
