From b5a39d6dd14ee5454e1c3100edb5807b1ce3de0a Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Mon, 26 Apr 2010 01:23:21 +0000 Subject: [PATCH] [WIN32CSR] - Rewrite harderror handling. The old code was a monster function, leaking memory, using ansi rather than unicode strings and not getting this right. It was also vulnerable to attacks, making csrss crash, when corrupt parameters were sent. svn path=/trunk/; revision=47027 --- .../subsystems/win32/csrss/win32csr/dllmain.c | 396 ------------- .../win32/csrss/win32csr/harderror.c | 552 ++++++++++++++++++ .../subsystems/win32/csrss/win32csr/w32csr.h | 7 + .../win32/csrss/win32csr/win32csr.rbuild | 2 + 4 files changed, 561 insertions(+), 396 deletions(-) create mode 100644 reactos/subsystems/win32/csrss/win32csr/harderror.c diff --git a/reactos/subsystems/win32/csrss/win32csr/dllmain.c b/reactos/subsystems/win32/csrss/win32csr/dllmain.c index 2b3c6b7a1a4..e1fc421ff7c 100644 --- a/reactos/subsystems/win32/csrss/win32csr/dllmain.c +++ b/reactos/subsystems/win32/csrss/win32csr/dllmain.c @@ -180,402 +180,6 @@ Win32CsrInitComplete(void) return TRUE; } -static BOOL WINAPI -Win32CsrHardError(IN PCSRSS_PROCESS_DATA ProcessData, - IN PHARDERROR_MSG HardErrorMessage) -{ - UINT responce = MB_OK; - NTSTATUS Status; - HANDLE hProcess; - OBJECT_ATTRIBUTES ObjectAttributes; - ULONG nParam = 0; - PRTL_MESSAGE_RESOURCE_ENTRY MessageResource; - ULONG_PTR ParameterList[MAXIMUM_HARDERROR_PARAMETERS]; - LPSTR CaptionText, MessageBody; - LPWSTR szxCaptionText, szxMessageBody; - DWORD SizeOfAllUnicodeStrings = 0; - PROCESS_BASIC_INFORMATION ClientBasicInfo; - UNICODE_STRING ClientFileNameU; - UNICODE_STRING TempStringU; - UNICODE_STRING ParameterStringU; - ANSI_STRING ParamStringA; - ULONG UnicodeStringParameterMask = HardErrorMessage->UnicodeStringParameterMask; - int MessageBoxResponse; - - HardErrorMessage->Response = ResponseNotHandled; - - DPRINT("NumberOfParameters = %d\n", HardErrorMessage->NumberOfParameters); - DPRINT("Status = %lx\n", HardErrorMessage->Status); - - // open client process - InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); - Status = NtOpenProcess(&hProcess, PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, &ObjectAttributes, &HardErrorMessage->h.ClientId); - if( !NT_SUCCESS(Status) ) { - DPRINT1("NtOpenProcess failed with code: %lx\n", Status); - return FALSE; - } - - // let's get a name of the client process to display it in the caption of a message box - - ClientFileNameU.MaximumLength = 0; - ClientFileNameU.Length = 0; - ClientFileNameU.Buffer = NULL; - Status = NtQueryInformationProcess(hProcess, - ProcessBasicInformation, - &ClientBasicInfo, - sizeof(ClientBasicInfo), - NULL); - if( NT_SUCCESS(Status) ) { - PLIST_ENTRY ModuleListHead; - PLIST_ENTRY Entry; - PLDR_DATA_TABLE_ENTRY Module; - PPEB_LDR_DATA Ldr; - PPEB Peb = ClientBasicInfo.PebBaseAddress; - - if( Peb ) - { - Status = NtReadVirtualMemory(hProcess, &Peb->Ldr, &Ldr, sizeof(Ldr), NULL); - if( NT_SUCCESS(Status) ) { - ModuleListHead = &Ldr->InLoadOrderModuleList; - Status = NtReadVirtualMemory( - hProcess, - &ModuleListHead->Flink, - &Entry, - sizeof(Entry), - NULL - ); - - if( NT_SUCCESS(Status) ) - { - if (Entry != ModuleListHead) - { - LDR_DATA_TABLE_ENTRY ModuleData; - Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); - - Status = NtReadVirtualMemory(hProcess, Module, &ModuleData, sizeof(ModuleData), NULL); - if( NT_SUCCESS(Status) ) { - PVOID ClientDllBase; - - Status = NtReadVirtualMemory( - hProcess, - &Peb->ImageBaseAddress, - &ClientDllBase, - sizeof(ClientDllBase), - NULL - ); - if( NT_SUCCESS(Status) && (ClientDllBase == ModuleData.DllBase) ) { - - ClientFileNameU.MaximumLength = ModuleData.BaseDllName.MaximumLength; - ClientFileNameU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, ClientFileNameU.MaximumLength); - Status = NtReadVirtualMemory( - hProcess, - ModuleData.BaseDllName.Buffer, - ClientFileNameU.Buffer, - ClientFileNameU.MaximumLength, - NULL - ); - if( NT_SUCCESS(Status) ) { - ClientFileNameU.Length = wcslen(ClientFileNameU.Buffer)*sizeof(wchar_t); - } - else { - RtlFreeHeap (RtlGetProcessHeap(), 0, ClientFileNameU.Buffer); - ClientFileNameU.Buffer = NULL; - } - - DPRINT("ClientFileNameU=\'%wZ\'\n", &ClientFileNameU); - } - } - } - } - } - } - } - - // read all unicode strings from client space - for(nParam = 0; nParam < HardErrorMessage->NumberOfParameters; nParam++, UnicodeStringParameterMask >>= 1) - { - if( UnicodeStringParameterMask & 0x01 ) { - Status = NtReadVirtualMemory(hProcess, - (PVOID)HardErrorMessage->Parameters[nParam], - (PVOID)&TempStringU, - sizeof(TempStringU), - NULL); - - if( NT_SUCCESS(Status) ) { - ParameterStringU.Buffer = (PWSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, TempStringU.MaximumLength); - if( !ParameterStringU.Buffer ) { - DPRINT1("Cannot allocate memory %d\n", TempStringU.MaximumLength); - NtClose(hProcess); - if( ClientFileNameU.Buffer ) { - RtlFreeHeap (RtlGetProcessHeap(), 0, ClientFileNameU.Buffer); - } - return FALSE; - } - - Status = NtReadVirtualMemory(hProcess, - (PVOID)TempStringU.Buffer, - (PVOID)ParameterStringU.Buffer, - TempStringU.MaximumLength, - NULL); - if( !NT_SUCCESS(Status) ) { - DPRINT1("NtReadVirtualMemory failed with code: %lx\n", Status); - RtlFreeHeap (RtlGetProcessHeap(), 0, ParameterStringU.Buffer); - if( ClientFileNameU.Buffer ) { - RtlFreeHeap (RtlGetProcessHeap(), 0, ClientFileNameU.Buffer); - } - NtClose(hProcess); - return FALSE; - } - ParameterStringU.Length = TempStringU.Length; - ParameterStringU.MaximumLength = TempStringU.MaximumLength; - DPRINT("ParameterStringU=\'%wZ\'\n", &ParameterStringU); - RtlUnicodeStringToAnsiString(&ParamStringA, &ParameterStringU, TRUE); - ParameterList[nParam] = (ULONG_PTR)ParamStringA.Buffer; - SizeOfAllUnicodeStrings += ParamStringA.MaximumLength; - } - } - else { - // it's not a unicode string - ParameterList[nParam] = HardErrorMessage->Parameters[nParam]; - } - } - - NtClose(hProcess); - - // get text string of the error code - Status = RtlFindMessage( - (PVOID)GetModuleHandle(TEXT("ntdll")), - (ULONG_PTR)RT_MESSAGETABLE, - LANG_NEUTRAL, - HardErrorMessage->Status, - &MessageResource ); - if( !NT_SUCCESS(Status) ) { - // WE HAVE TO DISPLAY HERE: "Unknown hard error" - if( ClientFileNameU.Buffer ) { - szxCaptionText = (LPWSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, ClientFileNameU.MaximumLength+64); - wsprintfW(szxCaptionText, L"%s - %hs", ClientFileNameU.Buffer, "Application Error"); - } else { - szxCaptionText = (LPWSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 64); - wsprintfW(szxCaptionText, L"System - Application Error"); - } - MessageBody = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 38); - wsprintfA(MessageBody, "Unknown hard error"); - } - else { - LPSTR NtStatusString; - UNICODE_STRING MessageU; - ANSI_STRING MessageA; - USHORT CaptionSize = 0; - - if( !MessageResource->Flags ) { - /* we've got an ansi string */ - DPRINT("MessageResource->Text=%s\n", (PSTR)MessageResource->Text); - RtlInitAnsiString(&MessageA, MessageResource->Text); - } - else { - /* we've got a unicode string */ - DPRINT("MessageResource->Text=%S\n", (PWSTR)MessageResource->Text); - RtlInitUnicodeString(&MessageU, (PWSTR)MessageResource->Text); - RtlUnicodeStringToAnsiString(&MessageA, &MessageU, TRUE); - } - - // check whether a caption exists - if( *MessageA.Buffer == '{' ) { - // get size of the caption - for( CaptionSize = 0; (CaptionSize < MessageA.Length) && ('}' != MessageA.Buffer[CaptionSize]); CaptionSize++); - - CaptionText = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, CaptionSize); - RtlCopyMemory(CaptionText, MessageA.Buffer+1, CaptionSize-1); - CaptionSize += 2; // "}\r\n" - 3 - - szxCaptionText = (LPWSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(wchar_t)*CaptionSize+ClientFileNameU.MaximumLength+128); - if( ClientFileNameU.Buffer ) { - wsprintfW(szxCaptionText, L"%s - %hs", ClientFileNameU.Buffer, CaptionText); - } else { - wsprintfW(szxCaptionText, L"System - %hs", CaptionText); - } - RtlFreeHeap (RtlGetProcessHeap(), 0, CaptionText); - } - else { - if( ClientFileNameU.Buffer ) { - szxCaptionText = (LPWSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, ClientFileNameU.MaximumLength); - wsprintfW(szxCaptionText, L"%s", ClientFileNameU.Buffer); - } else { - szxCaptionText = (LPWSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 14); // 14 - "System\0\0" - wsprintfW(szxCaptionText, L"System"); - } - } - DPRINT("ParameterList[0]=0x%lx\n", ParameterList[0]); - if( STATUS_UNHANDLED_EXCEPTION == HardErrorMessage->Status ) - { - PRTL_MESSAGE_RESOURCE_ENTRY MsgResException; - MessageBody = NULL; - Status = RtlFindMessage( - (PVOID)GetModuleHandle(TEXT("ntdll")), - (ULONG_PTR)RT_MESSAGETABLE, - LANG_NEUTRAL, - ParameterList[0], - &MsgResException); - - if( NT_SUCCESS(Status) ) - { - UNICODE_STRING ExcMessageU; - ANSI_STRING ExcMessageA; - if( !MsgResException->Flags ) { - /* we've got an ansi string */ - DPRINT("MsgResException->Text=%s\n", (PSTR)MsgResException->Text); - RtlInitAnsiString(&ExcMessageA, MsgResException->Text); - } - else { - /* we've got a unicode string */ - DPRINT("MsgResException->Text=%S\n", (PWSTR)MsgResException->Text); - RtlInitUnicodeString(&ExcMessageU, (PWSTR)MsgResException->Text); - RtlUnicodeStringToAnsiString(&ExcMessageA, &ExcMessageU, TRUE); - } - - MessageBody = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, MsgResException->Length+SizeOfAllUnicodeStrings+1024); // 1024 is a magic number I think it should be enough - if( STATUS_ACCESS_VIOLATION == ParameterList[0] ) { - LPSTR pOperationType; - if( ParameterList[2] ) pOperationType = "written"; - else pOperationType = "read"; - wsprintfA(MessageBody, ExcMessageA.Buffer, ParameterList[1], ParameterList[3], pOperationType); - } - else if( STATUS_IN_PAGE_ERROR == ParameterList[0] ) { - wsprintfA(MessageBody, ExcMessageA.Buffer, ParameterList[1], ParameterList[3], ParameterList[2]); - } - } - if( !MessageBody ) { - NtStatusString = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, MessageResource->Length-CaptionSize); - RtlCopyMemory(NtStatusString, MessageA.Buffer+CaptionSize, (MessageResource->Length-CaptionSize)-1); - - MessageBody = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, MessageResource->Length+SizeOfAllUnicodeStrings+1024); // 1024 is a magic number I think it should be enough - - wsprintfA(MessageBody, NtStatusString, - L"Unknown software exception", - ParameterList[0], - ParameterList[1]); - - RtlFreeHeap (RtlGetProcessHeap(), 0, NtStatusString); - } - } - else - { - NtStatusString = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, MessageResource->Length-CaptionSize); - RtlCopyMemory(NtStatusString, MessageA.Buffer+CaptionSize, (MessageResource->Length-CaptionSize)-1); - - MessageBody = (LPSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, MessageResource->Length+SizeOfAllUnicodeStrings+1024); // 1024 is a magic number I think it should be enough - - wsprintfA(MessageBody, NtStatusString, - ParameterList[0], - ParameterList[1], - ParameterList[2], - ParameterList[3]); - - RtlFreeHeap (RtlGetProcessHeap(), 0, NtStatusString); - } - if( MessageResource->Flags ) { - /* we've got a unicode string */ - RtlFreeAnsiString(&MessageA); - } - } - if( ClientFileNameU.Buffer ) { - RtlFreeHeap (RtlGetProcessHeap(), 0, ClientFileNameU.Buffer); - } - - szxMessageBody = (LPWSTR)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(wchar_t)*(strlen(MessageBody)+1)); - wsprintfW(szxMessageBody, L"%hs", MessageBody); - RtlFreeHeap (RtlGetProcessHeap(), 0, MessageBody); - - switch ( HardErrorMessage->ValidResponseOptions ) - { - case OptionAbortRetryIgnore: - responce = MB_ABORTRETRYIGNORE; - break; - - case OptionOk: - responce = MB_OK; - break; - - case OptionOkCancel: - responce = MB_OKCANCEL; - break; - - case OptionRetryCancel: - responce = MB_RETRYCANCEL; - break; - - case OptionYesNo: - responce = MB_YESNO; - break; - - case OptionYesNoCancel: - responce = MB_YESNOCANCEL; - break; - - case OptionShutdownSystem: - // XZ?? - break; - - default: - DPRINT1("Wrong option: ValidResponseOptions = %d\n", HardErrorMessage->ValidResponseOptions); - ASSERT(FALSE); - break; - } - - // FIXME: We should not use MessageBox !!!! - DPRINT1("%S\n", szxMessageBody); - MessageBoxResponse = MessageBoxW(0, szxMessageBody, szxCaptionText, responce|MB_ICONERROR|MB_SYSTEMMODAL|MB_SETFOREGROUND); - - RtlFreeHeap (RtlGetProcessHeap(), 0, szxMessageBody); - RtlFreeHeap (RtlGetProcessHeap(), 0, szxCaptionText); - - switch( MessageBoxResponse ) - { - case IDOK: - HardErrorMessage->Response = ResponseOk; - break; - - case IDCANCEL: - HardErrorMessage->Response = ResponseCancel; - break; - - case IDYES: - HardErrorMessage->Response = ResponseYes; - break; - - case IDNO: - HardErrorMessage->Response = ResponseNo; - break; - - case IDABORT: - HardErrorMessage->Response = ResponseAbort; - break; - - case IDIGNORE: - HardErrorMessage->Response = ResponseIgnore; - break; - - case IDRETRY: - HardErrorMessage->Response = ResponseRetry; - break; - - case 10://IDTRYAGAIN: - HardErrorMessage->Response = ResponseTryAgain; - break; - - case 11://IDCONTINUE: - HardErrorMessage->Response = ResponseContinue; - break; - - default: - ASSERT(FALSE); - break; - } - - return TRUE; -} - - BOOL WINAPI Win32CsrInitialization(PCSRSS_API_DEFINITION *ApiDefinitions, PCSRSS_OBJECT_DEFINITION *ObjectDefinitions, diff --git a/reactos/subsystems/win32/csrss/win32csr/harderror.c b/reactos/subsystems/win32/csrss/win32csr/harderror.c new file mode 100644 index 00000000000..a1b5a5dc5d3 --- /dev/null +++ b/reactos/subsystems/win32/csrss/win32csr/harderror.c @@ -0,0 +1,552 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: subsys/csrss/win32csr/dllmain.c + * PURPOSE: Initialization + * PROGRAMMERS: Dmitry Philippov (shedon@mail.ru) + * Timo Kreuzer (timo.kreuzer@reactos.org) + */ + +/* INCLUDES ******************************************************************/ + +#define NDEBUG +#include "w32csr.h" +#include +#include + +#define IDTRYAGAIN 10 +#define IDCONTINUE 11 + +/* FUNCTIONS *****************************************************************/ + +static +NTSTATUS +CsrpGetClientFileName( + OUT PUNICODE_STRING ClientFileNameU, + HANDLE hProcess) +{ + PLIST_ENTRY ModuleListHead; + PLIST_ENTRY Entry; + PLDR_DATA_TABLE_ENTRY Module; + PPEB_LDR_DATA Ldr; + PROCESS_BASIC_INFORMATION ClientBasicInfo; + LDR_DATA_TABLE_ENTRY ModuleData; + PVOID ClientDllBase; + NTSTATUS Status; + PPEB Peb; + + /* Initialize string */ + ClientFileNameU->MaximumLength = 0; + ClientFileNameU->Length = 0; + ClientFileNameU->Buffer = NULL; + + /* Query process information */ + Status = NtQueryInformationProcess(hProcess, + ProcessBasicInformation, + &ClientBasicInfo, + sizeof(ClientBasicInfo), + NULL); + if (!NT_SUCCESS(Status)) return Status; + + Peb = ClientBasicInfo.PebBaseAddress; + if (!Peb) return STATUS_UNSUCCESSFUL; + + Status = NtReadVirtualMemory(hProcess, &Peb->Ldr, &Ldr, sizeof(Ldr), NULL); + if (!NT_SUCCESS(Status)) return Status; + + ModuleListHead = &Ldr->InLoadOrderModuleList; + Status = NtReadVirtualMemory(hProcess, + &ModuleListHead->Flink, + &Entry, + sizeof(Entry), + NULL); + if (!NT_SUCCESS(Status)) return Status; + + if (Entry == ModuleListHead) return STATUS_UNSUCCESSFUL; + + Module = CONTAINING_RECORD(Entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks); + + Status = NtReadVirtualMemory(hProcess, + Module, + &ModuleData, + sizeof(ModuleData), + NULL); + if (!NT_SUCCESS(Status)) return Status; + + Status = NtReadVirtualMemory(hProcess, + &Peb->ImageBaseAddress, + &ClientDllBase, + sizeof(ClientDllBase), + NULL); + if (!NT_SUCCESS(Status)) return Status; + + if (ClientDllBase != ModuleData.DllBase) return STATUS_UNSUCCESSFUL; + + ClientFileNameU->MaximumLength = ModuleData.BaseDllName.MaximumLength; + ClientFileNameU->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + ClientFileNameU->MaximumLength); + + Status = NtReadVirtualMemory(hProcess, + ModuleData.BaseDllName.Buffer, + ClientFileNameU->Buffer, + ClientFileNameU->MaximumLength, + NULL); + if (!NT_SUCCESS(Status)) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, ClientFileNameU->Buffer); + ClientFileNameU->Buffer = NULL; + ClientFileNameU->MaximumLength = 0; + return Status; + } + + ClientFileNameU->Length = wcslen(ClientFileNameU->Buffer)*sizeof(wchar_t); + DPRINT("ClientFileNameU=\'%wZ\'\n", &ClientFileNameU); + + return STATUS_SUCCESS; +} + + +static +NTSTATUS +CsrpCaptureStringParameters( + OUT PULONG_PTR Parameters, + OUT PULONG SizeOfAllUnicodeStrings, + IN PHARDERROR_MSG HardErrorMessage, + HANDLE hProcess) +{ + ULONG nParam, UnicodeStringParameterMask, Size = 0; + NTSTATUS Status; + UNICODE_STRING TempStringU; + PWSTR ParamString; + + UnicodeStringParameterMask = HardErrorMessage->UnicodeStringParameterMask; + + /* Read all strings from client space */ + for (nParam = 0; + nParam < HardErrorMessage->NumberOfParameters; + nParam++, UnicodeStringParameterMask >>= 1) + { + Parameters[nParam] = 0; + + /* Check if the current parameter is a unicode string */ + if (UnicodeStringParameterMask & 0x01) + { + /* Read the UNICODE_STRING from the process memory */ + Status = NtReadVirtualMemory(hProcess, + (PVOID)HardErrorMessage->Parameters[nParam], + &TempStringU, + sizeof(TempStringU), + NULL); + + if (!NT_SUCCESS(Status)) return Status; + + /* Allocate a buffer for the string */ + ParamString = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + TempStringU.Length + sizeof(WCHAR)); + + if (!ParamString) + { + DPRINT1("Cannot allocate memory %d\n", TempStringU.Length); + return STATUS_NO_MEMORY; + } + + /* Read the string buffer from the process memory */ + Status = NtReadVirtualMemory(hProcess, + TempStringU.Buffer, + ParamString, + TempStringU.Length, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtReadVirtualMemory failed with code: %lx\n", Status); + RtlFreeHeap(RtlGetProcessHeap(), 0, ParamString); + return Status; + } + + /* Zero terminate the string */ + ParamString[TempStringU.Length / sizeof(WCHAR)] = 0; + DPRINT("ParamString=\'%S\'\n", ParamString); + + Parameters[nParam] = (ULONG_PTR)ParamString; + Size += TempStringU.Length; + } + else + { + /* It's not a unicode string */ + Parameters[nParam] = HardErrorMessage->Parameters[nParam]; + } + } + + *SizeOfAllUnicodeStrings = Size; + return STATUS_SUCCESS; +} + +static +VOID +CsrpFreeStringParameters( + IN OUT PULONG_PTR Parameters, + IN PHARDERROR_MSG HardErrorMessage) +{ + ULONG nParam, UnicodeStringParameterMask; + + UnicodeStringParameterMask = HardErrorMessage->UnicodeStringParameterMask; + + /* Loop all parameters */ + for (nParam = 0; + nParam < HardErrorMessage->NumberOfParameters; + nParam++, UnicodeStringParameterMask >>= 1) + { + /* Check if the current parameter is a string */ + if (UnicodeStringParameterMask & 0x01) + { + /* Free the string buffer */ + RtlFreeHeap(RtlGetProcessHeap(), 0, (PVOID)Parameters[nParam]); + } + } +} + + +static +NTSTATUS +CsrpFormatMessages( + OUT PUNICODE_STRING TextStringU, + OUT PUNICODE_STRING CaptionStringU, + IN PULONG_PTR Parameters, + IN ULONG SizeOfStrings, + IN PHARDERROR_MSG Message, + IN HANDLE hProcess) +{ + NTSTATUS Status; + UNICODE_STRING FileNameU, TempStringU, FormatU; + ANSI_STRING FormatA; + PRTL_MESSAGE_RESOURCE_ENTRY MessageResource; + PWSTR FormatString; + ULONG Size; + + /* Get the file name of the client process */ + CsrpGetClientFileName(&FileNameU, hProcess); + + /* Check if we have a file name */ + if (!FileNameU.Buffer) + { + /* No, use system */ + RtlInitUnicodeString(&FileNameU, L"System"); + } + + /* Get text string of the error code */ + Status = RtlFindMessage(GetModuleHandleW(L"ntdll"), + (ULONG_PTR)RT_MESSAGETABLE, + LANG_NEUTRAL, + Message->Status, + &MessageResource); + + if (NT_SUCCESS(Status)) + { + if (MessageResource->Flags) + { + RtlInitUnicodeString(&FormatU, (PWSTR)MessageResource->Text); + FormatA.Buffer = NULL; + } + else + { + RtlInitAnsiString(&FormatA, MessageResource->Text); + RtlAnsiStringToUnicodeString(&FormatU, &FormatA, TRUE); + } + } + else + { + /* Fall back to hardcoded value */ + RtlInitUnicodeString(&FormatU, L"Unknown Hard Error"); + FormatA.Buffer = NULL; + } + + FormatString = FormatU.Buffer; + + /* Check whether a caption exists */ + if (FormatString[0] == L'{') + { + /* Set caption start */ + TempStringU.Buffer = ++FormatString; + + /* Get size of the caption */ + for (Size = 0; *FormatString != 0 && *FormatString != L'}'; Size++) + FormatString++; + + /* Skip '}', '\r', '\n' */ + FormatString += 3; + + TempStringU.Length = Size * sizeof(WCHAR); + TempStringU.MaximumLength = TempStringU.Length; + } + else + { + /* FIXME: Set string based on severity */ + RtlInitUnicodeString(&TempStringU, L"Application Error"); + } + + /* Calculate buffer length for the caption */ + CaptionStringU->MaximumLength = FileNameU.Length + TempStringU.Length + + 4 * sizeof(WCHAR); + + /* Allocate a buffer for the caption */ + CaptionStringU->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + CaptionStringU->MaximumLength); + + /* Append the file name, seperator and the caption text */ + CaptionStringU->Length = 0; + RtlAppendUnicodeStringToString(CaptionStringU, &FileNameU); + RtlAppendUnicodeToString(CaptionStringU, L" - "); + RtlAppendUnicodeStringToString(CaptionStringU, &TempStringU); + + /* Zero terminate the buffer */ + CaptionStringU->Buffer[CaptionStringU->Length] = 0; + + /* Free the file name buffer */ + RtlFreeUnicodeString(&FileNameU); + + /* Check if this is an exception message */ + if (Message->Status == STATUS_UNHANDLED_EXCEPTION) + { + /* Handle special cases */ + if (Parameters[0] == STATUS_ACCESS_VIOLATION) + { + Parameters[0] = Parameters[1]; + Parameters[1] = Parameters[3]; + if (Parameters[2]) Parameters[2] = (ULONG_PTR)L"written"; + else Parameters[2] = (ULONG_PTR)L"read"; + MessageResource = NULL; + } + else if (Parameters[0] == STATUS_IN_PAGE_ERROR) + { + Parameters[0] = Parameters[1]; + Parameters[1] = Parameters[3]; + MessageResource = NULL; + } + else + { + /* Fall back to hardcoded value */ + Parameters[2] = Parameters[1]; + Parameters[1] = Parameters[0]; + Parameters[0] = (ULONG_PTR)L"unknown software exception"; + } + + if (!MessageResource) + { + /* Get text string of the exception code */ + Status = RtlFindMessage(GetModuleHandleW(L"ntdll"), + (ULONG_PTR)RT_MESSAGETABLE, + LANG_NEUTRAL, + Parameters[0], + &MessageResource); + + if (NT_SUCCESS(Status)) + { + if (FormatA.Buffer) RtlFreeUnicodeString(&FormatU); + + if (MessageResource->Flags) + { + RtlInitUnicodeString(&FormatU, (PWSTR)MessageResource->Text); + FormatA.Buffer = NULL; + } + else + { + RtlInitAnsiString(&FormatA, MessageResource->Text); + RtlAnsiStringToUnicodeString(&FormatU, &FormatA, TRUE); + } + } + else + { + /* Fall back to hardcoded value */ + Parameters[2] = Parameters[1]; + Parameters[1] = Parameters[0]; + Parameters[0] = (ULONG_PTR)L"unknown software exception"; + } + } + } + + /* Calculate length of text buffer */ + TextStringU->MaximumLength = wcslen(FormatString) * sizeof(WCHAR) + + SizeOfStrings + 42 * sizeof(WCHAR); + + /* Allocate a buffer for the text */ + TextStringU->Buffer = RtlAllocateHeap(RtlGetProcessHeap(), + HEAP_ZERO_MEMORY, + TextStringU->MaximumLength); + + /* Wrap in SEH to protect from invalid string parameters */ + _SEH2_TRY + { + /* Print the string into the buffer */ + StringCbPrintfW(TextStringU->Buffer, + TextStringU->MaximumLength, + FormatString, + Parameters[0], + Parameters[1], + Parameters[2], + Parameters[3], + Parameters[4]); + Status = STATUS_SUCCESS; + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + /* Set error and free buffers */ + Status = _SEH2_GetExceptionCode(); + RtlFreeHeap(RtlGetProcessHeap(), 0, TextStringU->Buffer); + RtlFreeHeap(RtlGetProcessHeap(), 0, CaptionStringU->Buffer); + } + _SEH2_END + + if (NT_SUCCESS(Status)) + { + TextStringU->Length = wcslen(TextStringU->Buffer) * sizeof(WCHAR); + } + + if (FormatA.Buffer) RtlFreeUnicodeString(&FormatU); + + return Status; +} + +static +ULONG +CsrpMessageBox( + PWSTR Text, + PWSTR Caption, + ULONG ValidResponseOptions, + ULONG Severity) +{ + ULONG Type, MessageBoxResponse; + + /* Set the message box type */ + switch (ValidResponseOptions) + { + case OptionAbortRetryIgnore: + Type = MB_ABORTRETRYIGNORE; + break; + case OptionOk: + Type = MB_OK; + break; + case OptionOkCancel: + Type = MB_OKCANCEL; + break; + case OptionRetryCancel: + Type = MB_RETRYCANCEL; + break; + case OptionYesNo: + Type = MB_YESNO; + break; + case OptionYesNoCancel: + Type = MB_YESNOCANCEL; + break; + case OptionShutdownSystem: + Type = MB_RETRYCANCEL; // FIXME??? + break; + /* Anything else is invalid */ + default: + return ResponseNotHandled; + } + + /* Set severity */ + if (Severity == STATUS_SEVERITY_INFORMATIONAL) Type |= MB_ICONINFORMATION; + else if (Severity == STATUS_SEVERITY_WARNING) Type |= MB_ICONWARNING; + else if (Severity == STATUS_SEVERITY_ERROR) Type |= MB_ICONERROR; + + Type |= MB_SYSTEMMODAL | MB_SETFOREGROUND; + + DPRINT("Text = '%S', Caption = '%S', Severity = %d, Type = 0x%lx\n", + Text, Caption, Severity, Type); + + /* Display a message box */ + MessageBoxResponse = MessageBoxW(0, Text, Caption, Type); + + /* Return response value */ + switch (MessageBoxResponse) + { + case IDOK: return ResponseOk; + case IDCANCEL: return ResponseCancel; + case IDYES: return ResponseYes; + case IDNO: return ResponseNo; + case IDABORT: return ResponseAbort; + case IDIGNORE: return ResponseIgnore; + case IDRETRY: return ResponseRetry; + case IDTRYAGAIN: return ResponseTryAgain; + case IDCONTINUE: return ResponseContinue; + } + + return ResponseNotHandled; +} + +BOOL +WINAPI +Win32CsrHardError( + IN PCSRSS_PROCESS_DATA ProcessData, + IN PHARDERROR_MSG Message) +{ + ULONG_PTR Parameters[MAXIMUM_HARDERROR_PARAMETERS]; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING TextU, CaptionU; + NTSTATUS Status; + HANDLE hProcess; + ULONG Size; + + /* Default to not handled */ + Message->Response = ResponseNotHandled; + + /* Make sure we don't have too many parameters */ + if (Message->NumberOfParameters > MAXIMUM_HARDERROR_PARAMETERS) + Message->NumberOfParameters = MAXIMUM_HARDERROR_PARAMETERS; + + /* Initialize object attributes */ + InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); + + /* Open client process */ + Status = NtOpenProcess(&hProcess, + PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, + &ObjectAttributes, + &Message->h.ClientId); + + if (!NT_SUCCESS(Status)) + { + DPRINT1("NtOpenProcess failed with code: %lx\n", Status); + return FALSE; + } + + /* Capture all string parameters from the process memory */ + Status = CsrpCaptureStringParameters(Parameters, &Size, Message, hProcess); + if (!NT_SUCCESS(Status)) + { + NtClose(hProcess); + return FALSE; + } + + /* Format the caption and message box text */ + Status = CsrpFormatMessages(&TextU, + &CaptionU, + Parameters, + Size, + Message, + hProcess); + + /* Cleanup */ + CsrpFreeStringParameters(Parameters, Message); + NtClose(hProcess); + + if (!NT_SUCCESS(Status)) + { + return FALSE; + } + + /* Display the message box */ + Message->Response = CsrpMessageBox(TextU.Buffer, + CaptionU.Buffer, + Message->ValidResponseOptions, + (ULONG)Message->Status >> 30); + + RtlFreeUnicodeString(&TextU); + RtlFreeUnicodeString(&CaptionU); + + return TRUE; +} + diff --git a/reactos/subsystems/win32/csrss/win32csr/w32csr.h b/reactos/subsystems/win32/csrss/win32csr/w32csr.h index f6f0f4e649c..5ecc378a7c7 100644 --- a/reactos/subsystems/win32/csrss/win32csr/w32csr.h +++ b/reactos/subsystems/win32/csrss/win32csr/w32csr.h @@ -35,4 +35,11 @@ /* shared header with console.dll */ #include "console.h" + +BOOL +WINAPI +Win32CsrHardError( + IN PCSRSS_PROCESS_DATA ProcessData, + IN PHARDERROR_MSG Message); + /* EOF */ diff --git a/reactos/subsystems/win32/csrss/win32csr/win32csr.rbuild b/reactos/subsystems/win32/csrss/win32csr/win32csr.rbuild index 7a14f63f806..eec81fcba60 100644 --- a/reactos/subsystems/win32/csrss/win32csr/win32csr.rbuild +++ b/reactos/subsystems/win32/csrss/win32csr/win32csr.rbuild @@ -14,6 +14,7 @@ advapi32 win32ksys psapi + pseh w32csr.h alias.c conio.c @@ -21,6 +22,7 @@ dllmain.c exitros.c guiconsole.c + harderror.c tuiconsole.c appswitch.c win32csr.rc