From 9e4f38abe61b600826360c14729cc54ea3ec7c3c Mon Sep 17 00:00:00 2001 From: Peter Jones Date: Fri, 2 Jul 2021 14:22:55 -0400 Subject: shim: move the bulk of set_second_stage() to its own file This moves set_second_stage() and some of the helper functions it uses out of shim.c, so that it's easier to write test cases for. Signed-off-by: Peter Jones --- include/load-options.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 include/load-options.h (limited to 'include/load-options.h') diff --git a/include/load-options.h b/include/load-options.h new file mode 100644 index 00000000..d2bee3bb --- /dev/null +++ b/include/load-options.h @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: BSD-2-Clause-Patent +/* + * load-options.h - all the stuff we need to parse the load options + */ + +#ifndef SHIM_ARGV_H_ +#define SHIM_ARGV_H_ + +EFI_STATUS generate_path_from_image_path(EFI_LOADED_IMAGE *li, + CHAR16 *ImagePath, + CHAR16 **PathName); + +EFI_STATUS parse_load_options(EFI_LOADED_IMAGE *li); + +extern CHAR16 *second_stage; +extern void *load_options; +extern UINT32 load_options_size; + +#endif /* !SHIM_ARGV_H_ */ +// vim:fenc=utf-8:tw=75:noet -- cgit v1.2.3 From 83850cd8df2db60a00b96e7757c6ff9c1d8cccec Mon Sep 17 00:00:00 2001 From: Eric Snowberg Date: Tue, 29 Aug 2023 17:25:42 -0400 Subject: Add configuration option to boot an alternative 2nd stage Add the ability for shim to load an optional configuration file. This new file is called "options.csv". The configuration file is completely optional. If used, it is located in the same directory as the booted shim. The "options.csv" file currently allows a single entry. Other options could be added to it in the future. The first and only entry in the file is the name of the secondary boot loader shim will load. The "options.csv" file is in Unicode LE format. This allows a signed shim to directly load a UKI without the need to rename it to grub. Shim's transitive trust is maintained. If the alternative 2nd stage can not be verified, it will not boot. Signed-off-by: Eric Snowberg --- Makefile | 2 +- include/load-options.h | 1 + load-options.c | 1 + shim.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 86 insertions(+), 2 deletions(-) (limited to 'include/load-options.h') diff --git a/Makefile b/Makefile index 257f343b..1c3190b9 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ CFLAGS += -DENABLE_SHIM_CERT else TARGETS += $(MMNAME) $(FBNAME) endif -OBJS = shim.o globals.o mok.o netboot.o cert.o dp.o replacements.o tpm.o version.o errlog.o sbat.o sbat_data.o sbat_var.o pe.o pe-relocate.o httpboot.o csv.o load-options.o +OBJS = shim.o globals.o mok.o netboot.o cert.o dp.o replacements.o tpm.o version.o errlog.o sbat.o sbat_data.o sbat_var.o pe.o pe-relocate.o httpboot.o csv.o load-options.o utils.o KEYS = shim_cert.h ocsp.* ca.* shim.crt shim.csr shim.p12 shim.pem shim.key shim.cer ORIG_SOURCES = shim.c globals.c mok.c netboot.c dp.c replacements.c tpm.c errlog.c sbat.c pe.c pe-relocate.c httpboot.c shim.h version.h $(wildcard include/*.h) cert.S sbat_var.S MOK_OBJS = MokManager.o PasswordCrypt.o crypt_blowfish.o errlog.o sbat_data.o globals.o dp.o diff --git a/include/load-options.h b/include/load-options.h index d2bee3bb..78b1dcce 100644 --- a/include/load-options.h +++ b/include/load-options.h @@ -13,6 +13,7 @@ EFI_STATUS generate_path_from_image_path(EFI_LOADED_IMAGE *li, EFI_STATUS parse_load_options(EFI_LOADED_IMAGE *li); extern CHAR16 *second_stage; +extern CHAR16 *optional_second_stage; extern void *load_options; extern UINT32 load_options_size; diff --git a/load-options.c b/load-options.c index e7b64471..091cb18b 100644 --- a/load-options.c +++ b/load-options.c @@ -6,6 +6,7 @@ #include "shim.h" CHAR16 *second_stage; +CHAR16 *optional_second_stage = NULL; void *load_options; UINT32 load_options_size; diff --git a/shim.c b/shim.c index 42b5bbcb..14355d27 100644 --- a/shim.c +++ b/shim.c @@ -1256,7 +1256,7 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle) EFI_STATUS efi_status; EFI_LOADED_IMAGE *li = NULL; - second_stage = DEFAULT_LOADER; + second_stage = (optional_second_stage) ? optional_second_stage : DEFAULT_LOADER; load_options = NULL; load_options_size = 0; @@ -1689,6 +1689,86 @@ done: return efi_status; } +/* Read optional options file */ +EFI_STATUS +load_shim_options(EFI_HANDLE image_handle) +{ + EFI_STATUS efi_status; + EFI_HANDLE device; + EFI_LOADED_IMAGE *li = NULL; + EFI_FILE_IO_INTERFACE *drive; + EFI_FILE *root; + EFI_FILE_HANDLE ofile; + CHAR16 *PathName = NULL; + CHAR16 *buffer; + UINTN comma0; + UINT64 bs; + + efi_status = gBS->HandleProtocol(image_handle, &EFI_LOADED_IMAGE_GUID, + (void **)&li); + if (EFI_ERROR(efi_status)) { + perror(L"Unable to init protocol\n"); + return efi_status; + } + + efi_status = generate_path_from_image_path(li, L"options.csv", &PathName); + if (EFI_ERROR(efi_status)) + goto done; + + device = li->DeviceHandle; + + efi_status = BS->HandleProtocol(device, &EFI_SIMPLE_FILE_SYSTEM_GUID, + (void **) &drive); + if (EFI_ERROR(efi_status)) + goto done; + + efi_status = drive->OpenVolume(drive, &root); + if (EFI_ERROR(efi_status)) { + perror(L"Failed to open fs: %r\n", efi_status); + goto done; + } + + efi_status = root->Open(root, &ofile, PathName, EFI_FILE_READ_ONLY, 0); + if (EFI_ERROR(efi_status)) { + if (efi_status != EFI_NOT_FOUND) + perror(L"Failed to open %s - %r\n", PathName, efi_status); + goto done; + } + + dprint(L"Loading optional second stage info from options.csv\n"); + efi_status = read_file(ofile, PathName, &buffer, &bs); + if (EFI_ERROR(efi_status)) { + perror(L"Failed to read file\n"); + goto done; + } + + /* + * This file may or may not start with the Unicode byte order marker. + * Since UEFI is defined as LE, this file must also be LE. + * If we find the LE byte order marker, just skip its. + */ + if (*buffer == 0xfeff) + buffer++; + + comma0 = StrCSpn(buffer, L","); + if (comma0 == 0) { + perror(L"Invalid csv file\n"); + goto done; + } + + /* + * Currently the options.csv file allows one entry for the optional + * secondary boot stage, anything afterwards is skipped. + */ + buffer[comma0] = L'\0'; + dprint(L"Optional 2nd stage:\"%s\"\n", buffer); + optional_second_stage=buffer; + +done: + FreePool(PathName); + return EFI_SUCCESS; +} + EFI_STATUS shim_init(void) { @@ -1973,6 +2053,8 @@ die: */ (void) del_variable(SHIM_RETAIN_PROTOCOL_VAR_NAME, SHIM_LOCK_GUID); + load_shim_options(image_handle); + efi_status = shim_init(); if (EFI_ERROR(efi_status)) { msg = SHIM_INIT; -- cgit v1.2.3