Fixed a few length calculation in NtEnumerateValueKey, which has resulted in a overfl...
[reactos.git] / reactos / ntoskrnl / cm / ntfunc.c
index 7f59824..57d5761 100644 (file)
@@ -184,35 +184,70 @@ NtCreateKey(OUT PHANDLE KeyHandle,
            IN ULONG CreateOptions,
            OUT PULONG Disposition)
 {
-  UNICODE_STRING RemainingPath;
+  UNICODE_STRING RemainingPath = {0};
+  BOOLEAN FreeRemainingPath = TRUE;
+  ULONG LocalDisposition;
   PKEY_OBJECT KeyObject;
-  NTSTATUS Status;
-  PVOID Object;
+  NTSTATUS Status = STATUS_SUCCESS;
+  PVOID Object = NULL;
   PWSTR Start;
   UNICODE_STRING ObjectName;
   OBJECT_CREATE_INFORMATION ObjectCreateInfo;
   unsigned i;
   REG_PRE_CREATE_KEY_INFORMATION PreCreateKeyInfo;
   REG_POST_CREATE_KEY_INFORMATION PostCreateKeyInfo;
+  KPROCESSOR_MODE PreviousMode;
+  UNICODE_STRING CapturedClass = {0};
+  HANDLE hKey;
 
   PAGED_CODE();
 
-  DPRINT("NtCreateKey (Name %wZ  KeyHandle 0x%p  Root 0x%p)\n",
-        ObjectAttributes->ObjectName,
-        KeyHandle,
-        ObjectAttributes->RootDirectory);
+  PreviousMode = KeGetPreviousMode();
+
+  if (PreviousMode != KernelMode)
+  {
+      _SEH_TRY
+      {
+          ProbeForWriteHandle(KeyHandle);
+          if (Disposition != NULL)
+          {
+              ProbeForWriteUlong(Disposition);
+          }
+      }
+      _SEH_HANDLE
+      {
+          Status = _SEH_GetExceptionCode();
+      }
+      _SEH_END;
+      
+      if (!NT_SUCCESS(Status))
+      {
+          return Status;
+      }
+  }
+  
+  if (Class != NULL)
+  {
+      Status = ProbeAndCaptureUnicodeString(&CapturedClass,
+                                            PreviousMode,
+                                            Class);
+      if (!NT_SUCCESS(Status))
+      {
+          return Status;
+      }
+  }
 
   /* Capture all the info */
   DPRINT("Capturing Create Info\n");
   Status = ObpCaptureObjectAttributes(ObjectAttributes,
-                                      KeGetPreviousMode(),
+                                      PreviousMode,
                                       CmiKeyType,
                                       &ObjectCreateInfo,
                                       &ObjectName);
   if (!NT_SUCCESS(Status))
     {
       DPRINT("ObpCaptureObjectAttributes() failed (Status %lx)\n", Status);
-      return Status;
+      goto Cleanup;
     }
 
   PostCreateKeyInfo.CompleteName = &ObjectName;
@@ -221,13 +256,12 @@ NtCreateKey(OUT PHANDLE KeyHandle,
   if (!NT_SUCCESS(Status))
     {
       ObpReleaseCapturedAttributes(&ObjectCreateInfo);
-      if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
-      return Status;
+      goto Cleanup;
     }
     
   Status = ObFindObject(&ObjectCreateInfo,
                         &ObjectName,
-                       (PVOID*)&Object,
+                        (PVOID*)&Object,
                         &RemainingPath,
                         CmiKeyType);
   ObpReleaseCapturedAttributes(&ObjectCreateInfo);
@@ -236,9 +270,9 @@ NtCreateKey(OUT PHANDLE KeyHandle,
       PostCreateKeyInfo.Object = NULL;
       PostCreateKeyInfo.Status = Status;
       CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
-      if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
+
       DPRINT("CmpFindObject failed, Status: 0x%x\n", Status);
-      return(Status);
+      goto Cleanup;
     }
 
   DPRINT("RemainingPath %wZ\n", &RemainingPath);
@@ -248,33 +282,29 @@ NtCreateKey(OUT PHANDLE KeyHandle,
       /* Fail if the key has been deleted */
       if (((PKEY_OBJECT) Object)->Flags & KO_MARKED_FOR_DELETE)
        {
-         ObDereferenceObject(Object);
-         RtlFreeUnicodeString(&RemainingPath);
           PostCreateKeyInfo.Object = NULL;
           PostCreateKeyInfo.Status = STATUS_UNSUCCESSFUL;
           CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
-          if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
+
          DPRINT("Object marked for delete!\n");
-         return(STATUS_UNSUCCESSFUL);
+         Status = STATUS_UNSUCCESSFUL;
+         goto Cleanup;
        }
 
-      if (Disposition)
-       *Disposition = REG_OPENED_EXISTING_KEY;
-
       Status = ObpCreateHandle(PsGetCurrentProcess(),
                              Object,
                              DesiredAccess,
                              TRUE,
-                             KeyHandle);
+                             &hKey);
 
       DPRINT("ObpCreateHandle failed Status 0x%x\n", Status);
-      ObDereferenceObject(Object);
-      RtlFreeUnicodeString(&RemainingPath);
+
       PostCreateKeyInfo.Object = NULL;
       PostCreateKeyInfo.Status = Status;
       CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
-      if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
-      return Status;
+
+      LocalDisposition = REG_OPENED_EXISTING_KEY;
+      goto SuccessReturn;
     }
 
   /* If RemainingPath contains \ we must return error
@@ -287,23 +317,23 @@ NtCreateKey(OUT PHANDLE KeyHandle,
     {
       if (L'\\' == RemainingPath.Buffer[i])
         {
-          ObDereferenceObject(Object);
-          DPRINT1("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath);
-          RtlFreeUnicodeString(&RemainingPath);
+          DPRINT("NtCreateKey() doesn't create trees! (found \'\\\' in remaining path: \"%wZ\"!)\n", &RemainingPath);
+
           PostCreateKeyInfo.Object = NULL;
           PostCreateKeyInfo.Status = STATUS_OBJECT_NAME_NOT_FOUND;
           CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
-          if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
-          return STATUS_OBJECT_NAME_NOT_FOUND;
+
+          Status = STATUS_OBJECT_NAME_NOT_FOUND;
+          goto Cleanup;
         }
     }
 
   DPRINT("RemainingPath %S  ParentObject 0x%p\n", RemainingPath.Buffer, Object);
 
-  Status = ObCreateObject(ExGetPreviousMode(),
+  Status = ObCreateObject(PreviousMode,
                          CmiKeyType,
                          NULL,
-                         ExGetPreviousMode(),
+                         PreviousMode,
                          NULL,
                          sizeof(KEY_OBJECT),
                          0,
@@ -315,8 +345,8 @@ NtCreateKey(OUT PHANDLE KeyHandle,
       PostCreateKeyInfo.Object = NULL;
       PostCreateKeyInfo.Status = Status;
       CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
-      if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
-      return(Status);
+
+      goto Cleanup;
     }
 
   Status = ObInsertObject((PVOID)KeyObject,
@@ -324,17 +354,17 @@ NtCreateKey(OUT PHANDLE KeyHandle,
                          DesiredAccess,
                          0,
                          NULL,
-                         KeyHandle);
+                         &hKey);
   if (!NT_SUCCESS(Status))
     {
       ObDereferenceObject(KeyObject);
-      RtlFreeUnicodeString(&RemainingPath);
       DPRINT1("ObInsertObject() failed!\n");
+
       PostCreateKeyInfo.Object = NULL;
       PostCreateKeyInfo.Status = Status;
       CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
-      if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
-      return(Status);
+
+      goto Cleanup;
     }
 
   KeyObject->ParentKey = Object;
@@ -361,7 +391,7 @@ NtCreateKey(OUT PHANDLE KeyHandle,
                        KeyObject,
                        &RemainingPath,
                        TitleIndex,
-                       Class,
+                       &CapturedClass,
                        CreateOptions);
   if (!NT_SUCCESS(Status))
     {
@@ -370,23 +400,23 @@ NtCreateKey(OUT PHANDLE KeyHandle,
       ExReleaseResourceLite(&CmiRegistryLock);
       KeLeaveCriticalRegion();
       ObDereferenceObject(KeyObject);
-      ObDereferenceObject(Object);
-      RtlFreeUnicodeString(&RemainingPath);
+
       PostCreateKeyInfo.Object = NULL;
       PostCreateKeyInfo.Status = STATUS_UNSUCCESSFUL;
       CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
-      if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
-      return STATUS_UNSUCCESSFUL;
+
+      Status = STATUS_UNSUCCESSFUL;
+      goto Cleanup;
     }
 
   if (Start == RemainingPath.Buffer)
     {
       KeyObject->Name = RemainingPath;
+      FreeRemainingPath = FALSE;
     }
   else
     {
       RtlpCreateUnicodeString(&KeyObject->Name, Start, NonPagedPool);
-      RtlFreeUnicodeString(&RemainingPath);
     }
 
   if (KeyObject->RegistryHive == KeyObject->ParentKey->RegistryHive)
@@ -400,10 +430,7 @@ NtCreateKey(OUT PHANDLE KeyHandle,
       KeyObject->KeyCell->SecurityKeyOffset = -1;
       /* This key must remain in memory unless it is deleted
         or file is unloaded */
-      ObReferenceObjectByPointer(KeyObject,
-                                STANDARD_RIGHTS_REQUIRED,
-                                NULL,
-                                UserMode);
+      ObReferenceObject(KeyObject);
     }
 
   CmiAddKeyToList(KeyObject->ParentKey, KeyObject);
@@ -414,18 +441,38 @@ NtCreateKey(OUT PHANDLE KeyHandle,
   ExReleaseResourceLite(&CmiRegistryLock);
   KeLeaveCriticalRegion();
 
-
-  ObDereferenceObject(Object);
-
-  if (Disposition)
-    *Disposition = REG_CREATED_NEW_KEY;
-
   PostCreateKeyInfo.Object = KeyObject;
   PostCreateKeyInfo.Status = Status;
   CmiCallRegisteredCallbacks(RegNtPostCreateKey, &PostCreateKeyInfo);
-  if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
 
   CmiSyncHives();
+  
+  LocalDisposition = REG_CREATED_NEW_KEY;
+
+SuccessReturn:
+  _SEH_TRY
+  {
+      *KeyHandle = hKey;
+      if (Disposition != NULL)
+      {
+          *Disposition = LocalDisposition;
+      }
+  }
+  _SEH_HANDLE
+  {
+      Status = _SEH_GetExceptionCode();
+  }
+  _SEH_END;
+
+Cleanup:
+  if (Class != NULL)
+  {
+    ReleaseCapturedUnicodeString(&CapturedClass,
+                                 PreviousMode);
+  }
+  if (ObjectName.Buffer) ExFreePool(ObjectName.Buffer);
+  if (FreeRemainingPath) RtlFreeUnicodeString(&RemainingPath);
+  if (Object != NULL) ObDereferenceObject(Object);
 
   return Status;
 }
@@ -1088,18 +1135,16 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
                   ROUND_UP(ValueFullInformation->DataOffset, sizeof(PVOID));
               ValueFullInformation->DataLength = ValueCell->DataSize & REG_DATA_SIZE_MASK;
 
-             if (Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) <
-                 NameSize)
+              if (Length < ValueFullInformation->DataOffset)
                {
                  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)
+              else if (Length - ValueFullInformation->DataOffset < DataSize) 
                {
-                 DataSize = ROUND_UP(Length - FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name[0]) - NameSize, sizeof(PVOID));
+                 DataSize = Length - ValueFullInformation->DataOffset;
                  Status = STATUS_BUFFER_OVERFLOW;
                  CHECKPOINT;
                }
@@ -1616,7 +1661,7 @@ NtQueryValueKey(IN HANDLE KeyHandle,
 
   if (!NT_SUCCESS(Status))
     {
-      DPRINT1("ObReferenceObjectByHandle() failed with status %x\n", Status);
+      DPRINT1("ObReferenceObjectByHandle() failed with status %x %p\n", Status, KeyHandle);
       return Status;
     }
   
@@ -2038,27 +2083,42 @@ NtDeleteValueKey (IN HANDLE KeyHandle,
   NTSTATUS Status;
   REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo;
   REG_POST_OPERATION_INFORMATION PostOperationInfo;
+  KPROCESSOR_MODE PreviousMode;
+  UNICODE_STRING CapturedValueName;
 
   PAGED_CODE();
+  
+  PreviousMode = KeGetPreviousMode();
 
   /* Verify that the handle is valid and is a registry key */
   Status = ObReferenceObjectByHandle(KeyHandle,
-               KEY_QUERY_VALUE,
+               KEY_SET_VALUE,
                CmiKeyType,
-               UserMode,
+               PreviousMode,
                (PVOID *)&KeyObject,
                NULL);
   if (!NT_SUCCESS(Status))
     {
       return Status;
     }
-  
+
+  Status = ProbeAndCaptureUnicodeString(&CapturedValueName,
+                                        PreviousMode,
+                                        ValueName);
+  if (!NT_SUCCESS(Status))
+    {
+      goto Fail;
+    }
   DeleteValueKeyInfo.Object = (PVOID)KeyObject;
-  DeleteValueKeyInfo.ValueName = ValueName;
+  DeleteValueKeyInfo.ValueName = &CapturedValueName;
 
+  /* FIXME - check if value exists before calling the callbacks? */
   Status = CmiCallRegisteredCallbacks(RegNtPreDeleteValueKey, &DeleteValueKeyInfo);
   if (!NT_SUCCESS(Status))
     {
+      ReleaseCapturedUnicodeString(&CapturedValueName,
+                                   PreviousMode);
+Fail:
       ObDereferenceObject(KeyObject);
       return Status;
     }
@@ -2081,6 +2141,9 @@ NtDeleteValueKey (IN HANDLE KeyHandle,
   ExReleaseResourceLite(&CmiRegistryLock);
   KeLeaveCriticalRegion();
 
+  ReleaseCapturedUnicodeString(&CapturedValueName,
+                               PreviousMode);
+
   PostOperationInfo.Object = (PVOID)KeyObject;
   PostOperationInfo.Status = Status;