- Formatting fixes
[reactos.git] / reactos / ntoskrnl / ex / error.c
index 83a6fd1..df15202 100644 (file)
@@ -1,10 +1,9 @@
 /*
  * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
+ * PROJECT:         ReactOS Kernel
  * FILE:            ntoskrnl/ex/error.c
  * PURPOSE:         Error Functions and Status/Exception Dispatching/Raising
- *
- * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net) - Created File
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
  */
 
 /* INCLUDES *****************************************************************/
@@ -13,6 +12,8 @@
 #define NDEBUG
 #include <internal/debug.h>
 
+#define TAG_ERR TAG('E', 'r', 'r', ' ')
+
 /* GLOBALS ****************************************************************/
 
 BOOLEAN ExReadyForErrors = FALSE;
@@ -21,11 +22,23 @@ PEPROCESS ExpDefaultErrorPortProcess = NULL;
 
 /* FUNCTIONS ****************************************************************/
 
+VOID
+NTAPI
+ExpRaiseHardError(IN NTSTATUS ErrorStatus,
+                  IN ULONG NumberOfParameters,
+                  IN ULONG UnicodeStringParameterMask,
+                  IN PULONG_PTR Parameters,
+                  IN ULONG ValidResponseOptions,
+                  OUT PULONG Response)
+{
+    UNIMPLEMENTED;
+}
+
 /*
  * @implemented
  */
 VOID
-STDCALL
+NTAPI
 ExRaiseAccessViolation(VOID)
 {
     /* Raise the Right Status */
@@ -36,7 +49,7 @@ ExRaiseAccessViolation(VOID)
  * @implemented
  */
 VOID
-STDCALL
+NTAPI
 ExRaiseDatatypeMisalignment (VOID)
 {
     /* Raise the Right Status */
@@ -47,17 +60,18 @@ ExRaiseDatatypeMisalignment (VOID)
  * @implemented
  */
 LONG
-STDCALL
+NTAPI
 ExSystemExceptionFilter(VOID)
 {
-    return KeGetPreviousMode() != KernelMode ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
+    return KeGetPreviousMode() != KernelMode ?
+           EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
 }
 
 /*
  * @unimplemented
  */
 VOID
-STDCALL
+NTAPI
 ExRaiseHardError(IN NTSTATUS ErrorStatus,
                  IN ULONG NumberOfParameters,
                  IN ULONG UnicodeStringParameterMask,
@@ -65,11 +79,19 @@ ExRaiseHardError(IN NTSTATUS ErrorStatus,
                  IN ULONG ValidResponseOptions,
                  OUT PULONG Response)
 {
-    UNIMPLEMENTED;
+    /* FIXME: Capture to user-mode! */
+
+    /* Now call the worker function */
+    ExpRaiseHardError(ErrorStatus,
+                      NumberOfParameters,
+                      UnicodeStringParameterMask,
+                      Parameters,
+                      ValidResponseOptions,
+                      Response);
 }
 
 NTSTATUS
-STDCALL
+NTAPI
 NtRaiseHardError(IN NTSTATUS ErrorStatus,
                  IN ULONG NumberOfParameters,
                  IN ULONG UnicodeStringParameterMask,
@@ -77,37 +99,184 @@ NtRaiseHardError(IN NTSTATUS ErrorStatus,
                  IN ULONG ValidResponseOptions,
                  OUT PULONG Response)
 {
+    NTSTATUS Status;
+    PULONG_PTR SafeParams = NULL;
+    ULONG SafeResponse;
+    UNICODE_STRING SafeString;
+    ULONG i;
+    ULONG ParamSize;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     DPRINT1("Hard error %x\n", ErrorStatus);
 
-    /* Call the Executive Function (WE SHOULD PUT SEH HERE/CAPTURE!) */
-    ExRaiseHardError(ErrorStatus,
-                     NumberOfParameters,
-                     UnicodeStringParameterMask,
-                     Parameters,
-                     ValidResponseOptions,
-                     Response);
+    /* Validate parameter count */
+    if (NumberOfParameters > MAXIMUM_HARDERROR_PARAMETERS)
+    {
+        /* Fail */
+        DPRINT1("Invalid parameters\n");
+        return STATUS_INVALID_PARAMETER_2;
+    }
+
+    /* Make sure we have some at least */
+    if ((Parameters) && !(NumberOfParameters))
+    {
+        /* Fail */
+        DPRINT1("Invalid parameters\n");
+        return STATUS_INVALID_PARAMETER_2;
+    }
+
+    /* Check if we were called from user-mode */
+    if (PreviousMode != KernelMode)
+    {
+        /* First validate the responses */
+        switch (ValidResponseOptions)
+        {
+            /* Check all valid cases */
+            case OptionAbortRetryIgnore:
+            case OptionOk:
+            case OptionOkCancel:
+            case OptionRetryCancel:
+            case OptionYesNo:
+            case OptionYesNoCancel:
+            case OptionShutdownSystem:
+                break;
+
+            /* Anything else is invalid */
+            default:
+                return STATUS_INVALID_PARAMETER_4;
+        }
+
+        /* Enter SEH Block */
+        _SEH_TRY
+        {
+            /* Validate the response pointer */
+            ProbeForWriteUlong(Response);
+
+            /* Check if we have parameters */
+            if (Parameters)
+            {
+                /* Validate the parameter pointers */
+                ParamSize = sizeof(ULONG_PTR) * NumberOfParameters;
+                ProbeForRead(Parameters, ParamSize, sizeof(ULONG_PTR));
+
+                /* Allocate a safe buffer */
+                SafeParams = ExAllocatePoolWithTag(PagedPool,
+                                                   ParamSize,
+                                                   TAG_ERR);
+
+                /* Copy them */
+                RtlMoveMemory(SafeParams, Parameters, ParamSize);
+
+                /* Nowo check if there's strings in it */
+                if (UnicodeStringParameterMask)
+                {
+                    /* Loop every string */
+                    for (i = 0; i < NumberOfParameters; i++)
+                    {
+                        /* Check if this parameter is a string */
+                        if (UnicodeStringParameterMask & (1 << i))
+                        {
+                            /* Probe the structure */
+                            ProbeForRead((PVOID)SafeParams[i],
+                                         sizeof(UNICODE_STRING),
+                                         sizeof(ULONG_PTR));
 
-    /* Return Success */
-    return STATUS_SUCCESS;
+                            /* Capture it */
+                            RtlMoveMemory(&SafeString,
+                                          (PVOID)SafeParams[i],
+                                          sizeof(UNICODE_STRING));
+
+                            /* Probe the buffer */
+                            ProbeForRead(SafeString.Buffer,
+                                         SafeString.MaximumLength,
+                                         sizeof(UCHAR));
+                        }
+                    }
+                }
+            }
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            /* Free captured buffer */
+            if (SafeParams) ExFreePool(SafeParams);
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        /* If we failed to capture/probe, bail out */
+        if (!NT_SUCCESS(Status)) return Status;
+
+        /* Call the system function directly, because we probed */
+        ExpRaiseHardError(ErrorStatus,
+                          NumberOfParameters,
+                          UnicodeStringParameterMask,
+                          SafeParams,
+                          ValidResponseOptions,
+                          &SafeResponse);
+    }
+    else
+    {
+        /* Reuse variable */
+        SafeParams = Parameters;
+
+        /*
+         * Call the Executive Function. It will probe and copy pointers to 
+         * user-mode
+         */
+        ExRaiseHardError(ErrorStatus,
+                         NumberOfParameters,
+                         UnicodeStringParameterMask,
+                         SafeParams,
+                         ValidResponseOptions,
+                         &SafeResponse);
+    }
+
+    /* Check if we were called in user-mode */
+    if (PreviousMode != KernelMode)
+    {
+        /* That means we have a buffer to free */
+        if (SafeParams) ExFreePool(SafeParams);
+
+        /* Enter SEH Block for return */
+        _SEH_TRY
+        {
+            /* Return the response */
+            *Response = SafeResponse;
+        }
+        _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+    }
+    else
+    {
+        /* Return the response */
+        *Response = SafeResponse;
+    }
+
+    /* Return status */
+    return Status;
 }
 
 NTSTATUS
-STDCALL
+NTAPI
 NtSetDefaultHardErrorPort(IN HANDLE PortHandle)
 {
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status = STATUS_UNSUCCESSFUL;
 
     /* Check if we have the Privilege */
-    if(!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode)) {
-
-        DPRINT1("NtSetDefaultHardErrorPort: Caller requires the SeTcbPrivilege privilege!\n");
+    if(!SeSinglePrivilegeCheck(SeTcbPrivilege, PreviousMode))
+    {
+        DPRINT1("NtSetDefaultHardErrorPort: Caller requires "
+                "the SeTcbPrivilege privilege!\n");
         return STATUS_PRIVILEGE_NOT_HELD;
     }
 
     /* Only called once during bootup, make sure we weren't called yet */
-    if(!ExReadyForErrors) {
-
+    if(!ExReadyForErrors)
+    {
+        /* Reference the port */
         Status = ObReferenceObjectByHandle(PortHandle,
                                            0,
                                            LpcPortObjectType,
@@ -116,14 +285,15 @@ NtSetDefaultHardErrorPort(IN HANDLE PortHandle)
                                            NULL);
 
         /* Check for Success */
-        if(NT_SUCCESS(Status)) {
-
+        if(NT_SUCCESS(Status))
+        {
             /* Save the data */
             ExpDefaultErrorPortProcess = PsGetCurrentProcess();
             ExReadyForErrors = TRUE;
         }
     }
 
+    /* Return status to caller */
     return Status;
 }