Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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);
}
Exemplo n.º 4
0
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);
}
Exemplo n.º 5
0
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
    {