[SMSS] Use RTL string-safe functions in critical places. Add validity checks for returned NtQueryValueKey() data. (#2704)

- Not all the wcscpy() / swprintf() calls have been converted to their
  string-safe equivalents. Instead I used the string-safe functions only
  for places where strings of unknown length were copied into fixed-size
  internal buffers. On the contrary, for known-fixed-length strings being
  copied or numbers being converted to string representations in large
  enough buffers, I kept the original function calls.

- Verify the registry data that has been returned by NtQueryValueKey():
  * When expecting (not multi) strings, check whether the data type is
    either REG_SZ or REG_EXPAND_SZ.
  * When expecting DWORD values, check whether the data type is
    REG_DWORD and whether the data length is (greater or) equal to
    sizeof(ULONG).
This commit is contained in:
Hermès Bélusca-Maïto 2020-04-30 18:42:16 +02:00
parent 8ee0ee6a88
commit 87e2ec585f
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
5 changed files with 80 additions and 44 deletions

View file

@ -789,12 +789,13 @@ SmpTranslateSystemPartitionInformation(VOID)
UNICODE_STRING UnicodeString, LinkTarget, SearchString, SystemPartition;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE KeyHandle, LinkHandle;
CHAR ValueBuffer[512 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)];
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
ULONG Length, Context;
CHAR DirInfoBuffer[512 + sizeof(OBJECT_DIRECTORY_INFORMATION)];
POBJECT_DIRECTORY_INFORMATION DirInfo = (PVOID)DirInfoBuffer;
size_t StrLength;
WCHAR LinkBuffer[MAX_PATH];
CHAR ValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 512];
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
CHAR DirInfoBuffer[sizeof(OBJECT_DIRECTORY_INFORMATION) + 512];
POBJECT_DIRECTORY_INFORMATION DirInfo = (PVOID)DirInfoBuffer;
/* Open the setup key */
RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\Setup");
@ -806,7 +807,7 @@ SmpTranslateSystemPartitionInformation(VOID)
Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("SMSS: can't open system setup key for reading: 0x%x\n", Status);
DPRINT1("SMSS: Cannot open system setup key for reading: 0x%x\n", Status);
return;
}
@ -819,14 +820,22 @@ SmpTranslateSystemPartitionInformation(VOID)
sizeof(ValueBuffer),
&Length);
NtClose(KeyHandle);
if (!NT_SUCCESS(Status))
if (!NT_SUCCESS(Status) ||
((PartialInfo->Type != REG_SZ) && (PartialInfo->Type != REG_EXPAND_SZ)))
{
DPRINT1("SMSS: can't query SystemPartition value: 0x%x\n", Status);
DPRINT1("SMSS: Cannot query SystemPartition value (Type %lu, Status 0x%x)\n",
PartialInfo->Type, Status);
return;
}
/* Initialize the system partition string string */
RtlInitUnicodeString(&SystemPartition, (PWCHAR)PartialInfo->Data);
/* Initialize the system partition string */
RtlInitEmptyUnicodeString(&SystemPartition,
(PWCHAR)PartialInfo->Data,
PartialInfo->DataLength);
RtlStringCbLengthW(SystemPartition.Buffer,
SystemPartition.MaximumLength,
&StrLength);
SystemPartition.Length = (USHORT)StrLength;
/* Enumerate the directory looking for the symbolic link string */
RtlInitUnicodeString(&SearchString, L"SymbolicLink");
@ -840,7 +849,7 @@ SmpTranslateSystemPartitionInformation(VOID)
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("SMSS: can't find drive letter for system partition\n");
DPRINT1("SMSS: Cannot find drive letter for system partition\n");
return;
}
@ -872,8 +881,8 @@ SmpTranslateSystemPartitionInformation(VOID)
/* Check if it matches the string we had found earlier */
if ((NT_SUCCESS(Status)) &&
((RtlEqualUnicodeString(&SystemPartition,
&LinkTarget,
TRUE)) ||
&LinkTarget,
TRUE)) ||
((RtlPrefixUnicodeString(&SystemPartition,
&LinkTarget,
TRUE)) &&
@ -896,7 +905,7 @@ SmpTranslateSystemPartitionInformation(VOID)
} while (NT_SUCCESS(Status));
if (!NT_SUCCESS(Status))
{
DPRINT1("SMSS: can't find drive letter for system partition\n");
DPRINT1("SMSS: Cannot find drive letter for system partition\n");
return;
}
@ -911,7 +920,7 @@ SmpTranslateSystemPartitionInformation(VOID)
Status = NtOpenKey(&KeyHandle, KEY_ALL_ACCESS, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("SMSS: can't open software setup key for writing: 0x%x\n",
DPRINT1("SMSS: Cannot open software setup key for writing: 0x%x\n",
Status);
return;
}
@ -1349,7 +1358,7 @@ NTAPI
SmpProcessModuleImports(IN PVOID Unused,
IN PCHAR ImportName)
{
ULONG Length = 0, Chars;
ULONG Length = 0;
WCHAR Buffer[MAX_PATH];
PWCHAR DllName, DllValue;
ANSI_STRING ImportString;
@ -1365,20 +1374,22 @@ SmpProcessModuleImports(IN PVOID Unused,
Status = RtlAnsiStringToUnicodeString(&ImportUnicodeString, &ImportString, FALSE);
if (!NT_SUCCESS(Status)) return;
/* Loop in case we find a forwarder */
ImportUnicodeString.MaximumLength = ImportUnicodeString.Length + sizeof(UNICODE_NULL);
/* Loop to find the DLL file extension */
while (Length < ImportUnicodeString.Length)
{
if (ImportUnicodeString.Buffer[Length / sizeof(WCHAR)] == L'.') break;
Length += sizeof(WCHAR);
}
/* Break up the values as needed */
/*
* Break up the values as needed; the buffer acquires the form:
* "dll_name.dll\0dll_name\0"
*/
DllValue = ImportUnicodeString.Buffer;
DllName = &ImportUnicodeString.Buffer[ImportUnicodeString.MaximumLength / sizeof(WCHAR)];
Chars = Length >> 1;
wcsncpy(DllName, ImportUnicodeString.Buffer, Chars);
DllName[Chars] = 0;
DllName = &ImportUnicodeString.Buffer[(ImportUnicodeString.Length + sizeof(UNICODE_NULL)) / sizeof(WCHAR)];
RtlStringCbCopyNW(DllName,
ImportUnicodeString.MaximumLength - (ImportUnicodeString.Length + sizeof(UNICODE_NULL)),
ImportUnicodeString.Buffer, Length);
/* Add the DLL to the list */
SmpSaveRegistryValue(&SmpKnownDllsList, DllName, DllValue, TRUE);
@ -1652,9 +1663,11 @@ SmpCreateDynamicEnvironmentVariables(VOID)
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING ValueName, DestinationString;
HANDLE KeyHandle, KeyHandle2;
ULONG ResultLength;
PWCHAR ValueData;
WCHAR ValueBuffer[512], ValueBuffer2[512];
ULONG ResultLength;
size_t StrLength;
WCHAR ValueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 512];
WCHAR ValueBuffer2[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 512];
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo2 = (PVOID)ValueBuffer2;
@ -1798,15 +1811,27 @@ SmpCreateDynamicEnvironmentVariables(VOID)
PartialInfo,
sizeof(ValueBuffer),
&ResultLength);
if (!NT_SUCCESS(Status))
if (!NT_SUCCESS(Status) ||
((PartialInfo->Type != REG_SZ) && (PartialInfo->Type != REG_EXPAND_SZ)))
{
NtClose(KeyHandle2);
NtClose(KeyHandle);
DPRINT1("SMSS: Unable to read %wZ\\%wZ - %x\n",
&DestinationString, &ValueName, Status);
DPRINT1("SMSS: Unable to read %wZ\\%wZ (Type %lu, Status 0x%x)\n",
&DestinationString, &ValueName, PartialInfo->Type, Status);
return Status;
}
/* Initialize the string so that it can be large enough
* to contain both the identifier and the vendor strings. */
RtlInitEmptyUnicodeString(&DestinationString,
(PWCHAR)PartialInfo->Data,
sizeof(ValueBuffer) -
FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data));
RtlStringCbLengthW(DestinationString.Buffer,
PartialInfo->DataLength,
&StrLength);
DestinationString.Length = (USHORT)StrLength;
/* As well as the vendor... */
RtlInitUnicodeString(&ValueName, L"VendorIdentifier");
Status = NtQueryValueKey(KeyHandle2,
@ -1816,23 +1841,27 @@ SmpCreateDynamicEnvironmentVariables(VOID)
sizeof(ValueBuffer2),
&ResultLength);
NtClose(KeyHandle2);
if (NT_SUCCESS(Status))
if (NT_SUCCESS(Status) &&
((PartialInfo2->Type == REG_SZ) || (PartialInfo2->Type == REG_EXPAND_SZ)))
{
/* To combine it into a single string */
swprintf((PWCHAR)PartialInfo->Data + wcslen((PWCHAR)PartialInfo->Data),
L", %s",
(PWCHAR)PartialInfo2->Data);
RtlStringCbPrintfW(DestinationString.Buffer + DestinationString.Length / sizeof(WCHAR),
DestinationString.MaximumLength - DestinationString.Length,
L", %.*s",
PartialInfo2->DataLength / sizeof(WCHAR),
(PWCHAR)PartialInfo2->Data);
DestinationString.Length = (USHORT)(wcslen(DestinationString.Buffer) * sizeof(WCHAR));
}
/* So that we can set this as the PROCESSOR_IDENTIFIER variable */
RtlInitUnicodeString(&ValueName, L"PROCESSOR_IDENTIFIER");
DPRINT("Setting %wZ to %S\n", &ValueName, PartialInfo->Data);
DPRINT("Setting %wZ to %wZ\n", &ValueName, &DestinationString);
Status = NtSetValueKey(KeyHandle,
&ValueName,
0,
REG_SZ,
PartialInfo->Data,
(wcslen((PWCHAR)PartialInfo->Data) + 1) * sizeof(WCHAR));
DestinationString.Buffer,
DestinationString.Length + sizeof(UNICODE_NULL));
if (!NT_SUCCESS(Status))
{
DPRINT1("SMSS: Failed writing %wZ environment variable - %x\n",
@ -1922,7 +1951,9 @@ SmpCreateDynamicEnvironmentVariables(VOID)
sizeof(ValueBuffer),
&ResultLength);
NtClose(KeyHandle2);
if (NT_SUCCESS(Status))
if (NT_SUCCESS(Status) &&
(PartialInfo->Type == REG_DWORD) &&
(PartialInfo->DataLength >= sizeof(ULONG)))
{
/* Convert from the integer value to the correct specifier */
RtlInitUnicodeString(&ValueName, L"SAFEBOOT_OPTION");
@ -1957,7 +1988,8 @@ SmpCreateDynamicEnvironmentVariables(VOID)
}
else
{
DPRINT1("SMSS: Failed querying safeboot option = %x\n", Status);
DPRINT1("SMSS: Failed to query SAFEBOOT option (Type %lu, Status 0x%x)\n",
PartialInfo->Type, Status);
}
}

View file

@ -94,7 +94,7 @@ SmpSbCreateSession(IN PVOID Reserved,
NtClose(ProcessInformation->ProcessHandle);
NtClose(ProcessInformation->ThreadHandle);
SmpDereferenceSubsystem(KnownSubsys);
DbgPrint("SmpSbCreateSession: NtDuplicateObject (Thread) Failed %lx\n", Status);
DPRINT1("SmpSbCreateSession: NtDuplicateObject (Thread) Failed %lx\n", Status);
return Status;
}

View file

@ -31,6 +31,8 @@
#include <ndk/umfuncs.h>
#include <ndk/kefuncs.h>
#include <ntstrsafe.h>
/* SM Protocol Header */
#include <sm/smmsg.h>

View file

@ -656,8 +656,8 @@ SmpLoadSubSystemsForMuSession(IN PULONG MuSessionId,
if ((NT_SUCCESS(Status2)) && (InitialCommandBuffer[0]))
{
/* Put the debugger string with the Winlogon string */
wcscat(InitialCommandBuffer, L" ");
wcscat(InitialCommandBuffer, InitialCommand->Buffer);
RtlStringCbCatW(InitialCommandBuffer, sizeof(InitialCommandBuffer), L" ");
RtlStringCbCatW(InitialCommandBuffer, sizeof(InitialCommandBuffer), InitialCommand->Buffer);
RtlInitUnicodeString(InitialCommand, InitialCommandBuffer);
}
}

View file

@ -380,7 +380,7 @@ SmpParseCommandLine(IN PUNICODE_STRING CommandLine,
else
{
/* Caller doesn't want flags, probably wants the image itself */
wcscpy(PathBuffer, Token.Buffer);
RtlStringCbCopyW(PathBuffer, sizeof(PathBuffer), Token.Buffer);
}
}
@ -427,9 +427,9 @@ SmpQueryRegistrySosOption(VOID)
UNICODE_STRING KeyName, ValueName;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE KeyHandle;
ULONG Length;
WCHAR ValueBuffer[VALUE_BUFFER_SIZE];
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo = (PVOID)ValueBuffer;
ULONG Length;
/* Open the key */
RtlInitUnicodeString(&KeyName,
@ -442,7 +442,7 @@ SmpQueryRegistrySosOption(VOID)
Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status))
{
DPRINT1("SMSS: can't open control key: 0x%x\n", Status);
DPRINT1("SMSS: Cannot open control key (Status 0x%x)\n", Status);
return FALSE;
}
@ -456,9 +456,11 @@ SmpQueryRegistrySosOption(VOID)
&Length);
ASSERT(Length < VALUE_BUFFER_SIZE);
NtClose(KeyHandle);
if (!NT_SUCCESS(Status))
if (!NT_SUCCESS(Status) ||
((PartialInfo->Type != REG_SZ) && (PartialInfo->Type != REG_EXPAND_SZ)))
{
DPRINT1("SMSS: can't query value key: 0x%x\n", Status);
DPRINT1("SMSS: Cannot query value key (Type %lu, Status 0x%x)\n",
PartialInfo->Type, Status);
return FALSE;
}