- Fix nasty APC delivery bug (in case a Kernel-Mode Special APC still returned with a Normal Routine, the Normal Routine was called with incorrect values (Special Routines take PVOID* arguments, while Normal Routines do not!))

- Remove APC from list before setting it to non-inserted.
 - Do proper thread termination piggybacking; terminate threads in user-mode as Hartmut correctly fixed.

svn path=/trunk/; revision=16635
This commit is contained in:
Alex Ionescu 2005-07-18 19:50:23 +00:00
parent 269fab698e
commit ce7fb8c1b9
2 changed files with 81 additions and 44 deletions

View file

@ -567,9 +567,9 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
/* Save Parameters so that it's safe to free the Object in Kernel Routine*/ /* Save Parameters so that it's safe to free the Object in Kernel Routine*/
NormalRoutine = Apc->NormalRoutine; NormalRoutine = Apc->NormalRoutine;
KernelRoutine = Apc->KernelRoutine; KernelRoutine = Apc->KernelRoutine;
NormalContext = Apc->NormalContext; NormalContext = Apc->NormalContext;
SystemArgument1 = Apc->SystemArgument1; SystemArgument1 = Apc->SystemArgument1;
SystemArgument2 = Apc->SystemArgument2; SystemArgument2 = Apc->SystemArgument2;
@ -577,8 +577,8 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
if (NormalRoutine == NULL) { if (NormalRoutine == NULL) {
/* Remove the APC from the list */ /* Remove the APC from the list */
Apc->Inserted = FALSE;
RemoveEntryList(ApcListEntry); RemoveEntryList(ApcListEntry);
Apc->Inserted = FALSE;
/* Go back to APC_LEVEL */ /* Go back to APC_LEVEL */
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
@ -586,10 +586,10 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
/* Call the Special APC */ /* Call the Special APC */
DPRINT("Delivering a Special APC: %x\n", Apc); DPRINT("Delivering a Special APC: %x\n", Apc);
KernelRoutine(Apc, KernelRoutine(Apc,
&NormalRoutine, &NormalRoutine,
&NormalContext, &NormalContext,
&SystemArgument1, &SystemArgument1,
&SystemArgument2); &SystemArgument2);
/* Raise IRQL and Lock again */ /* Raise IRQL and Lock again */
KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql); KeAcquireSpinLock(&Thread->ApcQueueLock, &OldIrql);
@ -612,8 +612,8 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
} }
/* Dequeue the APC */ /* Dequeue the APC */
RemoveEntryList(ApcListEntry);
Apc->Inserted = FALSE; Apc->Inserted = FALSE;
RemoveEntryList(ApcListEntry);
/* Go back to APC_LEVEL */ /* Go back to APC_LEVEL */
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
@ -621,10 +621,10 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
/* Call the Kernel APC */ /* Call the Kernel APC */
DPRINT("Delivering a Normal APC: %x\n", Apc); DPRINT("Delivering a Normal APC: %x\n", Apc);
KernelRoutine(Apc, KernelRoutine(Apc,
&NormalRoutine, &NormalRoutine,
&NormalContext, &NormalContext,
&SystemArgument1, &SystemArgument1,
&SystemArgument2); &SystemArgument2);
/* If There still is a Normal Routine, then we need to call this at PASSIVE_LEVEL */ /* If There still is a Normal Routine, then we need to call this at PASSIVE_LEVEL */
if (NormalRoutine != NULL) { if (NormalRoutine != NULL) {
@ -635,7 +635,7 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
/* Call and Raise IRQ back to APC_LEVEL */ /* Call and Raise IRQ back to APC_LEVEL */
DPRINT("Calling the Normal Routine for a Normal APC: %x\n", Apc); DPRINT("Calling the Normal Routine for a Normal APC: %x\n", Apc);
NormalRoutine(&NormalContext, &SystemArgument1, &SystemArgument2); NormalRoutine(NormalContext, SystemArgument1, SystemArgument2);
KeRaiseIrql(APC_LEVEL, &OldIrql); KeRaiseIrql(APC_LEVEL, &OldIrql);
} }
@ -657,23 +657,23 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); Apc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry);
/* Save Parameters so that it's safe to free the Object in Kernel Routine*/ /* Save Parameters so that it's safe to free the Object in Kernel Routine*/
NormalRoutine = Apc->NormalRoutine; NormalRoutine = Apc->NormalRoutine;
KernelRoutine = Apc->KernelRoutine; KernelRoutine = Apc->KernelRoutine;
NormalContext = Apc->NormalContext; NormalContext = Apc->NormalContext;
SystemArgument1 = Apc->SystemArgument1; SystemArgument1 = Apc->SystemArgument1;
SystemArgument2 = Apc->SystemArgument2; SystemArgument2 = Apc->SystemArgument2;
/* Remove the APC from Queue, restore IRQL and call the APC */ /* Remove the APC from Queue, restore IRQL and call the APC */
RemoveEntryList(ApcListEntry); RemoveEntryList(ApcListEntry);
Apc->Inserted = FALSE; Apc->Inserted = FALSE;
KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql); KeReleaseSpinLock(&Thread->ApcQueueLock, OldIrql);
DPRINT("Calling the Kernel Routine for for a User APC: %x\n", Apc); DPRINT("Calling the Kernel Routine for for a User APC: %x\n", Apc);
KernelRoutine(Apc, KernelRoutine(Apc,
&NormalRoutine, &NormalRoutine,
&NormalContext, &NormalContext,
&SystemArgument1, &SystemArgument1,
&SystemArgument2); &SystemArgument2);
if (NormalRoutine == NULL) { if (NormalRoutine == NULL) {
@ -685,11 +685,11 @@ KiDeliverApc(KPROCESSOR_MODE DeliveryMode,
/* Set up the Trap Frame and prepare for Execution in NTDLL.DLL */ /* Set up the Trap Frame and prepare for Execution in NTDLL.DLL */
DPRINT("Delivering a User APC: %x\n", Apc); DPRINT("Delivering a User APC: %x\n", Apc);
KiInitializeUserApc(Reserved, KiInitializeUserApc(Reserved,
TrapFrame, TrapFrame,
NormalRoutine, NormalRoutine,
NormalContext, NormalContext,
SystemArgument1, SystemArgument1,
SystemArgument2); SystemArgument2);
} }
} else { } else {

View file

@ -346,18 +346,23 @@ PsExitSpecialApc(PKAPC Apc,
PVOID* SystemArgument1, PVOID* SystemArgument1,
PVOID* SystemArguemnt2) PVOID* SystemArguemnt2)
{ {
NTSTATUS ExitStatus = (NTSTATUS)Apc->NormalContext; DPRINT1("PsExitSpecialApc called: 0x%x (proc: 0x%x)\n",
PsGetCurrentThread(), PsGetCurrentProcess());
DPRINT("PsExitSpecialApc called: 0x%x (proc: 0x%x)\n", PsGetCurrentThread(), PsGetCurrentProcess()); /* Don't do anything unless we are in User-Mode */
if (Apc->SystemArgument2)
{
NTSTATUS ExitStatus = (NTSTATUS)Apc->NormalContext;
/* Free the APC */ /* Free the APC */
ExFreePool(Apc); ExFreePool(Apc);
/* Terminate the Thread */ /* Terminate the Thread */
PspExitThread(ExitStatus); PspExitThread(ExitStatus);
/* we should never reach this point! */ /* we should never reach this point! */
KEBUGCHECK(0); KEBUGCHECK(0);
}
} }
VOID VOID
@ -366,14 +371,46 @@ PspExitNormalApc(PVOID NormalContext,
PVOID SystemArgument1, PVOID SystemArgument1,
PVOID SystemArgument2) PVOID SystemArgument2)
{ {
/* Not fully supported yet... must work out some issues that PKAPC Apc = (PKAPC)SystemArgument1;
* I don't understand yet -- Alex PETHREAD Thread = PsGetCurrentThread();
*/ NTSTATUS ExitStatus;
DPRINT1("APC2\n");
PspExitThread((NTSTATUS)NormalContext); DPRINT1("PspExitNormalApc called: 0x%x (proc: 0x%x)\n",
PsGetCurrentThread(), PsGetCurrentProcess());
/* we should never reach this point! */ /* This should never happen */
KEBUGCHECK(0); ASSERT(!SystemArgument2);
/* If this is a system thread, we can safely kill it from Kernel-Mode */
if (PsIsSystemThread(Thread))
{
/* Get the Exit Status */
DPRINT1("Killing System Thread\n");
ExitStatus = (NTSTATUS)Apc->NormalContext;
/* Free the APC */
ExFreePool(Apc);
/* Exit the Thread */
PspExitThread(ExitStatus);
}
/* If we're here, this is not a System Thread, so kill it from User-Mode */
DPRINT1("Initializing User-Mode APC\n");
KeInitializeApc(Apc,
&Thread->Tcb,
OriginalApcEnvironment,
PsExitSpecialApc,
NULL,
PspExitNormalApc,
UserMode,
NormalContext);
/* Now insert the APC with the User-Mode Flag */
KeInsertQueueApc(Apc, Apc, (PVOID)UserMode, 2);
/* Forcefully resume the thread */
KeForceResumeThread(&Thread->Tcb);
} }
/* /*
@ -402,14 +439,14 @@ PspTerminateThreadByPointer(PETHREAD Thread,
/* Allocate the APC */ /* Allocate the APC */
Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC); Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
/* Initialize a User Mode APC to Kill the Thread */ /* Initialize a Kernel Mode APC to Kill the Thread */
KeInitializeApc(Apc, KeInitializeApc(Apc,
&Thread->Tcb, &Thread->Tcb,
OriginalApcEnvironment, OriginalApcEnvironment,
PsExitSpecialApc, PsExitSpecialApc,
NULL, NULL,
PspExitNormalApc, PspExitNormalApc,
UserMode, KernelMode,
(PVOID)ExitStatus); (PVOID)ExitStatus);
/* Insert it into the APC Queue */ /* Insert it into the APC Queue */