Correctly handle small buffers in NtEnumerate[Value]Key and NtQuery[Value]Key registry routines:

- If buffer is too small to contain even fixed size information for specified type return STATUS_BUFFER_TOO_SMALL.
- If buffer is large enough to contain some information, but not all information requested, fill as much as we can and return STATUS_BUFFER_OVERFLOW.
- If we fill the entire buffer return STATUS_SUCCESS.

svn path=/trunk/; revision=11235
This commit is contained in:
Filip Navara 2004-10-08 21:19:12 +00:00
parent ef253bf9d3
commit 1e09759df9
2 changed files with 257 additions and 100 deletions

View file

@ -1,4 +1,4 @@
/* $Id: reg.c,v 1.58 2004/09/28 20:40:15 gvg Exp $ /* $Id: reg.c,v 1.59 2004/10/08 21:19:12 navaraf Exp $
* *
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries * PROJECT: ReactOS system libraries
@ -2304,7 +2304,7 @@ RegQueryValueExW (HKEY hKey,
BufferSize, BufferSize,
&ResultSize); &ResultSize);
DPRINT("Status 0x%X\n", Status); DPRINT("Status 0x%X\n", Status);
if (Status == STATUS_BUFFER_TOO_SMALL) if (Status == STATUS_BUFFER_OVERFLOW)
{ {
/* Return ERROR_SUCCESS and the buffer space needed for a successful call */ /* Return ERROR_SUCCESS and the buffer space needed for a successful call */
MaxCopy = 0; MaxCopy = 0;

View file

@ -313,7 +313,7 @@ NtEnumerateKey(IN HANDLE KeyHandle,
PKEY_NODE_INFORMATION NodeInformation; PKEY_NODE_INFORMATION NodeInformation;
PKEY_FULL_INFORMATION FullInformation; PKEY_FULL_INFORMATION FullInformation;
PDATA_CELL ClassCell; PDATA_CELL ClassCell;
ULONG NameSize; ULONG NameSize, ClassSize;
NTSTATUS Status; NTSTATUS Status;
DPRINT("KH %x I %d KIC %x KI %x L %d RL %x\n", DPRINT("KH %x I %d KIC %x KI %x L %d RL %x\n",
@ -444,6 +444,8 @@ NtEnumerateKey(IN HANDLE KeyHandle,
} }
} }
*ResultLength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]) + NameSize;
/* /*
* NOTE: It's perfetly valid to call NtEnumerateKey to get * NOTE: It's perfetly valid to call NtEnumerateKey to get
* all the information but name. Actually the NT4 sound * all the information but name. Actually the NT4 sound
@ -452,7 +454,7 @@ NtEnumerateKey(IN HANDLE KeyHandle,
*/ */
if (Length < FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0])) if (Length < FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]))
{ {
Status = STATUS_BUFFER_OVERFLOW; Status = STATUS_BUFFER_TOO_SMALL;
} }
else else
{ {
@ -463,7 +465,12 @@ NtEnumerateKey(IN HANDLE KeyHandle,
BasicInformation->TitleIndex = Index; BasicInformation->TitleIndex = Index;
BasicInformation->NameLength = NameSize; BasicInformation->NameLength = NameSize;
NameSize = min(NameSize, Length - FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0])); if (Length - FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]) < NameSize)
{
NameSize = Length - FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
if (SubKeyObject != NULL) if (SubKeyObject != NULL)
{ {
@ -487,8 +494,6 @@ NtEnumerateKey(IN HANDLE KeyHandle,
} }
} }
} }
*ResultLength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]) + NameSize;
break; break;
case KeyNodeInformation: case KeyNodeInformation:
@ -505,12 +510,14 @@ NtEnumerateKey(IN HANDLE KeyHandle,
NameSize *= sizeof(WCHAR); NameSize *= sizeof(WCHAR);
} }
} }
*ResultLength = FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) + ClassSize = SubKeyCell->ClassSize;
NameSize + SubKeyCell->ClassSize;
if (Length < *ResultLength) *ResultLength = FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) +
NameSize + ClassSize;
if (Length < FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]))
{ {
Status = STATUS_BUFFER_OVERFLOW; Status = STATUS_BUFFER_TOO_SMALL;
} }
else else
{ {
@ -521,51 +528,68 @@ NtEnumerateKey(IN HANDLE KeyHandle,
NodeInformation->TitleIndex = Index; NodeInformation->TitleIndex = Index;
NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) + NameSize; NodeInformation->ClassOffset = sizeof(KEY_NODE_INFORMATION) + NameSize;
NodeInformation->ClassLength = SubKeyCell->ClassSize; NodeInformation->ClassLength = SubKeyCell->ClassSize;
NodeInformation->NameLength = NameSize;
if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) < NameSize)
{
NameSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]);
ClassSize = 0;
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
else if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
NameSize < ClassSize)
{
ClassSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
NameSize;
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
if (SubKeyObject != NULL) if (SubKeyObject != NULL)
{ {
NodeInformation->NameLength = SubKeyObject->Name.Length;
RtlCopyMemory(NodeInformation->Name, RtlCopyMemory(NodeInformation->Name,
SubKeyObject->Name.Buffer, SubKeyObject->Name.Buffer,
SubKeyObject->Name.Length); NameSize);
} }
else else
{ {
NodeInformation->NameLength = NameSize;
if (SubKeyCell->Flags & REG_KEY_NAME_PACKED) if (SubKeyCell->Flags & REG_KEY_NAME_PACKED)
{ {
CmiCopyPackedName(NodeInformation->Name, CmiCopyPackedName(NodeInformation->Name,
SubKeyCell->Name, SubKeyCell->Name,
SubKeyCell->NameSize); NameSize / sizeof(WCHAR));
} }
else else
{ {
RtlCopyMemory(NodeInformation->Name, RtlCopyMemory(NodeInformation->Name,
SubKeyCell->Name, SubKeyCell->Name,
SubKeyCell->NameSize); NameSize);
} }
} }
if (SubKeyCell->ClassSize != 0) if (ClassSize != 0)
{ {
ClassCell = CmiGetCell (KeyObject->RegistryHive, ClassCell = CmiGetCell (KeyObject->RegistryHive,
SubKeyCell->ClassNameOffset, SubKeyCell->ClassNameOffset,
NULL); NULL);
RtlCopyMemory (NodeInformation->Name + SubKeyCell->NameSize, RtlCopyMemory (NodeInformation->Name + SubKeyCell->NameSize,
ClassCell->Data, ClassCell->Data,
SubKeyCell->ClassSize); ClassSize);
} }
} }
break; break;
case KeyFullInformation: case KeyFullInformation:
/* Check size of buffer */ ClassSize = SubKeyCell->ClassSize;
*ResultLength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]) +
SubKeyCell->ClassSize;
if (Length < *ResultLength) *ResultLength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]) +
ClassSize;
/* Check size of buffer */
if (Length < FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]))
{ {
Status = STATUS_BUFFER_OVERFLOW; Status = STATUS_BUFFER_TOO_SMALL;
} }
else else
{ {
@ -585,14 +609,22 @@ NtEnumerateKey(IN HANDLE KeyHandle,
CmiGetMaxValueNameLength(RegistryHive, SubKeyCell); CmiGetMaxValueNameLength(RegistryHive, SubKeyCell);
FullInformation->MaxValueDataLen = FullInformation->MaxValueDataLen =
CmiGetMaxValueDataLength(RegistryHive, SubKeyCell); CmiGetMaxValueDataLength(RegistryHive, SubKeyCell);
if (SubKeyCell->ClassSize != 0)
if (Length - FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]) < ClassSize)
{
ClassSize = Length - FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]);
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
if (ClassSize != 0)
{ {
ClassCell = CmiGetCell (KeyObject->RegistryHive, ClassCell = CmiGetCell (KeyObject->RegistryHive,
SubKeyCell->ClassNameOffset, SubKeyCell->ClassNameOffset,
NULL); NULL);
RtlCopyMemory (FullInformation->Class, RtlCopyMemory (FullInformation->Class,
ClassCell->Data, ClassCell->Data,
SubKeyCell->ClassSize); ClassSize);
} }
} }
break; break;
@ -626,7 +658,7 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
PKEY_CELL KeyCell; PKEY_CELL KeyCell;
PVALUE_CELL ValueCell; PVALUE_CELL ValueCell;
PDATA_CELL DataCell; PDATA_CELL DataCell;
ULONG NameSize; ULONG NameSize, DataSize;
PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation; PKEY_VALUE_BASIC_INFORMATION ValueBasicInformation;
PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation; PKEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
PKEY_VALUE_FULL_INFORMATION ValueFullInformation; PKEY_VALUE_FULL_INFORMATION ValueFullInformation;
@ -686,10 +718,12 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
{ {
NameSize *= sizeof(WCHAR); NameSize *= sizeof(WCHAR);
} }
*ResultLength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) + NameSize; *ResultLength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) + NameSize;
if (Length < *ResultLength)
if (Length < FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]))
{ {
Status = STATUS_BUFFER_OVERFLOW; Status = STATUS_BUFFER_TOO_SMALL;
} }
else else
{ {
@ -698,11 +732,20 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
ValueBasicInformation->TitleIndex = 0; ValueBasicInformation->TitleIndex = 0;
ValueBasicInformation->Type = ValueCell->DataType; ValueBasicInformation->Type = ValueCell->DataType;
ValueBasicInformation->NameLength = NameSize; ValueBasicInformation->NameLength = NameSize;
if (Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) <
NameSize)
{
NameSize = Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
if (ValueCell->Flags & REG_VALUE_NAME_PACKED) if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
{ {
CmiCopyPackedName(ValueBasicInformation->Name, CmiCopyPackedName(ValueBasicInformation->Name,
ValueCell->Name, ValueCell->Name,
ValueCell->NameSize); NameSize / sizeof(WCHAR));
} }
else else
{ {
@ -714,11 +757,14 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
break; break;
case KeyValuePartialInformation: case KeyValuePartialInformation:
DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
*ResultLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) + *ResultLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) +
(ValueCell->DataSize & REG_DATA_SIZE_MASK); DataSize;
if (Length < *ResultLength)
if (Length < FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]))
{ {
Status = STATUS_BUFFER_OVERFLOW; Status = STATUS_BUFFER_TOO_SMALL;
} }
else else
{ {
@ -727,18 +773,27 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
ValuePartialInformation->TitleIndex = 0; ValuePartialInformation->TitleIndex = 0;
ValuePartialInformation->Type = ValueCell->DataType; ValuePartialInformation->Type = ValueCell->DataType;
ValuePartialInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK; ValuePartialInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
if (Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) <
DataSize)
{
DataSize = Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET)) if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
{ {
DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL); DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
RtlCopyMemory(ValuePartialInformation->Data, RtlCopyMemory(ValuePartialInformation->Data,
DataCell->Data, DataCell->Data,
ValueCell->DataSize & REG_DATA_SIZE_MASK); DataSize);
} }
else else
{ {
RtlCopyMemory(ValuePartialInformation->Data, RtlCopyMemory(ValuePartialInformation->Data,
&ValueCell->DataOffset, &ValueCell->DataOffset,
ValueCell->DataSize & REG_DATA_SIZE_MASK); DataSize);
} }
} }
break; break;
@ -749,11 +804,14 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
{ {
NameSize *= sizeof(WCHAR); NameSize *= sizeof(WCHAR);
} }
*ResultLength = FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) + DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
NameSize + (ValueCell->DataSize & REG_DATA_SIZE_MASK);
if (Length < *ResultLength) *ResultLength = ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
Name[0]) + NameSize, sizeof(PVOID)) + DataSize;
if (Length < FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]))
{ {
Status = STATUS_BUFFER_OVERFLOW; Status = STATUS_BUFFER_TOO_SMALL;
} }
else else
{ {
@ -762,18 +820,6 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
ValueFullInformation->TitleIndex = 0; ValueFullInformation->TitleIndex = 0;
ValueFullInformation->Type = ValueCell->DataType; ValueFullInformation->Type = ValueCell->DataType;
ValueFullInformation->NameLength = NameSize; ValueFullInformation->NameLength = NameSize;
if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
{
CmiCopyPackedName(ValueFullInformation->Name,
ValueCell->Name,
ValueCell->NameSize);
}
else
{
RtlCopyMemory(ValueFullInformation->Name,
ValueCell->Name,
ValueCell->NameSize);
}
ValueFullInformation->DataOffset = ValueFullInformation->DataOffset =
(ULONG_PTR)ValueFullInformation->Name - (ULONG_PTR)ValueFullInformation->Name -
(ULONG_PTR)ValueFullInformation + (ULONG_PTR)ValueFullInformation +
@ -781,20 +827,48 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
ValueFullInformation->DataOffset = ValueFullInformation->DataOffset =
ROUND_UP(ValueFullInformation->DataOffset, sizeof(PVOID)); ROUND_UP(ValueFullInformation->DataOffset, sizeof(PVOID));
ValueFullInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK; ValueFullInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
if (Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) <
NameSize)
{
NameSize = Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
DataSize = 0;
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
else if (ROUND_UP(Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
Name[0]) - NameSize, sizeof(PVOID)) < DataSize)
{
DataSize = ROUND_UP(Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) - NameSize, sizeof(PVOID));
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
{
CmiCopyPackedName(ValueFullInformation->Name,
ValueCell->Name,
NameSize / sizeof(WCHAR));
}
else
{
RtlCopyMemory(ValueFullInformation->Name,
ValueCell->Name,
NameSize);
}
if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET)) if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
{ {
DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL); DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
RtlCopyMemory((PCHAR) ValueFullInformation RtlCopyMemory((PCHAR) ValueFullInformation
+ ValueFullInformation->DataOffset, + ValueFullInformation->DataOffset,
DataCell->Data, DataCell->Data, DataSize);
ValueCell->DataSize & REG_DATA_SIZE_MASK);
} }
else else
{ {
RtlCopyMemory((PCHAR) ValueFullInformation RtlCopyMemory((PCHAR) ValueFullInformation
+ ValueFullInformation->DataOffset, + ValueFullInformation->DataOffset,
&ValueCell->DataOffset, &ValueCell->DataOffset, DataSize);
ValueCell->DataSize & REG_DATA_SIZE_MASK);
} }
} }
break; break;
@ -941,6 +1015,7 @@ NtQueryKey(IN HANDLE KeyHandle,
PDATA_CELL ClassCell; PDATA_CELL ClassCell;
PKEY_OBJECT KeyObject; PKEY_OBJECT KeyObject;
PKEY_CELL KeyCell; PKEY_CELL KeyCell;
ULONG NameSize, ClassSize;
NTSTATUS Status; NTSTATUS Status;
DPRINT("NtQueryKey(KH %x KIC %x KI %x L %d RL %x)\n", DPRINT("NtQueryKey(KH %x KIC %x KI %x L %d RL %x)\n",
@ -976,11 +1051,12 @@ NtQueryKey(IN HANDLE KeyHandle,
switch (KeyInformationClass) switch (KeyInformationClass)
{ {
case KeyBasicInformation: case KeyBasicInformation:
/* Check size of buffer */ NameSize = KeyObject->Name.Length;
*ResultLength = sizeof(KEY_BASIC_INFORMATION) +
KeyObject->Name.Length;
if (Length < *ResultLength) *ResultLength = FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
/* Check size of buffer */
if (Length < FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]))
{ {
Status = STATUS_BUFFER_TOO_SMALL; Status = STATUS_BUFFER_TOO_SMALL;
} }
@ -993,17 +1069,28 @@ NtQueryKey(IN HANDLE KeyHandle,
BasicInformation->TitleIndex = 0; BasicInformation->TitleIndex = 0;
BasicInformation->NameLength = KeyObject->Name.Length; BasicInformation->NameLength = KeyObject->Name.Length;
if (Length - FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]) <
NameSize)
{
NameSize = Length - FIELD_OFFSET(KEY_BASIC_INFORMATION, Name[0]);
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
RtlCopyMemory(BasicInformation->Name, RtlCopyMemory(BasicInformation->Name,
KeyObject->Name.Buffer, KeyObject->Name.Buffer,
KeyObject->Name.Length); NameSize);
} }
break; break;
case KeyNodeInformation: case KeyNodeInformation:
/* Check size of buffer */ NameSize = KeyObject->Name.Length;
*ResultLength = sizeof(KEY_NODE_INFORMATION) + ClassSize = KeyCell->ClassSize;
KeyObject->Name.Length + KeyCell->ClassSize;
*ResultLength = FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) +
NameSize + ClassSize;
/* Check size of buffer */
if (Length < *ResultLength) if (Length < *ResultLength)
{ {
Status = STATUS_BUFFER_TOO_SMALL; Status = STATUS_BUFFER_TOO_SMALL;
@ -1020,28 +1107,46 @@ NtQueryKey(IN HANDLE KeyHandle,
NodeInformation->ClassLength = KeyCell->ClassSize; NodeInformation->ClassLength = KeyCell->ClassSize;
NodeInformation->NameLength = KeyObject->Name.Length; NodeInformation->NameLength = KeyObject->Name.Length;
if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) < NameSize)
{
NameSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]);
ClassSize = 0;
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
else if (Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
NameSize < ClassSize)
{
ClassSize = Length - FIELD_OFFSET(KEY_NODE_INFORMATION, Name[0]) -
NameSize;
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
RtlCopyMemory(NodeInformation->Name, RtlCopyMemory(NodeInformation->Name,
KeyObject->Name.Buffer, KeyObject->Name.Buffer,
KeyObject->Name.Length); NameSize);
if (KeyCell->ClassSize != 0) if (ClassSize != 0)
{ {
ClassCell = CmiGetCell (KeyObject->RegistryHive, ClassCell = CmiGetCell (KeyObject->RegistryHive,
KeyCell->ClassNameOffset, KeyCell->ClassNameOffset,
NULL); NULL);
RtlCopyMemory (NodeInformation->Name + KeyObject->Name.Length, RtlCopyMemory (NodeInformation->Name + KeyObject->Name.Length,
ClassCell->Data, ClassCell->Data,
KeyCell->ClassSize); ClassSize);
} }
} }
break; break;
case KeyFullInformation: case KeyFullInformation:
/* Check size of buffer */ ClassSize = KeyCell->ClassSize;
*ResultLength = sizeof(KEY_FULL_INFORMATION) +
KeyCell->ClassSize;
if (Length < *ResultLength) *ResultLength = FIELD_OFFSET(KEY_FULL_INFORMATION, Class) +
ClassSize;
/* Check size of buffer */
if (Length < FIELD_OFFSET(KEY_FULL_INFORMATION, Class))
{ {
Status = STATUS_BUFFER_TOO_SMALL; Status = STATUS_BUFFER_TOO_SMALL;
} }
@ -1062,14 +1167,21 @@ NtQueryKey(IN HANDLE KeyHandle,
CmiGetMaxValueNameLength(RegistryHive, KeyCell); CmiGetMaxValueNameLength(RegistryHive, KeyCell);
FullInformation->MaxValueDataLen = FullInformation->MaxValueDataLen =
CmiGetMaxValueDataLength(RegistryHive, KeyCell); CmiGetMaxValueDataLength(RegistryHive, KeyCell);
if (KeyCell->ClassSize != 0)
if (Length - FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]) < ClassSize)
{
ClassSize = Length - FIELD_OFFSET(KEY_FULL_INFORMATION, Class[0]);
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
if (ClassSize)
{ {
ClassCell = CmiGetCell (KeyObject->RegistryHive, ClassCell = CmiGetCell (KeyObject->RegistryHive,
KeyCell->ClassNameOffset, KeyCell->ClassNameOffset,
NULL); NULL);
RtlCopyMemory (FullInformation->Class, RtlCopyMemory (FullInformation->Class,
ClassCell->Data, ClassCell->Data, ClassSize);
KeyCell->ClassSize);
} }
} }
break; break;
@ -1097,7 +1209,7 @@ NtQueryValueKey(IN HANDLE KeyHandle,
OUT PULONG ResultLength) OUT PULONG ResultLength)
{ {
NTSTATUS Status; NTSTATUS Status;
ULONG NameSize; ULONG NameSize, DataSize;
PKEY_OBJECT KeyObject; PKEY_OBJECT KeyObject;
PREGISTRY_HIVE RegistryHive; PREGISTRY_HIVE RegistryHive;
PKEY_CELL KeyCell; PKEY_CELL KeyCell;
@ -1155,8 +1267,11 @@ NtQueryValueKey(IN HANDLE KeyHandle,
{ {
NameSize *= sizeof(WCHAR); NameSize *= sizeof(WCHAR);
} }
*ResultLength = sizeof(KEY_VALUE_BASIC_INFORMATION) + NameSize;
if (Length < *ResultLength) *ResultLength = FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) +
NameSize;
if (Length < FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]))
{ {
Status = STATUS_BUFFER_TOO_SMALL; Status = STATUS_BUFFER_TOO_SMALL;
} }
@ -1167,25 +1282,37 @@ NtQueryValueKey(IN HANDLE KeyHandle,
ValueBasicInformation->TitleIndex = 0; ValueBasicInformation->TitleIndex = 0;
ValueBasicInformation->Type = ValueCell->DataType; ValueBasicInformation->Type = ValueCell->DataType;
ValueBasicInformation->NameLength = NameSize; ValueBasicInformation->NameLength = NameSize;
if (Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]) <
NameSize)
{
NameSize = Length - FIELD_OFFSET(KEY_VALUE_BASIC_INFORMATION, Name[0]);
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
if (ValueCell->Flags & REG_VALUE_NAME_PACKED) if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
{ {
CmiCopyPackedName(ValueBasicInformation->Name, CmiCopyPackedName(ValueBasicInformation->Name,
ValueCell->Name, ValueCell->Name,
ValueCell->NameSize); NameSize / sizeof(WCHAR));
} }
else else
{ {
RtlCopyMemory(ValueBasicInformation->Name, RtlCopyMemory(ValueBasicInformation->Name,
ValueCell->Name, ValueCell->Name,
ValueCell->NameSize * sizeof(WCHAR)); NameSize);
} }
} }
break; break;
case KeyValuePartialInformation: case KeyValuePartialInformation:
*ResultLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION) DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
+ (ValueCell->DataSize & REG_DATA_SIZE_MASK);
if (Length < *ResultLength) *ResultLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) +
DataSize;
if (Length < FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]))
{ {
Status = STATUS_BUFFER_TOO_SMALL; Status = STATUS_BUFFER_TOO_SMALL;
} }
@ -1195,19 +1322,28 @@ NtQueryValueKey(IN HANDLE KeyHandle,
KeyValueInformation; KeyValueInformation;
ValuePartialInformation->TitleIndex = 0; ValuePartialInformation->TitleIndex = 0;
ValuePartialInformation->Type = ValueCell->DataType; ValuePartialInformation->Type = ValueCell->DataType;
ValuePartialInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK; ValuePartialInformation->DataLength = DataSize;
if (Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]) <
DataSize)
{
DataSize = Length - FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[0]);
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET)) if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
{ {
DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL); DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
RtlCopyMemory(ValuePartialInformation->Data, RtlCopyMemory(ValuePartialInformation->Data,
DataCell->Data, DataCell->Data,
ValueCell->DataSize & REG_DATA_SIZE_MASK); DataSize);
} }
else else
{ {
RtlCopyMemory(ValuePartialInformation->Data, RtlCopyMemory(ValuePartialInformation->Data,
&ValueCell->DataOffset, &ValueCell->DataOffset,
ValueCell->DataSize & REG_DATA_SIZE_MASK); DataSize);
} }
} }
break; break;
@ -1218,9 +1354,12 @@ NtQueryValueKey(IN HANDLE KeyHandle,
{ {
NameSize *= sizeof(WCHAR); NameSize *= sizeof(WCHAR);
} }
*ResultLength = sizeof(KEY_VALUE_FULL_INFORMATION) + DataSize = ValueCell->DataSize & REG_DATA_SIZE_MASK;
NameSize + (ValueCell->DataSize & REG_DATA_SIZE_MASK);
if (Length < *ResultLength) *ResultLength = ROUND_UP(FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
Name[0]) + NameSize, sizeof(PVOID)) + DataSize;
if (Length < FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]))
{ {
Status = STATUS_BUFFER_TOO_SMALL; Status = STATUS_BUFFER_TOO_SMALL;
} }
@ -1231,18 +1370,6 @@ NtQueryValueKey(IN HANDLE KeyHandle,
ValueFullInformation->TitleIndex = 0; ValueFullInformation->TitleIndex = 0;
ValueFullInformation->Type = ValueCell->DataType; ValueFullInformation->Type = ValueCell->DataType;
ValueFullInformation->NameLength = NameSize; ValueFullInformation->NameLength = NameSize;
if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
{
CmiCopyPackedName(ValueFullInformation->Name,
ValueCell->Name,
ValueCell->NameSize);
}
else
{
RtlCopyMemory(ValueFullInformation->Name,
ValueCell->Name,
ValueCell->NameSize);
}
ValueFullInformation->DataOffset = ValueFullInformation->DataOffset =
(ULONG_PTR)ValueFullInformation->Name - (ULONG_PTR)ValueFullInformation->Name -
(ULONG_PTR)ValueFullInformation + (ULONG_PTR)ValueFullInformation +
@ -1250,20 +1377,50 @@ NtQueryValueKey(IN HANDLE KeyHandle,
ValueFullInformation->DataOffset = ValueFullInformation->DataOffset =
ROUND_UP(ValueFullInformation->DataOffset, sizeof(PVOID)); ROUND_UP(ValueFullInformation->DataOffset, sizeof(PVOID));
ValueFullInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK; ValueFullInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
if (Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) <
NameSize)
{
NameSize = Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]);
DataSize = 0;
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
else if (ROUND_UP(Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
Name[0]) - NameSize, sizeof(PVOID)) < DataSize)
{
DataSize = ROUND_UP(Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION,
Name[0]) - NameSize, sizeof(PVOID));
Status = STATUS_BUFFER_OVERFLOW;
CHECKPOINT;
}
if (ValueCell->Flags & REG_VALUE_NAME_PACKED)
{
CmiCopyPackedName(ValueFullInformation->Name,
ValueCell->Name,
NameSize / sizeof(WCHAR));
}
else
{
RtlCopyMemory(ValueFullInformation->Name,
ValueCell->Name,
NameSize);
}
if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET)) if (!(ValueCell->DataSize & REG_DATA_IN_OFFSET))
{ {
DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL); DataCell = CmiGetCell (RegistryHive, ValueCell->DataOffset, NULL);
RtlCopyMemory((PCHAR) ValueFullInformation RtlCopyMemory((PCHAR) ValueFullInformation
+ ValueFullInformation->DataOffset, + ValueFullInformation->DataOffset,
DataCell->Data, DataCell->Data,
ValueCell->DataSize & REG_DATA_SIZE_MASK); DataSize);
} }
else else
{ {
RtlCopyMemory((PCHAR) ValueFullInformation RtlCopyMemory((PCHAR) ValueFullInformation
+ ValueFullInformation->DataOffset, + ValueFullInformation->DataOffset,
&ValueCell->DataOffset, &ValueCell->DataOffset,
ValueCell->DataSize & REG_DATA_SIZE_MASK); DataSize);
} }
} }
break; break;