NTKERNELAPI PVOID FASTCALL ObFastReferenceObject ( IN PEX_FAST_REF FastRef ) /*++ Routine Description: This routine attempts a fast reference of an object in a fast ref structure. Arguments: FastRef - Rundown block to be used for the reference Return Value: PVOID - Object that was referenced or NULL if we failed --*/ { EX_FAST_REF OldRef; PVOID Object; ULONG RefsToAdd, Unused; // // Attempt the fast reference // OldRef = ExFastReference (FastRef); Object = ExFastRefGetObject (OldRef); // // We fail if there wasn't an object or if it has no cached references // left. Both of these cases had the cached reference count zero. // Unused = ExFastRefGetUnusedReferences (OldRef); if (Unused <= 1) { if (Unused == 0) { return NULL; } // // If we took the counter to zero then attempt to make life easier for // the next referencer by resetting the counter to its max. Since we now // have a reference to the object we can do this. // RefsToAdd = ExFastRefGetAdditionalReferenceCount (); ObReferenceObjectEx (Object, RefsToAdd); // // Try to add the added references to the cache. If we fail then just // release them. // if (!ExFastRefAddAdditionalReferenceCounts (FastRef, Object, RefsToAdd)) { ObDereferenceObjectEx (Object, RefsToAdd); } } return Object; }
NTKERNELAPI PVOID FASTCALL ObFastReplaceObject ( IN PEX_FAST_REF FastRef, IN PVOID Object ) /*++ Routine Description: This routine does a swap of the object. This must be called while holding a lock. Arguments: FastRef - Rundown block to be used to do the swap. Return Value: PVOID - Object that was in the block before the swap.. --*/ { EX_FAST_REF OldRef; PVOID OldObject; ULONG RefsToReturn; // // If we have been given an object then bias it by the correct amount. // if (Object != NULL) { ObReferenceObjectEx (Object, ExFastRefGetAdditionalReferenceCount ()); } // // Do the swap // OldRef = ExFastRefSwapObject (FastRef, Object); OldObject = ExFastRefGetObject (OldRef); // // If there was an original object then we need to work out how many // cached references there were (if any) and return them. // if (OldObject != NULL) { RefsToReturn = ExFastRefGetUnusedReferences (OldRef); if (RefsToReturn > 0) { ObDereferenceObjectEx (OldObject, RefsToReturn); } } return OldObject; }
VOID NTAPI ExpTimerApcKernelRoutine(IN PKAPC Apc, IN OUT PKNORMAL_ROUTINE* NormalRoutine, IN OUT PVOID* NormalContext, IN OUT PVOID* SystemArgument1, IN OUT PVOID* SystemArguemnt2) { PETIMER Timer; KIRQL OldIrql; ULONG DerefsToDo = 1; PETHREAD Thread = PsGetCurrentThread(); /* We need to find out which Timer we are */ Timer = CONTAINING_RECORD(Apc, ETIMER, TimerApc); /* Lock the Timer */ KeAcquireSpinLock(&Timer->Lock, &OldIrql); /* Lock the Thread's Active Timer List*/ KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock); /* Make sure that the Timer is valid, and that it belongs to this thread */ if ((Timer->ApcAssociated) && (&Thread->Tcb == Timer->TimerApc.Thread)) { /* Check if it's not periodic */ if (!Timer->Period) { /* Remove it from the Active Timers List */ RemoveEntryList(&Timer->ActiveTimerListEntry); /* Disable it */ Timer->ApcAssociated = FALSE; DerefsToDo++; } } else { /* Clear the normal routine */ *NormalRoutine = NULL; } /* Release locks */ KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock); KeReleaseSpinLock(&Timer->Lock, OldIrql); /* Dereference as needed */ ObDereferenceObjectEx(Timer, DerefsToDo); }
VOID NTAPI ExTimerRundown(VOID) { PETHREAD Thread = PsGetCurrentThread(); KIRQL OldIrql; PLIST_ENTRY CurrentEntry; PETIMER Timer; ULONG DerefsToDo; /* Lock the Thread's Active Timer List and loop it */ KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql); CurrentEntry = Thread->ActiveTimerListHead.Flink; while (CurrentEntry != &Thread->ActiveTimerListHead) { /* Get the timer */ Timer = CONTAINING_RECORD(CurrentEntry, ETIMER, ActiveTimerListEntry); /* Reference it */ ObReferenceObject(Timer); DerefsToDo = 1; /* Unlock the list */ KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql); /* Lock the Timer */ KeAcquireSpinLock(&Timer->Lock, &OldIrql); /* Lock the list again */ KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock); /* Make sure that the timer is valid */ if ((Timer->ApcAssociated) && (&Thread->Tcb == Timer->TimerApc.Thread)) { /* Remove it from the list */ RemoveEntryList(&Timer->ActiveTimerListEntry); Timer->ApcAssociated = FALSE; /* Cancel the timer and remove its DPC and APC */ KeCancelTimer(&Timer->KeTimer); KeRemoveQueueDpc(&Timer->TimerDpc); if (KeRemoveQueueApc(&Timer->TimerApc)) DerefsToDo++; /* Add another dereference to do */ DerefsToDo++; } /* Unlock the list */ KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock); /* Unlock the Timer */ KeReleaseSpinLock(&Timer->Lock, OldIrql); /* Dereference it */ ObDereferenceObjectEx(Timer, DerefsToDo); /* Loop again */ KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql); CurrentEntry = Thread->ActiveTimerListHead.Flink; } /* Release lock and return */ KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql); }
NTSTATUS NTAPI PspCreateThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ProcessHandle, IN PEPROCESS TargetProcess, OUT PCLIENT_ID ClientId, IN PCONTEXT ThreadContext, IN PINITIAL_TEB InitialTeb, IN BOOLEAN CreateSuspended, IN PKSTART_ROUTINE StartRoutine OPTIONAL, IN PVOID StartContext OPTIONAL) { HANDLE hThread; PEPROCESS Process; PETHREAD Thread; PTEB TebBase = NULL; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status, AccessStatus; HANDLE_TABLE_ENTRY CidEntry; ACCESS_STATE LocalAccessState; PACCESS_STATE AccessState = &LocalAccessState; AUX_ACCESS_DATA AuxData; BOOLEAN Result, SdAllocated; PSECURITY_DESCRIPTOR SecurityDescriptor; SECURITY_SUBJECT_CONTEXT SubjectContext; PAGED_CODE(); PSTRACE(PS_THREAD_DEBUG, "ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n", ThreadContext, TargetProcess, ProcessHandle); /* If we were called from PsCreateSystemThread, then we're kernel mode */ if (StartRoutine) PreviousMode = KernelMode; /* Reference the Process by handle or pointer, depending on what we got */ if (ProcessHandle) { /* Normal thread or System Thread */ Status = ObReferenceObjectByHandle(ProcessHandle, PROCESS_CREATE_THREAD, PsProcessType, PreviousMode, (PVOID*)&Process, NULL); PSREFTRACE(Process); } else { /* System thread inside System Process, or Normal Thread with a bug */ if (StartRoutine) { /* Reference the Process by Pointer */ ObReferenceObject(TargetProcess); Process = TargetProcess; Status = STATUS_SUCCESS; } else { /* Fake ObReference returning this */ Status = STATUS_INVALID_HANDLE; } } /* Check for success */ if (!NT_SUCCESS(Status)) return Status; /* Also make sure that User-Mode isn't trying to create a system thread */ if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess)) { /* Fail */ ObDereferenceObject(Process); return STATUS_INVALID_HANDLE; } /* Create Thread Object */ Status = ObCreateObject(PreviousMode, PsThreadType, ObjectAttributes, PreviousMode, NULL, sizeof(ETHREAD), 0, 0, (PVOID*)&Thread); if (!NT_SUCCESS(Status)) { /* We failed; dereference the process and exit */ ObDereferenceObject(Process); return Status; } /* Zero the Object entirely */ RtlZeroMemory(Thread, sizeof(ETHREAD)); /* Initialize rundown protection */ ExInitializeRundownProtection(&Thread->RundownProtect); /* Initialize exit code */ Thread->ExitStatus = STATUS_PENDING; /* Set the Process CID */ Thread->ThreadsProcess = Process; Thread->Cid.UniqueProcess = Process->UniqueProcessId; /* Create Cid Handle */ CidEntry.Object = Thread; CidEntry.GrantedAccess = 0; Thread->Cid.UniqueThread = ExCreateHandle(PspCidTable, &CidEntry); if (!Thread->Cid.UniqueThread) { /* We couldn't create the CID, dereference the thread and fail */ ObDereferenceObject(Thread); return STATUS_INSUFFICIENT_RESOURCES; } /* Save the read cluster size */ Thread->ReadClusterSize = MmReadClusterSize; /* Initialize the LPC Reply Semaphore */ KeInitializeSemaphore(&Thread->LpcReplySemaphore, 0, 1); /* Initialize the list heads and locks */ InitializeListHead(&Thread->LpcReplyChain); InitializeListHead(&Thread->IrpList); InitializeListHead(&Thread->PostBlockList); InitializeListHead(&Thread->ActiveTimerListHead); KeInitializeSpinLock(&Thread->ActiveTimerListLock); /* Acquire rundown protection */ if (!ExAcquireRundownProtection (&Process->RundownProtect)) { /* Fail */ ObDereferenceObject(Thread); return STATUS_PROCESS_IS_TERMINATING; } /* Now let the kernel initialize the context */ if (ThreadContext) { /* User-mode Thread, create Teb */ Status = MmCreateTeb(Process, &Thread->Cid, InitialTeb, &TebBase); if (!NT_SUCCESS(Status)) { /* Failed to create the TEB. Release rundown and dereference */ ExReleaseRundownProtection(&Process->RundownProtect); ObDereferenceObject(Thread); return Status; } /* Set the Start Addresses */ Thread->StartAddress = (PVOID)KeGetContextPc(ThreadContext); Thread->Win32StartAddress = (PVOID)KeGetContextReturnRegister(ThreadContext); /* Let the kernel intialize the Thread */ Status = KeInitThread(&Thread->Tcb, NULL, PspUserThreadStartup, NULL, Thread->StartAddress, ThreadContext, TebBase, &Process->Pcb); } else { /* System Thread */ Thread->StartAddress = StartRoutine; PspSetCrossThreadFlag(Thread, CT_SYSTEM_THREAD_BIT); /* Let the kernel intialize the Thread */ Status = KeInitThread(&Thread->Tcb, NULL, PspSystemThreadStartup, StartRoutine, StartContext, NULL, NULL, &Process->Pcb); } /* Check if we failed */ if (!NT_SUCCESS(Status)) { /* Delete the TEB if we had done */ if (TebBase) MmDeleteTeb(Process, TebBase); /* Release rundown and dereference */ ExReleaseRundownProtection(&Process->RundownProtect); ObDereferenceObject(Thread); return Status; } /* Lock the process */ KeEnterCriticalRegion(); ExAcquirePushLockExclusive(&Process->ProcessLock); /* Make sure the proces didn't just die on us */ if (Process->ProcessDelete) goto Quickie; /* Check if the thread was ours, terminated and it was user mode */ if ((Thread->Terminated) && (ThreadContext) && (Thread->ThreadsProcess == Process)) { /* Cleanup, we don't want to start it up and context switch */ goto Quickie; } /* * Insert the Thread into the Process's Thread List * Note, this is the ETHREAD Thread List. It is removed in * ps/kill.c!PspExitThread. */ InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry); Process->ActiveThreads++; /* Start the thread */ KeStartThread(&Thread->Tcb); /* Release the process lock */ ExReleasePushLockExclusive(&Process->ProcessLock); KeLeaveCriticalRegion(); /* Release rundown */ ExReleaseRundownProtection(&Process->RundownProtect); /* Notify WMI */ //WmiTraceProcess(Process, TRUE); //WmiTraceThread(Thread, InitialTeb, TRUE); /* Notify Thread Creation */ PspRunCreateThreadNotifyRoutines(Thread, TRUE); /* Reference ourselves as a keep-alive */ ObReferenceObjectEx(Thread, 2); /* Suspend the Thread if we have to */ if (CreateSuspended) KeSuspendThread(&Thread->Tcb); /* Check if we were already terminated */ if (Thread->Terminated) KeForceResumeThread(&Thread->Tcb); /* Create an access state */ Status = SeCreateAccessStateEx(NULL, ThreadContext ? PsGetCurrentProcess() : Process, &LocalAccessState, &AuxData, DesiredAccess, &PsThreadType->TypeInfo.GenericMapping); if (!NT_SUCCESS(Status)) { /* Access state failed, thread is dead */ PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT); /* If we were suspended, wake it up */ if (CreateSuspended) KeResumeThread(&Thread->Tcb); /* Dispatch thread */ KeReadyThread(&Thread->Tcb); /* Dereference completely to kill it */ ObDereferenceObjectEx(Thread, 2); return Status; } /* Insert the Thread into the Object Manager */ Status = ObInsertObject(Thread, AccessState, DesiredAccess, 0, NULL, &hThread); /* Delete the access state if we had one */ if (AccessState) SeDeleteAccessState(AccessState); /* Check for success */ if (NT_SUCCESS(Status)) { /* Wrap in SEH to protect against bad user-mode pointers */ _SEH2_TRY { /* Return Cid and Handle */ if (ClientId) *ClientId = Thread->Cid; *ThreadHandle = hThread; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Thread insertion failed, thread is dead */ PspSetCrossThreadFlag(Thread, CT_DEAD_THREAD_BIT); /* If we were suspended, wake it up */ if (CreateSuspended) KeResumeThread(&Thread->Tcb); /* Dispatch thread */ KeReadyThread(&Thread->Tcb); /* Dereference it, leaving only the keep-alive */ ObDereferenceObject(Thread); /* Close its handle, killing it */ ObCloseHandle(ThreadHandle, PreviousMode); /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; } else {