Index: dll/ntdll/ldr/ldrinit.c =================================================================== --- dll/ntdll/ldr/ldrinit.c (revision 69258) +++ dll/ntdll/ldr/ldrinit.c (working copy) @@ -77,7 +77,7 @@ //extern LIST_ENTRY RtlCriticalSectionList; -VOID RtlpInitializeVectoredExceptionHandling(VOID); +VOID NTAPI RtlpInitializeVectoredExceptionHandling(VOID); VOID NTAPI RtlpInitDeferedCriticalSection(VOID); VOID NTAPI RtlInitializeHeapManager(VOID); extern BOOLEAN RtlpPageHeapEnabled; Index: lib/rtl/i386/except.c =================================================================== --- lib/rtl/i386/except.c (revision 69258) +++ lib/rtl/i386/except.c (working copy) @@ -74,10 +74,13 @@ ULONG_PTR StackLow, StackHigh; ULONG_PTR RegistrationFrameEnd; - /* Perform vectored exception handling (a dummy in kernel mode) */ + /* Perform vectored exception handling for user mode */ if (RtlCallVectoredExceptionHandlers(ExceptionRecord, Context)) { - /* Exception handled, continue execution */ + /* Exception handled, now call vectored continue handlers */ + RtlCallVectoredContinueHandlers(ExceptionRecord, Context); + + /* Continue execution */ return TRUE; } @@ -139,7 +142,7 @@ /* Handle the dispositions */ switch (Disposition) { - /* Continue searching */ + /* Continue execution */ case ExceptionContinueExecution: /* Check if it was non-continuable */ @@ -157,7 +160,11 @@ } else { - /* Return to caller */ + /* In user mode, call any registered vectored continue handlers */ + RtlCallVectoredContinueHandlers(ExceptionRecord, + Context); + + /* Execution continues */ return TRUE; } Index: lib/rtl/rtlp.h =================================================================== --- lib/rtl/rtlp.h (revision 69258) +++ lib/rtl/rtlp.h (working copy) @@ -67,6 +67,13 @@ IN PCONTEXT Context ); +VOID +NTAPI +RtlCallVectoredContinueHandlers( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context +); + typedef struct _DISPATCHER_CONTEXT { PEXCEPTION_REGISTRATION_RECORD RegistrationPointer; Index: lib/rtl/vectoreh.c =================================================================== --- lib/rtl/vectoreh.c (revision 69258) +++ lib/rtl/vectoreh.c (working copy) @@ -13,201 +13,323 @@ #define NDEBUG #include -static RTL_CRITICAL_SECTION RtlpVectoredExceptionLock; -static LIST_ENTRY RtlpVectoredExceptionHead; -static volatile LONG RtlpVectoredExceptionsInstalled; +RTL_CRITICAL_SECTION RtlpVectoredHandlerLock; +LIST_ENTRY RtlpVectoredExceptionList, RtlpVectoredContinueList; -typedef struct _RTL_VECTORED_EXCEPTION_HANDLER +typedef struct _RTL_VECTORED_HANDLER_ENTRY { - LIST_ENTRY ListEntry; - PVECTORED_EXCEPTION_HANDLER VectoredHandler; - ULONG Refs; - BOOLEAN Deleted; -} RTL_VECTORED_EXCEPTION_HANDLER, *PRTL_VECTORED_EXCEPTION_HANDLER; + LIST_ENTRY ListEntry; + PVECTORED_EXCEPTION_HANDLER VectoredHandler; + ULONG Refs; +} RTL_VECTORED_HANDLER_ENTRY, *PRTL_VECTORED_HANDLER_ENTRY; /* FUNCTIONS ***************************************************************/ +VOID +NTAPI +RtlpInitializeVectoredExceptionHandling(VOID) +{ + /* Initialize our two lists and the common lock */ + InitializeListHead(&RtlpVectoredExceptionList); + InitializeListHead(&RtlpVectoredContinueList); + RtlInitializeCriticalSection(&RtlpVectoredHandlerLock); +} + BOOLEAN NTAPI -RtlCallVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord, - IN PCONTEXT Context) +RtlpCallVectoredHandlers(IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context, + IN PLIST_ENTRY VectoredHandlerList) { - PLIST_ENTRY CurrentEntry; - PRTL_VECTORED_EXCEPTION_HANDLER veh = NULL; - PVECTORED_EXCEPTION_HANDLER VectoredHandler; - EXCEPTION_POINTERS ExceptionInfo; - BOOLEAN Remove = FALSE; - BOOLEAN Ret = FALSE; + PLIST_ENTRY CurrentEntry; + PRTL_VECTORED_HANDLER_ENTRY VectoredExceptionHandler; + PVECTORED_EXCEPTION_HANDLER VectoredHandler; + EXCEPTION_POINTERS ExceptionInfo; + BOOLEAN HandlerRemoved; + LONG HandlerReturn; - ExceptionInfo.ExceptionRecord = ExceptionRecord; - ExceptionInfo.ContextRecord = Context; + /* + * Initialize these in case there are no entries, + * or if no one handled the exception + */ + HandlerRemoved = FALSE; + HandlerReturn = EXCEPTION_CONTINUE_SEARCH; - if(RtlpVectoredExceptionsInstalled) - { - RtlEnterCriticalSection(&RtlpVectoredExceptionLock); - CurrentEntry = RtlpVectoredExceptionHead.Flink; - while (CurrentEntry != &RtlpVectoredExceptionHead) + /* Set up the data to pass to the handler */ + ExceptionInfo.ExceptionRecord = ExceptionRecord; + ExceptionInfo.ContextRecord = Context; + + /* Grab the lock */ + RtlEnterCriticalSection(&RtlpVectoredHandlerLock); + + /* Loop entries */ + CurrentEntry = VectoredHandlerList->Flink; + while (CurrentEntry != VectoredHandlerList) { - veh = CONTAINING_RECORD(CurrentEntry, - RTL_VECTORED_EXCEPTION_HANDLER, - ListEntry); - veh->Refs++; - RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); - - VectoredHandler = RtlDecodePointer(veh->VectoredHandler); - if(VectoredHandler(&ExceptionInfo) == EXCEPTION_CONTINUE_EXECUTION) - { - RtlEnterCriticalSection(&RtlpVectoredExceptionLock); - if (--veh->Refs == 0) + /* Get the struct */ + VectoredExceptionHandler = CONTAINING_RECORD(CurrentEntry, + RTL_VECTORED_HANDLER_ENTRY, + ListEntry); + + /* Reference it so it doesn't go away while we are using it */ + VectoredExceptionHandler->Refs++; + + /* Drop the lock before calling the handler */ + RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); + + /* + * Get the function pointer, decoding it so we will crash + * if malicious code has altered it -- that is, if VectoredHandler + * is set to a non-encoded pointer + */ + VectoredHandler = RtlDecodePointer(VectoredExceptionHandler->VectoredHandler); + + /* Call the handler */ + HandlerReturn = VectoredHandler(&ExceptionInfo); + + /* Handler called -- grab the lock to dereference */ + RtlEnterCriticalSection(&RtlpVectoredHandlerLock); + + /* Dereference and see if it got deleted */ + VectoredExceptionHandler->Refs--; + if (VectoredExceptionHandler->Refs == 0) { - RemoveEntryList (&veh->ListEntry); - InterlockedDecrement (&RtlpVectoredExceptionsInstalled); - Remove = TRUE; + /* It did -- do we have to free it now? */ + if (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) + { + /* We don't, just remove it from the list and break out */ + RemoveEntryList(&VectoredExceptionHandler->ListEntry); + HandlerRemoved = TRUE; + break; + } + + /* + * Get the next entry before freeing, + * and remove the current one from the list + */ + CurrentEntry = VectoredExceptionHandler->ListEntry.Flink; + RemoveEntryList(&VectoredExceptionHandler->ListEntry); + + /* Free the entry outside of the lock, then reacquire it */ + RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); + RtlFreeHeap(RtlGetProcessHeap(), + 0, + VectoredExceptionHandler); + RtlEnterCriticalSection(&RtlpVectoredHandlerLock); } - Ret = TRUE; - break; - } + else + { + /* No delete -- should we continue execution? */ + if (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) + { + /* Break out */ + break; + } + else + { + /* Continue searching the list */ + CurrentEntry = CurrentEntry->Flink; + } + } + } - RtlEnterCriticalSection(&RtlpVectoredExceptionLock); - - if (--veh->Refs == 0) - { - CurrentEntry = veh->ListEntry.Flink; - RemoveEntryList (&veh->ListEntry); - InterlockedDecrement (&RtlpVectoredExceptionsInstalled); - RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); - + /* Let go of the lock now */ + RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); + + /* Anything to free? */ + if (HandlerRemoved) + { + /* Get rid of it */ RtlFreeHeap(RtlGetProcessHeap(), 0, - veh); - RtlEnterCriticalSection(&RtlpVectoredExceptionLock); - } - else - CurrentEntry = CurrentEntry->Flink; + VectoredExceptionHandler); } - - RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); - } - - if (Remove) - { - RtlFreeHeap(RtlGetProcessHeap(), - 0, - veh); - } - return Ret; + /* Return whether to continue execution (ignored for continue handlers) */ + return (HandlerReturn == EXCEPTION_CONTINUE_EXECUTION) ? TRUE : FALSE; } -VOID -RtlpInitializeVectoredExceptionHandling(VOID) +PVOID +NTAPI +RtlpAddVectoredHandler(IN ULONG FirstHandler, + IN PVECTORED_EXCEPTION_HANDLER VectoredHandler, + IN PLIST_ENTRY VectoredHandlerList) { - InitializeListHead(&RtlpVectoredExceptionHead); - RtlInitializeCriticalSection(&RtlpVectoredExceptionLock); - RtlpVectoredExceptionsInstalled = 0; -} + PRTL_VECTORED_HANDLER_ENTRY VectoredHandlerEntry; + /* Allocate our structure */ + VectoredHandlerEntry = RtlAllocateHeap(RtlGetProcessHeap(), + 0, + sizeof(RTL_VECTORED_HANDLER_ENTRY)); + if (!VectoredHandlerEntry) return NULL; -/* - * @implemented - */ -PVOID NTAPI DECLSPEC_HOTPATCH -RtlAddVectoredExceptionHandler(IN ULONG FirstHandler, - IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) -{ - PRTL_VECTORED_EXCEPTION_HANDLER veh; + /* Set it up, encoding the pointer (counteracts malicious tinkering) */ + VectoredHandlerEntry->VectoredHandler = RtlEncodePointer(VectoredHandler); + VectoredHandlerEntry->Refs = 1; - veh = RtlAllocateHeap(RtlGetProcessHeap(), - 0, - sizeof(RTL_VECTORED_EXCEPTION_HANDLER)); - if(veh != NULL) - { - veh->VectoredHandler = RtlEncodePointer(VectoredHandler); - veh->Refs = 1; - veh->Deleted = FALSE; - RtlEnterCriticalSection(&RtlpVectoredExceptionLock); - if(FirstHandler != 0) + /* Lock the list before modifying it */ + RtlEnterCriticalSection(&RtlpVectoredHandlerLock); + + /* + * While holding the list lock, insert the handler + * at beginning or end of list according to caller. + */ + if (FirstHandler) { - InsertHeadList(&RtlpVectoredExceptionHead, - &veh->ListEntry); + InsertHeadList(VectoredHandlerList, + &VectoredHandlerEntry->ListEntry); } else { - InsertTailList(&RtlpVectoredExceptionHead, - &veh->ListEntry); + InsertTailList(VectoredHandlerList, + &VectoredHandlerEntry->ListEntry); } - InterlockedIncrement (&RtlpVectoredExceptionsInstalled); - RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); - } - return veh; + /* Done with the list, unlock it */ + RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); + + /* Return pointer to the structure as the handle */ + return VectoredHandlerEntry; } - -/* - * @implemented - */ -ULONG NTAPI -RtlRemoveVectoredExceptionHandler(IN PVOID VectoredHandlerHandle) +ULONG +NTAPI +RtlpRemoveVectoredHandler(IN PVOID VectoredHandlerHandle, + IN PLIST_ENTRY VectoredHandlerList) { - PLIST_ENTRY CurrentEntry; - PRTL_VECTORED_EXCEPTION_HANDLER veh = NULL; - BOOLEAN Remove = FALSE; - ULONG Ret = FALSE; + PLIST_ENTRY CurrentEntry; + PRTL_VECTORED_HANDLER_ENTRY VectoredExceptionHandler; + BOOLEAN HandlerRemoved; + BOOLEAN HandlerFound; - RtlEnterCriticalSection(&RtlpVectoredExceptionLock); - for(CurrentEntry = RtlpVectoredExceptionHead.Flink; - CurrentEntry != &RtlpVectoredExceptionHead; - CurrentEntry = CurrentEntry->Flink) - { - veh = CONTAINING_RECORD(CurrentEntry, - RTL_VECTORED_EXCEPTION_HANDLER, - ListEntry); - if(veh == VectoredHandlerHandle) + /* Initialize these in case we don't find anything */ + HandlerRemoved = FALSE; + HandlerFound = FALSE; + + /* Acquire list lock */ + RtlEnterCriticalSection(&RtlpVectoredHandlerLock); + + /* Loop the list */ + CurrentEntry = VectoredHandlerList->Flink; + while (CurrentEntry != VectoredHandlerList) { - if (!veh->Deleted) - { - if (--veh->Refs == 0) + /* Get the struct */ + VectoredExceptionHandler = CONTAINING_RECORD(CurrentEntry, + RTL_VECTORED_HANDLER_ENTRY, + ListEntry); + + /* Does it match? */ + if (VectoredExceptionHandler == VectoredHandlerHandle) { - RemoveEntryList (&veh->ListEntry); - Remove = TRUE; + /* + * Great, this means it is a valid entry. + * However, it may be in use by the exception + * dispatcher, so we have a ref count to respect. + * If we can't clear it now then it will be done + * after it is not in use anymore. + */ + VectoredExceptionHandler->Refs--; + if (VectoredExceptionHandler->Refs == 0) + { + /* Not in use, ok to remove and free */ + RemoveEntryList(&VectoredExceptionHandler->ListEntry); + HandlerRemoved = TRUE; + } + + /* Found what we are looking for, stop searching */ + HandlerFound = TRUE; + break; } - veh->Deleted = TRUE; - Ret = TRUE; - break; - } + else + { + /* Get the next entry */ + CurrentEntry = CurrentEntry->Flink; + } } - } - RtlLeaveCriticalSection(&RtlpVectoredExceptionLock); - if(Remove) - { - RtlFreeHeap(RtlGetProcessHeap(), - 0, - veh); - } + /* Done with the list, let go of the lock */ + RtlLeaveCriticalSection(&RtlpVectoredHandlerLock); - return Ret; + /* Can we free what we found? */ + if (HandlerRemoved) + { + /* Do it */ + RtlFreeHeap(RtlGetProcessHeap(), + 0, + VectoredExceptionHandler); + } + + /* Return whether we found it */ + return (ULONG)HandlerFound; } +BOOLEAN +NTAPI +RtlCallVectoredExceptionHandlers(IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context) +{ + /* Call the shared routine */ + return RtlpCallVectoredHandlers(ExceptionRecord, + Context, + &RtlpVectoredExceptionList); +} + +VOID +NTAPI +RtlCallVectoredContinueHandlers(IN PEXCEPTION_RECORD ExceptionRecord, + IN PCONTEXT Context) +{ + /* + * Call the shared routine (ignoring result, + * execution always continues at this point) + */ + (VOID)RtlpCallVectoredHandlers(ExceptionRecord, + Context, + &RtlpVectoredContinueList); +} + +DECLSPEC_HOTPATCH PVOID NTAPI +RtlAddVectoredExceptionHandler(IN ULONG FirstHandler, + IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) +{ + /* Call the shared routine */ + return RtlpAddVectoredHandler(FirstHandler, + VectoredHandler, + &RtlpVectoredExceptionList); +} + DECLSPEC_HOTPATCH -RtlAddVectoredContinueHandler( - IN ULONG FirstHandler, - IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) +PVOID +NTAPI +RtlAddVectoredContinueHandler(IN ULONG FirstHandler, + IN PVECTORED_EXCEPTION_HANDLER VectoredHandler) { - UNIMPLEMENTED; - return NULL; + /* Call the shared routine */ + return RtlpAddVectoredHandler(FirstHandler, + VectoredHandler, + &RtlpVectoredContinueList); } +//DECLSPEC_HOTPATCH ULONG NTAPI -RtlRemoveVectoredContinueHandler( - IN PVOID VectoredHandlerHandle) +RtlRemoveVectoredExceptionHandler(IN PVOID VectoredHandlerHandle) { - UNIMPLEMENTED; - return FALSE; + /* Call the shared routine */ + return RtlpRemoveVectoredHandler(VectoredHandlerHandle, + &RtlpVectoredExceptionList); } +//DECLSPEC_HOTPATCH +ULONG +NTAPI +RtlRemoveVectoredContinueHandler(IN PVOID VectoredHandlerHandle) +{ + /* Call the shared routine */ + return RtlpRemoveVectoredHandler(VectoredHandlerHandle, + &RtlpVectoredContinueList); +} + /* EOF */ Index: ntoskrnl/rtl/libsupp.c =================================================================== --- ntoskrnl/rtl/libsupp.c (revision 69258) +++ ntoskrnl/rtl/libsupp.c (working copy) @@ -764,12 +764,20 @@ BOOLEAN NTAPI -RtlCallVectoredExceptionHandlers( - _In_ PEXCEPTION_RECORD ExceptionRecord, - _In_ PCONTEXT Context) +RtlCallVectoredExceptionHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PCONTEXT Context) { /* In the kernel we don't have vectored exception handlers */ return FALSE; } +VOID +NTAPI +RtlCallVectoredContinueHandlers(_In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PCONTEXT Context) +{ + /* No vectored continue handlers in kernel mode either */ + return; +} + /* EOF */