fallback: show a countdown menu before reset

Some machines with the faulty firmware may keep booting the default boot
path instead of the boot option we create. To avoid the infinite reset
loop, this commit introduce a countdown screen before fallback resets the
system, so the user can interrupt the system reset and choose to boot
the restored boot option. The "Always continue boot" option creates a
BS+RT+NV variable, FB_NO_REBOOT, to make fallback boot the first boot
option afterward without asking. The user can revert the behavior by
removing the variable.

https://github.com/rhboot/shim/issues/128

Signed-off-by: Gary Lin <glin@suse.com>

This is a backport from devel of:

  commit da6284569c4b5d60d14e6187f696f54cccb7b3d2
  Author: Gary Lin <glin@suse.com>
  Date:   Wed May 23 18:13:05 2018 +0800

      fallback: show a countdown menu before reset

      Some machines with the faulty firmware may keep booting the default boot
      path instead of the boot option we create. To avoid the infinite reset
      loop, this commit introduce a countdown screen before fallback resets the
      system, so the user can interrupt the system reset and choose to boot
      the restored boot option. The "Always continue boot" option creates a
      BS+RT+NV variable, FB_NO_REBOOT, to make fallback boot the first boot
      option afterward without asking. The user can revert the behavior by
      removing the variable.

      https://github.com/rhboot/shim/issues/128

      Signed-off-by: Gary Lin <glin@suse.com>

Signed-off-by: Peter Jones <pjones@redhat.com>
This commit is contained in:
Gary Lin 2018-05-23 18:13:05 +08:00 committed by Javier Martinez Canillas
parent 4e111bf1af
commit a5db51a52e

View File

@ -9,6 +9,8 @@
#include "shim.h"
#define NO_REBOOT L"FB_NO_REBOOT"
EFI_LOADED_IMAGE *this_image = NULL;
int
@ -971,6 +973,65 @@ try_start_first_option(EFI_HANDLE parent_image_handle)
return efi_status;
}
static UINT32
get_fallback_no_reboot(void)
{
EFI_STATUS efi_status;
UINT32 no_reboot;
UINTN size = sizeof(UINT32);
efi_status = gRT->GetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
NULL, &size, &no_reboot);
if (!EFI_ERROR(efi_status)) {
return no_reboot;
}
return 0;
}
static EFI_STATUS
set_fallback_no_reboot(void)
{
EFI_STATUS efi_status;
UINT32 no_reboot = 1;
efi_status = gRT->SetVariable(NO_REBOOT, &SHIM_LOCK_GUID,
EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS,
sizeof(UINT32), &no_reboot);
return efi_status;
}
static int
draw_countdown(void)
{
CHAR16 *title = L"Boot Option Restoration";
CHAR16 *message = L"Press any key to stop system reset";
int timeout;
timeout = console_countdown(title, message, 5);
return timeout;
}
static int
get_user_choice(void)
{
int choice;
CHAR16 *title[] = {L"Boot Option Restored", NULL};
CHAR16 *menu_strings[] = {
L"Reset system",
L"Continue boot",
L"Always continue boot",
NULL
};
do {
choice = console_select(title, menu_strings, 0);
} while (choice < 0 || choice > 2);
return choice;
}
extern EFI_STATUS
efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab);
@ -1037,6 +1098,26 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
VerbosePrint(L"tpm not present, starting the first image\n");
try_start_first_option(image);
} else {
if (get_fallback_no_reboot() == 1) {
VerbosePrint(L"NO_REBOOT is set, starting the first image\n");
try_start_first_option(image);
}
int timeout = draw_countdown();
if (timeout == 0)
goto reset;
int choice = get_user_choice();
if (choice == 0) {
goto reset;
} else if (choice == 2) {
efi_status = set_fallback_no_reboot();
if (EFI_ERROR(efi_status))
goto reset;
}
VerbosePrint(L"tpm present, starting the first image\n");
try_start_first_option(image);
reset:
VerbosePrint(L"tpm present, resetting system\n");
}