From 57787bb8815cc60a2aefeb87c8fc611efb5b494e Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Sat, 12 Mar 2005 08:54:41 +0000 Subject: [PATCH] Thomas Weidenmueller - Implement support for vectored exception handlers. - Add code for querying process cookie. svn path=/trunk/; revision=13962 --- reactos/include/ntdll/rtl.h | 7 ++ reactos/include/ntos/zwtypes.h | 12 ++- reactos/lib/ntdll/def/ntdll.def | 8 +- reactos/lib/ntdll/ldr/startup.c | 5 + reactos/lib/ntdll/rtl/exception.c | 141 ++++++++++++++++++++++++- reactos/lib/ntdll/rtl/misc.c | 30 ++++++ reactos/ntoskrnl/include/internal/ps.h | 1 + reactos/ntoskrnl/ps/process.c | 111 +++++++++++++++---- 8 files changed, 288 insertions(+), 27 deletions(-) diff --git a/reactos/include/ntdll/rtl.h b/reactos/include/ntdll/rtl.h index cb73f5526b1..c9967143c64 100644 --- a/reactos/include/ntdll/rtl.h +++ b/reactos/include/ntdll/rtl.h @@ -770,6 +770,13 @@ NTSTATUS STDCALL RtlDeleteTimerQueue(HANDLE TimerQueue); +PVOID +STDCALL +RtlEncodePointer(IN PVOID Pointer); + +PVOID +STDCALL +RtlDecodePointer(IN PVOID Pointer); #ifndef __NTDRIVER__ diff --git a/reactos/include/ntos/zwtypes.h b/reactos/include/ntos/zwtypes.h index 1483c5778b6..da23d54efc1 100755 --- a/reactos/include/ntos/zwtypes.h +++ b/reactos/include/ntos/zwtypes.h @@ -1219,9 +1219,17 @@ extern IMPORTED ULONG NtBuildNumber; #define ProcessSessionInformation 24 #define ProcessForegroundInformation 25 #define ProcessWow64Information 26 -/* ReactOS private. */ #define ProcessImageFileName 27 -#define MaxProcessInfoClass 28 +#define ProcessLUIDDeviceMapsEnabled 28 +#define ProcessBreakOnTermination 29 +#define ProcessDebugObjectHandle 30 +#define ProcessDebugFlags 31 +#define ProcessHandleTracing 32 +#define ProcessUnknown33 33 +#define ProcessUnknown34 34 +#define ProcessUnknown35 35 +#define ProcessCookie 36 +#define MaxProcessInfoClass 36 /* * thread query / set information class diff --git a/reactos/lib/ntdll/def/ntdll.def b/reactos/lib/ntdll/def/ntdll.def index f9101bae979..e392a1dabd0 100644 --- a/reactos/lib/ntdll/def/ntdll.def +++ b/reactos/lib/ntdll/def/ntdll.def @@ -225,7 +225,6 @@ NtSetEaFile@16 NtSetEvent@8 NtSetHighEventPair@4 NtSetHighWaitLowEventPair@4 -NtSetHighWaitLowThread@0 NtSetInformationFile@20 NtSetInformationJobObject@16 NtSetInformationKey@16 @@ -238,7 +237,6 @@ NtSetIoCompletion@20 NtSetLdtEntries@24 NtSetLowEventPair@4 NtSetLowWaitHighEventPair@4 -NtSetLowWaitHighThread@0 NtSetSecurityObject@12 NtSetSystemEnvironmentValue@8 NtSetSystemInformation@12 @@ -298,6 +296,7 @@ RtlAddAuditAccessAce@24 RtlAddAuditAccessAceEx@28 ;RtlAddCompoundAce RtlAddRange@36 +RtlAddVectoredExceptionHandler@8 RtlAdjustPrivilege@16 RtlAllocateAndInitializeSid@44 RtlAllocateHandle@8 @@ -364,6 +363,7 @@ RtlCreateUserThread@40 RtlCustomCPToUnicodeN@24 RtlCutoverTimeToSystemTime@16 RtlDeNormalizeProcessParams@4 +RtlDecodePointer=RtlEncodePointer@4 RtlDecompressBuffer@24 RtlDecompressFragment@32 RtlDelete@4 @@ -396,6 +396,7 @@ RtlDowncaseUnicodeString@12 RtlDumpResource@4 RtlDuplicateUnicodeString@12 RtlEmptyAtomTable@8 +RtlEncodePointer@4 RtlEnlargedIntegerMultiply@8 RtlEnlargedUnsignedDivide@16 RtlEnlargedUnsignedMultiply@8 @@ -593,6 +594,7 @@ RtlRealSuccessor@4 RtlReleasePebLock@0 RtlReleaseResource@4 ;RtlRemoteCall +RtlRemoveVectoredExceptionHandler@4 RtlResetRtlTranslations@4 RtlRestoreLastWin32Error@4=RtlSetLastWin32Error@4 RtlRunDecodeUnicodeString@8 @@ -849,7 +851,6 @@ ZwSetEaFile@16 ZwSetEvent@8 ZwSetHighEventPair@4 ZwSetHighWaitLowEventPair@4 -ZwSetHighWaitLowThread@0 ZwSetInformationFile@20 ZwSetInformationKey@16 ZwSetInformationObject@16 @@ -861,7 +862,6 @@ ZwSetIoCompletion@20 ZwSetLdtEntries@24 ZwSetLowEventPair@4 ZwSetLowWaitHighEventPair@4 -ZwSetLowWaitHighThread@0 ZwSetSecurityObject@12 ZwSetSystemEnvironmentValue@8 ZwSetSystemInformation@12 diff --git a/reactos/lib/ntdll/ldr/startup.c b/reactos/lib/ntdll/ldr/startup.c index e775fab0ab6..c6e972a9123 100644 --- a/reactos/lib/ntdll/ldr/startup.c +++ b/reactos/lib/ntdll/ldr/startup.c @@ -39,6 +39,8 @@ PLDR_MODULE ExeModule; NTSTATUS LdrpAttachThread (VOID); +VOID RtlpInitializeVectoredExceptionHandling(VOID); + #define VALUE_BUFFER_SIZE 256 @@ -306,6 +308,9 @@ __true_LdrInitializeThunk (ULONG Unknown1, ZwTerminateProcess(NtCurrentProcess(),STATUS_UNSUCCESSFUL); } + /* initialized vectored exception handling */ + RtlpInitializeVectoredExceptionHandling(); + /* initalize peb lock support */ RtlInitializeCriticalSection (&PebLock); Peb->FastPebLock = &PebLock; diff --git a/reactos/lib/ntdll/rtl/exception.c b/reactos/lib/ntdll/rtl/exception.c index 2dde23719e7..6a91cd665d0 100644 --- a/reactos/lib/ntdll/rtl/exception.c +++ b/reactos/lib/ntdll/rtl/exception.c @@ -22,6 +22,19 @@ #define NDEBUG #include +static CRITICAL_SECTION RtlpVectoredExceptionLock; +static LIST_ENTRY RtlpVectoredExceptionHead; + +typedef struct _RTL_VECTORED_EXCEPTION_HANDLER +{ + LIST_ENTRY ListEntry; + PVECTORED_EXCEPTION_HANDLER VectoredHandler; +} RTL_VECTORED_EXCEPTION_HANDLER, *PRTL_VECTORED_EXCEPTION_HANDLER; + +/* FIXME - stupid ld won't resolve RtlDecodePointer! Since their implementation + is the same just use RtlEncodePointer for now! */ +#define RtlDecodePointer RtlEncodePointer + /* FUNCTIONS ***************************************************************/ VOID STDCALL @@ -35,20 +48,63 @@ ULONG RtlpDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT Context); +EXCEPTION_DISPOSITION +RtlpExecuteVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context) +{ + PLIST_ENTRY CurrentEntry; + PRTL_VECTORED_EXCEPTION_HANDLER veh; + PVECTORED_EXCEPTION_HANDLER VectoredHandler; + EXCEPTION_POINTERS ExceptionInfo; + + ExceptionInfo.ExceptionRecord = ExceptionRecord; + ExceptionInfo.ContextRecord = Context; + + if(RtlpVectoredExceptionHead.Flink != &RtlpVectoredExceptionHead) + { + RtlEnterCriticalSection(&RtlpVectoredExceptionLock); + for(CurrentEntry = RtlpVectoredExceptionHead.Flink; + CurrentEntry != &RtlpVectoredExceptionHead; + CurrentEntry = CurrentEntry->Flink) + { + veh = CONTAINING_RECORD(CurrentEntry, + RTL_VECTORED_EXCEPTION_HANDLER, + ListEntry); + VectoredHandler = RtlDecodePointer(veh->VectoredHandler); + if(VectoredHandler(&ExceptionInfo) == EXCEPTION_CONTINUE_EXECUTION) + { + RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); + return ExceptionContinueSearch; + } + } + RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); + } + + return ExceptionContinueExecution; +} + VOID STDCALL KiUserExceptionDispatcher(PEXCEPTION_RECORD ExceptionRecord, PCONTEXT Context) { EXCEPTION_RECORD NestedExceptionRecord; NTSTATUS Status; - - if (RtlpDispatchException(ExceptionRecord, Context) != ExceptionContinueExecution) + + if(RtlpExecuteVectoredExceptionHandlers(ExceptionRecord, + Context) != ExceptionContinueExecution) { Status = NtContinue(Context, FALSE); } else { - Status = NtRaiseException(ExceptionRecord, Context, FALSE); + if(RtlpDispatchException(ExceptionRecord, Context) != ExceptionContinueExecution) + { + Status = NtContinue(Context, FALSE); + } + else + { + Status = NtRaiseException(ExceptionRecord, Context, FALSE); + } } NestedExceptionRecord.ExceptionCode = Status; @@ -87,4 +143,83 @@ RtlBaseProcessStart(PTHREAD_START_ROUTINE StartAddress, NtTerminateProcess(NtCurrentProcess(), ExitStatus); } + +VOID +RtlpInitializeVectoredExceptionHandling(VOID) +{ + InitializeListHead(&RtlpVectoredExceptionHead); + RtlInitializeCriticalSection(&RtlpVectoredExceptionLock); +} + + +/* + * @implemented + */ +PVOID STDCALL +RtlAddVectoredExceptionHandler(IN ULONG FirstHandler, + IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) +{ + PRTL_VECTORED_EXCEPTION_HANDLER veh; + + veh = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + sizeof(RTL_VECTORED_EXCEPTION_HANDLER)); + if(veh != NULL) + { + veh->VectoredHandler = RtlEncodePointer(VectoredHandler); + RtlEnterCriticalSection(&RtlpVectoredExceptionLock); + if(FirstHandler != 0) + { + InsertHeadList(&RtlpVectoredExceptionHead, + &veh->ListEntry); + } + else + { + InsertTailList(&RtlpVectoredExceptionHead, + &veh->ListEntry); + } + RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); + } + + return veh; +} + + +/* + * @implemented + */ +ULONG STDCALL +RtlRemoveVectoredExceptionHandler(IN PVOID VectoredHandlerHandle) +{ + PLIST_ENTRY CurrentEntry; + PRTL_VECTORED_EXCEPTION_HANDLER veh = NULL; + ULONG Removed = FALSE; + + RtlEnterCriticalSection(&RtlpVectoredExceptionLock); + for(CurrentEntry = RtlpVectoredExceptionHead.Flink; + CurrentEntry != &RtlpVectoredExceptionHead; + CurrentEntry = CurrentEntry->Flink) + { + veh = CONTAINING_RECORD(CurrentEntry, + RTL_VECTORED_EXCEPTION_HANDLER, + ListEntry); + if(veh == VectoredHandlerHandle) + { + RemoveEntryList(&veh->ListEntry); + Removed = TRUE; + break; + } + } + RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); + + if(Removed) + { + RtlFreeHeap(RtlGetProcessHeap(), + 0, + veh); + } + + return Removed; +} + /* EOF */ diff --git a/reactos/lib/ntdll/rtl/misc.c b/reactos/lib/ntdll/rtl/misc.c index 75345916583..4f36db063ae 100644 --- a/reactos/lib/ntdll/rtl/misc.c +++ b/reactos/lib/ntdll/rtl/misc.c @@ -15,6 +15,9 @@ #include #include +#define NDEBUG +#include + /********************************************************************** * NAME EXPORTED * RtlGetNtProductType @@ -107,3 +110,30 @@ RtlGetNtGlobalFlags(VOID) PPEB pPeb = NtCurrentPeb(); return pPeb->NtGlobalFlag; } + + +/* + * @implemented + */ +PVOID +STDCALL +RtlEncodePointer(IN PVOID Pointer) +{ + ULONG Cookie; + NTSTATUS Status; + + Status = NtQueryInformationProcess(NtCurrentProcess(), + ProcessCookie, + &Cookie, + sizeof(Cookie), + NULL); + + if(!NT_SUCCESS(Status)) + { + DPRINT1("Failed to receive the process cookie! Status: 0x%x\n", Status); + return Pointer; + } + + return (PVOID)((ULONG_PTR)Pointer ^ Cookie); +} + diff --git a/reactos/ntoskrnl/include/internal/ps.h b/reactos/ntoskrnl/include/internal/ps.h index 1be0eeefe19..a38f72ddbaf 100644 --- a/reactos/ntoskrnl/include/internal/ps.h +++ b/reactos/ntoskrnl/include/internal/ps.h @@ -416,6 +416,7 @@ struct _EPROCESS PRTL_BITMAP VadPhysicalPagesBitMap; ULONG VadPhysicalPages; KSPIN_LOCK AweLock; + ULONG Cookie; /* * FIXME - ReactOS specified - remove the following fields ASAP!!! diff --git a/reactos/ntoskrnl/ps/process.c b/reactos/ntoskrnl/ps/process.c index ac2f018c615..2c485c9d285 100644 --- a/reactos/ntoskrnl/ps/process.c +++ b/reactos/ntoskrnl/ps/process.c @@ -67,6 +67,18 @@ static const INFORMATION_CLASS_INFO PsProcessInfoClass[] = ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessForegroundInformation */ ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWow64Information */ ICI_SQ_SAME( sizeof(UNICODE_STRING), sizeof(ULONG), ICIF_QUERY | ICIF_SIZE_VARIABLE), /* ProcessImageFileName */ + + /* FIXME */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessLUIDDeviceMapsEnabled */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessBreakOnTermination */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessDebugObjectHandle */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessDebugFlags */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessHandleTracing */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessUnknown33 */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessUnknown34 */ + ICI_SQ_SAME( 0, 0, 0 ), /* ProcessUnknown35 */ + + ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY), /* ProcessCookie */ }; #define MAX_PROCESS_NOTIFY_ROUTINE_COUNT 8 @@ -1338,23 +1350,28 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle, DPRINT1("NtQueryInformationProcess() failed, Status: 0x%x\n", Status); return Status; } - - /* - * TODO: Here we should probably check that ProcessInformationLength - * bytes indeed are writable at address ProcessInformation. - */ - - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_QUERY_INFORMATION, - PsProcessType, - PreviousMode, - (PVOID*)&Process, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - + + if(ProcessInformationClass != ProcessCookie) + { + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_QUERY_INFORMATION, + PsProcessType, + PreviousMode, + (PVOID*)&Process, + NULL); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + } + else if(ProcessHandle != NtCurrentProcess()) + { + /* retreiving the process cookie is only allowed for the calling process + itself! XP only allowes NtCurrentProcess() as process handles even if a + real handle actually represents the current process. */ + return STATUS_INVALID_PARAMETER; + } + switch (ProcessInformationClass) { case ProcessBasicInformation: @@ -1731,6 +1748,60 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle, } break; } + + case ProcessCookie: + { + ULONG Cookie; + + /* receive the process cookie, this is only allowed for the current + process! */ + + Process = PsGetCurrentProcess(); + + Cookie = Process->Cookie; + if(Cookie == 0) + { + LARGE_INTEGER SystemTime; + ULONG NewCookie; + PKPRCB Prcb; + + /* generate a new cookie */ + + KeQuerySystemTime(&SystemTime); + + Prcb = &KeGetCurrentKPCR()->PrcbData; + + NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^ + SystemTime.u.LowPart ^ SystemTime.u.HighPart; + + /* try to set the new cookie, return the current one if another thread + set it in the meanwhile */ + Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie, + NewCookie, + Cookie); + if(Cookie == 0) + { + /* successfully set the cookie */ + Cookie = NewCookie; + } + } + + _SEH_TRY + { + *(PULONG)ProcessInformation = Cookie; + if (ReturnLength) + { + *ReturnLength = sizeof(ULONG); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + break; + } /* * Note: The following 10 information classes are verified to not be @@ -1750,7 +1821,11 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle, Status = STATUS_INVALID_INFO_CLASS; } - ObDereferenceObject(Process); + if(ProcessInformationClass != ProcessCookie) + { + ObDereferenceObject(Process); + } + return Status; }