[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
This commit is contained in:
Timo Kreuzer 2010-04-26 01:23:21 +00:00
parent 89a4d76d9d
commit b5a39d6dd1
4 changed files with 561 additions and 396 deletions

View file

@ -180,402 +180,6 @@ Win32CsrInitComplete(void)
return TRUE; 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 BOOL WINAPI
Win32CsrInitialization(PCSRSS_API_DEFINITION *ApiDefinitions, Win32CsrInitialization(PCSRSS_API_DEFINITION *ApiDefinitions,
PCSRSS_OBJECT_DEFINITION *ObjectDefinitions, PCSRSS_OBJECT_DEFINITION *ObjectDefinitions,

View file

@ -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 <debug.h>
#include <strsafe.h>
#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;
}

View file

@ -35,4 +35,11 @@
/* shared header with console.dll */ /* shared header with console.dll */
#include "console.h" #include "console.h"
BOOL
WINAPI
Win32CsrHardError(
IN PCSRSS_PROCESS_DATA ProcessData,
IN PHARDERROR_MSG Message);
/* EOF */ /* EOF */

View file

@ -14,6 +14,7 @@
<library>advapi32</library> <library>advapi32</library>
<library>win32ksys</library> <library>win32ksys</library>
<library>psapi</library> <library>psapi</library>
<library>pseh</library>
<pch>w32csr.h</pch> <pch>w32csr.h</pch>
<file>alias.c</file> <file>alias.c</file>
<file>conio.c</file> <file>conio.c</file>
@ -21,6 +22,7 @@
<file>dllmain.c</file> <file>dllmain.c</file>
<file>exitros.c</file> <file>exitros.c</file>
<file>guiconsole.c</file> <file>guiconsole.c</file>
<file>harderror.c</file>
<file>tuiconsole.c</file> <file>tuiconsole.c</file>
<file>appswitch.c</file> <file>appswitch.c</file>
<file>win32csr.rc</file> <file>win32csr.rc</file>