[25 bug fixes]:

- Implement KeReadStateThread.
- Fix PspTerminateProcess to handle case where there's no threads in the process.
- Fix check in PspTerminateProcess. ObClearProcessHandleTable gets called if there's a debug port, not if there's an object table.
- Simplfy PspReapRoutine.
- Fix PspExitThread to wait for all other threads before continuing to kill the last thread. Should fix lots of race/wait conditions.
- PspExitThread should check for !DeadThread and not !Terminated before determining if it should free the TEB. Also, the DbgK handle should only be closed if the thread isn't already dead.
- Fixup formatting of some code to warn less on MSVC.
- Fail various APIs if acquiring rundown protection failed.
- Fix Process Quantum/Priority settings.
- Grant PROCESS_TERMINATE by default.
- Add PROCESS_SET_INFORMATION, STANDARD_RIGHTS_ALL and PROCESS_SET_QUOTA to the default process granted access mask.
- Initialize process/thread/image notification callbacks durin phase 0 Ps initialization.
- The Audit Name belongs to the system process, not the idle process.
- Detect more failures in phase 0 startup.
- Fix various race conditions/incorrect checks in ps/security.c related to impersonation information. Also allow PspAssignPrimaryToken to be called directly with the token pointer and not only the handle.
- Wrap system thread startup stub in SEH and write a SEH filter function to print out debug information when a system thread dies unexpectedly.

svn path=/trunk/; revision=25504
This commit is contained in:
Alex Ionescu 2007-01-18 09:44:49 +00:00
parent ccee43a360
commit 9522e0a02b
11 changed files with 355 additions and 211 deletions

View file

@ -215,6 +215,10 @@ NTSTATUS
NTAPI
KeSuspendThread(PKTHREAD Thread);
BOOLEAN
NTAPI
KeReadStateThread(IN PKTHREAD Thread);
BOOLEAN
FASTCALL
KiSwapContext(

View file

@ -93,7 +93,8 @@ VOID
NTAPI
LpcpSaveDataInfoMessage(
IN PLPCP_PORT_OBJECT Port,
IN PLPCP_MESSAGE Message
IN PLPCP_MESSAGE Message,
IN ULONG LockHeld
);
//

View file

@ -175,7 +175,7 @@ NTAPI
PspSetPrimaryToken(
IN PEPROCESS Process,
IN HANDLE TokenHandle OPTIONAL,
IN PTOKEN Token OPTIONAL
IN PACCESS_TOKEN Token OPTIONAL
);
NTSTATUS

View file

@ -46,6 +46,17 @@ KeFindNextRightSetAffinity(IN UCHAR Number,
return (UCHAR)Result;
}
BOOLEAN
NTAPI
KeReadStateThread(IN PKTHREAD Thread)
{
ASSERT_THREAD(Thread);
/* Return signal state */
return (BOOLEAN)Thread->DispatcherHeader.SignalState;
}
KPRIORITY
NTAPI
KeQueryBasePriorityThread(IN PKTHREAD Thread)

View file

@ -57,7 +57,8 @@ LpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
VOID
NTAPI
LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
IN PLPCP_MESSAGE Message)
IN PLPCP_MESSAGE Message,
IN ULONG LockFlags)
{
PAGED_CODE();
@ -402,7 +403,7 @@ NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
if (Message->Request.u2.s2.DataInfoOffset)
{
/* It does, save it, and don't free the message below */
LpcpSaveDataInfoMessage(Port, Message);
LpcpSaveDataInfoMessage(Port, Message, 1);
Message = NULL;
}
}

View file

@ -391,7 +391,7 @@ NtRequestWaitReplyPort(IN HANDLE PortHandle,
(Message->Request.u2.s2.DataInfoOffset))
{
/* Save the data information */
LpcpSaveDataInfoMessage(Port, Message);
LpcpSaveDataInfoMessage(Port, Message, 0);
}
else
{

View file

@ -18,6 +18,7 @@
LIST_ENTRY PspReaperListHead = {0};
WORK_QUEUE_ITEM PspReaperWorkItem;
LARGE_INTEGER ShortTime = {{-10 * 100 * 1000, -1}};
/* PRIVATE FUNCTIONS *********************************************************/
@ -81,7 +82,8 @@ NTAPI
PspTerminateProcess(IN PEPROCESS Process,
IN NTSTATUS ExitStatus)
{
PETHREAD Thread = NULL;
PETHREAD Thread;
NTSTATUS Status = STATUS_NOTHING_TO_TERMINATE;
PAGED_CODE();
PSTRACE(PS_KILL_DEBUG,
"Process: %p ExitStatus: %p\n", Process, ExitStatus);
@ -100,22 +102,26 @@ PspTerminateProcess(IN PEPROCESS Process,
InterlockedOr((PLONG)&Process->Flags, PSF_PROCESS_DELETE_BIT);
/* Get the first thread */
Thread = PsGetNextProcessThread(Process, Thread);
Thread = PsGetNextProcessThread(Process, NULL);
while (Thread)
{
/* Kill it */
PSREFTRACE(Thread);
PspTerminateThreadByPointer(Thread, ExitStatus, FALSE);
PSREFTRACE(Thread);
Thread = PsGetNextProcessThread(Process, Thread);
/* We had at least one thread, so termination is OK */
Status = STATUS_SUCCESS;
}
/* Clear the handle table */
if (Process->ObjectTable) ObClearProcessHandleTable(Process);
/* Check if there was nothing to terminate or if we have a debug port */
if ((Status == STATUS_NOTHING_TO_TERMINATE) || (Process->DebugPort))
{
/* Clear the handle table anyway */
ObClearProcessHandleTable(Process);
}
/* Return success*/
PSREFTRACE(Process);
return STATUS_SUCCESS;
/* Return status */
return Status;
}
NTSTATUS
@ -163,19 +169,16 @@ VOID
NTAPI
PspReapRoutine(IN PVOID Context)
{
PLIST_ENTRY *ListAddr;
PLIST_ENTRY NextEntry;
PSINGLE_LIST_ENTRY NextEntry;
PETHREAD Thread;
PSTRACE(PS_KILL_DEBUG, "Context: %p\n", Context);
/* Get the Reaper Address Pointer */
ListAddr = &PspReaperListHead.Flink;
/* Start main loop */
do
{
/* Write magic value and return the next entry to process */
NextEntry = InterlockedExchangePointer(ListAddr, (PVOID)1);
NextEntry = InterlockedExchangePointer(&PspReaperListHead.Flink,
(PVOID)1);
ASSERT((NextEntry != NULL) && (NextEntry != (PVOID)1));
/* Start inner loop */
@ -190,15 +193,16 @@ PspReapRoutine(IN PVOID Context)
Thread->Tcb.InitialStack = NULL;
/* Move to the next entry */
NextEntry = NextEntry->Flink;
NextEntry = NextEntry->Next;
/* Dereference this thread */
ObDereferenceObject(Thread);
PSREFTRACE(Thread);
} while ((NextEntry != NULL) && (NextEntry != (PVOID)1));
/* Remove magic value, keep looping if it got changed */
} while (InterlockedCompareExchangePointer(ListAddr, 0, 1) != (PVOID)1);
} while (InterlockedCompareExchangePointer(&PspReaperListHead.Flink,
0,
1) != (PVOID)1);
}
VOID
@ -245,7 +249,7 @@ PspDeleteProcess(IN PVOID ObjectBody)
/* Check if we have a debug port */
if (Process->DebugPort)
{
/* Dererence the Debug Port */
/* Deference the Debug Port */
ObDereferenceObject(Process->DebugPort);
Process->DebugPort = NULL;
}
@ -253,7 +257,7 @@ PspDeleteProcess(IN PVOID ObjectBody)
/* Check if we have an exception port */
if (Process->ExceptionPort)
{
/* Dererence the Exception Port */
/* Deference the Exception Port */
ObDereferenceObject(Process->ExceptionPort);
Process->ExceptionPort = NULL;
}
@ -261,7 +265,7 @@ PspDeleteProcess(IN PVOID ObjectBody)
/* Check if we have a section object */
if (Process->SectionObject)
{
/* Dererence the Section Object */
/* Deference the Section Object */
ObDereferenceObject(Process->SectionObject);
Process->SectionObject = NULL;
}
@ -279,7 +283,7 @@ PspDeleteProcess(IN PVOID ObjectBody)
/* Kill the Object Info */
ObKillProcess(Process);
/* Dettach */
/* Detach */
KeUnstackDetachProcess(&ApcState);
}
@ -295,7 +299,7 @@ PspDeleteProcess(IN PVOID ObjectBody)
/* Clean the Address Space */
PspExitProcess(FALSE, Process);
/* Dettach */
/* Detach */
KeUnstackDetachProcess(&ApcState);
/* Completely delete the Address Space */
@ -303,7 +307,7 @@ PspDeleteProcess(IN PVOID ObjectBody)
}
/* See if we have a PID */
if(Process->UniqueProcessId)
if (Process->UniqueProcessId)
{
/* Delete the PID */
if (!(ExDestroyHandle(PspCidTable, Process->UniqueProcessId)))
@ -331,7 +335,6 @@ PspDeleteProcess(IN PVOID ObjectBody)
/* Destroy the Quota Block */
PspDestroyQuotaBlock(Process);
PSREFTRACE(Process);
}
VOID
@ -368,7 +371,6 @@ PspDeleteThread(IN PVOID ObjectBody)
PspDeleteThreadSecurity(Thread);
/* Make sure the thread was inserted, before continuing */
PSREFTRACE(Thread);
if (!Process) return;
/* Check if the thread list is valid */
@ -388,8 +390,6 @@ PspDeleteThread(IN PVOID ObjectBody)
/* Dereference the Process */
ObDereferenceObject(Process);
PSREFTRACE(Thread);
PSREFTRACE(Process);
}
/*
@ -404,7 +404,7 @@ PspExitThread(IN NTSTATUS ExitStatus)
NTSTATUS Status;
PTEB Teb;
PEPROCESS CurrentProcess;
PETHREAD Thread;
PETHREAD Thread, OtherThread, PreviousThread = NULL;
PVOID DeallocationStack;
ULONG Dummy;
BOOLEAN Last = FALSE;
@ -421,8 +421,6 @@ PspExitThread(IN NTSTATUS ExitStatus)
ASSERT((Thread) == PsGetCurrentThread());
/* Can't terminate a thread if it attached another process */
PSREFTRACE(Thread);
PSREFTRACE(CurrentProcess);
if (KeIsAttachedProcess())
{
/* Bugcheck */
@ -434,7 +432,7 @@ PspExitThread(IN NTSTATUS ExitStatus)
}
/* Lower to Passive Level */
KfLowerIrql(PASSIVE_LEVEL);
KeLowerIrql(PASSIVE_LEVEL);
/* Can't be a worker thread */
if (Thread->ActiveExWorker)
@ -453,9 +451,9 @@ PspExitThread(IN NTSTATUS ExitStatus)
/* Bugcheck */
KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT,
0,
Thread->Tcb.KernelApcDisable,
APC_LEVEL,
0);
Thread->Tcb.CombinedApcDisable,
0,
1);
}
/* Lock the thread */
@ -500,7 +498,44 @@ PspExitThread(IN NTSTATUS ExitStatus)
CurrentProcess->ExitStatus = ExitStatus;
}
/* FIXME: Wait on the other threads to finish */
/* Loop all the current threads */
FirstEntry = &CurrentProcess->ThreadListHead;
CurrentEntry = FirstEntry->Flink;
while (FirstEntry != CurrentEntry)
{
/* Get the thread on the list */
OtherThread = CONTAINING_RECORD(CurrentEntry,
ETHREAD,
ThreadListEntry);
/* Check if it's a thread that's still alive */
if ((OtherThread != Thread) &&
!(KeReadStateThread(&OtherThread->Tcb)) &&
(ObReferenceObjectSafe(OtherThread)))
{
/* It's a live thread and we referenced it, unlock process */
ExReleasePushLockExclusive(&CurrentProcess->ProcessLock);
KeLeaveCriticalRegion();
/* Wait on the thread */
KeWaitForSingleObject(OtherThread,
Executive,
KernelMode,
FALSE,
NULL);
/* Check if we had a previous thread to dereference */
if (PreviousThread) ObDereferenceObject(PreviousThread);
/* Remember the thread and re-lock the process */
PreviousThread = OtherThread;
KeEnterCriticalRegion();
ExAcquirePushLockExclusive(&CurrentProcess->ProcessLock);
}
/* Go to the next thread */
CurrentEntry = CurrentEntry->Flink;
}
}
else if (ExitStatus != STATUS_THREAD_IS_TERMINATING)
{
@ -512,6 +547,9 @@ PspExitThread(IN NTSTATUS ExitStatus)
ExReleasePushLockExclusive(&CurrentProcess->ProcessLock);
KeLeaveCriticalRegion();
/* Check if we had a previous thread to dereference */
if (PreviousThread) ObDereferenceObject(PreviousThread);
/* Check if the process has a debug port and if this is a user thread */
if ((CurrentProcess->DebugPort) && !(Thread->SystemThread))
{
@ -570,15 +608,20 @@ PspExitThread(IN NTSTATUS ExitStatus)
/* Save the Create Time */
TerminationMsg.CreateTime = Thread->CreateTime;
TryAgain:
/* Send the LPC Message */
Status = LpcRequestPort(TerminationPort->Port, &TerminationMsg.h);
if ((Status == STATUS_NO_MEMORY) ||
(Status == STATUS_INSUFFICIENT_RESOURCES))
/* Loop trying to send message */
while (TRUE)
{
/* Wait a bit and try again */
KeDelayExecutionThread(KernelMode, FALSE, &ShortPsLockDelay);
goto TryAgain;
/* Send the LPC Message */
Status = LpcRequestPort(TerminationPort->Port,
&TerminationMsg.h);
if ((Status == STATUS_NO_MEMORY) ||
(Status == STATUS_INSUFFICIENT_RESOURCES))
{
/* Wait a bit and try again */
KeDelayExecutionThread(KernelMode, FALSE, &ShortTime);
continue;
}
break;
}
/* Dereference this LPC Port */
@ -591,7 +634,8 @@ TryAgain:
ExFreePool(TerminationPort);
/* Keep looping as long as there is a port */
} while ((TerminationPort = NextPort));
TerminationPort = NextPort;
} while (TerminationPort);
}
else if (((ExitStatus == STATUS_THREAD_IS_TERMINATING) &&
(Thread->DeadThread)) ||
@ -627,16 +671,20 @@ TryAgain:
/* Save the Create Time */
TerminationMsg.CreateTime = Thread->CreateTime;
TryAgain2:
/* Send the LPC Message */
Status = LpcRequestPort(CurrentProcess->ExceptionPort,
&TerminationMsg.h);
if ((Status == STATUS_NO_MEMORY) ||
(Status == STATUS_INSUFFICIENT_RESOURCES))
/* Loop trying to send message */
while (TRUE)
{
/* Wait a bit and try again */
KeDelayExecutionThread(KernelMode, FALSE, &ShortPsLockDelay);
goto TryAgain2;
/* Send the LPC Message */
Status = LpcRequestPort(CurrentProcess->ExceptionPort,
&TerminationMsg.h);
if ((Status == STATUS_NO_MEMORY) ||
(Status == STATUS_INSUFFICIENT_RESOURCES))
{
/* Wait a bit and try again */
KeDelayExecutionThread(KernelMode, FALSE, &ShortTime);
continue;
}
break;
}
}
}
@ -646,7 +694,6 @@ TryAgain2:
PsW32ThreadCalloutExit);
/* If we are the last thread and have a W32 Process */
PSREFTRACE(Thread);
if ((Last) && (CurrentProcess->Win32Process))
{
/* Run it down too */
@ -674,26 +721,30 @@ TryAgain2:
/* Check if we have a TEB */
Teb = Thread->Tcb.Teb;
if(Teb)
if (Teb)
{
/* Check if the thread isn't terminated and if we should free stack */
if (!(Thread->Terminated) && (Teb->FreeStackOnTermination))
/* Check if the thread is still alive */
if (!Thread->DeadThread)
{
/* Set the TEB's Deallocation Stack as the Base Address */
Dummy = 0;
DeallocationStack = Teb->DeallocationStack;
/* Check if we need to free its stack */
if (Teb->FreeStackOnTermination)
{
/* Set the TEB's Deallocation Stack as the Base Address */
Dummy = 0;
DeallocationStack = Teb->DeallocationStack;
/* Free the Thread's Stack */
ZwFreeVirtualMemory(NtCurrentProcess(),
&DeallocationStack,
&Dummy,
MEM_RELEASE);
/* Free the Thread's Stack */
ZwFreeVirtualMemory(NtCurrentProcess(),
&DeallocationStack,
&Dummy,
MEM_RELEASE);
}
/* Free the debug handle */
if (Teb->DbgSsReserved[1]) ObCloseHandle(Teb->DbgSsReserved[1],
UserMode);
}
/* Free the debug handle */
if (Teb->DbgSsReserved[1]) ObCloseHandle(Teb->DbgSsReserved[1],
UserMode);
/* Decommit the TEB */
MmDeleteTeb(CurrentProcess, Teb);
Thread->Tcb.Teb = NULL;
@ -710,8 +761,6 @@ TryAgain2:
ASSERT(Thread->Tcb.CombinedApcDisable == 0);
/* Check if this is the final thread or not */
PSREFTRACE(Thread);
PSREFTRACE(CurrentProcess);
if (Last)
{
/* Set the process exit time */
@ -736,7 +785,6 @@ TryAgain2:
/* Kill the process in the Object Manager */
ObKillProcess(CurrentProcess);
PSREFTRACE(CurrentProcess);
/* Check if we have a section object */
if (CurrentProcess->SectionObject)
@ -768,6 +816,7 @@ TryAgain2:
FirstEntry = KeFlushQueueApc(&Thread->Tcb, UserMode);
if (FirstEntry)
{
/* Start with the first entry */
CurrentEntry = FirstEntry;
do
{
@ -781,7 +830,7 @@ TryAgain2:
if (Apc->RundownRoutine)
{
/* Call its own routine */
(Apc->RundownRoutine)(Apc);
Apc->RundownRoutine(Apc);
}
else
{
@ -800,12 +849,12 @@ TryAgain2:
/* Flush the APC queue, which should be empty */
FirstEntry = KeFlushQueueApc(&Thread->Tcb, KernelMode);
if (FirstEntry)
if ((FirstEntry) || (Thread->Tcb.CombinedApcDisable != 0))
{
/* Bugcheck time */
KEBUGCHECKEX(KERNEL_APC_PENDING_DURING_EXIT,
(ULONG_PTR)FirstEntry,
Thread->Tcb.KernelApcDisable,
Thread->Tcb.CombinedApcDisable,
KeGetCurrentIrql(),
0);
}
@ -814,8 +863,6 @@ TryAgain2:
if (Last) KeSetProcess(&CurrentProcess->Pcb, 0, FALSE);
/* Terminate the Thread from the Scheduler */
PSREFTRACE(Thread);
PSREFTRACE(CurrentProcess);
KeTerminateThread(0);
}
@ -927,10 +974,11 @@ PspTerminateThreadByPointer(IN PETHREAD Thread,
Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC);
/* Set the Terminated Flag */
Flags = Thread->CrossThreadFlags | 1;
Flags = Thread->CrossThreadFlags | CT_TERMINATED_BIT;
/* Set it, and check if it was already set while we were running */
if (!(InterlockedExchange((PLONG)&Thread->CrossThreadFlags, Flags) & 1))
if (!(InterlockedExchange((PLONG)&Thread->CrossThreadFlags, Flags) &
CT_TERMINATED_BIT))
{
/* Initialize a Kernel Mode APC to Kill the Thread */
KeInitializeApc(Apc,
@ -961,7 +1009,6 @@ PspTerminateThreadByPointer(IN PETHREAD Thread,
ExFreePool(Apc);
/* Return Status */
PSREFTRACE(Thread);
return Status;
}
@ -1006,7 +1053,6 @@ PspExitProcess(IN BOOLEAN LastThread,
}
/* Check if we are the last thread */
PSREFTRACE(Process);
if (LastThread)
{
/* Check if we have to set the Timer Resolution */
@ -1088,7 +1134,12 @@ NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,
}
/* Lock the Process */
ExAcquireRundownProtection(&Process->RundownProtect);
if (!ExAcquireRundownProtection(&Process->RundownProtect))
{
/* Failed to lock, fal */
ObDereferenceObject (Process);
return STATUS_PROCESS_IS_TERMINATING;
}
/* Set the delete flag */
if (!KillByHandle) InterlockedOr((PLONG)&Process->Flags,
@ -1113,7 +1164,8 @@ NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,
}
/* Move to the next thread */
} while((Thread = PsGetNextProcessThread(Process, Thread)));
Thread = PsGetNextProcessThread(Process, Thread);
} while (Thread);
}
/* Unlock the process */

View file

@ -397,7 +397,6 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
(PVOID*)&Parent,
NULL);
if (!NT_SUCCESS(Status)) return Status;
PSREFTRACE(Parent);
/* If this process should be in a job but the parent isn't */
if ((InJob) && (!Parent->Job))
@ -434,7 +433,6 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Clean up the Object */
PSREFTRACE(Process);
RtlZeroMemory(Process, sizeof(EPROCESS));
/* Initialize pushlock and rundown protection */
@ -485,14 +483,15 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
if (Parent != PsInitialSystemProcess)
{
/* It's not, so acquire the process rundown */
ExAcquireRundownProtection(&Process->RundownProtect);
if (ExAcquireRundownProtection(&Process->RundownProtect))
{
/* If the parent has a section, use it */
SectionObject = Parent->SectionObject;
if (SectionObject) ObReferenceObject(SectionObject);
/* If the parent has a section, use it */
SectionObject = Parent->SectionObject;
if (SectionObject) ObReferenceObject(SectionObject);
/* Release process rundown */
ExReleaseRundownProtection(&Process->RundownProtect);
/* Release process rundown */
ExReleaseRundownProtection(&Process->RundownProtect);
}
/* If we don't have a section object */
if (!SectionObject)
@ -647,23 +646,25 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
AccessState,
DesiredAccess,
1,
(PVOID*)&Process,
NULL,
&hProcess);
/* Free the access state */
if (AccessState) SeDeleteAccessState(AccessState);
/* Cleanup on failure */
PSREFTRACE(Process);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Compute Quantum and Priority */
Process->Pcb.BasePriority = (SCHAR)PspComputeQuantumAndPriority(Process,
0,
&Quantum);
ASSERT(IsListEmpty(&Process->ThreadListHead) == TRUE);
Process->Pcb.BasePriority =
(SCHAR)PspComputeQuantumAndPriority(Process,
PsProcessPriorityBackground,
&Quantum);
Process->Pcb.QuantumReset = Quantum;
/* Check if we have a parent other then the initial system process */
Process->GrantedAccess = PROCESS_TERMINATE;
if ((Parent) && (Parent != PsInitialSystemProcess))
{
/* Get the process's SD */
@ -683,7 +684,6 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
SubjectContext.ClientToken = NULL;
/* Do the access check */
if (!SecurityDescriptor) DPRINT1("FIX PS SDs!!\n");
Result = SeAccessCheck(SecurityDescriptor,
&SubjectContext,
FALSE,
@ -712,7 +712,9 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
PROCESS_CREATE_THREAD |
PROCESS_DUP_HANDLE |
PROCESS_CREATE_PROCESS |
PROCESS_SET_INFORMATION);
PROCESS_SET_INFORMATION |
STANDARD_RIGHTS_ALL |
PROCESS_SET_QUOTA);
}
else
{
@ -720,14 +722,10 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
Process->GrantedAccess = PROCESS_ALL_ACCESS;
}
/* Sanity check */
ASSERT(IsListEmpty(&Process->ThreadListHead));
/* Set the Creation Time */
KeQuerySystemTime(&Process->CreateTime);
/* Protect against bad user-mode pointer */
PSREFTRACE(Process);
_SEH_TRY
{
/* Save the process handle */
@ -753,8 +751,6 @@ Cleanup:
if (Parent) ObDereferenceObject(Parent);
/* Return status to caller */
PSREFTRACE(Process);
if (Parent) PSREFTRACE(Parent);
return Status;
}
@ -1387,8 +1383,6 @@ NtOpenProcess(OUT PHANDLE ProcessHandle,
/* Dereference the Process */
ObDereferenceObject(Process);
PSREFTRACE(Process);
if (Thread) PSREFTRACE(Thread);
}
else
{

View file

@ -231,7 +231,6 @@ PsLocateSystemDll(VOID)
KeBugCheckEx(PROCESS1_INITIALIZATION_FAILED, Status, 4, 0, 0);
}
/* Map it */
Status = PspMapSystemDll(PsGetCurrentProcess(), &PspSystemDllBase);
if (!NT_SUCCESS(Status))
@ -290,9 +289,7 @@ PspInitPhase0(VOID)
MM_SYSTEMSIZE SystemSize;
UNICODE_STRING Name;
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
/* FIXME: Initialize Lock Data do it STATIC */
ShortPsLockDelay.QuadPart = -100LL;
ULONG i;
/* Get the system size */
SystemSize = MmQuerySystemSize();
@ -320,11 +317,23 @@ PspInitPhase0(VOID)
break;
}
/* Setup callbacks */
for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++)
{
ExInitializeCallBack(&PspThreadNotifyRoutine[i]);
}
for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++)
{
ExInitializeCallBack(&PspProcessNotifyRoutine[i]);
}
for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++)
{
ExInitializeCallBack(&PspLoadImageNotifyRoutine[i]);
}
/* Setup the quantum table */
PsChangeQuantumTable(FALSE, PsRawPrioritySeparation);
/* Setup callbacks when we implement Generic Callbacks */
/* Set quota settings */
if (!PspDefaultPagedLimit) PspDefaultPagedLimit = 0;
if (!PspDefaultNonPagedLimit) PspDefaultNonPagedLimit = 0;
@ -406,6 +415,7 @@ PspInitPhase0(VOID)
/* Create the CID Handle table */
PspCidTable = ExCreateHandleTable(NULL);
if (!PspCidTable) return FALSE;
/* FIXME: Initialize LDT/VDM support */
@ -447,11 +457,22 @@ PspInitPhase0(VOID)
strcpy(PsInitialSystemProcess->ImageFileName, "System");
/* Allocate a structure for the audit name */
PsIdleProcess->SeAuditProcessCreationInfo.ImageFileName =
ExAllocatePoolWithTag(PagedPool, sizeof(UNICODE_STRING), TAG_SEPA);
if (!PsIdleProcess->SeAuditProcessCreationInfo.ImageFileName) KEBUGCHECK(0);
PsInitialSystemProcess->SeAuditProcessCreationInfo.ImageFileName =
ExAllocatePoolWithTag(PagedPool,
sizeof(OBJECT_NAME_INFORMATION),
TAG_SEPA);
if (!PsInitialSystemProcess->SeAuditProcessCreationInfo.ImageFileName)
{
/* Allocation failed */
return FALSE;
}
/* Setup the system initailization thread */
/* Zero it */
RtlZeroMemory(PsInitialSystemProcess->
SeAuditProcessCreationInfo.ImageFileName,
sizeof(OBJECT_NAME_INFORMATION));
/* Setup the system initialization thread */
Status = PsCreateSystemThread(&SysThreadHandle,
THREAD_ALL_ACCESS,
&ObjectAttributes,

View file

@ -45,6 +45,7 @@ VOID
NTAPI
PspDeleteThreadSecurity(IN PETHREAD Thread)
{
PPS_IMPERSONATION_INFORMATION ImpersonationInfo = Thread->ImpersonationInfo;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);
@ -52,14 +53,14 @@ PspDeleteThreadSecurity(IN PETHREAD Thread)
if (Thread->ActiveImpersonationInfo)
{
/* Dereference its token */
ObDereferenceObject(Thread->ImpersonationInfo->Token);
ObDereferenceObject(ImpersonationInfo->Token);
}
/* Check if we have impersonation info */
if (Thread->ImpersonationInfo)
if (ImpersonationInfo)
{
/* Free it */
ExFreePool(Thread->ImpersonationInfo);
ExFreePool(ImpersonationInfo);
PspClearCrossThreadFlag(Thread, CT_ACTIVE_IMPERSONATION_INFO_BIT);
Thread->ImpersonationInfo = NULL;
}
@ -91,7 +92,11 @@ PspInitializeProcessSecurity(IN PEPROCESS Process,
ObFastDereferenceObject(&Parent->Token, ParentToken);
/* Set the new Token */
ObInitializeFastReference(&Process->Token, NewToken);
if (NT_SUCCESS(Status))
{
/* Initailize the fast reference */
ObInitializeFastReference(&Process->Token, NewToken);
}
}
else
{
@ -133,26 +138,24 @@ PspWriteTebImpersonationInfo(IN PETHREAD Thread,
Attached = TRUE;
}
/* Check if we're in a different thread */
if (Thread != CurrentThread)
/* Check if we're in a different thread or acquire rundown */
if ((Thread == CurrentThread) ||
(ExAcquireRundownProtection(&Thread->RundownProtect)))
{
/* Acquire thread rundown protection */
ExAcquireRundownProtection(&Thread->RundownProtect);
}
/* Check if the thread is impersonating */
IsImpersonating = (BOOLEAN)Thread->ActiveImpersonationInfo;
if (IsImpersonating)
{
/* Set TEB data */
Teb->ImpersonationLocale = -1;
Teb->IsImpersonating = 1;
}
else
{
/* Set TEB data */
Teb->ImpersonationLocale = 0;
Teb->IsImpersonating = 0;
/* Check if the thread is impersonating */
IsImpersonating = (BOOLEAN)Thread->ActiveImpersonationInfo;
if (IsImpersonating)
{
/* Set TEB data */
Teb->ImpersonationLocale = -1;
Teb->IsImpersonating = 1;
}
else
{
/* Set TEB data */
Teb->ImpersonationLocale = 0;
Teb->IsImpersonating = 0;
}
}
/* Check if we're in a different thread */
@ -162,7 +165,7 @@ PspWriteTebImpersonationInfo(IN PETHREAD Thread,
ExReleaseRundownProtection(&Thread->RundownProtect);
}
/* Dettach */
/* Detach */
if (Attached) KeUnstackDetachProcess(&ApcState);
}
@ -170,29 +173,40 @@ PspWriteTebImpersonationInfo(IN PETHREAD Thread,
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PspAssignPrimaryToken(IN PEPROCESS Process,
IN PTOKEN Token)
IN HANDLE Token,
IN PACCESS_TOKEN AccessToken OPTIONAL)
{
PACCESS_TOKEN OldToken;
PACCESS_TOKEN NewToken = AccessToken, OldToken;
NTSTATUS Status;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Process: %p Token: %p\n", Process, Token);
/* Lock the process */
/* Check if we don't have a pointer */
if (!AccessToken)
{
/* Reference it from the handle */
Status = ObReferenceObjectByHandle(Token,
TOKEN_ASSIGN_PRIMARY,
SepTokenObjectType,
ExGetPreviousMode(),
&NewToken,
NULL);
if (!NT_SUCCESS(Status)) return Status;
}
/* Exchange tokens */
Status = SeExchangePrimaryToken(Process, NewToken, &OldToken);
/* Acquire and release the lock */
PspLockProcessSecurityExclusive(Process);
/* Exchange them */
Status = SeExchangePrimaryToken(Process, Token, &OldToken);
/* Release the lock */
PspUnlockProcessSecurityExclusive(Process);
/* Dereference Tokens and Return */
if (NT_SUCCESS(Status)) ObDereferenceObject(OldToken);
ObDereferenceObject(Token);
if (AccessToken) ObDereferenceObject(NewToken);
return Status;
}
@ -200,10 +214,11 @@ NTSTATUS
NTAPI
PspSetPrimaryToken(IN PEPROCESS Process,
IN HANDLE TokenHandle OPTIONAL,
IN PTOKEN Token OPTIONAL)
IN PACCESS_TOKEN Token OPTIONAL)
{
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
BOOLEAN IsChild;
PACCESS_TOKEN NewToken = Token;
NTSTATUS Status, AccessStatus;
BOOLEAN Result, SdAllocated;
PSECURITY_DESCRIPTOR SecurityDescriptor;
@ -218,17 +233,17 @@ PspSetPrimaryToken(IN PEPROCESS Process,
TOKEN_ASSIGN_PRIMARY,
SepTokenObjectType,
PreviousMode,
(PVOID*)&Token,
(PVOID*)&NewToken,
NULL);
if (!NT_SUCCESS(Status)) return Status;
}
/* Check if this is a child */
Status = SeIsTokenChild(Token, &IsChild);
Status = SeIsTokenChild(NewToken, &IsChild);
if (!NT_SUCCESS(Status))
{
/* Failed, dereference */
if (TokenHandle) ObDereferenceObject(Token);
if (TokenHandle) ObDereferenceObject(NewToken);
return Status;
}
@ -246,7 +261,7 @@ PspSetPrimaryToken(IN PEPROCESS Process,
}
/* Assign the token */
Status = PspAssignPrimaryToken(Process, Token);
Status = PspAssignPrimaryToken(Process, NULL, NewToken);
if (NT_SUCCESS(Status))
{
/*
@ -264,7 +279,6 @@ PspSetPrimaryToken(IN PEPROCESS Process,
SubjectContext.ClientToken = NULL;
/* Do the access check */
if (!SecurityDescriptor) DPRINT1("FIX PS SDs!!\n");
Result = SeAccessCheck(SecurityDescriptor,
&SubjectContext,
FALSE,
@ -283,6 +297,19 @@ PspSetPrimaryToken(IN PEPROCESS Process,
/* Remove access if it failed */
if (!Result) Process->GrantedAccess = 0;
/* Setup granted access */
Process->GrantedAccess |= (PROCESS_VM_OPERATION |
PROCESS_VM_READ |
PROCESS_VM_WRITE |
PROCESS_QUERY_INFORMATION |
PROCESS_TERMINATE |
PROCESS_CREATE_THREAD |
PROCESS_DUP_HANDLE |
PROCESS_CREATE_PROCESS |
PROCESS_SET_INFORMATION |
STANDARD_RIGHTS_ALL |
PROCESS_SET_QUOTA);
}
/* Dereference the process */
@ -290,7 +317,7 @@ PspSetPrimaryToken(IN PEPROCESS Process,
}
/* Dereference the token */
if (TokenHandle) ObDereferenceObject(Token);
if (Token) ObDereferenceObject(NewToken);
return Status;
}
@ -352,7 +379,7 @@ NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
/* Open the process token */
Status = PsOpenTokenOfProcess(ProcessHandle, &Token);
if(NT_SUCCESS(Status))
if (NT_SUCCESS(Status))
{
/* Reference it by handle and dereference the pointer */
Status = ObOpenObjectByPointer(Token,
@ -365,7 +392,7 @@ NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
ObDereferenceObject(Token);
/* Make sure we got a handle */
if(NT_SUCCESS(Status))
if (NT_SUCCESS(Status))
{
/* Enter SEH for write */
_SEH_TRY
@ -487,10 +514,7 @@ PsAssignImpersonationToken(IN PETHREAD Thread,
return STATUS_BAD_TOKEN_TYPE;
}
/* Check if this is a job, which we don't support yet */
if (Thread->ThreadsProcess->Job) KEBUGCHECK(0);
/* Get the impersionation level */
/* Get the impersonation level */
ImpersonationLevel = SeTokenImpersonationLevel(Token);
/* Call the impersonation API */
@ -501,7 +525,7 @@ PsAssignImpersonationToken(IN PETHREAD Thread,
ImpersonationLevel);
/* Dereference the token and return status */
if (Token) ObDereferenceObject(Token);
ObDereferenceObject(Token);
return Status;
}
@ -546,13 +570,17 @@ PsRevertThreadToSelf(IN PETHREAD Thread)
/* Release thread security */
PspUnlockThreadSecurityExclusive(Thread);
/* Check if we had a token */
if (Token)
{
/* Dereference the impersonation token */
ObDereferenceObject(Token);
/* Write impersonation info to the TEB */
PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
}
}
/* Dereference the impersonation token */
if (Token) ObDereferenceObject(Token);
/* Write impersonation info to the TEB */
PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
}
/*
@ -566,7 +594,7 @@ PsImpersonateClient(IN PETHREAD Thread,
IN BOOLEAN EffectiveOnly,
IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
{
PPS_IMPERSONATION_INFORMATION Impersonation;
PPS_IMPERSONATION_INFORMATION Impersonation, OldData;
PTOKEN OldToken = NULL;
PAGED_CODE();
PSTRACE(PS_SECURITY_DEBUG, "Thread: %p, Token: %p\n", Thread, Token);
@ -591,8 +619,9 @@ PsImpersonateClient(IN PETHREAD Thread,
OldToken = Thread->ImpersonationInfo->Token;
}
/* Unlock the process */
/* Unlock the process and write TEB information */
PspUnlockThreadSecurityExclusive(Thread);
PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
}
}
else
@ -608,12 +637,15 @@ PsImpersonateClient(IN PETHREAD Thread,
if (!Impersonation) return STATUS_INSUFFICIENT_RESOURCES;
/* Update the pointer */
if (InterlockedCompareExchangePointer(&Thread->ImpersonationInfo,
Impersonation,
NULL))
OldData = InterlockedCompareExchangePointer(&Thread->
ImpersonationInfo,
Impersonation,
NULL);
if (OldData)
{
/* Someone beat us to it, free our copy */
ExFreePool(Impersonation);
Impersonation = OldData;
}
}
@ -644,13 +676,13 @@ PsImpersonateClient(IN PETHREAD Thread,
/* Unlock the thread */
PspUnlockThreadSecurityExclusive(Thread);
/* Write impersonation info to the TEB */
PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
}
/* Write impersonation info to the TEB */
PspWriteTebImpersonationInfo(Thread, PsGetCurrentThread());
/* Dereference the token and return success */
if (OldToken) ObDereferenceObject(OldToken);
if (OldToken) PsDereferenceImpersonationToken(OldToken);
return STATUS_SUCCESS;
}
@ -674,9 +706,6 @@ PsReferenceEffectiveToken(IN PETHREAD Thread,
Process = Thread->ThreadsProcess;
if (!Thread->ActiveImpersonationInfo)
{
*TokenType = TokenPrimary;
*EffectiveOnly = FALSE;
/* Fast Reference the Token */
Token = ObFastReferenceObject(&Process->Token);
@ -709,6 +738,10 @@ PsReferenceEffectiveToken(IN PETHREAD Thread,
*TokenType = TokenImpersonation;
*EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
*Level = Thread->ImpersonationInfo->ImpersonationLevel;
/* Unlock the Process */
PspUnlockProcessSecurityShared(Process);
return Token;
}
/* Unlock the Process */
@ -716,6 +749,8 @@ PsReferenceEffectiveToken(IN PETHREAD Thread,
}
/* Return the token */
*TokenType = TokenPrimary;
*EffectiveOnly = FALSE;
return Token;
}

View file

@ -51,9 +51,8 @@ PspUserThreadStartup(IN PKSTART_ROUTINE StartRoutine,
Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
}
/* Check if this is a system thread, or if we're hiding */
PSREFTRACE(Thread);
if (!(Thread->SystemThread) && !(Thread->HideFromDebugger))
/* Check if this is a dead thread, or if we're hiding */
if (!(Thread->DeadThread) && !(Thread->HideFromDebugger))
{
/* We're not, so notify the debugger */
DbgkCreateThread(StartContext);
@ -113,6 +112,30 @@ PspUserThreadStartup(IN PKSTART_ROUTINE StartRoutine,
}
}
_SEH_FILTER(PspUnhandledExceptionInSystemThread)
{
PEXCEPTION_POINTERS ExceptionPointers= _SEH_GetExceptionPointers();
/* Print debugging information */
DPRINT1("PS: Unhandled Kernel Mode Exception Pointers = 0x%p\n",
ExceptionPointers);
DPRINT1("Code %x Addr %p Info0 %p Info1 %p Info2 %p Info3 %p\n",
ExceptionPointers->ExceptionRecord->ExceptionCode,
ExceptionPointers->ExceptionRecord->ExceptionAddress,
ExceptionPointers->ExceptionRecord->ExceptionInformation[0],
ExceptionPointers->ExceptionRecord->ExceptionInformation[1],
ExceptionPointers->ExceptionRecord->ExceptionInformation[2],
ExceptionPointers->ExceptionRecord->ExceptionInformation[3]);
/* Bugcheck the system */
KeBugCheckEx(0x7E,
ExceptionPointers->ExceptionRecord->ExceptionCode,
(ULONG_PTR)ExceptionPointers->ExceptionRecord->ExceptionAddress,
(ULONG_PTR)ExceptionPointers->ExceptionRecord,
(ULONG_PTR)ExceptionPointers->ContextRecord);
return 0;
}
VOID
NTAPI
PspSystemThreadStartup(IN PKSTART_ROUTINE StartRoutine,
@ -127,12 +150,20 @@ PspSystemThreadStartup(IN PKSTART_ROUTINE StartRoutine,
Thread = PsGetCurrentThread();
/* Make sure the thread isn't gone */
PSREFTRACE(Thread);
if (!(Thread->Terminated) && !(Thread->DeadThread))
_SEH_TRY
{
/* Call it the Start Routine */
StartRoutine(StartContext);
if (!(Thread->Terminated) && !(Thread->DeadThread))
{
/* Call it the Start Routine */
StartRoutine(StartContext);
}
}
_SEH_EXCEPT(PspUnhandledExceptionInSystemThread)
{
/* Bugcheck if we got here */
KeBugCheck(KMODE_EXCEPTION_NOT_HANDLED);
}
_SEH_END;
/* Exit the thread */
PspTerminateThreadByPointer(Thread, STATUS_SUCCESS, TRUE);
@ -192,7 +223,6 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
{
/* Reference the Process by Pointer */
ObReferenceObject(TargetProcess);
PSREFTRACE(TargetProcess);
Process = TargetProcess;
Status = STATUS_SUCCESS;
}
@ -232,7 +262,6 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
}
/* Zero the Object entirely */
PSREFTRACE(Thread);
RtlZeroMemory(Thread, sizeof(ETHREAD));
/* Initialize rundown protection */
@ -270,7 +299,12 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
KeInitializeSpinLock(&Thread->ActiveTimerListLock);
/* Acquire rundown protection */
ExAcquireRundownProtection(&Process->RundownProtect);
if (!ExAcquireRundownProtection (&Process->RundownProtect))
{
/* Fail */
ObDereferenceObject(Thread);
return STATUS_PROCESS_IS_TERMINATING;
}
/* Now let the kernel initialize the context */
if (ThreadContext)
@ -317,7 +351,6 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
}
/* Check if we failed */
PSREFTRACE(Thread);
if (!NT_SUCCESS(Status))
{
/* Delete the TEB if we had done */
@ -400,6 +433,7 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
/* Dereference completely to kill it */
ObDereferenceObjectEx(Thread, 2);
return Status;
}
/* Insert the Thread into the Object Manager */
@ -411,7 +445,6 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
&hThread);
/* Delete the access state if we had one */
PSREFTRACE(Thread);
if (AccessState) SeDeleteAccessState(AccessState);
/* Check for success */
@ -461,7 +494,6 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
ASSERT(!(Thread->CreateTime.HighPart & 0xF0000000));
/* Make sure the thread isn't dead */
PSREFTRACE(Thread);
if (!Thread->DeadThread)
{
/* Get the thread's SD */
@ -493,7 +525,6 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
SubjectContext.ClientToken = NULL;
/* Do the access check */
if (!SecurityDescriptor) DPRINT1("FIX PS SDs!!\n");
Result = SeAccessCheck(SecurityDescriptor,
&SubjectContext,
FALSE,
@ -525,14 +556,12 @@ PspCreateThread(OUT PHANDLE ThreadHandle,
}
/* Dispatch thread */
PSREFTRACE(Thread);
KeReadyThread(&Thread->Tcb);
/* Dereference it, leaving only the keep-alive */
ObDereferenceObject(Thread);
/* Return */
PSREFTRACE(Thread);
return Status;
/* Most annoying failure case ever, where we undo almost all manually */
@ -541,7 +570,6 @@ Quickie:
ExReleasePushLockExclusive(&Process->ProcessLock);
/* Uninitailize it */
PSREFTRACE(Thread);
KeUninitThread(&Thread->Tcb);
/* If we had a TEB, delete it */
@ -552,7 +580,6 @@ Quickie:
/* Dereference the thread and return failure */
ObDereferenceObject(Thread);
PSREFTRACE(Thread);
return STATUS_PROCESS_IS_TERMINATING;
}
@ -841,7 +868,7 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
"ProcessHandle: %p Context: %p\n", ProcessHandle, ThreadContext);
/* Check if this was from user-mode */
if(KeGetPreviousMode() != KernelMode)
if (KeGetPreviousMode() != KernelMode)
{
/* Make sure that we got a context */
if (!ThreadContext) return STATUS_INVALID_PARAMETER;
@ -865,14 +892,12 @@ NtCreateThread(OUT PHANDLE ThreadHandle,
/* Check the Initial TEB */
ProbeForRead(InitialTeb, sizeof(INITIAL_TEB), sizeof(ULONG));
SafeInitialTeb = *InitialTeb;
}
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
/* Handle any failures in our SEH checks */
if (!NT_SUCCESS(Status)) return Status;
}
else