Fixed ProbeForRead* macros: make sure the data always is read while probing it
[reactos.git] / reactos / ntoskrnl / include / internal / ntoskrnl.h
index ac39b77..64917b5 100644 (file)
 #include "ldr.h"
 #include "kd.h"
 #include "ex.h"
-#include "xhal.h"
-#include "v86m.h"
-#include "fs.h"
-#include "port.h"
+#include "fsrtl.h"
+#include "lpc.h"
 #include "rtl.h"
 #ifdef KDBG
 #include "../kdbg/kdb.h"
@@ -92,11 +90,11 @@ static __inline
 NTSTATUS
 NTAPI
 ProbeAndCaptureUnicodeString(OUT PUNICODE_STRING Dest,
-                             KPROCESSOR_MODE CurrentMode,
+                             IN KPROCESSOR_MODE CurrentMode,
                              IN PUNICODE_STRING UnsafeSrc)
 {
     NTSTATUS Status = STATUS_SUCCESS;
-    PVOID Buffer;
+    WCHAR *Buffer;
     ASSERT(Dest != NULL);
 
     /* Probe the structure and buffer*/
@@ -108,11 +106,43 @@ ProbeAndCaptureUnicodeString(OUT PUNICODE_STRING Dest,
                          sizeof(UNICODE_STRING),
                          sizeof(ULONG));
             *Dest = *UnsafeSrc;
-            if(Dest->Length > 0)
+            if(Dest->Buffer != NULL)
             {
-                ProbeForRead(Dest->Buffer,
-                             Dest->Length,
-                             sizeof(WCHAR));
+                if (Dest->Length != 0)
+                {
+                    ProbeForRead(Dest->Buffer,
+                                 Dest->Length,
+                                 sizeof(WCHAR));
+
+                    /* Allocate space for the buffer */
+                    Buffer = ExAllocatePoolWithTag(PagedPool,
+                                                   Dest->Length + sizeof(WCHAR),
+                                                   TAG('U', 'S', 'T', 'R'));
+                    if (Buffer == NULL)
+                    {
+                        Status = STATUS_INSUFFICIENT_RESOURCES;
+                        _SEH_LEAVE;
+                    }
+
+                    /* Copy it */
+                    RtlCopyMemory(Buffer, Dest->Buffer, Dest->Length);
+                    Buffer[Dest->Length / sizeof(WCHAR)] = UNICODE_NULL;
+
+                    /* Set it as the buffer */
+                    Dest->Buffer = Buffer;
+                }
+                else
+                {
+                    /* sanitize structure */
+                    Dest->MaximumLength = 0;
+                    Dest->Buffer = NULL;
+                }
+            }
+            else
+            {
+                /* sanitize structure */
+                Dest->Length = 0;
+                Dest->MaximumLength = 0;
             }
         }
         _SEH_HANDLE
@@ -120,24 +150,14 @@ ProbeAndCaptureUnicodeString(OUT PUNICODE_STRING Dest,
             Status = _SEH_GetExceptionCode();
         }
         _SEH_END;
-
-        if (!NT_SUCCESS(Status)) return Status;
     }
     else
     {
-        /* Just copy it directly */
+        /* Just copy the UNICODE_STRING structure, don't allocate new memory!
+           We trust the caller to supply valid pointers and data. */
         *Dest = *UnsafeSrc;
     }
 
-    /* Allocate space for the buffer */
-    Buffer = ExAllocatePool(PagedPool, Dest->MaximumLength);
-
-    /* Copy it */
-    RtlCopyMemory(Buffer, Dest->Buffer, Dest->MaximumLength);
-
-    /* Set it as the buffer */
-    Dest->Buffer = Buffer;
-
     /* Return */
     return Status;
 }
@@ -146,9 +166,12 @@ static __inline
 VOID
 NTAPI
 ReleaseCapturedUnicodeString(IN PUNICODE_STRING CapturedString,
-                             KPROCESSOR_MODE CurrentMode)
+                             IN KPROCESSOR_MODE CurrentMode)
 {
-    if(CurrentMode != KernelMode) ExFreePool(CapturedString->Buffer);
+    if(CurrentMode != KernelMode && CapturedString->Buffer != NULL)
+    {
+        ExFreePool(CapturedString->Buffer);
+    }
 }
 
 /*
@@ -185,7 +208,7 @@ ReleaseCapturedUnicodeString(IN PUNICODE_STRING CapturedString,
     (((ULONG_PTR)(Ptr) + sizeof(Type) - 1 < (ULONG_PTR)(Ptr) ||                \
         (ULONG_PTR)(Ptr) + sizeof(Type) - 1 >= (ULONG_PTR)MmUserProbeAddress) ?   \
             ExRaiseStatus (STATUS_ACCESS_VIOLATION), Default :                    \
-            *(Type *)(Ptr))
+            *(volatile Type *)(Ptr))
 
 #define ProbeForReadBoolean(Ptr) ProbeForReadGenericType(Ptr, BOOLEAN, FALSE)
 #define ProbeForReadUchar(Ptr) ProbeForReadGenericType(Ptr, UCHAR, 0)
@@ -204,6 +227,138 @@ ReleaseCapturedUnicodeString(IN PUNICODE_STRING CapturedString,
 #define ProbeForReadLargeInteger(Ptr) ((LARGE_INTEGER)ProbeForReadGenericType(&(Ptr)->QuadPart, LONGLONG, 0))
 #define ProbeForReadUlargeInteger(Ptr) ((ULARGE_INTEGER)ProbeForReadGenericType(&(Ptr)->QuadPart, ULONGLONG, 0))
 
+/*
+ * generic information class probing code
+ */
+
+#define ICIF_QUERY               0x1
+#define ICIF_SET                 0x2
+#define ICIF_QUERY_SIZE_VARIABLE 0x4
+#define ICIF_SET_SIZE_VARIABLE   0x8
+#define ICIF_SIZE_VARIABLE (ICIF_QUERY_SIZE_VARIABLE | ICIF_SET_SIZE_VARIABLE)
+
+typedef struct _INFORMATION_CLASS_INFO
+{
+  ULONG RequiredSizeQUERY;
+  ULONG RequiredSizeSET;
+  ULONG AlignmentSET;
+  ULONG AlignmentQUERY;
+  ULONG Flags;
+} INFORMATION_CLASS_INFO, *PINFORMATION_CLASS_INFO;
+
+#define ICI_SQ_SAME(Size, Alignment, Flags)                                    \
+  { Size, Size, Alignment, Alignment, Flags }
+
+#define ICI_SQ(SizeQuery, SizeSet, AlignmentQuery, AlignmentSet, Flags)        \
+  { SizeQuery, SizeSet, AlignmentQuery, AlignmentSet, Flags }
+
+static inline NTSTATUS
+DefaultSetInfoBufferCheck(UINT Class,
+                          const INFORMATION_CLASS_INFO *ClassList,
+                          UINT ClassListEntries,
+                          PVOID Buffer,
+                          ULONG BufferLength,
+                          KPROCESSOR_MODE PreviousMode)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    if (Class >= 0 && Class < ClassListEntries)
+    {
+        if (!(ClassList[Class].Flags & ICIF_SET))
+        {
+            Status = STATUS_INVALID_INFO_CLASS;
+        }
+        else if (ClassList[Class].RequiredSizeSET > 0 &&
+                 BufferLength != ClassList[Class].RequiredSizeSET)
+        {
+            if (!(ClassList[Class].Flags & ICIF_SET_SIZE_VARIABLE))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+            }
+        }
+
+        if (NT_SUCCESS(Status))
+        {
+            if (PreviousMode != KernelMode)
+            {
+                _SEH_TRY
+                {
+                    ProbeForRead(Buffer,
+                                 BufferLength,
+                                 ClassList[Class].AlignmentSET);
+                }
+                _SEH_HANDLE
+                {
+                    Status = _SEH_GetExceptionCode();
+                }
+                _SEH_END;
+            }
+        }
+    }
+    else
+        Status = STATUS_INVALID_INFO_CLASS;
+
+    return Status;
+}
+
+static inline NTSTATUS
+DefaultQueryInfoBufferCheck(UINT Class,
+                            const INFORMATION_CLASS_INFO *ClassList,
+                            UINT ClassListEntries,
+                            PVOID Buffer,
+                            ULONG BufferLength,
+                            PULONG ReturnLength,
+                            KPROCESSOR_MODE PreviousMode)
+{
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    if (Class >= 0 && Class < ClassListEntries)
+    {
+        if (!(ClassList[Class].Flags & ICIF_QUERY))
+        {
+            Status = STATUS_INVALID_INFO_CLASS;
+        }
+        else if (ClassList[Class].RequiredSizeQUERY > 0 &&
+                 BufferLength != ClassList[Class].RequiredSizeQUERY)
+        {
+            if (!(ClassList[Class].Flags & ICIF_QUERY_SIZE_VARIABLE))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+            }
+        }
+
+        if (NT_SUCCESS(Status))
+        {
+            if (PreviousMode != KernelMode)
+            {
+                _SEH_TRY
+                {
+                    if (Buffer != NULL)
+                    {
+                        ProbeForWrite(Buffer,
+                                      BufferLength,
+                                      ClassList[Class].AlignmentQUERY);
+                    }
+
+                    if (ReturnLength != NULL)
+                    {
+                        ProbeForWriteUlong(ReturnLength);
+                    }
+                }
+                _SEH_HANDLE
+                {
+                    Status = _SEH_GetExceptionCode();
+                }
+                _SEH_END;
+            }
+        }
+    }
+    else
+        Status = STATUS_INVALID_INFO_CLASS;
+
+    return Status;
+}
+
 /*
  * Use IsPointerOffset to test whether a pointer should be interpreted as an offset
  * or as a pointer