NTSTATUS FatInitialize ( VOID ) { NTSTATUS Status; /* Allocate the device table with 2 entries*/ FatDeviceTableEntries = 2; FatDeviceTable = BlMmAllocateHeap(sizeof(PBL_FILE_ENTRY) * FatDeviceTableEntries); if (FatDeviceTable) { /* Zero it out */ RtlZeroMemory(FatDeviceTable, sizeof(PBL_FILE_ENTRY) * FatDeviceTableEntries); /* Allocate a 512 byte buffer for long file name conversion */ FatpLongFileName = BlMmAllocateHeap(512); Status = FatpLongFileName != NULL ? STATUS_SUCCESS : STATUS_NO_MEMORY; } else { /* No memory, fail */ Status = STATUS_NO_MEMORY; } /* Return back to caller */ return Status; }
NTSTATUS BlCopyBootOptions ( _In_ PBL_BCD_OPTION OptionList, _Out_ PBL_BCD_OPTION *CopiedOptions ) { NTSTATUS Status; ULONG OptionSize; PBL_BCD_OPTION Options; /* Assume no options */ Status = STATUS_SUCCESS; *CopiedOptions = NULL; /* Get the size of the list and allocate a copy for it */ OptionSize = BlGetBootOptionListSize(OptionList); Options = BlMmAllocateHeap(OptionSize); if (!Options) { return STATUS_NO_MEMORY; } /* Make the copy and return it to the caller */ RtlCopyMemory(Options, OptionList, OptionSize); *CopiedOptions = Options; return Status; }
NTSTATUS MmBaInitialize ( VOID ) { NTSTATUS Status; ULONG Size; /* Allocate 8 table entries */ MmBlockAllocatorTableEntries = 8; Size = sizeof(BL_BLOCK_DESCRIPTOR) * MmBlockAllocatorTableEntries; MmBlockAllocatorTable = BlMmAllocateHeap(Size); if (MmBlockAllocatorTable) { /* Zero them out -- we're all done */ Status = STATUS_SUCCESS; RtlZeroMemory(MmBlockAllocatorTable, Size); MmBlockAllocatorInitialized = 1; } else { /* Bail out since we're out of memory */ Status = STATUS_NO_MEMORY; MmBlockAllocatorInitialized = 0; } /* Return initialization status */ return Status; }
NTSTATUS BlpIoInitialize ( VOID ) { NTSTATUS Status; ULONG Size; /* Allocate the I/O table */ IoMgrRoutineEntries = 4; Size = IoMgrRoutineEntries * sizeof(PVOID); IoMgrDestroyRoutineTable = BlMmAllocateHeap(Size); if (IoMgrDestroyRoutineTable) { /* Zero it out */ RtlZeroMemory(IoMgrDestroyRoutineTable, Size); /* Initialize the device manager */ Status = BlpDeviceInitialize(); /* Initialize the file manager */ if (NT_SUCCESS(Status)) { Status = BlpFileInitialize(); } } else { /* No memory */ Status = STATUS_NO_MEMORY; } /* Return initialization status */ return Status; }
PWCHAR FileIoCopyFileName ( _In_ PWCHAR FilePath ) { PWCHAR Separator, FileCopy; ULONG PathSize; Separator = wcsrchr(FilePath, '\\'); if (!Separator) { return NULL; } PathSize = wcslen(Separator) * sizeof(WCHAR); FileCopy = BlMmAllocateHeap(PathSize); if (!FileCopy) { return NULL; } wcsncpy(FileCopy, Separator + 1, PathSize / sizeof(WCHAR)); return FileCopy; }
NTSTATUS BlpMmCreateBlockAllocator ( VOID ) { PBL_BLOCK_DESCRIPTOR BlockInfo; ULONG BlockId; NTSTATUS Status; /* If the block allocator isn't initialized, bail out */ BlockId = -1; if (!MmBlockAllocatorInitialized) { goto Quickie; } /* Allocate a block descriptor and zero it out */ BlockInfo = BlMmAllocateHeap(sizeof(*BlockInfo)); if (!BlockInfo) { goto Quickie; } RtlZeroMemory(BlockInfo, sizeof(*BlockInfo)); /* Setup the block descriptor */ BlockInfo->Attributes = 0; BlockInfo->Type = BlLoaderBlockMemory; BlockInfo->Unknown = 1; BlockInfo->Unknown2 = 1; BlockInfo->Size = PAGE_SIZE; BlockInfo->Count = 128; BlockInfo->Count2 = 128; InitializeListHead(&BlockInfo->ListHead); /* Add it to the list of block descriptors */ Status = BlTblSetEntry(&MmBlockAllocatorTable, &MmBlockAllocatorTableEntries, BlockInfo, &BlockId, MmBapPurgeBlockAllocatorTableEntry); if (NT_SUCCESS(Status)) { /* Add the initial reference and store the block ID */ BlockInfo->ReferenceCount = 1; BlockInfo->BlockId = BlockId; } Quickie: /* On failure, free the block descriptor */ if (BlockId == -1) { BlMmFreeHeap(BlockInfo); } /* Return the block descriptor ID, or -1 on failure */ return BlockId; }
PVOID NTAPI RtlpAllocateMemory ( _In_ ULONG Bytes, _In_ ULONG Tag ) { UNREFERENCED_PARAMETER(Tag); return BlMmAllocateHeap(Bytes); }
NTSTATUS BlpGetBootOptionIntegerList ( _In_ PBL_BCD_OPTION List, _In_ ULONG Type, _Out_ PULONGLONG* Value, _Out_ PULONGLONG Count, _In_ BOOLEAN NoCopy ) { PBL_BCD_OPTION Option; BcdElementType ElementType; PULONGLONG ValueCopy; /* Make sure this is a BCD_TYPE_INTEGER_LIST */ ElementType.PackedValue = Type; if (ElementType.Format != BCD_TYPE_INTEGER_LIST) { return STATUS_INVALID_PARAMETER; } /* Return the data */ Option = MiscGetBootOption(List, Type); if (!Option) { return STATUS_NOT_FOUND; } /* Check if a copy should be made of it */ if (NoCopy) { /* Nope, return the raw value */ *Value = (PULONGLONG)((ULONG_PTR)Option + Option->DataOffset); } else { /* Allocate a buffer for the copy */ ValueCopy = BlMmAllocateHeap(Option->DataSize); if (!ValueCopy) { return STATUS_NO_MEMORY; } /* Copy the data in */ RtlCopyMemory(ValueCopy, (PVOID)((ULONG_PTR)Option + Option->DataOffset), Option->DataSize); /* Return our copy */ *Value = ValueCopy; } /* Return count and success */ *Count = Option->DataSize / sizeof(ULONGLONG); return STATUS_SUCCESS; }
NTSTATUS BlGetBootOptionGuidList ( _In_ PBL_BCD_OPTION List, _In_ ULONG Type, _Out_ PGUID *Value, _In_ PULONG Count ) { NTSTATUS Status; PBL_BCD_OPTION Option; PGUID GuidCopy, Guid; ULONG GuidCount; BcdElementType ElementType; /* Make sure this is a BCD_TYPE_OBJECT_LIST */ ElementType.PackedValue = Type; if (ElementType.Format != BCD_TYPE_OBJECT_LIST) { return STATUS_INVALID_PARAMETER; } /* Return the data */ Option = MiscGetBootOption(List, Type); if (!Option) { /* Set failure if no data exists */ Status = STATUS_NOT_FOUND; } else { /* Get the GUIDs and allocate a copy for them */ Guid = (PGUID)((ULONG_PTR)Option + Option->DataOffset); GuidCopy = BlMmAllocateHeap(Option->DataSize); if (GuidCopy) { /* Copy the GUIDs */ RtlCopyMemory(GuidCopy, Guid, Option->DataSize); /* Return the number of GUIDs and the start of the array */ GuidCount = Option->DataSize / sizeof(GUID); *Value = GuidCopy; *Count = GuidCount; Status = STATUS_SUCCESS; } else { /* No memory for the copy */ Status = STATUS_NO_MEMORY; } } /* All good */ return Status; }
NTSTATUS BlHtStore ( _In_ ULONG TableId, _In_ PBL_HASH_ENTRY Entry, _In_ PVOID Data, _In_ ULONG DataSize ) { PBL_HASH_NODE HashNode; NTSTATUS Status; PLIST_ENTRY HashLinkHead; PBL_HASH_TABLE HashTable; /* Check for invalid tablle ID, missing arguments, or malformed entry */ if ((HtTableSize <= TableId) || !(Entry) || !(Data) || !(Entry->Size) || !(Entry->Value) || !(DataSize) || ((Entry->Flags & BL_HT_VALUE_IS_INLINE) && (Entry->Size != sizeof(ULONG)))) { /* Fail the call */ Status = STATUS_INVALID_PARAMETER; goto Quickie; } /* Get the hash table for this ID */ HashTable = HtTableArray[TableId]; /* Allocate a hash node */ HashNode = BlMmAllocateHeap(sizeof(*HashNode)); if (!HashNode) { Status = STATUS_NO_MEMORY; goto Quickie; } /* Capture all the data*/ HashNode->Entry.Size = Entry->Size; HashNode->Entry.Flags = Entry->Flags; HashNode->Entry.Value = Entry->Value; HashNode->Value.DataSize = DataSize; HashNode->Value.Data = Data; /* Insert it into the bucket list and return success */ HashLinkHead = &HashTable->HashLinks[HashTable->HashFunction(Entry, HashTable->Size)]; InsertTailList(HashLinkHead, &HashNode->ListEntry); Status = STATUS_SUCCESS; Quickie: return Status; }
VOID MmMdFreeGlobalDescriptors ( VOID ) { PBL_MEMORY_DESCRIPTOR Descriptor, OldDescriptor; ULONG Index = 0; PLIST_ENTRY OldFlink, OldBlink; /* Make sure we're not int middle of a call using a descriptor */ if (MmDescriptorCallTreeCount != 1) { return; } /* Loop every current global descriptor */ while (Index < MmGlobalMemoryDescriptorsUsed) { /* Does it have any valid pageS? */ OldDescriptor = &MmGlobalMemoryDescriptors[Index]; if (OldDescriptor->PageCount) { /* Allocate a copy of it */ Descriptor = BlMmAllocateHeap(sizeof(*Descriptor)); if (!Descriptor) { return; } /* Save the links */ OldBlink = OldDescriptor->ListEntry.Blink; OldFlink = OldDescriptor->ListEntry.Flink; /* Make the copy */ *Descriptor = *OldDescriptor; /* Fix the links */ OldBlink->Flink = &Descriptor->ListEntry; OldFlink->Blink = &Descriptor->ListEntry; /* Zero the descriptor */ RtlZeroMemory(OldDescriptor, sizeof(*OldDescriptor)); } /* Keep going */ Index++; } /* All global descriptors freed */ MmGlobalMemoryDescriptorsUsed = 0; }
PVOID NTAPI CmpAllocate ( _In_ SIZE_T Size, _In_ BOOLEAN Paged, _In_ ULONG Tag ) { UNREFERENCED_PARAMETER(Paged); UNREFERENCED_PARAMETER(Tag); /* Call the heap allocator */ return BlMmAllocateHeap(Size); }
NTSTATUS BlpFileRegisterFileSystem ( _In_ PBL_FS_INIT_CALLBACK InitCallback, _In_ PBL_FS_DESTROY_CALLBACK DestroyCallback, _In_ PBL_FS_MOUNT_CALLBACK MountCallback, _In_ PBL_FS_PURGE_CALLBACK PurgeCallback, _In_ ULONG Flags ) { PBL_FILE_SYSTEM_ENTRY FsEntry; NTSTATUS Status; /* Allocate an entry */ FsEntry = BlMmAllocateHeap(sizeof(*FsEntry)); if (!FsEntry) { return STATUS_NO_MEMORY; } /* Initialize the file system */ Status = InitCallback(); if (!NT_SUCCESS(Status)) { BlMmFreeHeap(FsEntry); return Status; } /* Register the callbacks */ FsEntry->MountCallback = MountCallback; FsEntry->DestroyCallback = DestroyCallback; FsEntry->InitCallback = InitCallback; FsEntry->PurgeCallback = PurgeCallback; /* Insert in the right location in the list */ if (Flags & BL_FS_REGISTER_AT_HEAD_FLAG) { InsertHeadList(&RegisteredFileSystems, &FsEntry->ListEntry); } else { InsertTailList(&RegisteredFileSystems, &FsEntry->ListEntry); } /* Return */ return STATUS_SUCCESS; }
NTSTATUS BcdOpenStoreFromFile ( _In_ PUNICODE_STRING FileName, _In_ PHANDLE BcdHandle ) { ULONG Length; PBL_FILE_PATH_DESCRIPTOR FilePath; NTSTATUS Status; HANDLE LocalHandle; /* Assume failure */ LocalHandle = NULL; /* Allocate a path descriptor */ Length = FileName->Length + sizeof(*FilePath); FilePath = BlMmAllocateHeap(Length); if (!FilePath) { return STATUS_NO_MEMORY; } /* Initialize it */ FilePath->Version = 1; FilePath->PathType = InternalPath; FilePath->Length = Length; /* Copy the name and NULL-terminate it */ RtlCopyMemory(FilePath->Path, FileName->Buffer, Length); FilePath->Path[Length / sizeof(WCHAR)] = UNICODE_NULL; /* Open the BCD */ Status = BiAddStoreFromFile(FilePath, &LocalHandle); if (NT_SUCCESS(Status)) { /* Return the handle on success */ *BcdHandle = LocalHandle; } /* Free the descriptor and return the status */ BlMmFreeHeap(FilePath); return Status; }
PWCHAR FileIoCopyParentDirectoryPath ( _In_ PWCHAR FilePath ) { ULONG PathSize, PathSizeWithNull; PWCHAR Backslash, ParentCopy; PathSize = wcslen(FilePath) * sizeof(WCHAR); PathSizeWithNull = PathSize + sizeof(UNICODE_NULL); if (PathSizeWithNull < PathSize) { return NULL; } ParentCopy = BlMmAllocateHeap(PathSizeWithNull); if (!ParentCopy) { return NULL; } wcsncpy(ParentCopy, FilePath, PathSizeWithNull / sizeof(WCHAR)); Backslash = wcsrchr(ParentCopy, '\\'); if (!Backslash) { BlMmFreeHeap(ParentCopy); return NULL; } if (Backslash == ParentCopy) { ++Backslash; } *Backslash = UNICODE_NULL; return ParentCopy; }
NTSTATUS BlTblSetEntry ( _Inout_ PVOID** Table, _Inout_ PULONG Count, _In_ PVOID Entry, _Out_ PULONG EntryIndex, _In_ PBL_TBL_SET_ROUTINE Callback ) { ULONG NewCount; NTSTATUS Status = STATUS_SUCCESS; ULONG Index = 0; PVOID* NewTable; /* Make sure all the parameters were specified */ if (!(Table) || !(*Table) || !(Count) || !(Callback)) { return STATUS_INVALID_PARAMETER; } /* Read the current table */ NewTable = *Table; NewCount = *Count; /* Iterate over it */ while (Index < NewCount) { /* Look for a free index */ if (!NewTable[Index]) { goto SetIndex; } /* No free index yet, keep going */ ++Index; } /* No free index was found, try to purge some entries */ Index = 0; while (Index < NewCount) { /* Call each purge callback, trying to make space */ Status = Callback(NewTable[Index]); if (NT_SUCCESS(Status)) { /* We should have this slot available now */ goto SetIndex; } /* Keep trying to purge more */ ++Index; } /* Double the table */ NewTable = BlMmAllocateHeap(2 * sizeof(PVOID) * NewCount); if (!NewTable) { return STATUS_NO_MEMORY; } /* Clear the new table, and copy the old entries */ RtlZeroMemory(&NewTable[NewCount], sizeof(PVOID) * NewCount); RtlCopyMemory(NewTable, *Table, sizeof(PVOID) * NewCount); /* Free the old table */ BlMmFreeHeap(*Table); /* Return the new table and count */ *Count = 2 * NewCount; *Table = NewTable; SetIndex: /* Set the index and return */ NewTable[Index] = Entry; *EntryIndex = Index; return Status; }
NTSTATUS BlpFileInitialize ( VOID ) { NTSTATUS Status; /* Allocate the file table */ FileEntries = 16; FileTable = BlMmAllocateHeap(sizeof(PBL_FILE_ENTRY) * FileEntries); if (!FileTable) { return STATUS_INVALID_PARAMETER; } /* Initialize it */ RtlZeroMemory(FileTable, sizeof(PBL_FILE_ENTRY) * FileEntries); InitializeListHead(&RegisteredFileSystems); #if 0 /* Initialize the network file system */ Status = BlpFileRegisterFileSystem(NetRegisterFunctionTable.Init, NetRegisterFunctionTable.Destroy, NetRegisterFunctionTable.Mount, NetRegisterFunctionTable.Purge, 1); if (NT_SUCCESS(Status)) { /* Initialize NTFS */ Status = BlpFileRegisterFileSystem(NtfsRegisterFunctionTable.Init, NtfsRegisterFunctionTable.Destroy, NtfsRegisterFunctionTable.Mount, NtfsRegisterFunctionTable.Purge, 0); } if (NT_SUCCESS(Status)) #endif { /* Initialize FAT */ Status = BlpFileRegisterFileSystem(FatRegisterFunctionTable.Init, FatRegisterFunctionTable.Destroy, FatRegisterFunctionTable.Mount, FatRegisterFunctionTable.Purge, 0); } #if 0 if (NT_SUCCESS(Status)) { /* Initialize EXFAT (FatPlus) */ Status = BlpFileRegisterFileSystem(FppRegisterFunctionTable.Init, FppRegisterFunctionTable.Destroy, FppRegisterFunctionTable.Mount, FppRegisterFunctionTable.Purge, 0); } if (NT_SUCCESS(Status)) { /* Initialize WIM */ Status = BlpFileRegisterFileSystem(WimRegisterFunctionTable.Init, WimRegisterFunctionTable.Destroy, WimRegisterFunctionTable.Mount, WimRegisterFunctionTable.Purge, 0); } if (NT_SUCCESS(Status)) { /* Initialize UDFS */ Status = BlpFileRegisterFileSystem(UdfsRegisterFunctionTable.Init, UdfsRegisterFunctionTable.Destroy, UdfsRegisterFunctionTable.Mount, UdfsRegisterFunctionTable.Purge, 0); } #endif if (NT_SUCCESS(Status)) { /* Initialize El-Torito CDFS */ Status = BlpFileRegisterFileSystem(EtfsRegisterFunctionTable.Init, EtfsRegisterFunctionTable.Destroy, EtfsRegisterFunctionTable.Mount, EtfsRegisterFunctionTable.Purge, 0); } /* Destroy the file manager if any of the file systems didn't initialize */ if (!NT_SUCCESS(Status)) { if (FileTable) { //BlpFileDestroy(); } } return Status; }
NTSTATUS BiEnumerateElements ( _In_ HANDLE BcdHandle, _In_ HANDLE ObjectHandle, _In_ ULONG RootElementType, _In_ ULONG Flags, _Out_opt_ PBCD_PACKED_ELEMENT Elements, _Inout_ PULONG ElementSize, _Out_ PULONG ElementCount ) { HANDLE ElementsHandle, ElementHandle; ULONG TotalLength, RegistryElementDataLength, RemainingLength; NTSTATUS Status; ULONG i; PVOID ElementData, SubObjectList, RegistryElementData; BcdElementType ElementType; PBCD_PACKED_ELEMENT PreviousElement, ElementsStart; ULONG SubElementCount, SubKeyCount, SubObjectCount, ElementDataLength; PWCHAR ElementName; PWCHAR* SubKeys; /* Assume failure */ *ElementCount = 0; /* Initialize all locals that are checked at the end*/ SubKeys = NULL; ElementsHandle = NULL; ElementHandle = NULL; ElementData = NULL; RegistryElementData = NULL; PreviousElement = NULL; ElementName = NULL; SubObjectList = NULL; TotalLength = 0; ElementDataLength = 0; SubObjectCount = 0; RemainingLength = 0; ElementsStart = Elements; /* Open the root object key's elements */ Status = BiOpenKey(ObjectHandle, L"Elements", &ElementsHandle); if (!NT_SUCCESS(Status)) { goto Quickie; } /* Enumerate all elements */ Status = BiEnumerateSubKeys(ElementsHandle, &SubKeys, &SubKeyCount); if (!NT_SUCCESS(Status)) { goto Quickie; } /* Iterate over each one */ for (i = 0; i < SubKeyCount; i++) { /* Open the element */ ElementName = SubKeys[i]; Status = BiOpenKey(ElementsHandle, ElementName, &ElementHandle); if (!NT_SUCCESS(Status)) { EfiPrintf(L"ELEMENT ERROR: %lx\r\n", Status); EfiStall(100000); break; } /* The name of the element is its data type */ ElementType.PackedValue = wcstoul(SubKeys[i], NULL, 16); if (!(ElementType.PackedValue) || (ElementType.PackedValue == -1)) { EfiPrintf(L"Value invalid\r\n"); BiCloseKey(ElementHandle); ElementHandle = 0; continue; } /* Read the appropriate registry value type for this element */ Status = BiGetRegistryValue(ElementHandle, L"Element", BiConvertElementFormatToValueType( ElementType.Format), &RegistryElementData, &RegistryElementDataLength); if (!NT_SUCCESS(Status)) { EfiPrintf(L"Element invalid\r\n"); break; } /* Now figure out how much space the converted element will need */ ElementDataLength = 0; Status = BiConvertRegistryDataToElement(ObjectHandle, RegistryElementData, RegistryElementDataLength, ElementType, NULL, &ElementDataLength); if (Status != STATUS_BUFFER_TOO_SMALL) { break; } /* Allocate a buffer big enough for the converted element */ ElementData = BlMmAllocateHeap(ElementDataLength); if (!ElementData) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } /* And actually convert it this time around */ Status = BiConvertRegistryDataToElement(ObjectHandle, RegistryElementData, RegistryElementDataLength, ElementType, ElementData, &ElementDataLength); if (!NT_SUCCESS(Status)) { break; } /* Safely add space for the packed element header */ Status = RtlULongAdd(TotalLength, FIELD_OFFSET(BCD_PACKED_ELEMENT, Data), &TotalLength); if (!NT_SUCCESS(Status)) { break; } /* Safely add space for the data of the element itself */ Status = RtlULongAdd(TotalLength, ElementDataLength, &TotalLength); if (!NT_SUCCESS(Status)) { break; } /* One more element */ ++*ElementCount; /* See how much space we were given */ RemainingLength = *ElementSize; if (RemainingLength >= TotalLength) { /* Set the next pointer */ Elements->NextEntry = (PBCD_PACKED_ELEMENT)((ULONG_PTR)ElementsStart + TotalLength); /* Fill this one out */ Elements->RootType.PackedValue = RootElementType; Elements->Version = 1; Elements->Type = ElementType.PackedValue; Elements->Size = ElementDataLength; /* Add the data */ RtlCopyMemory(Elements->Data, ElementData, ElementDataLength); RemainingLength -= TotalLength; /* Move to the next element on the next pass */ PreviousElement = Elements; Elements = Elements->NextEntry; } else { /* We're out of space */ RemainingLength = 0; } /* Are we enumerating devices, and is this a device? */ if ((Flags & BCD_ENUMERATE_FLAG_DEVICES) && (ElementType.Format == BCD_TYPE_DEVICE)) { /* Yep, so go inside to enumerate it */ Status = BiEnumerateSubElements(BcdHandle, ElementData, ElementType.PackedValue, Flags, &Elements, &ElementDataLength, &SubElementCount); if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL)) { /* Safely add the length of the sub elements */ Status = RtlULongAdd(TotalLength, ElementDataLength, &TotalLength); if (!NT_SUCCESS(Status)) { break; } /* Add the sub elements to the total */ *ElementCount += SubElementCount; /* See if we have enough space*/ if (*ElementSize >= TotalLength) { /* Were there any subelements? */ if (SubElementCount) { /* Update to keep track of these new subelements */ ElementDataLength = *ElementSize - TotalLength; /* Link the subelements into the chain */ PreviousElement = Elements; PreviousElement->NextEntry = (PBCD_PACKED_ELEMENT)((ULONG_PTR)ElementsStart + TotalLength); Elements = PreviousElement->NextEntry; } } else { /* We're out of space */ ElementDataLength = 0; } } else if ((Status != STATUS_NOT_FOUND) && (Status != STATUS_OBJECT_NAME_NOT_FOUND)) { /* Fatal error trying to read the data, so fail */ break; } } else if ((Flags & BCD_ENUMERATE_FLAG_DEEP) && (ElementType.PackedValue == BcdLibraryObjectList_InheritedObjects)) { /* Inherited objects are requsted, so allocate a buffer for them */ SubObjectList = BlMmAllocateHeap(ElementDataLength); if (!SubObjectList) { Status = STATUS_INSUFFICIENT_RESOURCES; break; } /* Copy the elements into the list. They are arrays of GUIDs */ RtlCopyMemory(SubObjectList, ElementData, ElementDataLength); SubObjectCount = ElementDataLength / sizeof(GUID); } /* Free our local buffers */ BlMmFreeHeap(ElementData); BlMmFreeHeap(RegistryElementData); ElementData = NULL; RegistryElementData = NULL; /* Close the key */ BiCloseKey(ElementHandle); ElementHandle = NULL; ElementName = NULL; } /* Did we end up here with a sub object list after successful loop parsing? */ if ((i != 0) && (i == SubKeyCount) && (SubObjectList)) { /* We will actually enumerate it now, at the end */ Status = BiEnumerateSubObjectElements(BcdHandle, SubObjectList, SubObjectCount, Flags, Elements, &RemainingLength, &SubElementCount); if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL)) { /* Safely add the length of the sub elements */ Status = RtlULongAdd(TotalLength, RemainingLength, &TotalLength); if ((NT_SUCCESS(Status)) && (SubElementCount)) { /* Add the sub elements to the total */ *ElementCount += SubElementCount; /* Don't touch PreviousElement anymore */ PreviousElement = NULL; } } } Quickie: /* Free the sub object list, if any */ if (SubObjectList) { BlMmFreeHeap(SubObjectList); } /* Free any local element data */ if (ElementData) { BlMmFreeHeap(ElementData); } /* Free any local registry data */ if (RegistryElementData) { BlMmFreeHeap(RegistryElementData); } /* Close the handle if still opened */ if (ElementHandle) { BiCloseKey(ElementHandle); } /* Terminate the last element, if any */ if (PreviousElement) { PreviousElement->NextEntry = NULL; } /* Close the root handle if still opened */ if (ElementsHandle) { BiCloseKey(ElementsHandle); } /* Set failure code if out of space */ if (*ElementSize < TotalLength) { Status = STATUS_BUFFER_TOO_SMALL; } /* Other errors will send a notification error */ if (!(NT_SUCCESS(Status)) && (Status != STATUS_BUFFER_TOO_SMALL)) { BiNotifyEnumerationError(ObjectHandle, ElementName, Status); } /* Finally free the subkeys array */ if (SubKeys) { BlMmFreeHeap(SubKeys); } /* And return the required, final length and status */ *ElementSize = TotalLength; return Status; }
NTSTATUS BlGetBootOptionString ( _In_ PBL_BCD_OPTION List, _In_ ULONG Type, _Out_ PWCHAR* Value ) { NTSTATUS Status; PBL_BCD_OPTION Option; PWCHAR String, StringCopy; ULONG StringLength; BcdElementType ElementType; //PGUID AppIdentifier; /* Make sure this is a BCD_STRING */ ElementType.PackedValue = Type; if (ElementType.Format != BCD_TYPE_STRING) { return STATUS_INVALID_PARAMETER; } /* Return the data */ Option = MiscGetBootOption(List, Type); if (Option) { /* Extract the string */ String = (PWCHAR)((ULONG_PTR)Option + Option->DataOffset); Status = STATUS_SUCCESS; } else { /* No string is present */ String = NULL; Status = STATUS_NOT_FOUND; } /* Compute the data size */ StringLength = Option->DataSize / sizeof(WCHAR); #ifdef _SECURE_BOOT_ /* Filter out SecureBoot Options */ AppIdentifier = BlGetApplicationIdentifier(); Status = BlpBootOptionCallbackString(AppIdentifier, Type, String, StringLength, &String, &StringLength); #else #endif /* Make sure we have a valid, non-filtered string */ if (NT_SUCCESS(Status)) { /* Check if we have space for one more character */ Status = RtlULongAdd(StringLength, 1, &StringLength); if (NT_SUCCESS(Status)) { /* Check if it's safe to multiply by two */ Status = RtlULongMult(StringLength, sizeof(WCHAR), &StringLength); if (NT_SUCCESS(Status)) { /* Allocate a copy for the string */ StringCopy = BlMmAllocateHeap(StringLength); if (StringCopy) { /* NULL-terminate it */ RtlCopyMemory(StringCopy, String, StringLength - sizeof(UNICODE_NULL)); StringCopy[StringLength] = UNICODE_NULL; *Value = StringCopy; Status = STATUS_SUCCESS; } else { /* No memory, fail */ Status = STATUS_NO_MEMORY; } } } } /* All done */ return Status; }
NTSTATUS BiLoadHive ( _In_ PBL_FILE_PATH_DESCRIPTOR FilePath, _Out_ PHANDLE HiveHandle ) { ULONG DeviceId; PHBASE_BLOCK BaseBlock, NewBaseBlock; PBI_KEY_OBJECT KeyObject; PBI_KEY_HIVE BcdHive; PBL_DEVICE_DESCRIPTOR BcdDevice; ULONG PathLength, DeviceLength, HiveSize, HiveLength, NewHiveSize; PWCHAR HiveName, LogName; BOOLEAN HaveWriteAccess; NTSTATUS Status; PVOID LogData; PHHIVE Hive; UNICODE_STRING KeyString; PCM_KEY_NODE RootNode; HCELL_INDEX CellIndex; /* Initialize variables */ DeviceId = -1; BaseBlock = NULL; BcdHive = NULL; KeyObject = NULL; LogData = NULL; LogName = NULL; /* Initialize the crypto seed */ if (!BiHiveHashLibraryInitialized) { HvSymcryptSeed = 0x82EF4D887A4E55C5; BiHiveHashLibraryInitialized = TRUE; } /* Extract and validate the input path */ BcdDevice = (PBL_DEVICE_DESCRIPTOR)&FilePath->Path; PathLength = FilePath->Length; DeviceLength = BcdDevice->Size; HiveName = (PWCHAR)((ULONG_PTR)BcdDevice + BcdDevice->Size); if (PathLength <= DeviceLength) { /* Doesn't make sense, bail out */ Status = STATUS_INVALID_PARAMETER; goto Quickie; } /* Attempt to open the underlying device for RW access */ HaveWriteAccess = TRUE; Status = BlpDeviceOpen(BcdDevice, BL_DEVICE_READ_ACCESS | BL_DEVICE_WRITE_ACCESS, 0, &DeviceId); if (!NT_SUCCESS(Status)) { /* Try for RO access instead */ HaveWriteAccess = FALSE; Status = BlpDeviceOpen(BcdDevice, BL_DEVICE_READ_ACCESS, 0, &DeviceId); if (!NT_SUCCESS(Status)) { /* No access at all -- bail out */ goto Quickie; } } /* Now try to load the hive on disk */ Status = BlImgLoadImageWithProgress2(DeviceId, BlLoaderRegistry, HiveName, (PVOID*)&BaseBlock, &HiveSize, 0, FALSE, NULL, NULL); if (!NT_SUCCESS(Status)) { EfiPrintf(L"Hive read failure: % lx\r\n", Status); goto Quickie; } /* Allocate a hive structure */ BcdHive = BlMmAllocateHeap(sizeof(*BcdHive)); if (!BcdHive) { Status = STATUS_NO_MEMORY; goto Quickie; } /* Initialize it */ RtlZeroMemory(BcdHive, sizeof(*BcdHive)); BcdHive->BaseBlock = BaseBlock; BcdHive->HiveSize = HiveSize; if (HaveWriteAccess) { BcdHive->Flags |= BI_HIVE_WRITEABLE; } /* Make sure the hive was at least one bin long */ if (HiveSize < sizeof(*BaseBlock)) { Status = STATUS_REGISTRY_CORRUPT; goto Quickie; } /* Make sure the hive contents are at least one bin long */ HiveLength = BaseBlock->Length; if (BaseBlock->Length < sizeof(*BaseBlock)) { Status = STATUS_REGISTRY_CORRUPT; goto Quickie; } /* Validate the initial bin (the base block) */ if (!HvIsInPlaceBaseBlockValid(BaseBlock)) { EfiPrintf(L"Recovery not implemented\r\n"); Status = STATUS_REGISTRY_CORRUPT; goto Quickie; } /* Check if there's log recovery that needs to happen */ if (BaseBlock->Sequence1 != BaseBlock->Sequence2) { EfiPrintf(L"Log fix not implemented: %lx %lx\r\n"); Status = STATUS_REGISTRY_CORRUPT; goto Quickie; } /* * Check if the whole hive doesn't fit in the buffer. * Note: HiveLength does not include the size of the baseblock itself */ if (HiveSize < (HiveLength + sizeof(*BaseBlock))) { EfiPrintf(L"Need bigger hive buffer path\r\n"); /* Allocate a slightly bigger buffer */ NewHiveSize = HiveLength + sizeof(*BaseBlock); Status = MmPapAllocatePagesInRange((PVOID*)&NewBaseBlock, BlLoaderRegistry, NewHiveSize >> PAGE_SHIFT, 0, 0, NULL, 0); if (!NT_SUCCESS(Status)) { goto Quickie; } /* Copy the current data in there */ RtlCopyMemory(NewBaseBlock, BaseBlock, HiveSize); /* Free the old data */ EfiPrintf(L"Leaking old hive buffer\r\n"); //MmPapFreePages(BaseBlock, 1); /* Update our pointers */ BaseBlock = NewBaseBlock; HiveSize = NewHiveSize; BcdHive->BaseBlock = BaseBlock; BcdHive->HiveSize = HiveSize; }
NTSTATUS DsppLoadFontFile ( _In_ PWCHAR FontFileName ) { PBL_DEVICE_DESCRIPTOR FontDevice; NTSTATUS Status; ULONG NameLength, DirectoryLength, TotalLength; PWCHAR FontPath, FontDirectory; BL_LIBRARY_PARAMETERS LibraryParameters; BOOLEAN CustomDirectory, CustomDevice; /* Initialize locals */ CustomDirectory = TRUE; CustomDevice = TRUE; FontDevice = NULL; FontPath = NULL; FontDirectory = NULL; /* Check if a custom font path should be used */ Status = BlGetBootOptionString(BlpApplicationEntry.BcdData, BcdLibraryString_FontPath, &FontDirectory); if (!NT_SUCCESS(Status)) { /* Nope, use the one configured by the library */ CustomDirectory = FALSE; RtlCopyMemory(&LibraryParameters, &BlpLibraryParameters, sizeof(LibraryParameters)), FontDirectory = LibraryParameters.FontBaseDirectory; } /* Do we still not have a font directory? */ if (!FontDirectory) { /* Use the boot device and boot directory */ FontDevice = BlpBootDevice; FontDirectory = L"\\EFI\\Microsoft\\Boot\\Fonts"; CustomDevice = FALSE; } else { /* Otherwise, if we have a font directory, what device is the app on? */ Status = BlGetBootOptionDevice(BlpApplicationEntry.BcdData, BcdLibraryDevice_ApplicationDevice, &FontDevice, NULL); if (!NT_SUCCESS(Status)) { /* If we don't know the device, we can't open the path */ goto Quickie; } } /* Figure out the length of the file name, and of the directory */ NameLength = wcslen(FontFileName); DirectoryLength = wcslen(FontDirectory); /* Safely add them up*/ Status = RtlULongAdd(NameLength, DirectoryLength, &TotalLength); if (!NT_SUCCESS(Status)) { goto Quickie; } /* Convert to bytes */ Status = RtlULongLongToULong(TotalLength * sizeof(WCHAR), &TotalLength); if (!NT_SUCCESS(Status)) { goto Quickie; } /* Add a terminating NUL */ Status = RtlULongAdd(TotalLength, sizeof(UNICODE_NULL), &TotalLength); if (!NT_SUCCESS(Status)) { goto Quickie; } /* Allocate the final buffer for it */ FontPath = BlMmAllocateHeap(TotalLength); if (!FontPath) { Status = STATUS_NO_MEMORY; goto Quickie; } /* Concatenate the directory with the file name */ wcscpy(FontPath, FontDirectory); wcscat(FontPath, FontFileName); /* Try to load this font */ Status = BfLoadFontFile(FontDevice, FontPath); Quickie: /* Check if we had a custom font device allocated and free it */ if ((CustomDevice) && (FontDevice)) { BlMmFreeHeap(FontDevice); } /* Check if we had a custom font directory allocated and free it */ if ((FontDirectory) && (CustomDirectory)) { BlMmFreeHeap(FontDirectory); } /* Check if we had allocated a font path and free it */ if (FontPath) { BlMmFreeHeap(FontPath); } /* Return back */ return Status; }
NTSTATUS DsppInitialize ( _In_ ULONG Flags ) { BL_LIBRARY_PARAMETERS LibraryParameters = BlpLibraryParameters; BOOLEAN NoGraphics, HighestMode; NTSTATUS Status; PBL_DISPLAY_MODE DisplayMode; ULONGLONG GraphicsResolution; PBL_GRAPHICS_CONSOLE GraphicsConsole; PBL_TEXT_CONSOLE TextConsole, RemoteConsole; /* Initialize font data */ BfiCachedStrikeData = 0; InitializeListHead(&BfiDeferredListHead); InitializeListHead(&BfiFontFileListHead); /* Allocate the font rectangle */ BfiGraphicsRectangle = BlMmAllocateHeap(90); if (!BfiGraphicsRectangle) { return STATUS_NO_MEMORY; } /* Display re-initialization not yet handled */ if (LibraryParameters.LibraryFlags & BL_LIBRARY_FLAG_REINITIALIZE_ALL) { EfiPrintf(L"Display path not handled\r\n"); return STATUS_NOT_SUPPORTED; } /* Check if no graphics console is needed */ if ((Flags & BL_LIBRARY_FLAG_NO_GRAPHICS_CONSOLE) || (DsppGraphicsDisabledByBcd())) { /* Remember this */ NoGraphics = TRUE; } else { /* No graphics -- remember this */ NoGraphics = FALSE; } /* On first load, we always initialize a graphics display */ GraphicsConsole = NULL; if (!(Flags & BL_LIBRARY_FLAG_REINITIALIZE_ALL) || !(NoGraphics)) { /* Default to mode 0 (1024x768) */ DisplayMode = &ConsoleGraphicalResolutionList[0]; /* Check what resolution to use*/ Status = BlGetBootOptionInteger(BlpApplicationEntry.BcdData, BcdLibraryInteger_GraphicsResolution, &GraphicsResolution); if (NT_SUCCESS(Status)) { ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG; EfiPrintf(L"Display selection not yet handled\r\n"); return STATUS_NOT_IMPLEMENTED; } /* Check if the highest mode should be forced */ Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, BcdLibraryBoolean_GraphicsForceHighestMode, &HighestMode); if (NT_SUCCESS(Status)) { ConsoleGraphicalResolutionListFlags |= BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG; EfiPrintf(L"High res mode not yet handled\r\n"); return STATUS_NOT_IMPLEMENTED; } /* Do we need graphics mode after all? */ if (!NoGraphics) { /* Yep -- go allocate it */ GraphicsConsole = BlMmAllocateHeap(sizeof(*GraphicsConsole)); if (GraphicsConsole) { /* Construct it */ Status = ConsoleGraphicalConstruct(GraphicsConsole); if (!NT_SUCCESS(Status)) { EfiPrintf(L"GFX FAILED: %lx\r\n", Status); BlMmFreeHeap(GraphicsConsole); GraphicsConsole = NULL; } else { /* TEST */ RtlFillMemory(GraphicsConsole->FrameBuffer, GraphicsConsole->FrameBufferSize, 0x55); } } } /* Are we using something else than the default mode? */ if (DisplayMode != &ConsoleGraphicalResolutionList[0]) { EfiPrintf(L"Display path not handled\r\n"); return STATUS_NOT_SUPPORTED; } /* Mask out all the flags now */ ConsoleGraphicalResolutionListFlags &= ~(BL_DISPLAY_GRAPHICS_FORCED_VIDEO_MODE_FLAG | BL_DISPLAY_GRAPHICS_FORCED_HIGH_RES_MODE_FLAG); } /* Do we have a graphics console? */ TextConsole = NULL; if (!GraphicsConsole) { /* Nope -- go allocate a text console */ TextConsole = BlMmAllocateHeap(sizeof(*TextConsole)); if (TextConsole) { /* Construct it */ Status = ConsoleTextLocalConstruct(TextConsole, TRUE); if (!NT_SUCCESS(Status)) { BlMmFreeHeap(TextConsole); TextConsole = NULL; } } } /* Initialize all globals to NULL */ DspRemoteInputConsole = NULL; DspTextConsole = NULL; DspGraphicalConsole = NULL; /* If we don't have a text console, go get a remote console */ RemoteConsole = NULL; if (!TextConsole) { ConsoleCreateRemoteConsole(&RemoteConsole); } /* Do we have a remote console? */ if (!RemoteConsole) { /* Nope -- what about a graphical one? */ if (GraphicsConsole) { /* Yes, use it for both graphics and text */ DspGraphicalConsole = GraphicsConsole; DspTextConsole = GraphicsConsole; } else if (TextConsole) { /* Nope, but we have a text console */ DspTextConsole = TextConsole; } /* Console has been setup */ return STATUS_SUCCESS; } /* We have a remote console -- have to figure out how to use it*/ EfiPrintf(L"Display path not handled\r\n"); return STATUS_NOT_SUPPORTED; }
NTSTATUS ConsoleEfiTextFindModeFromAllowed ( _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextProtocol, _In_ PBL_DISPLAY_MODE SupportedModes, _In_ ULONG MaxIndex, _Out_ PULONG SupportedMode ) { EFI_SIMPLE_TEXT_OUTPUT_MODE ModeInfo; ULONG MaxMode, MaxQueriedMode, Mode, i, MatchingMode; UINTN HRes, VRes; ULONGLONG ModeListSize; PBL_DISPLAY_MODE ModeEntry, ModeList, SupportedModeEntry; NTSTATUS Status; /* Read information on the current mode */ EfiConOutReadCurrentMode(TextProtocol, &ModeInfo); /* Figure out the max mode, and how many modes we'll have to read */ MaxMode = ModeInfo.MaxMode; ModeListSize = sizeof(*ModeEntry) * ModeInfo.MaxMode; if (ModeListSize > MAXULONG) { return STATUS_INTEGER_OVERFLOW; } /* Allocate a list for all the supported EFI modes */ ModeList = BlMmAllocateHeap(ModeListSize); if (!ModeList) { return STATUS_INSUFFICIENT_RESOURCES; } /* Scan all the EFI modes */ EfiPrintf(L"Scanning through %d modes\r\n", MaxMode); for (MaxQueriedMode = 0, Mode = 0; Mode < MaxMode; Mode++) { /* Query information on this mode */ ModeEntry = &ModeList[MaxQueriedMode]; if (NT_SUCCESS(EfiConOutQueryMode(TextProtocol, Mode, &HRes, &VRes))) { /* This mode was succesfully queried. Save the data */ EfiPrintf(L"EFI Firmware Supported Mode %d is H: %d V: %d\r\n", Mode, HRes, VRes); ModeEntry->HRes = HRes; ModeEntry->VRes = VRes; ModeEntry->HRes2 = HRes; MaxQueriedMode = Mode + 1; } } /* Loop all the supported mode entries */ for (i = 0; i < MaxIndex; i++) { /* Loop all the UEFI queried modes */ SupportedModeEntry = &SupportedModes[i]; for (MatchingMode = 0; MatchingMode < MaxQueriedMode; MatchingMode++) { /* Check if the UEFI mode is compatible with our supported mode */ ModeEntry = &ModeList[MatchingMode]; EfiPrintf(L"H1: %d V1: %d - H2: %d - V2: %d\r\n", ModeEntry->HRes, ModeEntry->VRes, SupportedModeEntry->HRes, SupportedModeEntry->VRes); if ((ModeEntry->HRes == SupportedModeEntry->HRes) && (ModeEntry->VRes == SupportedModeEntry->VRes)) { /* Yep -- free the mode list and return this mode */ BlMmFreeHeap(ModeList); *SupportedMode = MatchingMode; return STATUS_SUCCESS; } } } /* We can't do anything -- there are no matching modes */ Status = STATUS_UNSUCCESSFUL; BlMmFreeHeap(ModeList); return Status; }
NTSTATUS BcdEnumerateAndUnpackElements ( _In_ HANDLE BcdHandle, _In_ HANDLE ObjectHandle, _Out_opt_ PBCD_ELEMENT Elements, _Inout_ PULONG ElementSize, _Out_ PULONG ElementCount ) { PVOID LocalElements; NTSTATUS Status; ULONG LocalElementCount, LocalElementSize; /* Make sure required parameters are there */ if (!(ElementSize) || !(ElementCount) || ((Elements) && (!*ElementSize))) { return STATUS_INVALID_PARAMETER; } /* Set initial count to zero */ *ElementCount = 0; /* Do the initial enumeration to figure out the size required */ LocalElementSize = 0; LocalElementCount = 0; Status = BiEnumerateElements(BcdHandle, ObjectHandle, 0, BCD_ENUMERATE_FLAG_IN_ORDER | BCD_ENUMERATE_FLAG_DEVICES | BCD_ENUMERATE_FLAG_DEEP, NULL, &LocalElementSize, &LocalElementCount); if (Status != STATUS_BUFFER_TOO_SMALL) { return Status; } /* Now allocate a buffer large enough to hold them */ LocalElements = BlMmAllocateHeap(LocalElementSize); if (!LocalElements) { return STATUS_INSUFFICIENT_RESOURCES; } /* Zero out the array and do the real enumeration this time around */ RtlZeroMemory(LocalElements, LocalElementSize); Status = BiEnumerateElements(BcdHandle, ObjectHandle, 0, BCD_ENUMERATE_FLAG_IN_ORDER | BCD_ENUMERATE_FLAG_DEVICES | BCD_ENUMERATE_FLAG_DEEP, LocalElements, &LocalElementSize, &LocalElementCount); if (!NT_SUCCESS(Status)) { return Status; } /* Now we know the real count */ *ElementCount = LocalElementCount; /* Now unpack the data */ Status = BiConvertBcdElements(LocalElements, Elements, ElementSize, &LocalElementCount); if (NT_SUCCESS(Status)) { /* Not all elements may have been converted */ *ElementCount = LocalElementCount; } /* Free the local (unpacked) buffer and return status */ BlMmFreeHeap(LocalElements); return Status; }
NTSTATUS BlHtCreate ( _In_ ULONG Size, _In_ PBL_HASH_TABLE_HASH_FUNCTION HashFunction, _In_ PBL_HASH_TABLE_COMPARE_FUNCTION CompareFunction, _Out_ PULONG Id ) { NTSTATUS Status; PBL_HASH_TABLE HashTable; ULONG i; /* Assume failure */ HashTable = NULL; /* Can't create a table with no ID */ if (!Id) { return STATUS_INVALID_PARAMETER; } /* Check if we don't already have a hash table table */ if (!HtTableSize) { /* Allocate it and zero it out */ HtTableSize = 4; HtTableArray = BlMmAllocateHeap(HtTableSize * sizeof(PVOID)); if (!HtTableArray) { Status = STATUS_NO_MEMORY; goto Quickie; } RtlZeroMemory(HtTableArray, HtTableSize * sizeof(PVOID)); HtTableEntries = 0; } /* Allocate the hash table */ HashTable = BlMmAllocateHeap(sizeof(*HashTable)); if (!HashTable) { Status = STATUS_NO_MEMORY; goto Quickie; } /* Fill it out */ HashTable->HashFunction = HashFunction ? HashFunction : DefaultHashFunction; HashTable->CompareFunction = CompareFunction ? CompareFunction : HtpCompareKeys; HashTable->Size = Size ? Size : 13; /* Allocate the hash links, one for each bucket */ HashTable->HashLinks = BlMmAllocateHeap(sizeof(LIST_ENTRY) * HashTable->Size); if (!HashTable->HashLinks) { Status = STATUS_NO_MEMORY; goto Quickie; } /* Initialize the hash links */ for (i = 0; i < HashTable->Size; i++) { InitializeListHead(&HashTable->HashLinks[i]); } /* Save us in the table of hash tables */ Status = BlTblSetEntry((PVOID**)&HtTableArray, &Size, HashTable, Id, TblDoNotPurgeEntry); if (NT_SUCCESS(Status)) { /* One more -- we're done */ ++HtTableEntries; return Status; } Quickie: /* Check if we just allocated the table array now */ if (!(HtTableEntries) && (HtTableArray)) { /* Free it */ BlMmFreeHeap(HtTableArray); HtTableArray = NULL; HtTableSize = 0; } /* Check if we allocated a hash table*/ if (HashTable) { /* With links? */ if (HashTable->HashLinks) { /* Free them */ BlMmFreeHeap(HashTable->HashLinks); } /* Free the table*/ BlMmFreeHeap(HashTable); } /* We're done */ return Status; }
NTSTATUS BiOpenKey( _In_ HANDLE ParentHandle, _In_ PWCHAR KeyName, _Out_ PHANDLE Handle ) { PBI_KEY_OBJECT ParentKey, NewKey; PBI_KEY_HIVE ParentHive; NTSTATUS Status; ULONG NameLength, SubNameLength, NameBytes; PWCHAR NameStart, NameBuffer; UNICODE_STRING KeyString; HCELL_INDEX KeyCell; PHHIVE Hive; PCM_KEY_NODE ParentNode; /* Convert from a handle to our key object */ ParentKey = (PBI_KEY_OBJECT)ParentHandle; /* Extract the hive and node information */ ParentHive = ParentKey->KeyHive; ParentNode = ParentKey->KeyNode; Hive = &ParentKey->KeyHive->Hive.Hive; /* Initialize variables */ KeyCell = HCELL_NIL; Status = STATUS_SUCCESS; NameBuffer = NULL; /* Loop as long as there's still portions of the key name in play */ NameLength = wcslen(KeyName); while (NameLength) { /* Find the first path separator */ NameStart = wcschr(KeyName, OBJ_NAME_PATH_SEPARATOR); if (NameStart) { /* Look only at the key before the separator */ SubNameLength = NameStart - KeyName; ++NameStart; } else { /* No path separator, this is the final leaf key */ SubNameLength = NameLength; } /* Free the name buffer from the previous pass if needed */ if (NameBuffer) { BlMmFreeHeap(NameBuffer); } /* Allocate a buffer to hold the name of this specific subkey only */ NameBytes = SubNameLength * sizeof(WCHAR); NameBuffer = BlMmAllocateHeap(NameBytes + sizeof(UNICODE_NULL)); if (!NameBuffer) { Status = STATUS_NO_MEMORY; goto Quickie; } /* Copy and null-terminate the name of the subkey */ RtlCopyMemory(NameBuffer, KeyName, NameBytes); NameBuffer[SubNameLength] = UNICODE_NULL; /* Convert it into a UNICODE_STRING and try to find it */ RtlInitUnicodeString(&KeyString, NameBuffer); KeyCell = CmpFindSubKeyByName(Hive, ParentNode, &KeyString); if (KeyCell == HCELL_NIL) { Status = STATUS_OBJECT_NAME_NOT_FOUND; goto Quickie; } /* We found it -- get the key node out of it */ ParentNode = (PCM_KEY_NODE)HvGetCell(Hive, KeyCell); if (!ParentNode) { Status = STATUS_REGISTRY_CORRUPT; goto Quickie; } /* Update the key name to the next remaining path element */ KeyName = NameStart; if (NameStart) { /* Update the length to the remainder of the path */ NameLength += -1 - SubNameLength; } else { /* There's nothing left, this was the leaf key */ NameLength = 0; } } /* Allocate a key object */ NewKey = BlMmAllocateHeap(sizeof(*NewKey)); if (!NewKey) { /* Bail out if we had no memory for it */ Status = STATUS_NO_MEMORY; goto Quickie; } /* Fill out the key object data */ NewKey->KeyNode = ParentNode; NewKey->KeyHive = ParentHive; NewKey->KeyName = NameBuffer; NewKey->KeyCell = KeyCell; /* Add a reference to the hive */ ++ParentHive->ReferenceCount; /* Return the object back to the caller */ *Handle = NewKey; Quickie: /* If we had a name buffer, free it */ if (NameBuffer) { BlMmFreeHeap(NameBuffer); } /* Return status of the open operation */ return Status; }
NTSTATUS BlAppendBootOptions ( _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry, _In_ PBL_BCD_OPTION Options ) { ULONG OptionsSize, CurrentSize; PBL_BCD_OPTION NewOptions, CurrentOptions, NextOption; NTSTATUS Status; ULONG CurrentOffset; /* Get the current options */ CurrentOptions = AppEntry->BcdData; /* Calculate the size of the current, and the appended options */ CurrentSize = BlGetBootOptionListSize(CurrentOptions); OptionsSize = BlGetBootOptionListSize(Options); /* Allocate a buffer for the concatenated (new) options */ NewOptions = BlMmAllocateHeap(CurrentSize + OptionsSize); if (!NewOptions) { return STATUS_NO_MEMORY; } /* Copy the old options, and the ones to be added */ RtlCopyMemory(NewOptions, CurrentOptions, CurrentSize); RtlCopyMemory(&NewOptions[OptionsSize], Options, OptionsSize); /* We made it! */ Status = STATUS_SUCCESS; /* Scan through to the last option in the list */ CurrentOffset = 0; do { NextOption = (PBL_BCD_OPTION)((ULONG_PTR)NewOptions + CurrentOffset); CurrentOffset = NextOption->NextEntryOffset; } while (CurrentOffset); /* Every other option now has to have its offset adjusted */ do { NextOption->NextEntryOffset += OptionsSize; NextOption = (PBL_BCD_OPTION)((ULONG_PTR)NewOptions + NextOption->NextEntryOffset); } while (NextOption->NextEntryOffset); /* If we already had internal options, free them */ if (AppEntry->Flags & BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL) { BlMmFreeHeap(AppEntry->BcdData); } /* Write the new pointer */ AppEntry->BcdData = NewOptions; /* Options are now internal, not external */ AppEntry->Flags &= ~BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL; AppEntry->Flags |= BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL; return Status; }
NTSTATUS BlGetBootOptionDevice ( _In_ PBL_BCD_OPTION List, _In_ ULONG Type, _Out_ PBL_DEVICE_DESCRIPTOR* Value, _In_opt_ PBL_BCD_OPTION* ExtraOptions ) { NTSTATUS Status; PBL_BCD_OPTION Option, ListData, ListCopy, SecureListData; PBCD_DEVICE_OPTION BcdDevice; ULONG DeviceSize, ListOffset, ListSize; PBL_DEVICE_DESCRIPTOR DeviceDescriptor, SecureDescriptor; //PGUID AppIdentifier; BcdElementType ElementType; /* Make sure this is a BCD_TYPE_DEVICE */ ElementType.PackedValue = Type; if (ElementType.Format != BCD_TYPE_DEVICE) { return STATUS_INVALID_PARAMETER; } /* Return the data */ Option = MiscGetBootOption(List, Type); if (!Option) { /* Set failure if no data exists */ Status = STATUS_NOT_FOUND; } else { /* Otherwise, read the size of the BCD device encoded */ BcdDevice = (PBCD_DEVICE_OPTION)((ULONG_PTR)Option + Option->DataOffset); DeviceSize = BcdDevice->DeviceDescriptor.Size; /* Allocate a buffer to copy it into */ DeviceDescriptor = BlMmAllocateHeap(DeviceSize); if (!DeviceDescriptor) { return STATUS_NO_MEMORY; } /* Copy it into that buffer */ RtlCopyMemory(DeviceDescriptor, &BcdDevice->DeviceDescriptor, DeviceSize); Status = STATUS_SUCCESS; } /* Check if extra options were requested */ if (ExtraOptions) { /* See where they are */ ListOffset = Option->ListOffset; if (ListOffset) { /* See how big they are */ ListData = (PBL_BCD_OPTION)((ULONG_PTR)Option + ListOffset); ListSize = BlGetBootOptionListSize(ListData); /* Allocate a buffer to hold them into */ ListCopy = BlMmAllocateHeap(ListSize); if (!ListCopy) { Status = STATUS_NO_MEMORY; goto Quickie; } /* Copy them in there */ RtlCopyMemory(ListCopy, ListData, ListSize); } } #ifdef _SECURE_BOOT_ /* Filter out SecureBoot Options */ AppIdentifier = BlGetApplicationIdentifier(); if (BlpBootOptionCallbacks) { DeviceCallback = BlpBootOptionCallbacks->Device; if (DeviceCallback) { Status = DeviceCallback(BlpBootOptionCallbackCookie, Status, 0, AppIdentifier, Type, &SecureDescriptor, PtrOptionData); } } #else /* No secure boot, so the secure descriptors are the standard ones */ SecureDescriptor = DeviceDescriptor; SecureListData = ListCopy; #endif /* Check if the data was read correctly */ if (NT_SUCCESS(Status)) { /* Check if we had a new descriptor after filtering */ if (SecureDescriptor != DeviceDescriptor) { /* Yep -- if we had an old one, free it */ if (DeviceDescriptor) { BlMmFreeHeap(DeviceDescriptor); } } /* Check if we had a new list after filtering */ if (SecureListData != ListCopy) { /* Yep -- if we had an old list, free it */ if (ListCopy) { BlMmFreeHeap(ListCopy); } } /* Finally, check if the caller wanted extra options */ if (ExtraOptions) { /* Yep -- so pass the caller our copy */ *ExtraOptions = ListCopy; ListCopy = NULL; } /* Caller always wants data back, so pass them our copy */ *Value = DeviceDescriptor; DeviceDescriptor = NULL; } Quickie: /* On the failure path, if these buffers are active, we should free them */ if (ListCopy) { BlMmFreeHeap(ListCopy); } if (DeviceDescriptor) { BlMmFreeHeap(DeviceDescriptor); } /* All done */ return Status; }