diff --git a/BOOT/ENVIRON/LIB/EFI/efiinit.c b/BOOT/ENVIRON/LIB/EFI/efiinit.c index 8da1760..6f02104 100644 --- a/BOOT/ENVIRON/LIB/EFI/efiinit.c +++ b/BOOT/ENVIRON/LIB/EFI/efiinit.c @@ -24,6 +24,106 @@ UCHAR EfiInitScratch[2048]; const EFI_GUID EfiLoadedImageProtocol = LOADED_IMAGE_PROTOCOL; const EFI_GUID EfiDevicePathProtocol = DEVICE_PATH_PROTOCOL; +NTSTATUS +EfiInitpAppendPathString ( + IN PWCHAR Destination, + IN ULONG BufferSize, + IN PWCHAR Source, + IN ULONG SourceSize, + IN OUT PULONG BufferUsed + ) + +/*++ + +Routine Description: + + Appends a soure path to a destination path. + +Arguments: + + Destination - the path to append to. + + BufferSize - the maximum number of bytes to append. + + Source - the source path to append to Destination. + + SourceSize - the size of Source, in bytes. + + BufferUsed - pointer to a ULONG to store the number of bytes appended in. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_INVALID_PARAMETER if Destination is not valid, + STATUS_BUFFER_TOO_SMALL if BufferSize is too small. + +--*/ + +{ + ULONG Position; + + // + // Verify that Source uses wide characters. + // + if (SourceSize % sizeof(WCHAR) != 0) { + return STATUS_INVALID_PARAMETER; + } + + // + // Remove NULL terminator. + // + if (SourceSize >= sizeof(WCHAR)) { + Position = (SourceSize / sizeof(WCHAR)) - 1; + if (Source[Position] == UNICODE_NULL) { + SourceSize -= sizeof(UNICODE_NULL); + } + } + + // + // Remove leading separator. + // + if (SourceSize >= sizeof(WCHAR)) { + if (Source[0] == L'\\') { + Source++; + SourceSize -= sizeof(WCHAR); + } + } + + // + // Remove trailing separator. + // + if (SourceSize >= sizeof(WCHAR)) { + Position = (SourceSize / sizeof(WCHAR)) - 1; + if (Source[Position] == L'\\') { + SourceSize -= sizeof(WCHAR); + } + } + + // + // Check if Source is empty. + // + if (SourceSize == 0) { + *BufferUsed = 0; + return STATUS_SUCCESS; + } + + // + // Make sure the buffer is large enough. + // + if (BufferSize < SourceSize + sizeof(WCHAR)) { + return STATUS_BUFFER_TOO_SMALL; + } + + // + // Append separator and Source to Destination. + // + Destination[0] = L'\\'; + RtlCopyMemory(Destination + 1, Source, SourceSize); + + *BufferUsed = SourceSize + sizeof(WCHAR); + return STATUS_SUCCESS; +} + EFI_DEVICE_PATH * EfiInitpGetDeviceNode ( IN EFI_DEVICE_PATH *DevicePath @@ -287,10 +387,70 @@ Return Value: --*/ { - (VOID)EfiFilePath; - (VOID)OptionType; - (VOID)Option; - (VOID)BufferSize; + NTSTATUS Status; + EFI_DEVICE_PATH *Node; + PWCHAR PathStart, Position; + ULONG BufferRemaining, Length, Appended; + + // + // Check for available buffer space. + // + if (BufferSize < sizeof(BOOT_APPLICATION_ENTRY_OPTION)) { + return STATUS_INVALID_PARAMETER; + } + + // + // Set up option structure. + // + RtlZeroMemory(Option, sizeof(BOOT_APPLICATION_ENTRY_OPTION)); + Option->Type = OptionType; + Option->DataOffset = sizeof(BOOT_APPLICATION_ENTRY_OPTION); + + // + // Add to the path one file path node at a time. + // + Option->DataSize = 0; + BufferRemaining = BufferSize - sizeof(BOOT_APPLICATION_ENTRY_OPTION); + Node = EfiFilePath; + PathStart = (PWCHAR)((PUCHAR)Option + Option->DataOffset); + Position = PathStart; + while (!IsDevicePathEndType(Node)) { + if (DevicePathType(Node) != MEDIA_DEVICE_PATH || DevicePathSubType(Node) != MEDIA_FILEPATH_DP) { + Node = NextDevicePathNode(Node); + continue; + } + + Status = RtlULongSub(DevicePathNodeLength(Node), FIELD_OFFSET(FILEPATH_DEVICE_PATH, PathName), &Length); + if (!NT_SUCCESS(Status)) { + return Status; + } + + Status = EfiInitpAppendPathString(Position, BufferRemaining, &((FILEPATH_DEVICE_PATH *)Node)->PathName[0], Length, &Appended); + if (!NT_SUCCESS(Status)) { + return Status; + } + + Option->DataSize += Appended; + BufferRemaining -= Appended; + Position = (PWCHAR)((PUCHAR)Position + Appended); + Node = NextDevicePathNode(Node); + } + + // + // Terminate path string. + // + if (BufferRemaining < sizeof(UNICODE_NULL)) { + return STATUS_INVALID_PARAMETER; + } + *Position = L'\0'; + Option->DataSize += sizeof(UNICODE_NULL); + + // + // The path option is invalid if the path is NULL. + // + if (Position == PathStart) { + Option->IsInvalid = TRUE; + } return STATUS_SUCCESS; } diff --git a/SDK/INC/NT/ntrtl.h b/SDK/INC/NT/ntrtl.h index b1ed812..25ca4ae 100644 --- a/SDK/INC/NT/ntrtl.h +++ b/SDK/INC/NT/ntrtl.h @@ -18,6 +18,7 @@ Abstract: #include #include +#include // // Memory operations. @@ -27,6 +28,47 @@ Abstract: #define RtlFillMemory(Destination, Length, Fill) memset((Destination), (Fill), (Length)) #define RtlZeroMemory(Destination, Length) memset((Destination), 0, (Length)) +#define ULONG_ERROR 0xFFFFFFFFUL + +FORCEINLINE +NTSTATUS +RtlULongSub ( + IN ULONG ulMinuend, + IN ULONG ulSubtrahend, + IN OUT PULONG pulResult + ) + +/*++ + +Routine Description: + + Calculates the difference of two ULONG values. + +Arguments: + + ulMinuend - The value to subtract ulSubtrahend from. + + ulSubtrahend - The value to subtract from ulMinuend. + + pulResult - Pointer to a ULONG to store the difference in. + +Return Value: + + STATUS_SUCCESS if successful. + STATUS_INTEGER_OVERFLOW if unsuccessful. + +--*/ + +{ + if (ulMinuend >= ulSubtrahend) { + *pulResult = ulMinuend - ulSubtrahend; + return STATUS_SUCCESS; + } + + *pulResult = ULONG_ERROR; + return STATUS_INTEGER_OVERFLOW; +} + VOID NTAPI RtlInitUnicodeString ( diff --git a/SDK/INC/NT/ntstatus.h b/SDK/INC/NT/ntstatus.h index 36bba8a..0be2847 100644 --- a/SDK/INC/NT/ntstatus.h +++ b/SDK/INC/NT/ntstatus.h @@ -29,6 +29,7 @@ Abstract: #define STATUS_DISK_CORRUPT_ERROR ((NTSTATUS) 0xC0000032L) #define STATUS_DEVICE_ALREADY_ATTACHED ((NTSTATUS) 0xC0000038L) #define STATUS_DISK_FULL ((NTSTATUS) 0xC000007FL) +#define STATUS_INTEGER_OVERFLOW ((NTSTATUS) 0xC0000095L) #define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS) 0xC000009AL) #define STATUS_MEDIA_WRITE_PROTECTED ((NTSTATUS) 0xC00000A2L) #define STATUS_DEVICE_NOT_READY ((NTSTATUS) 0xC00000A3L)