[NTOS:CM]
authorThomas Faber <thomas.faber@reactos.org>
Mon, 2 May 2016 13:19:44 +0000 (13:19 +0000)
committerThomas Faber <thomas.faber@reactos.org>
Mon, 2 May 2016 13:19:44 +0000 (13:19 +0000)
- Correctly handle NULL Data with nonzero DataSize in NtSetValueKey
ROSTESTS-200 #resolve

svn path=/trunk/; revision=71232

reactos/ntoskrnl/config/ntapi.c
rostests/apitests/ntdll/CMakeLists.txt
rostests/apitests/ntdll/NtSetValueKey.c [new file with mode: 0644]
rostests/apitests/ntdll/testlist.c

index 04a169f..993b2bb 100644 (file)
@@ -630,11 +630,11 @@ NtSetValueKey(IN HANDLE KeyHandle,
         Data = NULL;
 
     /* Probe and copy the data */
-    if ((PreviousMode != KernelMode) && Data)
+    if ((PreviousMode != KernelMode) && (DataSize != 0))
     {
         PVOID DataCopy = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM);
         if (!DataCopy)
-            return STATUS_NO_MEMORY;
+            return STATUS_INSUFFICIENT_RESOURCES;
         _SEH2_TRY
         {
             ProbeForRead(Data, DataSize, 1);
index dbe8f65..cbd19aa 100644 (file)
@@ -18,6 +18,7 @@ list(APPEND SOURCE
     NtQuerySystemEnvironmentValue.c
     NtQueryVolumeInformationFile.c
     NtSaveKey.c
+    NtSetValueKey.c
     RtlAllocateHeap.c
     RtlBitmap.c
     RtlCopyMappedMemory.c
diff --git a/rostests/apitests/ntdll/NtSetValueKey.c b/rostests/apitests/ntdll/NtSetValueKey.c
new file mode 100644 (file)
index 0000000..6da3c9e
--- /dev/null
@@ -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);
+}
index 1dadf0d..f13f249 100644 (file)
@@ -21,6 +21,7 @@ extern void func_NtQueryKey(void);
 extern void func_NtQuerySystemEnvironmentValue(void);
 extern void func_NtQueryVolumeInformationFile(void);
 extern void func_NtSaveKey(void);
+extern void func_NtSetValueKey(void);
 extern void func_NtSystemInformation(void);
 extern void func_RtlAllocateHeap(void);
 extern void func_RtlBitmap(void);
@@ -63,6 +64,7 @@ const struct test winetest_testlist[] =
     { "NtQuerySystemEnvironmentValue",  func_NtQuerySystemEnvironmentValue },
     { "NtQueryVolumeInformationFile",   func_NtQueryVolumeInformationFile },
     { "NtSaveKey",                      func_NtSaveKey},
+    { "NtSetValueKey",                  func_NtSetValueKey},
     { "NtSystemInformation",            func_NtSystemInformation },
     { "RtlAllocateHeap",                func_RtlAllocateHeap },
     { "RtlBitmapApi",                   func_RtlBitmap },