From ba3178b813ef2cb1838333d9845dafa20eee1a16 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Sun, 17 Jan 2016 21:48:00 +0000 Subject: [PATCH] [CMLIB/NTOSKRNL]: Move key deletion functions to cmlib, so that UEFI boot library can use them. [BOOTLIB]: Implement BCD element deletion (bootreg: implement key deletion) [BOOTMGR]: Implement BL_FATAL_ERROR_BCD_ENTRIES fatal error. [BOOTMGR]: Stubplement support for memory list data parsing (when memtest.efi will run), and stubplement support for boot persistent data blobs. [BOOTMGR]: Stubplement boot sequence support, create stub for boot entry population. [BOOTMGR]: Stubplement boot entry selection, create stub for boot entry enumeration. Mostly factoring-level changes to get us closer to the needed code paths. svn path=/trunk/; revision=70609 --- reactos/boot/environ/app/bootmgr/bootmgr.c | 174 +++++++++++++++++- reactos/boot/environ/app/bootmgr/bootmgr.h | 1 + reactos/boot/environ/include/bcd.h | 6 + reactos/boot/environ/include/bl.h | 21 +++ reactos/boot/environ/lib/bootlib.c | 30 ++- reactos/boot/environ/lib/misc/bcd.c | 60 ++++++ reactos/boot/environ/lib/misc/bootreg.c | 63 +++++++ reactos/lib/cmlib/CMakeLists.txt | 1 + .../{ntoskrnl/config => lib/cmlib}/cmkeydel.c | 9 +- reactos/lib/cmlib/cmlib.h | 7 + reactos/ntoskrnl/include/internal/cm.h | 8 - reactos/ntoskrnl/ntos.cmake | 1 - 12 files changed, 362 insertions(+), 19 deletions(-) rename reactos/{ntoskrnl/config => lib/cmlib}/cmkeydel.c (95%) diff --git a/reactos/boot/environ/app/bootmgr/bootmgr.c b/reactos/boot/environ/app/bootmgr/bootmgr.c index 68f738a67df..6b2757d4543 100644 --- a/reactos/boot/environ/app/bootmgr/bootmgr.c +++ b/reactos/boot/environ/app/bootmgr/bootmgr.c @@ -550,6 +550,23 @@ BmFatalErrorEx ( ErrorResourceId = 9002; break; + case BL_FATAL_ERROR_BCD_ENTRIES: + + /* File name is in parameter 1 */ + FileName = (PWCHAR)Parameter1; + + /* The NTSTATUS code is in parameter 2*/ + ErrorStatus = (NTSTATUS)Parameter2; + + /* Build the error string */ + swprintf(FormatString, + L"\nNo valid entries found in the boot configuration data file %s\n", + FileName); + + /* Select the resource ID message */ + ErrorResourceId = 9007; + break; + case BL_FATAL_ERROR_BCD_PARSE: /* File name isin parameter 1 */ @@ -1168,7 +1185,22 @@ BmpProcessBadMemory ( VOID ) { - EfiPrintf(L"Bad page list persistence \r\n"); + BL_PD_DATA_BLOB BadMemoryData; + NTSTATUS Status; + + /* Try to get the memory data from the memtest application */ + BadMemoryData.BlobSize = 0; + BadMemoryData.Data = NULL; + BadMemoryData.DataSize = 0; + Status = BlPdQueryData(&BadMemoryGuid, NULL, &BadMemoryData); + if (Status != STATUS_BUFFER_TOO_SMALL) + { + /* No results, or some other error */ + return Status; + } + + /* Not yet implemented */ + EfiPrintf(L"Bad page list persistence not implemented\r\n"); return STATUS_NOT_IMPLEMENTED; } @@ -1179,7 +1211,37 @@ BmPurgeOption ( _In_ ULONG Type ) { - EfiPrintf(L"Key BCD delete not yet implemented\r\n"); + HANDLE ObjectHandle; + NTSTATUS Status; + + /* Open the object */ + Status = BcdOpenObject(BcdHandle, ObjectId, &ObjectHandle); + if (NT_SUCCESS(Status)) + { + /* Delete the element */ + BcdDeleteElement(ObjectHandle, Type); + + /* Close the object and set success */ + BiCloseKey(ObjectHandle); + Status = STATUS_SUCCESS; + } + + /* Return the result */ + return Status; +} + +NTSTATUS +BmpPopulateBootEntryList ( + _In_ HANDLE BcdHandle, + _In_ PGUID SequenceList, + _In_ ULONG Flags, + _Out_ PBL_LOADED_APPLICATION_ENTRY* BootSequence, + _Out_ PULONG SequenceCount + ) +{ + EfiPrintf(L"Fixed sequences not yet supported\r\n"); + *SequenceCount = 0; + *BootSequence = NULL; return STATUS_NOT_IMPLEMENTED; } @@ -1193,9 +1255,50 @@ BmGetBootSequence ( _Out_ PULONG SequenceCount ) { - EfiPrintf(L"Fixed sequences not yet supported\r\n"); + PBL_LOADED_APPLICATION_ENTRY* Sequence; + ULONG Count; + NTSTATUS Status; + + /* Allocate the sequence list */ + Sequence = BlMmAllocateHeap(SequenceListCount * sizeof(*Sequence)); + if (!Sequence) + { + return STATUS_NO_MEMORY; + } + + /* Populate the sequence list */ + Status = BmpPopulateBootEntryList(BcdHandle, + SequenceList, + Flags, + Sequence, + &Count); + if (!NT_SUCCESS(Status)) + { + /* Free the list on failure */ + BlMmFreeHeap(Sequence); + } + else + { + /* Otherwise, set success and return the list and count */ + Status = STATUS_SUCCESS; + *BootSequence = Sequence; + *SequenceCount = Count; + } + + /* All done */ + return Status; +} + +NTSTATUS +BmEnumerateBootEntries ( + _In_ HANDLE BcdHandle, + _Out_ PBL_LOADED_APPLICATION_ENTRY **Sequence, + _Out_ PULONG SequenceCount + ) +{ + EfiPrintf(L"Boot enumeration not yet implemented\r\n"); + *Sequence = NULL; *SequenceCount = 0; - *BootSequence = NULL; return STATUS_NOT_IMPLEMENTED; } @@ -1207,8 +1310,69 @@ BmpGetSelectedBootEntry ( _Out_ PBOOLEAN ExitBootManager ) { + NTSTATUS Status; + PBL_LOADED_APPLICATION_ENTRY* Sequence; + PBL_LOADED_APPLICATION_ENTRY Entry, SelectedEntry; + ULONG Count, BootIndex; + + /* Initialize locals */ + BootIndex = 0; + Count = 0; + Sequence = NULL; + SelectedEntry = NULL; + + /* Enumerate all the boot entries */ + Status = BmEnumerateBootEntries(BcdHandle, &Sequence, &Count); + if (!NT_SUCCESS(Status)) + { + /* Bail out if we failed */ + goto Quickie; + } + + /* Check if there are no entries */ + if (!Count) + { + /* This is fatal -- kill the system */ + Status = STATUS_FILE_INVALID; + BmFatalErrorEx(BL_FATAL_ERROR_BCD_ENTRIES, (ULONG_PTR)L"\\BCD", Status, 0, 0); + goto Quickie; + } + EfiPrintf(L"Boot selection not yet implemented\r\n"); - return STATUS_NOT_IMPLEMENTED; + *SelectedBootEntry = NULL; + +Quickie: + /* We are done -- did we have a sequence? */ + if (Sequence) + { + /* Do we have any boot entries we parsed? */ + while (BootIndex < Count) + { + /* Get the current boot entry */ + Entry = Sequence[BootIndex]; + + /* Did we fail, or is is not the selected one? */ + if ((Entry) && ((Entry != SelectedEntry) || !(NT_SUCCESS(Status)))) + { + /* Destroy it, as it won't be needed */ + BlDestroyBootEntry(Entry); + } + else if (Entry == SelectedEntry) + { + /* It's the selected one, return its index */ + *EntryIndex = BootIndex; + } + + /* Move to the next entry */ + BootIndex++; + } + + /* Free the sequence of entries */ + BlMmFreeHeap(Sequence); + } + + /* Return the selection result */ + return Status; } NTSTATUS diff --git a/reactos/boot/environ/app/bootmgr/bootmgr.h b/reactos/boot/environ/app/bootmgr/bootmgr.h index ad6c148c5a2..d0115942361 100644 --- a/reactos/boot/environ/app/bootmgr/bootmgr.h +++ b/reactos/boot/environ/app/bootmgr/bootmgr.h @@ -53,6 +53,7 @@ typedef struct _BL_PACKED_BOOT_ERROR } BL_PACKED_BOOT_ERROR, *PBL_PACKED_BOOT_ERROR; #define BL_FATAL_ERROR_BCD_READ 0x01 +#define BL_FATAL_ERROR_BCD_ENTRIES 0x03 #define BL_FATAL_ERROR_GENERIC 0x04 #define BL_FATAL_ERROR_BCD_PARSE 0x07 diff --git a/reactos/boot/environ/include/bcd.h b/reactos/boot/environ/include/bcd.h index f00133c9e33..9d3d7fa98cf 100644 --- a/reactos/boot/environ/include/bcd.h +++ b/reactos/boot/environ/include/bcd.h @@ -245,6 +245,12 @@ BcdOpenObject ( _Out_ PHANDLE ObjectHandle ); +NTSTATUS +BcdDeleteElement ( + _In_ HANDLE ObjectHandle, + _In_ ULONG Type + ); + NTSTATUS BcdEnumerateAndUnpackElements ( _In_ HANDLE BcdHandle, diff --git a/reactos/boot/environ/include/bl.h b/reactos/boot/environ/include/bl.h index 0801f11922c..2a1cac435bc 100644 --- a/reactos/boot/environ/include/bl.h +++ b/reactos/boot/environ/include/bl.h @@ -47,6 +47,8 @@ /* DEFINES *******************************************************************/ +DEFINE_GUID(BadMemoryGuid, 0x54B8275B, 0xD431, 0x473F, 0xAC, 0xFB, 0xE5, 0x36, 0xA0, 0x84, 0x94, 0xA3); + #define BL_APPLICATION_FLAG_CONVERTED_FROM_EFI 0x01 #define BL_APP_ENTRY_SIGNATURE "BTAPENT" @@ -1142,6 +1144,13 @@ typedef struct _COORD ULONG Y; } COORD, *PCOORD; +typedef struct _BL_PD_DATA_BLOB +{ + PVOID Data; + ULONG DataSize; + ULONG BlobSize; +} BL_PD_DATA_BLOB, *PBL_PD_DATA_BLOB; + /* INLINE ROUTINES ***********************************************************/ FORCEINLINE @@ -1535,6 +1544,13 @@ BlDestroyBootEntry ( _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry ); +NTSTATUS +BlPdQueryData ( + _In_ const GUID* DataGuid, + _In_ PVOID Unknown, + _Inout_ PBL_PD_DATA_BLOB DataBlob + ); + /* FIRMWARE UTILITY ROUTINES *************************************************/ EFI_STATUS @@ -1774,6 +1790,11 @@ BiEnumerateSubKeys ( _Out_ PULONG SubKeyCount ); +NTSTATUS +BiDeleteKey ( + _In_ HANDLE KeyHandle + ); + VOID BiDereferenceHive ( _In_ HANDLE KeyHandle diff --git a/reactos/boot/environ/lib/bootlib.c b/reactos/boot/environ/lib/bootlib.c index 785efd8d4f0..d023532c8f1 100644 --- a/reactos/boot/environ/lib/bootlib.c +++ b/reactos/boot/environ/lib/bootlib.c @@ -20,7 +20,7 @@ BL_LOADED_APPLICATION_ENTRY BlpApplicationEntry; BOOLEAN BlpLibraryParametersInitialized; ULONG PdPersistAllocations; -LIST_ENTRY BlBadpListHead; +LIST_ENTRY BlpPdListHead; /* FUNCTIONS *****************************************************************/ @@ -283,7 +283,7 @@ InitializeLibrary ( /* Initialize the boot application persistent data */ PdPersistAllocations = 0; - InitializeListHead(&BlBadpListHead); + InitializeListHead(&BlpPdListHead); #ifdef BL_TPM_SUPPORT /* Now setup the security subsystem in phase 1 */ @@ -451,3 +451,29 @@ BlDestroyBootEntry ( /* Free the entry itself */ BlMmFreeHeap(AppEntry); } + +NTSTATUS +BlPdQueryData ( + _In_ const GUID* DataGuid, + _In_ PVOID Unknown, + _Inout_ PBL_PD_DATA_BLOB DataBlob + ) +{ + /* Check for invalid or missing parameters */ + if (!(DataBlob) || + !(DataGuid) || + ((DataBlob->BlobSize) && !(DataBlob->Data))) + { + return STATUS_INVALID_PARAMETER; + } + + /* Check if there's no persistent data blobs */ + if (IsListEmpty(&BlpPdListHead)) + { + return STATUS_NOT_FOUND; + } + + /* Not yet handled, TODO */ + EfiPrintf(L"Boot persistent data not yet implemented\r\n"); + return STATUS_NOT_IMPLEMENTED; +} diff --git a/reactos/boot/environ/lib/misc/bcd.c b/reactos/boot/environ/lib/misc/bcd.c index 31c76c5bfdf..ed0dc3643d4 100644 --- a/reactos/boot/environ/lib/misc/bcd.c +++ b/reactos/boot/environ/lib/misc/bcd.c @@ -556,6 +556,66 @@ Quickie: return Status; } +NTSTATUS +BcdDeleteElement ( + _In_ HANDLE ObjectHandle, + _In_ ULONG Type + ) +{ + NTSTATUS Status; + HANDLE ElementsHandle, ElementHandle; + WCHAR TypeString[22]; + + /* Open the elements key */ + Status = BiOpenKey(ObjectHandle, L"Elements", &ElementsHandle); + if (NT_SUCCESS(Status)) + { + /* Convert the element ID into a string */ + if (!_ultow(Type, TypeString, 16)) + { + /* Failed to do so */ + Status = STATUS_UNSUCCESSFUL; + } + else + { + /* Open the element specifically */ + Status = BiOpenKey(ElementHandle, TypeString, &ElementHandle); + if (NT_SUCCESS(Status)) + { + /* Delete it */ + Status = BiDeleteKey(ElementHandle); + if (NT_SUCCESS(Status)) + { + /* No point in closing the handle anymore */ + ElementHandle = NULL; + } + } + else + { + /* The element doesn't exist */ + Status = STATUS_NOT_FOUND; + } + + /* Check if we should close the key */ + if (ElementHandle) + { + /* Do it */ + BiCloseKey(ElementHandle); + } + } + } + + /* Check if we should close the elements handle */ + if (ElementsHandle) + { + /* Do it */ + BiCloseKey(ElementsHandle); + } + + /* Return whatever the result was */ + return Status; +} + NTSTATUS BiEnumerateSubElements ( _In_ HANDLE BcdHandle, diff --git a/reactos/boot/environ/lib/misc/bootreg.c b/reactos/boot/environ/lib/misc/bootreg.c index 278ca1c4f4d..e9eebab597a 100644 --- a/reactos/boot/environ/lib/misc/bootreg.c +++ b/reactos/boot/environ/lib/misc/bootreg.c @@ -887,3 +887,66 @@ Quickie: return Status; } +NTSTATUS +BiDeleteKey ( + _In_ HANDLE KeyHandle + ) +{ + NTSTATUS Status; + PBI_KEY_OBJECT KeyObject; + PHHIVE Hive; + ULONG SubKeyCount, i; + PWCHAR* SubKeyList; + HANDLE SubKeyHandle; + + /* Get the key object and hive */ + KeyObject = (PBI_KEY_OBJECT)KeyHandle; + Hive = &KeyObject->KeyHive->Hive.Hive; + + /* Make sure the hive is writeable */ + if (!(KeyObject->KeyHive->Flags & BI_HIVE_WRITEABLE)) + { + return STATUS_MEDIA_WRITE_PROTECTED; + } + + /* Enumerate all of the subkeys */ + Status = BiEnumerateSubKeys(KeyHandle, &SubKeyList, &SubKeyCount); + if ((NT_SUCCESS(Status)) && (SubKeyCount > 0)) + { + /* Loop through each one */ + for (i = 0; i < SubKeyCount; i++) + { + /* Open a handle to it */ + Status = BiOpenKey(KeyHandle, SubKeyList[i], &SubKeyHandle); + if (NT_SUCCESS(Status)) + { + /* Recursively call us to delete it */ + Status = BiDeleteKey(SubKeyHandle); + if (Status != STATUS_SUCCESS) + { + /* Close the key on failure */ + BiCloseKey(SubKeyHandle); + } + } + } + } + + /* Check if we had a list of subkeys */ + if (SubKeyList) + { + /* Free it */ + BlMmFreeHeap(SubKeyList); + } + + /* Delete this key cell */ + Status = CmpFreeKeyByCell(Hive, KeyObject->KeyCell, TRUE); + if (NT_SUCCESS(Status)) + { + /* Mark the hive as requiring a flush */ + KeyObject->KeyHive->Flags |= BI_FLUSH_HIVE; + BiCloseKey(KeyHandle); + } + + /* All done */ + return Status; +} \ No newline at end of file diff --git a/reactos/lib/cmlib/CMakeLists.txt b/reactos/lib/cmlib/CMakeLists.txt index 7ec7cadf2d3..88053243c38 100644 --- a/reactos/lib/cmlib/CMakeLists.txt +++ b/reactos/lib/cmlib/CMakeLists.txt @@ -6,6 +6,7 @@ add_definitions( list(APPEND SOURCE cminit.c cmindex.c + cmkeydel.c cmname.c cmvalue.c hivebin.c diff --git a/reactos/ntoskrnl/config/cmkeydel.c b/reactos/lib/cmlib/cmkeydel.c similarity index 95% rename from reactos/ntoskrnl/config/cmkeydel.c rename to reactos/lib/cmlib/cmkeydel.c index e47bc03aa82..82cfaf5c7ae 100644 --- a/reactos/ntoskrnl/config/cmkeydel.c +++ b/reactos/lib/cmlib/cmkeydel.c @@ -1,14 +1,14 @@ /* * PROJECT: ReactOS Kernel * LICENSE: GPL - See COPYING in the top level directory - * FILE: ntoskrnl/config/cmkeydel.c - * PURPOSE: Configuration Manager - Key Body Deletion + * FILE: lib/cmlib/cmkeydel.c + * PURPOSE: Configuration Manager Library - Key Body Deletion * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) */ /* INCLUDES ******************************************************************/ -#include "ntoskrnl.h" +#include "cmlib.h" #define NDEBUG #include "debug.h" @@ -214,6 +214,9 @@ CmpFreeKeyByCell(IN PHHIVE Hive, HvFreeCell(Hive, CellData->u.KeyNode.ValueList.List); } + /* FIXME: This leaks the security desriptor! */ + DPRINT1("Potentially leaking key security descriptor. Please call CmpFreeSecurityDescriptor"); + /* Free the key body itself, and then return our status */ if (!CmpFreeKeyBody(Hive, Cell)) return STATUS_INSUFFICIENT_RESOURCES; return STATUS_SUCCESS; diff --git a/reactos/lib/cmlib/cmlib.h b/reactos/lib/cmlib/cmlib.h index 69763e9acf0..2ec6eaaf413 100644 --- a/reactos/lib/cmlib/cmlib.h +++ b/reactos/lib/cmlib/cmlib.h @@ -671,6 +671,13 @@ CmpCopyKeyValueList( IN HSTORAGE_TYPE StorageType ); +NTSTATUS +NTAPI +CmpFreeKeyByCell( + IN PHHIVE Hive, + IN HCELL_INDEX Cell, + IN BOOLEAN Unlink +); /******************************************************************************/ diff --git a/reactos/ntoskrnl/include/internal/cm.h b/reactos/ntoskrnl/include/internal/cm.h index 8d641977a9c..2a6f980204f 100644 --- a/reactos/ntoskrnl/include/internal/cm.h +++ b/reactos/ntoskrnl/include/internal/cm.h @@ -1059,14 +1059,6 @@ DelistKeyBodyFromKCB( IN BOOLEAN LockHeld ); -NTSTATUS -NTAPI -CmpFreeKeyByCell( - IN PHHIVE Hive, - IN HCELL_INDEX Cell, - IN BOOLEAN Unlink -); - VOID NTAPI CmpAcquireTwoKcbLocksExclusiveByKey( diff --git a/reactos/ntoskrnl/ntos.cmake b/reactos/ntoskrnl/ntos.cmake index 728c14ed00b..2363d5fd897 100644 --- a/reactos/ntoskrnl/ntos.cmake +++ b/reactos/ntoskrnl/ntos.cmake @@ -58,7 +58,6 @@ list(APPEND SOURCE ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmhvlist.c ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cminit.c ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmkcbncb.c - ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmkeydel.c ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmlazy.c ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmmapvw.c ${REACTOS_SOURCE_DIR}/ntoskrnl/config/cmnotify.c