Index: ntoskrnl/config/ntapi.c
===================================================================
--- ntoskrnl/config/ntapi.c	(revision 59957)
+++ ntoskrnl/config/ntapi.c	(working copy)
@@ -605,14 +605,58 @@
               IN ULONG DataSize)
 {
     NTSTATUS Status;
-    PCM_KEY_BODY KeyObject;
+    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+    PCM_KEY_BODY KeyObject = NULL;
     REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
     REG_POST_OPERATION_INFORMATION PostOperationInfo;
-    UNICODE_STRING ValueNameCopy = *ValueName;
+    PVOID CapturedData = NULL;
+    UNICODE_STRING ValueNameCopy;
     PAGED_CODE();
     DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n",
         KeyHandle, ValueName, TitleIndex, Type, DataSize);
 
+    if (PreviousMode != KernelMode)
+    {
+        /* Probe and capture the unicode string */
+        Status = ProbeAndCaptureUnicodeString(&ValueNameCopy,
+                                              PreviousMode,
+                                              ValueName);
+        if (!NT_SUCCESS(Status)) return Status;
+        
+        _SEH2_TRY
+        {
+            /* Probe the Data parameter */
+            ProbeForRead(Data, DataSize, sizeof(UCHAR));
+
+            /* Allocate memory for the data */
+            CapturedData = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM);
+            if (CapturedData == NULL)
+            {
+                /* Fail */
+                ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
+                _SEH2_YIELD(return STATUS_INSUFFICIENT_RESOURCES);
+            }
+
+            /* Copy the data */
+            RtlCopyMemory(CapturedData, Data, DataSize);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Fail */
+            if (CapturedData) ExFreePoolWithTag(CapturedData, TAG_CM);
+            ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
+
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        /* Use the pointers directly for kernel mode */
+        CapturedData = Data;
+        ValueNameCopy = *ValueName;
+    }
+
     /* Verify that the handle is valid and is a registry key */
     Status = ObReferenceObjectByHandle(KeyHandle,
                                        KEY_SET_VALUE,
@@ -620,7 +664,7 @@
                                        ExGetPreviousMode(),
                                        (PVOID*)&KeyObject,
                                        NULL);
-    if (!NT_SUCCESS(Status)) return Status;
+    if (!NT_SUCCESS(Status)) goto Cleanup;
 
     /* Make sure the name is aligned, not too long, and the data under 4GB */
     if ( (ValueNameCopy.Length > 32767) ||
@@ -628,8 +672,8 @@
          (DataSize > 0x80000000))
     {
         /* Fail */
-        ObDereferenceObject(KeyObject);
-        return STATUS_INVALID_PARAMETER;
+        Status = STATUS_INVALID_PARAMETER;
+        goto Cleanup;
     }
 
     /* Ignore any null characters at the end */
@@ -644,17 +688,17 @@
     if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
     {
         /* Fail */
-        ObDereferenceObject(KeyObject);
-        return STATUS_ACCESS_DENIED;
+        Status = STATUS_ACCESS_DENIED;
+        goto Cleanup;
     }
 
     /* Setup callback */
     PostOperationInfo.Object = (PVOID)KeyObject;
     SetValueKeyInfo.Object = (PVOID)KeyObject;
-    SetValueKeyInfo.ValueName = ValueName;
+    SetValueKeyInfo.ValueName = &ValueNameCopy;
     SetValueKeyInfo.TitleIndex = TitleIndex;
     SetValueKeyInfo.Type = Type;
-    SetValueKeyInfo.Data = Data;
+    SetValueKeyInfo.Data = CapturedData;
     SetValueKeyInfo.DataSize = DataSize;
 
     /* Do the callback */
@@ -665,7 +709,7 @@
         Status = CmSetValueKey(KeyObject->KeyControlBlock,
                                &ValueNameCopy,
                                Type,
-                               Data,
+                               CapturedData,
                                DataSize);
     }
 
@@ -673,8 +717,17 @@
     PostOperationInfo.Status = Status;
     CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
 
+Cleanup:
+
+    /* Free the captured parameters */
+    ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
+    if ((PreviousMode != KernelMode) && CapturedData)
+    {
+        ExFreePoolWithTag(CapturedData, TAG_CM);
+    }
+
     /* Dereference and return status */
-    ObDereferenceObject(KeyObject);
+    if (KeyObject) ObDereferenceObject(KeyObject);
     return Status;
 }
 
