mirror of
https://github.com/reactos/reactos.git
synced 2025-01-04 05:20:54 +00:00
[NTOS:CM]
- Correctly handle NULL Data with nonzero DataSize in NtSetValueKey ROSTESTS-200 #resolve svn path=/trunk/; revision=71232
This commit is contained in:
parent
8357726420
commit
c55c338dfa
4 changed files with 214 additions and 2 deletions
|
@ -630,11 +630,11 @@ NtSetValueKey(IN HANDLE KeyHandle,
|
||||||
Data = NULL;
|
Data = NULL;
|
||||||
|
|
||||||
/* Probe and copy the data */
|
/* Probe and copy the data */
|
||||||
if ((PreviousMode != KernelMode) && Data)
|
if ((PreviousMode != KernelMode) && (DataSize != 0))
|
||||||
{
|
{
|
||||||
PVOID DataCopy = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM);
|
PVOID DataCopy = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM);
|
||||||
if (!DataCopy)
|
if (!DataCopy)
|
||||||
return STATUS_NO_MEMORY;
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
_SEH2_TRY
|
_SEH2_TRY
|
||||||
{
|
{
|
||||||
ProbeForRead(Data, DataSize, 1);
|
ProbeForRead(Data, DataSize, 1);
|
||||||
|
|
|
@ -18,6 +18,7 @@ list(APPEND SOURCE
|
||||||
NtQuerySystemEnvironmentValue.c
|
NtQuerySystemEnvironmentValue.c
|
||||||
NtQueryVolumeInformationFile.c
|
NtQueryVolumeInformationFile.c
|
||||||
NtSaveKey.c
|
NtSaveKey.c
|
||||||
|
NtSetValueKey.c
|
||||||
RtlAllocateHeap.c
|
RtlAllocateHeap.c
|
||||||
RtlBitmap.c
|
RtlBitmap.c
|
||||||
RtlCopyMappedMemory.c
|
RtlCopyMappedMemory.c
|
||||||
|
|
209
rostests/apitests/ntdll/NtSetValueKey.c
Normal file
209
rostests/apitests/ntdll/NtSetValueKey.c
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS API tests
|
||||||
|
* LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
|
||||||
|
* PURPOSE: Test for NtSetValueKey
|
||||||
|
* PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <apitest.h>
|
||||||
|
|
||||||
|
#include <winreg.h>
|
||||||
|
#define WIN32_NO_STATUS
|
||||||
|
#include <ndk/cmfuncs.h>
|
||||||
|
#include <ndk/obfuncs.h>
|
||||||
|
#include <ndk/rtlfuncs.h>
|
||||||
|
#include <strsafe.h>
|
||||||
|
|
||||||
|
START_TEST(NtSetValueKey)
|
||||||
|
{
|
||||||
|
NTSTATUS Status;
|
||||||
|
HANDLE ParentKeyHandle;
|
||||||
|
HANDLE KeyHandle;
|
||||||
|
UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SOFTWARE\\ntdll-apitest-NtSetValueKey");
|
||||||
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||||
|
UNICODE_STRING ValueName;
|
||||||
|
WCHAR Default[] = L"Default";
|
||||||
|
WCHAR Hello[] = L"Hello";
|
||||||
|
WCHAR Empty[] = L"";
|
||||||
|
NTSTATUS QueryStatus;
|
||||||
|
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
|
||||||
|
ULONG PartialInfoLength;
|
||||||
|
ULONG ResultLength;
|
||||||
|
const struct
|
||||||
|
{
|
||||||
|
ULONG Type;
|
||||||
|
PVOID Data;
|
||||||
|
ULONG DataSize;
|
||||||
|
NTSTATUS StatusExisting;
|
||||||
|
NTSTATUS StatusNew;
|
||||||
|
NTSTATUS StatusExisting2;
|
||||||
|
NTSTATUS StatusNew2;
|
||||||
|
} Tests[] =
|
||||||
|
{
|
||||||
|
{ REG_NONE, NULL, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Empty REG_NONE value */
|
||||||
|
{ REG_SZ, Hello, sizeof(Hello), STATUS_SUCCESS, STATUS_SUCCESS }, /* Regular string */
|
||||||
|
{ REG_SZ, Empty, sizeof(Empty), STATUS_SUCCESS, STATUS_SUCCESS }, /* Empty string */
|
||||||
|
{ REG_SZ, NULL, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Zero length */
|
||||||
|
{ REG_SZ, Hello, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Zero length, non-null data */
|
||||||
|
{ REG_SZ, (PVOID)(LONG_PTR)-4, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Zero length, kernel data */
|
||||||
|
{ REG_SZ, NULL, 1, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION }, /* Non-zero length (odd), null data */
|
||||||
|
{ REG_SZ, NULL, 2, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION }, /* Non-zero length (even), null data */
|
||||||
|
{ REG_SZ, NULL, 4, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION }, /* CM_KEY_VALUE_SMALL, null data */
|
||||||
|
{ REG_SZ, NULL, 5, STATUS_INVALID_PARAMETER, STATUS_ACCESS_VIOLATION, /* CM_KEY_VALUE_SMALL+1, null data */
|
||||||
|
STATUS_ACCESS_VIOLATION, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */
|
||||||
|
{ REG_SZ, NULL, 6, STATUS_INVALID_PARAMETER, STATUS_ACCESS_VIOLATION, /* CM_KEY_VALUE_SMALL+2, null data */
|
||||||
|
STATUS_ACCESS_VIOLATION, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */
|
||||||
|
{ REG_SZ, NULL, 0x7fff0000, STATUS_INVALID_PARAMETER, STATUS_INSUFFICIENT_RESOURCES, /* MI_USER_PROBE_ADDRESS, null data */
|
||||||
|
STATUS_INSUFFICIENT_RESOURCES, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */
|
||||||
|
{ REG_SZ, NULL, 0x7fff0001, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, /* MI_USER_PROBE_ADDRESS+1, null data */
|
||||||
|
STATUS_INSUFFICIENT_RESOURCES, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */
|
||||||
|
{ REG_SZ, NULL, 0x7fffffff, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, /* <2GB, null data */
|
||||||
|
STATUS_INVALID_PARAMETER, STATUS_INVALID_PARAMETER }, /* win7 */
|
||||||
|
{ REG_SZ, NULL, 0x80000000, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, /* 2GB, null data */
|
||||||
|
STATUS_INVALID_PARAMETER, STATUS_INVALID_PARAMETER }, /* win7 */
|
||||||
|
{ REG_BINARY, NULL, 5, STATUS_INVALID_PARAMETER, STATUS_ACCESS_VIOLATION, /* ROSTESTS-200 */
|
||||||
|
STATUS_ACCESS_VIOLATION, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */
|
||||||
|
};
|
||||||
|
ULONG i;
|
||||||
|
|
||||||
|
Status = RtlOpenCurrentUser(READ_CONTROL, &ParentKeyHandle);
|
||||||
|
ok(Status == STATUS_SUCCESS, "RtlOpenCurrentUser returned %lx\n", Status);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
skip("No user key handle\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
InitializeObjectAttributes(&ObjectAttributes,
|
||||||
|
&KeyName,
|
||||||
|
OBJ_CASE_INSENSITIVE,
|
||||||
|
ParentKeyHandle,
|
||||||
|
NULL);
|
||||||
|
Status = NtCreateKey(&KeyHandle,
|
||||||
|
KEY_QUERY_VALUE | KEY_SET_VALUE | DELETE,
|
||||||
|
&ObjectAttributes,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
REG_OPTION_VOLATILE,
|
||||||
|
NULL);
|
||||||
|
ok(Status == STATUS_SUCCESS, "NtCreateKey returned %lx\n", Status);
|
||||||
|
if (!NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
NtClose(ParentKeyHandle);
|
||||||
|
skip("No key handle\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PartialInfoLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[128]);
|
||||||
|
PartialInfo = HeapAlloc(GetProcessHeap(), 0, PartialInfoLength);
|
||||||
|
if (PartialInfo == NULL)
|
||||||
|
{
|
||||||
|
NtDeleteKey(KeyHandle);
|
||||||
|
NtClose(KeyHandle);
|
||||||
|
NtClose(ParentKeyHandle);
|
||||||
|
skip("No key handle\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < RTL_NUMBER_OF(Tests); i++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Existing value
|
||||||
|
*/
|
||||||
|
/* Make sure it exists */
|
||||||
|
RtlInitUnicodeString(&ValueName, L"ExistingValue");
|
||||||
|
Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_SZ, Default, sizeof(Default));
|
||||||
|
ok(Status == STATUS_SUCCESS, "[%lu] NtSetValueKey failed with %lx", i, Status);
|
||||||
|
|
||||||
|
/* Set it */
|
||||||
|
Status = NtSetValueKey(KeyHandle, &ValueName, 0, Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
|
||||||
|
if (Status == Tests[i].StatusExisting2)
|
||||||
|
ok(Status == Tests[i].StatusExisting || Status == Tests[i].StatusExisting2, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx or %lx\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusExisting, Tests[i].StatusExisting2);
|
||||||
|
else
|
||||||
|
ok(Status == Tests[i].StatusExisting, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusExisting);
|
||||||
|
|
||||||
|
/* Check it */
|
||||||
|
RtlZeroMemory(PartialInfo, PartialInfoLength);
|
||||||
|
QueryStatus = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength);
|
||||||
|
ok(QueryStatus == STATUS_SUCCESS, "[%lu, %p, %lu] NtQueryValueKey failed with %lx\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus);
|
||||||
|
if (NT_SUCCESS(QueryStatus))
|
||||||
|
{
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex);
|
||||||
|
ok(PartialInfo->Type == Tests[i].Type, "[%lu, %p, %lu] Type = %lu\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type);
|
||||||
|
ok(PartialInfo->DataLength == Tests[i].DataSize, "[%lu, %p, %lu] DataLength = %lu\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength);
|
||||||
|
ok(!memcmp(PartialInfo->Data, Tests[i].Data, Tests[i].DataSize), "[%lu, %p, %lu] Data does not match set value\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex);
|
||||||
|
ok(PartialInfo->Type == REG_SZ, "[%lu, %p, %lu] Type = %lu\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type);
|
||||||
|
ok(PartialInfo->DataLength == sizeof(Default), "[%lu, %p, %lu] DataLength = %lu\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength);
|
||||||
|
ok(!memcmp(PartialInfo->Data, Default, sizeof(Default)), "[%lu, %p, %lu] Data does not match default\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* New value
|
||||||
|
*/
|
||||||
|
/* Make sure it doesn't exist */
|
||||||
|
RtlInitUnicodeString(&ValueName, L"NewValue");
|
||||||
|
Status = NtDeleteValueKey(KeyHandle, &ValueName);
|
||||||
|
ok(Status == STATUS_SUCCESS || Status == STATUS_OBJECT_NAME_NOT_FOUND,
|
||||||
|
"[%lu] NtDeleteValueKey failed with %lx", i, Status);
|
||||||
|
|
||||||
|
/* Set it */
|
||||||
|
Status = NtSetValueKey(KeyHandle, &ValueName, 0, Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
|
||||||
|
if (Tests[i].StatusNew2)
|
||||||
|
ok(Status == Tests[i].StatusNew || Status == Tests[i].StatusNew2, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx or %lx\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusNew, Tests[i].StatusNew2);
|
||||||
|
else
|
||||||
|
ok(Status == Tests[i].StatusNew, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusNew);
|
||||||
|
|
||||||
|
/* Check it */
|
||||||
|
RtlZeroMemory(PartialInfo, PartialInfoLength);
|
||||||
|
QueryStatus = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength);
|
||||||
|
if (NT_SUCCESS(Status))
|
||||||
|
{
|
||||||
|
ok(QueryStatus == STATUS_SUCCESS, "[%lu, %p, %lu] NtQueryValueKey failed with %lx\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus);
|
||||||
|
if (NT_SUCCESS(QueryStatus))
|
||||||
|
{
|
||||||
|
ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex);
|
||||||
|
ok(PartialInfo->Type == Tests[i].Type, "[%lu, %p, %lu] Type = %lu\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type);
|
||||||
|
ok(PartialInfo->DataLength == Tests[i].DataSize, "[%lu, %p, %lu] DataLength = %lu\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength);
|
||||||
|
ok(!memcmp(PartialInfo->Data, Tests[i].Data, Tests[i].DataSize), "[%lu, %p, %lu] Data does not match set value\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ok(QueryStatus == STATUS_OBJECT_NAME_NOT_FOUND, "[%lu, %p, %lu] QueryStatus = %lx\n",
|
||||||
|
Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HeapFree(GetProcessHeap(), 0, PartialInfo);
|
||||||
|
Status = NtDeleteKey(KeyHandle);
|
||||||
|
ok(Status == STATUS_SUCCESS, "NtDeleteKey returned %lx\n", Status);
|
||||||
|
Status = NtClose(KeyHandle);
|
||||||
|
ok(Status == STATUS_SUCCESS, "NtClose returned %lx\n", Status);
|
||||||
|
Status = NtClose(ParentKeyHandle);
|
||||||
|
ok(Status == STATUS_SUCCESS, "NtClose returned %lx\n", Status);
|
||||||
|
}
|
|
@ -21,6 +21,7 @@ extern void func_NtQueryKey(void);
|
||||||
extern void func_NtQuerySystemEnvironmentValue(void);
|
extern void func_NtQuerySystemEnvironmentValue(void);
|
||||||
extern void func_NtQueryVolumeInformationFile(void);
|
extern void func_NtQueryVolumeInformationFile(void);
|
||||||
extern void func_NtSaveKey(void);
|
extern void func_NtSaveKey(void);
|
||||||
|
extern void func_NtSetValueKey(void);
|
||||||
extern void func_NtSystemInformation(void);
|
extern void func_NtSystemInformation(void);
|
||||||
extern void func_RtlAllocateHeap(void);
|
extern void func_RtlAllocateHeap(void);
|
||||||
extern void func_RtlBitmap(void);
|
extern void func_RtlBitmap(void);
|
||||||
|
@ -63,6 +64,7 @@ const struct test winetest_testlist[] =
|
||||||
{ "NtQuerySystemEnvironmentValue", func_NtQuerySystemEnvironmentValue },
|
{ "NtQuerySystemEnvironmentValue", func_NtQuerySystemEnvironmentValue },
|
||||||
{ "NtQueryVolumeInformationFile", func_NtQueryVolumeInformationFile },
|
{ "NtQueryVolumeInformationFile", func_NtQueryVolumeInformationFile },
|
||||||
{ "NtSaveKey", func_NtSaveKey},
|
{ "NtSaveKey", func_NtSaveKey},
|
||||||
|
{ "NtSetValueKey", func_NtSetValueKey},
|
||||||
{ "NtSystemInformation", func_NtSystemInformation },
|
{ "NtSystemInformation", func_NtSystemInformation },
|
||||||
{ "RtlAllocateHeap", func_RtlAllocateHeap },
|
{ "RtlAllocateHeap", func_RtlAllocateHeap },
|
||||||
{ "RtlBitmapApi", func_RtlBitmap },
|
{ "RtlBitmapApi", func_RtlBitmap },
|
||||||
|
|
Loading…
Reference in a new issue