Skip to content

Commit

Permalink
Allow fallback to use the system's LoadImage/StartImage .
Browse files Browse the repository at this point in the history
Track use of the system's LoadImage(), and when the next StartImage()
call is for an image the system verified, allow that to count as
participating, since it has been verified by the system's db.

Signed-off-by: Peter Jones <pjones@redhat.com>
  • Loading branch information
vathpela committed Feb 14, 2014
1 parent a0bb782 commit 06495f6
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 35 deletions.
68 changes: 67 additions & 1 deletion replacements.c
Expand Up @@ -60,26 +60,82 @@

static EFI_SYSTEM_TABLE *systab;

static typeof(systab->BootServices->LoadImage) system_load_image;
static typeof(systab->BootServices->StartImage) system_start_image;
static typeof(systab->BootServices->Exit) system_exit;
static typeof(systab->BootServices->ExitBootServices) system_exit_boot_services;

static EFI_HANDLE last_loaded_image;

void
unhook_system_services(void)
{
systab->BootServices->Exit = system_exit;
systab->BootServices->LoadImage = system_load_image;
systab->BootServices->StartImage = system_start_image;
systab->BootServices->ExitBootServices = system_exit_boot_services;
}

static EFI_STATUS EFIAPI
load_image(BOOLEAN BootPolicy, EFI_HANDLE ParentImageHandle,
EFI_DEVICE_PATH *DevicePath, VOID *SourceBuffer,
UINTN SourceSize, EFI_HANDLE *ImageHandle)
{
EFI_STATUS status;
unhook_system_services();

status = systab->BootServices->LoadImage(BootPolicy,
ParentImageHandle, DevicePath,
SourceBuffer, SourceSize, ImageHandle);
hook_system_services(systab);
if (EFI_ERROR(status))
last_loaded_image = NULL;
else
last_loaded_image = *ImageHandle;
return status;
}

static EFI_STATUS EFIAPI
start_image(EFI_HANDLE image_handle, UINTN *exit_data_size, CHAR16 **exit_data)
{
EFI_STATUS status;
unhook_system_services();

/* We have to uninstall shim's protocol here, because if we're
* On the fallback.efi path, then our call pathway is:
*
* shim->fallback->shim->grub
* ^ ^ ^
* | | \- gets protocol #0
* | \- installs its protocol (#1)
* \- installs its protocol (#0)
* and if we haven't removed this, then grub will get the *first*
* shim's protocol, but it'll get the second shim's systab
* replacements. So even though it will participate and verify
* the kernel, the systab never finds out.
*/
if (image_handle == last_loaded_image) {
loader_is_participating = 1;
uninstall_shim_protocols();
}
status = systab->BootServices->StartImage(image_handle, exit_data_size, exit_data);
if (EFI_ERROR(status))
if (EFI_ERROR(status)) {
if (image_handle == last_loaded_image) {
EFI_STATUS status2 = install_shim_protocols();

if (EFI_ERROR(status2)) {
Print(L"Something has gone seriously wrong: %d\n",
status2);
Print(L"shim cannot continue, sorry.\n");
systab->BootServices->Stall(5000000);
systab->RuntimeServices->ResetSystem(
EfiResetShutdown,
EFI_SECURITY_VIOLATION, 0, NULL);
}
}
hook_system_services(systab);
loader_is_participating = 0;
}
return status;
}

Expand Down Expand Up @@ -123,6 +179,16 @@ hook_system_services(EFI_SYSTEM_TABLE *local_systab)

/* We need to hook various calls to make this work... */

/* We need LoadImage() hooked so that fallback.c can load shim
* without having to fake LoadImage as well. This allows it
* to call the system LoadImage(), and have us track the output
* and mark loader_is_participating in start_image. This means
* anything added by fallback has to be verified by the system db,
* which we want to preserve anyway, since that's all launching
* through BDS gives us. */
system_load_image = systab->BootServices->LoadImage;
systab->BootServices->LoadImage = load_image;

/* we need StartImage() so that we can allow chain booting to an
* image trusted by the firmware */
system_start_image = systab->BootServices->StartImage;
Expand Down
3 changes: 3 additions & 0 deletions replacements.h
Expand Up @@ -41,4 +41,7 @@ extern int loader_is_participating;
extern void hook_system_services(EFI_SYSTEM_TABLE *local_systab);
extern void unhook_system_services(void);

extern EFI_STATUS install_shim_protocols(void);
extern void uninstall_shim_protocols(void);

#endif /* SHIM_REPLACEMENTS_H */
85 changes: 51 additions & 34 deletions shim.c
Expand Up @@ -1707,11 +1707,56 @@ EFI_STATUS set_second_stage (EFI_HANDLE image_handle)
return EFI_SUCCESS;
}

EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
static SHIM_LOCK shim_lock_interface;
static EFI_HANDLE shim_lock_handle;

EFI_STATUS
install_shim_protocols(void)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
EFI_STATUS efi_status;
/*
* Install the protocol
*/
efi_status = uefi_call_wrapper(BS->InstallProtocolInterface, 4,
&shim_lock_handle, &shim_lock_guid,
EFI_NATIVE_INTERFACE, &shim_lock_interface);
if (EFI_ERROR(efi_status)) {
console_error(L"Could not install security protocol",
efi_status);
return efi_status;
}

#if defined(OVERRIDE_SECURITY_POLICY)
/*
* Install the security protocol hook
*/
security_policy_install(shim_verify);
#endif

return EFI_SUCCESS;
}

void
uninstall_shim_protocols(void)
{
EFI_GUID shim_lock_guid = SHIM_LOCK_GUID;
static SHIM_LOCK shim_lock_interface;
EFI_HANDLE handle = NULL;
#if defined(OVERRIDE_SECURITY_POLICY)
/*
* Clean up the security protocol hook
*/
security_policy_uninstall();
#endif

/*
* If we're back here then clean everything up before exiting
*/
uefi_call_wrapper(BS->UninstallProtocolInterface, 3, shim_lock_handle,
&shim_lock_guid, &shim_lock_interface);
}

EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
{
EFI_STATUS efi_status;

verification_method = VERIFIED_BY_NOTHING;
Expand Down Expand Up @@ -1768,24 +1813,9 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)
}
}

/*
* Install the protocol
*/
efi_status = uefi_call_wrapper(BS->InstallProtocolInterface, 4,
&handle, &shim_lock_guid, EFI_NATIVE_INTERFACE,
&shim_lock_interface);
if (EFI_ERROR(efi_status)) {
console_error(L"Could not install security protocol",
efi_status);
efi_status = install_shim_protocols();
if (EFI_ERROR(efi_status))
return efi_status;
}

#if defined(OVERRIDE_SECURITY_POLICY)
/*
* Install the security protocol hook
*/
security_policy_install(shim_verify);
#endif

/*
* Enter MokManager if necessary
Expand All @@ -1810,20 +1840,7 @@ EFI_STATUS efi_main (EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *passed_systab)

efi_status = init_grub(image_handle);

#if defined(OVERRIDE_SECURITY_POLICY)
/*
* Clean up the security protocol hook
*/
security_policy_uninstall();
#endif

/*
* If we're back here then clean everything up before exiting
*/
uefi_call_wrapper(BS->UninstallProtocolInterface, 3, handle,
&shim_lock_guid, &shim_lock_interface);


uninstall_shim_protocols();
/*
* Remove our hooks from system services.
*/
Expand Down

0 comments on commit 06495f6

Please sign in to comment.