Skip to content

Commit

Permalink
Add configuration option to boot an alternative 2nd stage
Browse files Browse the repository at this point in the history
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 <eric.snowberg@oracle.com>
  • Loading branch information
esnowberg committed Jan 22, 2025
1 parent 69503d7 commit 3dc8ba8
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions include/load-options.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions load-options.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "shim.h"

CHAR16 *second_stage;
CHAR16 *optional_second_stage = NULL;
void *load_options;
UINT32 load_options_size;

Expand Down
83 changes: 82 additions & 1 deletion shim.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -1668,6 +1668,85 @@ load_unbundled_trust(EFI_HANDLE image_handle)
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;
}

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';
console_print(L"Optional 2nd stage: %s\n", buffer);
optional_second_stage=buffer;

done:
FreePool(PathName);
return EFI_SUCCESS;
}

EFI_STATUS
shim_init(void)
{
Expand Down Expand Up @@ -1952,6 +2031,8 @@ efi_main (EFI_HANDLE passed_image_handle, EFI_SYSTEM_TABLE *passed_systab)
*/
(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;
Expand Down

0 comments on commit 3dc8ba8

Please sign in to comment.