From 44ab46cfa981092a2ed7aca553394cc02b39eb8c Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Fri, 8 Jan 2016 06:03:55 +0000 Subject: [PATCH] [BOOTMGFW]: Implement additional startup logic [BOOTLIB]: Implement initial SecureBoot support. [BOOTLIB]: Implement UEFI Variable query support. svn path=/trunk/; revision=70543 --- reactos/boot/environ/app/bootmgr/bootmgr.c | 104 +++++++++- reactos/boot/environ/include/bl.h | 22 ++ .../boot/environ/include/efi/GlobalVariable.h | 192 ++++++++++++++++++ .../boot/environ/lib/firmware/efi/firmware.c | 158 ++++++++++++++ reactos/boot/environ/lib/misc/util.c | 55 +++++ 5 files changed, 525 insertions(+), 6 deletions(-) create mode 100644 reactos/boot/environ/include/efi/GlobalVariable.h diff --git a/reactos/boot/environ/app/bootmgr/bootmgr.c b/reactos/boot/environ/app/bootmgr/bootmgr.c index 87625df3e68..12c8bd12799 100644 --- a/reactos/boot/environ/app/bootmgr/bootmgr.c +++ b/reactos/boot/environ/app/bootmgr/bootmgr.c @@ -1041,6 +1041,16 @@ BmpBgDisplayClearScreen ( return STATUS_NOT_IMPLEMENTED; } +NTSTATUS +BlXmiWrite ( + _In_ PWCHAR XmlTag + ) +{ + /* Sigh */ + EfiPrintf(L"XML: %s\r\n", XmlTag); + return STATUS_NOT_IMPLEMENTED; +} + NTSTATUS BlXmiInitialize ( _In_ PWCHAR Stylesheet @@ -1082,17 +1092,77 @@ BmFwVerifySelfIntegrity ( VOID ) { - EfiPrintf(L"Device Type %d Local Type %d\r\n", BlpBootDevice->DeviceType, BlpBootDevice->Local.Type); + /* Check if we're booted by UEFI off the DVD directlry */ if ((BlpBootDevice->DeviceType == LocalDevice) && (BlpBootDevice->Local.Type == CdRomDevice) && (BlpApplicationFlags & BL_APPLICATION_FLAG_CONVERTED_FROM_EFI)) { + /* Windows actually bypasses integrity checks in this case. Works for us */ return STATUS_SUCCESS; } + /* Our binaries aren't signed, so always return failure */ return 0xC0000428; } +NTSTATUS +BmFwRegisterRevocationList ( + VOID + ) +{ + NTSTATUS Status; + BOOLEAN SecureBootEnabled; + + /* Is SecureBoot enabled? */ + Status = BlSecureBootIsEnabled(&SecureBootEnabled); + if ((NT_SUCCESS(Status)) && (SecureBootEnabled)) + { + EfiPrintf(L"SB not implemented revok\r\n"); + return STATUS_NOT_IMPLEMENTED; + } + else + { + /* Nothing to do without SecureBoot */ + Status = STATUS_SUCCESS; + } + + /* Return revocation result back to caller */ + return Status; +} + +NTSTATUS +BmResumeFromHibernate ( + _Out_ PHANDLE BcdResumeHandle + ) +{ + NTSTATUS Status; + BOOLEAN AttemptResume; + + /* Should we attempt to resume from hibernation? */ + Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, + BcdBootMgrBoolean_AttemptResume, + &AttemptResume); + if (!NT_SUCCESS(Status)) + { + /* Nope. Is automatic restart on crash enabled? */ + AttemptResume = FALSE; + Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, + BcdOSLoaderBoolean_DisableCrashAutoReboot, + &AttemptResume); + AttemptResume = (NT_SUCCESS(Status) && (AttemptResume)); + } + + /* Don't do anything if there's no need to resume anything */ + if (!AttemptResume) + { + return STATUS_SUCCESS; + } + + /* Not yet implemented */ + EfiPrintf(L"Resume not supported\r\n"); + return STATUS_NOT_IMPLEMENTED; +} + /*++ * @name BmMain * @@ -1116,7 +1186,7 @@ BmMain ( PBL_RETURN_ARGUMENTS ReturnArguments; BOOLEAN RebootOnError; PGUID AppIdentifier; - HANDLE BcdHandle; + HANDLE BcdHandle, ResumeBcdHandle; PBL_BCD_OPTION EarlyOptions; PWCHAR Stylesheet; BOOLEAN XmlLoaded, DisableIntegrity, TestSigning; @@ -1267,14 +1337,36 @@ BmMain ( } } -// BlXmiWrite(L""); + /* Write out the first XML tag */ + BlXmiWrite(L""); - //BlSecureBootCheckForFactoryReset(); + /* Check for factory resset */ + BlSecureBootCheckForFactoryReset(); + + /* Load the revocation list */ + Status = BmFwRegisterRevocationList(); + if (!NT_SUCCESS(Status)) + { + goto Failure; + } + + /* Register our custom progress routine */ + BlUtlRegisterProgressRoutine(); + + /* Display state is not currently cached */ + BmDisplayStateCached = FALSE; + + /* Check if w need to resume from hibernate */ + Status = BmResumeFromHibernate(&ResumeBcdHandle); + if (!NT_SUCCESS(Status)) + { + goto Failure; + } /* do more stuff!! */ - EfiPrintf(BlResourceFindMessage(BM_MSG_TEST)); - EfiPrintf(Stylesheet); + //EfiPrintf(BlResourceFindMessage(BM_MSG_TEST)); + //EfiPrintf(Stylesheet); EfiStall(10000000); Failure: diff --git a/reactos/boot/environ/include/bl.h b/reactos/boot/environ/include/bl.h index c78683ec0e8..1b24b402710 100644 --- a/reactos/boot/environ/include/bl.h +++ b/reactos/boot/environ/include/bl.h @@ -39,6 +39,7 @@ #include #include #include +#include /* Registry Headers */ #define __FREELDR_H @@ -1528,6 +1529,11 @@ BlUtlInitialize ( VOID ); +NTSTATUS +BlUtlRegisterProgressRoutine ( + VOID + ); + VOID BlFwReboot ( VOID @@ -1538,6 +1544,21 @@ BlGetApplicationIdentifier ( VOID ); +NTSTATUS +BlpSecureBootEFIIsEnabled ( + VOID + ); + +NTSTATUS +BlSecureBootIsEnabled ( + _Out_ PBOOLEAN SecureBootEnabled + ); + +NTSTATUS +BlSecureBootCheckForFactoryReset ( + VOID + ); + NTSTATUS BlGetApplicationBaseAndSize ( _Out_ PVOID* ImageBase, @@ -2302,6 +2323,7 @@ extern EFI_GUID EfiBlockIoProtocol; extern EFI_GUID EfiSimpleTextInputExProtocol; extern EFI_GUID EfiRootAcpiTableGuid; extern EFI_GUID EfiRootAcpiTable10Guid; +extern EFI_GUID EfiGlobalVariable; extern ULONG ConsoleGraphicalResolutionListFlags; extern BL_DISPLAY_MODE ConsoleGraphicalResolutionList[]; extern BL_DISPLAY_MODE ConsoleTextResolutionList[]; diff --git a/reactos/boot/environ/include/efi/GlobalVariable.h b/reactos/boot/environ/include/efi/GlobalVariable.h new file mode 100644 index 00000000000..f9737b36528 --- /dev/null +++ b/reactos/boot/environ/include/efi/GlobalVariable.h @@ -0,0 +1,192 @@ +/** @file + GUID for EFI (NVRAM) Variables. + + Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + + @par Revision Reference: + GUID defined in UEFI 2.1 +**/ + +#ifndef __GLOBAL_VARIABLE_GUID_H__ +#define __GLOBAL_VARIABLE_GUID_H__ + +#define EFI_GLOBAL_VARIABLE \ + { \ + 0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C } \ + } + +extern EFI_GUID gEfiGlobalVariableGuid; + +// +// Follow UEFI 2.4 spec: +// To prevent name collisions with possible future globally defined variables, +// other internal firmware data variables that are not defined here must be +// saved with a unique VendorGuid other than EFI_GLOBAL_VARIABLE or +// any other GUID defined by the UEFI Specification. Implementations must +// only permit the creation of variables with a UEFI Specification-defined +// VendorGuid when these variables are documented in the UEFI Specification. +// +// Note: except the globally defined variables defined below, the spec also defines +// L"Boot####" - A boot load option. +// L"Driver####" - A driver load option. +// L"SysPrep####" - A System Prep application load option. +// L"Key####" - Describes hot key relationship with a Boot#### load option. +// The attribute for them is NV+BS+RT, #### is a printed hex value, and no 0x or h +// is included in the hex value. They can not be expressed as a #define like other globally +// defined variables, it is because we can not list the Boot0000, Boot0001, etc one by one. +// + +/// +/// The language codes that the firmware supports. This value is deprecated. +/// Its attribute is BS+RT. +/// +#define EFI_LANG_CODES_VARIABLE_NAME L"LangCodes" +/// +/// The language code that the system is configured for. This value is deprecated. +/// Its attribute is NV+BS+RT. +/// +#define EFI_LANG_VARIABLE_NAME L"Lang" +/// +/// The firmware's boot managers timeout, in seconds, before initiating the default boot selection. +/// Its attribute is NV+BS+RT. +/// +#define EFI_TIME_OUT_VARIABLE_NAME L"Timeout" +/// +/// The language codes that the firmware supports. +/// Its attribute is BS+RT. +/// +#define EFI_PLATFORM_LANG_CODES_VARIABLE_NAME L"PlatformLangCodes" +/// +/// The language code that the system is configured for. +/// Its attribute is NV+BS+RT. +/// +#define EFI_PLATFORM_LANG_VARIABLE_NAME L"PlatformLang" +/// +/// The device path of the default input/output/error output console. +/// Its attribute is NV+BS+RT. +/// +#define EFI_CON_IN_VARIABLE_NAME L"ConIn" +#define EFI_CON_OUT_VARIABLE_NAME L"ConOut" +#define EFI_ERR_OUT_VARIABLE_NAME L"ErrOut" +/// +/// The device path of all possible input/output/error output devices. +/// Its attribute is BS+RT. +/// +#define EFI_CON_IN_DEV_VARIABLE_NAME L"ConInDev" +#define EFI_CON_OUT_DEV_VARIABLE_NAME L"ConOutDev" +#define EFI_ERR_OUT_DEV_VARIABLE_NAME L"ErrOutDev" +/// +/// The ordered boot option load list. +/// Its attribute is NV+BS+RT. +/// +#define EFI_BOOT_ORDER_VARIABLE_NAME L"BootOrder" +/// +/// The boot option for the next boot only. +/// Its attribute is NV+BS+RT. +/// +#define EFI_BOOT_NEXT_VARIABLE_NAME L"BootNext" +/// +/// The boot option that was selected for the current boot. +/// Its attribute is BS+RT. +/// +#define EFI_BOOT_CURRENT_VARIABLE_NAME L"BootCurrent" +/// +/// The types of boot options supported by the boot manager. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME L"BootOptionSupport" +/// +/// The ordered driver load option list. +/// Its attribute is NV+BS+RT. +/// +#define EFI_DRIVER_ORDER_VARIABLE_NAME L"DriverOrder" +/// +/// The ordered System Prep Application load option list. +/// Its attribute is NV+BS+RT. +/// +#define EFI_SYS_PREP_ORDER_VARIABLE_NAME L"SysPrepOrder" +/// +/// Identifies the level of hardware error record persistence +/// support implemented by the platform. This variable is +/// only modified by firmware and is read-only to the OS. +/// Its attribute is NV+BS+RT. +/// +#define EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME L"HwErrRecSupport" +/// +/// Whether the system is operating in setup mode (1) or not (0). +/// All other values are reserved. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_SETUP_MODE_NAME L"SetupMode" +/// +/// The Key Exchange Key Signature Database. +/// Its attribute is NV+BS+RT+AT. +/// +#define EFI_KEY_EXCHANGE_KEY_NAME L"KEK" +/// +/// The public Platform Key. +/// Its attribute is NV+BS+RT+AT. +/// +#define EFI_PLATFORM_KEY_NAME L"PK" +/// +/// Array of GUIDs representing the type of signatures supported +/// by the platform firmware. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_SIGNATURE_SUPPORT_NAME L"SignatureSupport" +/// +/// Whether the platform firmware is operating in Secure boot mode (1) or not (0). +/// All other values are reserved. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_SECURE_BOOT_MODE_NAME L"SecureBoot" +/// +/// The OEM's default Key Exchange Key Signature Database. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_KEK_DEFAULT_VARIABLE_NAME L"KEKDefault" +/// +/// The OEM's default public Platform Key. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_PK_DEFAULT_VARIABLE_NAME L"PKDefault" +/// +/// The OEM's default secure boot signature store. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_DB_DEFAULT_VARIABLE_NAME L"dbDefault" +/// +/// The OEM's default secure boot blacklist signature store. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_DBX_DEFAULT_VARIABLE_NAME L"dbxDefault" +/// +/// The OEM's default secure boot timestamp signature store. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_DBT_DEFAULT_VARIABLE_NAME L"dbtDefault" +/// +/// Allows the firmware to indicate supported features and actions to the OS. +/// Its attribute is BS+RT. +/// +#define EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME L"OsIndicationsSupported" +/// +/// Allows the OS to request the firmware to enable certain features and to take certain actions. +/// Its attribute is NV+BS+RT. +/// +#define EFI_OS_INDICATIONS_VARIABLE_NAME L"OsIndications" +/// +/// Whether the system is configured to use only vendor provided +/// keys or not. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_VENDOR_KEYS_VARIABLE_NAME L"VendorKeys" + +#endif diff --git a/reactos/boot/environ/lib/firmware/efi/firmware.c b/reactos/boot/environ/lib/firmware/efi/firmware.c index 97c592f3d67..3f520f8032b 100644 --- a/reactos/boot/environ/lib/firmware/efi/firmware.c +++ b/reactos/boot/environ/lib/firmware/efi/firmware.c @@ -33,9 +33,14 @@ EFI_GUID EfiSimpleTextInputExProtocol = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; EFI_GUID EfiBlockIoProtocol = EFI_BLOCK_IO_PROTOCOL_GUID; EFI_GUID EfiRootAcpiTableGuid = EFI_ACPI_20_TABLE_GUID; EFI_GUID EfiRootAcpiTable10Guid = EFI_ACPI_TABLE_GUID; +EFI_GUID EfiGlobalVariable = EFI_GLOBAL_VARIABLE; +EFI_GUID BlpEfiSecureBootPrivateNamespace = { 0x77FA9ABD , 0x0359, 0x4D32, { 0xBD, 0x60, 0x28, 0xF4, 0xE7, 0x8F, 0x78, 0x4B } }; WCHAR BlScratchBuffer[8192]; +BOOLEAN BlpFirmwareChecked; +BOOLEAN BlpFirmwareEnabled; + /* FUNCTIONS *****************************************************************/ EFI_DEVICE_PATH * @@ -268,6 +273,159 @@ EfiCloseProtocol ( return Status; } +NTSTATUS +EfiGetVariable ( + _In_ PWCHAR VariableName, + _In_ EFI_GUID* VendorGuid, + _Out_opt_ PULONG Attributes, + _Inout_ PULONG DataSize, + _Out_ PVOID Data + ) +{ + EFI_STATUS EfiStatus; + NTSTATUS Status; + BL_ARCH_MODE OldMode; + ULONG LocalAttributes; + + /* Are we in protected mode? */ + OldMode = CurrentExecutionContext->Mode; + if (OldMode != BlRealMode) + { + /* FIXME: Not yet implemented */ + return STATUS_NOT_IMPLEMENTED; + } + + /* Call the runtime API */ + EfiStatus = EfiRT->GetVariable(VariableName, + VendorGuid, + (UINT32*)&LocalAttributes, + (UINTN*)DataSize, + Data); + + /* Switch back to protected mode if we came from there */ + if (OldMode != BlRealMode) + { + BlpArchSwitchContext(OldMode); + } + + /* Return attributes back to the caller if asked to */ + if (Attributes) + { + *Attributes = LocalAttributes; + } + + /* Convert the errot to an NTSTATUS and return it */ + Status = EfiGetNtStatusCode(EfiStatus); + return Status; +} + +NTSTATUS +BlpSecureBootEFIIsEnabled ( + VOID + ) +{ + NTSTATUS Status; + BOOLEAN SetupMode, SecureBoot; + ULONG DataSize; + + /* Assume setup mode enabled, and no secure boot */ + SecureBoot = FALSE; + SetupMode = TRUE; + + /* Get the SetupMode variable */ + DataSize = sizeof(SetupMode); + Status = EfiGetVariable(L"SetupMode", + &EfiGlobalVariable, + NULL, + &DataSize, + &SetupMode); + if (NT_SUCCESS(Status)) + { + /* If it worked, get the SecureBoot variable */ + DataSize = sizeof(SecureBoot); + Status = EfiGetVariable(L"SecureBoot", + &EfiGlobalVariable, + NULL, + &DataSize, + &SecureBoot); + if (NT_SUCCESS(Status)) + { + /* In setup mode or without secureboot turned on, return failure */ + if ((SecureBoot != TRUE) || (SetupMode)) + { + Status = STATUS_INVALID_SIGNATURE; + } + + // BlpSbdiStateFlags |= 8u; + } + } + + /* Return secureboot status */ + return Status; +} + +NTSTATUS +BlSecureBootIsEnabled ( + _Out_ PBOOLEAN SecureBootEnabled + ) +{ + NTSTATUS Status; + + /* Have we checked before ? */ + if (!BlpFirmwareChecked) + { + /* First time checking */ + Status = BlpSecureBootEFIIsEnabled(); + if NT_SUCCESS(Status) + { + /* Yep, it's on */ + BlpFirmwareEnabled = TRUE; + } + + /* Don't check again */ + BlpFirmwareChecked = TRUE; + } + + /* Return the firmware result */ + *SecureBootEnabled = BlpFirmwareEnabled; + return STATUS_SUCCESS; +} + +NTSTATUS +BlSecureBootCheckForFactoryReset ( + VOID + ) +{ + BOOLEAN SecureBootEnabled; + NTSTATUS Status; + ULONG DataSize; + + /* Initialize locals */ + DataSize = 0; + SecureBootEnabled = FALSE; + + /* Check if secureboot is enabled */ + Status = BlSecureBootIsEnabled(&SecureBootEnabled); + if (!(NT_SUCCESS(Status)) || !(SecureBootEnabled)) + { + /* It's not. Check if there's a revocation list */ + Status = EfiGetVariable(L"RevocationList", + &BlpEfiSecureBootPrivateNamespace, + NULL, + &DataSize, + NULL); + if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL)) + { + /* We don't support this yet */ + EfiPrintf(L"Not yet supported\r\n"); + Status = STATUS_NOT_IMPLEMENTED; + } + } + + /* Return back to the caller */ + return Status; +} + NTSTATUS EfiConInReset ( VOID diff --git a/reactos/boot/environ/lib/misc/util.c b/reactos/boot/environ/lib/misc/util.c index dbeb79a6d14..bd37bebe8bb 100644 --- a/reactos/boot/environ/lib/misc/util.c +++ b/reactos/boot/environ/lib/misc/util.c @@ -28,6 +28,8 @@ ULONG UtlNextUpdatePercentage; BOOLEAN UtlProgressNeedsInfoUpdate; PVOID UtlProgressInfo; + + /* FUNCTIONS *****************************************************************/ NTSTATUS @@ -176,6 +178,7 @@ BlUtlGetAcpiTable ( return STATUS_NOT_FOUND; } + VOID BlUtlUpdateProgress ( _In_ ULONG Percentage, @@ -216,6 +219,58 @@ BlUtlInitialize ( return STATUS_SUCCESS; } +VOID +BmUpdateProgressInfo ( + _In_ PVOID Uknown, + _In_ PWCHAR ProgressInfo + ) +{ + EfiPrintf(L"Progress Info: %s\r\n", ProgressInfo); +} + +VOID +BmUpdateProgress ( + _In_ PVOID Unknown, + _In_ ULONG Percent, + _Out_ PBOOLEAN Completed + ) +{ + EfiPrintf(L"Progress: %d\r\n", Percent); + if (Completed) + { + *Completed = TRUE; + } +} + +NTSTATUS +BlUtlRegisterProgressRoutine ( + VOID + ) +{ + /* One shouldn't already exist */ + if (UtlProgressRoutine) + { + return STATUS_UNSUCCESSFUL; + } + + /* Set the routine, and no context */ + UtlProgressRoutine = BmUpdateProgress; + UtlProgressContext = NULL; + + /* Progress increases by one */ + UtlProgressGranularity = 1; + + /* Set progress to zero for now */ + UtlCurrentPercentComplete = 0; + UtlNextUpdatePercentage = 0; + + /* Set the info routine if there is one */ + UtlProgressInfoRoutine = BmUpdateProgressInfo; + + /* All good */ + return STATUS_SUCCESS; +} + PVOID BlTblFindEntry ( _In_ PVOID *Table,