예제 #1
0
NTSTATUS
PsLookupProcessByProcessId(
    __in HANDLE ProcessId,
    __deref_out PEPROCESS *Process
    )

/*++

Routine Description:

    This function accepts the process id of a process and returns a
    referenced pointer to the process.

Arguments:

    ProcessId - Specifies the Process ID of the process.

    Process - Returns a referenced pointer to the process specified by the
        process id.

Return Value:

    STATUS_SUCCESS - A process was located based on the contents of
        the process id.

    STATUS_INVALID_PARAMETER - The process was not found.

--*/

{

    PHANDLE_TABLE_ENTRY CidEntry;
    PEPROCESS lProcess;
    PETHREAD CurrentThread;
    NTSTATUS Status;

    PAGED_CODE();

    Status = STATUS_INVALID_PARAMETER;

    CurrentThread = PsGetCurrentThread ();
    KeEnterCriticalRegionThread (&CurrentThread->Tcb);

    CidEntry = ExMapHandleToPointer(PspCidTable, ProcessId);
    if (CidEntry != NULL) {
        lProcess = (PEPROCESS)CidEntry->Object;
        if (lProcess->Pcb.Header.Type == ProcessObject &&
            lProcess->GrantedAccess != 0) {
            if (ObReferenceObjectSafe(lProcess)) {
               *Process = lProcess;
                Status = STATUS_SUCCESS;
            }
        }

        ExUnlockHandleTableEntry(PspCidTable, CidEntry);
    }

    KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
    return Status;
}
예제 #2
0
NTSTATUS
MmPrefetchPagesIntoLockedMdl (
    IN PFILE_OBJECT FileObject,
    IN PLARGE_INTEGER FileOffset,
    IN SIZE_T Length,
    OUT PMDL *MdlOut
    )

/*++

Routine Description:

    This routine fills an MDL with pages described by the file object's
    offset and length.

    This routine is for cache manager usage only.

Arguments:

    FileObject - Supplies a pointer to the file object for a file which was
                 opened with NO_INTERMEDIATE_BUFFERING clear, i.e., for
                 which CcInitializeCacheMap was called by the file system.

    FileOffset - Supplies the byte offset in the file for the desired data.

    Length - Supplies the length of the desired data in bytes.

    MdlOut - On output it returns a pointer to an Mdl describing
             the desired data.

Return Value:

    NTSTATUS.

Environment:

    Kernel mode. PASSIVE_LEVEL.

--*/

{
    MI_READ_INFO MiReadInfo;
    NTSTATUS status;
    LOGICAL ApcNeeded;
    PETHREAD CurrentThread;

    ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);

    RtlZeroMemory (&MiReadInfo, sizeof(MiReadInfo));

    MiReadInfo.FileObject = FileObject;
    MiReadInfo.FileOffset = *FileOffset;
    MiReadInfo.LengthInBytes = Length;

    //
    // Prepare for the impending read : allocate MDLs, inpage blocks,
    // reference count subsections, etc.
    //

    status = MiCcPrepareReadInfo (&MiReadInfo);

    if (!NT_SUCCESS (status)) {
        MiCcReleasePrefetchResources (&MiReadInfo, status);
        return status;
    }

    ASSERT (MiReadInfo.InPageSupport != NULL);

    //
    // APCs must be disabled once we put a page in transition.  Otherwise
    // a thread suspend will stop us from issuing the I/O - this will hang
    // any other threads that need the same page.
    //

    CurrentThread = PsGetCurrentThread();
    ApcNeeded = FALSE;

    KeEnterCriticalRegionThread (&CurrentThread->Tcb);

    //
    // The nested fault count protects this thread from deadlocks where a
    // special kernel APC fires and references the same user page(s) we are
    // putting in transition.
    //

    KeEnterGuardedRegionThread (&CurrentThread->Tcb);
    ASSERT (CurrentThread->ActiveFaultCount == 0);
    CurrentThread->ActiveFaultCount += 1;
    KeLeaveGuardedRegionThread (&CurrentThread->Tcb);

    //
    // Allocate physical memory, lock down all the pages and issue any
    // I/O that may be needed.  When MiCcPutPagesInTransition returns
    // STATUS_SUCCESS or STATUS_ISSUE_PAGING_IO, it guarantees that the
    // ApiMdl contains reference-counted (locked-down) pages.
    //

    status = MiCcPutPagesInTransition (&MiReadInfo);

    if (NT_SUCCESS (status)) {

        //
        // No I/O was issued because all the pages were already resident and
        // have now been locked down.
        //

        ASSERT (MiReadInfo.ApiMdl != NULL);
    }
    else if (status == STATUS_ISSUE_PAGING_IO) {

        //
        // Wait for the I/O to complete.  Note APCs must remain disabled.
        //

        ASSERT (MiReadInfo.InPageSupport != NULL);
    
        status = MiCcCompletePrefetchIos (&MiReadInfo);
    }
    else {

        //
        // Some error occurred (like insufficient memory, etc) so fail
        // the request by falling through.
        //
    }

    //
    // Release acquired resources like pool, subsections, etc.
    //

    MiCcReleasePrefetchResources (&MiReadInfo, status);

    //
    // Only now that the I/O have been completed (not just issued) can
    // APCs be re-enabled.  This prevents a user-issued suspend APC from
    // keeping a shared page in transition forever.
    //

    KeEnterGuardedRegionThread (&CurrentThread->Tcb);

    ASSERT (CurrentThread->ActiveFaultCount == 1);

    CurrentThread->ActiveFaultCount -= 1;

    if (CurrentThread->ApcNeeded == 1) {
        ApcNeeded = TRUE;
        CurrentThread->ApcNeeded = 0;
    }

    KeLeaveGuardedRegionThread (&CurrentThread->Tcb);

    KeLeaveCriticalRegionThread (&CurrentThread->Tcb);

    ASSERT (KeGetCurrentIrql() == PASSIVE_LEVEL);
    ASSERT (CurrentThread->ActiveFaultCount == 0);
    ASSERT (CurrentThread->ApcNeeded == 0);

    if (ApcNeeded == TRUE) {
        IoRetryIrpCompletions ();
    }

    *MdlOut = MiReadInfo.ApiMdl;

    return status;
}
예제 #3
0
NTSTATUS
PsLookupProcessThreadByCid(
    __in PCLIENT_ID Cid,
    __deref_opt_out PEPROCESS *Process,
    __deref_out PETHREAD *Thread
    )

/*++

Routine Description:

    This function accepts The Client ID of a thread, and returns a
    referenced pointer to the thread, and possibly a referenced pointer
    to the process.

Arguments:

    Cid - Specifies the Client ID of the thread.

    Process - If specified, returns a referenced pointer to the process
        specified in the Cid.

    Thread - Returns a referenced pointer to the thread specified in the
        Cid.

Return Value:

    STATUS_SUCCESS - A process and thread were located based on the contents
        of the Cid.

    STATUS_INVALID_CID - The specified Cid is invalid.

--*/

{

    PHANDLE_TABLE_ENTRY CidEntry;
    PETHREAD lThread;
    PETHREAD CurrentThread;
    PEPROCESS lProcess;
    NTSTATUS Status;

    PAGED_CODE();


    lThread = NULL;

    CurrentThread = PsGetCurrentThread ();
    KeEnterCriticalRegionThread (&CurrentThread->Tcb);

    CidEntry = ExMapHandleToPointer(PspCidTable, Cid->UniqueThread);
    if (CidEntry != NULL) {
        lThread = (PETHREAD)CidEntry->Object;
        if (!ObReferenceObjectSafe (lThread)) {
            lThread = NULL;
        }
        ExUnlockHandleTableEntry(PspCidTable, CidEntry);
    }

    KeLeaveCriticalRegionThread (&CurrentThread->Tcb);

    Status = STATUS_INVALID_CID;
    if (lThread != NULL) {
        //
        // This could be a thread or a process. Check its a thread.
        //
        if (lThread->Tcb.Header.Type != ThreadObject ||
            lThread->Cid.UniqueProcess != Cid->UniqueProcess ||
            lThread->GrantedAccess == 0) {
            ObDereferenceObject (lThread);
        } else {
            *Thread = lThread;
            if (ARGUMENT_PRESENT (Process)) {
                lProcess = THREAD_TO_PROCESS (lThread);
                *Process = lProcess;
                //
                // Since the thread holds a reference to the process this reference does not have to
                // be protected.
                //
                ObReferenceObject (lProcess);
            }
            Status = STATUS_SUCCESS;
        }

    }

    return Status;
}
예제 #4
0
NTSTATUS
PsLookupThreadByThreadId(
    __in HANDLE ThreadId,
    __deref_out PETHREAD *Thread
    )

/*++

Routine Description:

    This function accepts the thread id of a thread and returns a
    referenced pointer to the thread.

Arguments:

    ThreadId - Specifies the Thread ID of the thread.

    Thread - Returns a referenced pointer to the thread specified by the
        thread id.

Return Value:

    STATUS_SUCCESS - A thread was located based on the contents of
        the thread id.

    STATUS_INVALID_PARAMETER - The thread was not found.

--*/

{

    PHANDLE_TABLE_ENTRY CidEntry;
    PETHREAD lThread;
    PETHREAD CurrentThread;
    NTSTATUS Status;

    PAGED_CODE();

    Status = STATUS_INVALID_PARAMETER;

    CurrentThread = PsGetCurrentThread ();
    KeEnterCriticalRegionThread (&CurrentThread->Tcb);

    CidEntry = ExMapHandleToPointer(PspCidTable, ThreadId);
    if (CidEntry != NULL) {
        lThread = (PETHREAD)CidEntry->Object;
        if (lThread->Tcb.Header.Type == ThreadObject && lThread->GrantedAccess) {

            if (ObReferenceObjectSafe(lThread)) {
                *Thread = lThread;
                Status = STATUS_SUCCESS;
            }
        }

        ExUnlockHandleTableEntry(PspCidTable, CidEntry);
    }

    KeLeaveCriticalRegionThread (&CurrentThread->Tcb);

    return Status;
}
예제 #5
0
PEX_CALLBACK_ROUTINE_BLOCK
ExReferenceCallBackBlock (
    IN OUT PEX_CALLBACK CallBack
    )
/*++

Routine Description:

    This function takes a reference on the call back block inside the
    callback structure.

Arguments:

    CallBack - Call back to obtain the call back block from

Return Value:

    PEX_CALLBACK_ROUTINE_BLOCK - Referenced structure or NULL if these wasn't one

--*/
{
    EX_FAST_REF OldRef;
    PEX_CALLBACK_ROUTINE_BLOCK CallBackBlock;

    //
    // Get a reference to the callback block if we can.
    //
    OldRef = ExFastReference (&CallBack->RoutineBlock);

    //
    // If there is no callback then return
    //
    if (ExFastRefObjectNull (OldRef)) {
        return NULL;
    }
    //
    // If we didn't get a reference then use a lock to get one.
    //
    if (!ExFastRefCanBeReferenced (OldRef)) {
        PKTHREAD CurrentThread;
        CurrentThread = KeGetCurrentThread ();

        KeEnterCriticalRegionThread (CurrentThread);

        ExAcquirePushLockExclusive (&ExpCallBackFlush);

        CallBackBlock = ExFastRefGetObject (CallBack->RoutineBlock);
        if (CallBackBlock && !ExAcquireRundownProtection (&CallBackBlock->RundownProtect)) {
            CallBackBlock = NULL;
        }

        ExReleasePushLockExclusive (&ExpCallBackFlush);

        KeLeaveCriticalRegionThread (CurrentThread);

        if (CallBackBlock == NULL) {
            return NULL;
        }

    } else {
        CallBackBlock = ExFastRefGetObject (OldRef);

        //
        // If we just removed the last reference then attempt fix it up.
        //
        if (ExFastRefIsLastReference (OldRef) && !ExpCallBackReturnRefs) {
            ULONG RefsToAdd;

            RefsToAdd = ExFastRefGetAdditionalReferenceCount ();

            //
            // If we can't add the references then just give up
            //
            if (ExAcquireRundownProtectionEx (&CallBackBlock->RundownProtect,
                                              RefsToAdd)) {
                //
                // Repopulate the cached refs. If this fails we just give them back.
                //
                if (!ExFastRefAddAdditionalReferenceCounts (&CallBack->RoutineBlock,
                                                            CallBackBlock,
                                                            RefsToAdd)) {
                    ExReleaseRundownProtectionEx (&CallBackBlock->RundownProtect,
                                                  RefsToAdd);
                }
            }
        }
    }

    return CallBackBlock;
}
예제 #6
0
BOOLEAN
ExCompareExchangeCallBack (
    IN OUT PEX_CALLBACK CallBack,
    IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock,
    IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock
    )
/*++

Routine Description:

    This function assigns, removes or swaps a low overhead callback function.

Arguments:

    CallBack - Callback structure to be modified

    NewBlock - New block to be installed in the callback

    OldBlock - The old block that must be there now to be replaced

Return Value:

    BOOLEAN - TRUE: The swap occured, FALSE: The swap failed

--*/
{
    EX_FAST_REF OldRef;
    PEX_CALLBACK_ROUTINE_BLOCK ReplacedBlock;

    if (NewBlock != NULL) {
        //
        // Add the additional references to the routine block
        //
        if (!ExAcquireRundownProtectionEx (&NewBlock->RundownProtect,
                                           ExFastRefGetAdditionalReferenceCount () + 1)) {
            ASSERTMSG ("Callback block is already undergoing rundown", FALSE);
            return FALSE;
        }
    }

    //
    // Attempt to replace the existing object and balance all the reference counts
    //
    OldRef = ExFastRefCompareSwapObject (&CallBack->RoutineBlock,
                                         NewBlock,
                                         OldBlock);

    ReplacedBlock = ExFastRefGetObject (OldRef);

    //
    // See if the swap occured. If it didn't undo the original references we added.
    // If it did then release remaining references on the original
    //
    if (ReplacedBlock == OldBlock) {
        PKTHREAD CurrentThread;
        //
        // We need to flush out any slow referencers at this point. We do this by
        // acquiring and releasing a lock.
        //
        if (ReplacedBlock != NULL) {
            CurrentThread = KeGetCurrentThread ();

            KeEnterCriticalRegionThread (CurrentThread);

            ExAcquireReleasePushLockExclusive (&ExpCallBackFlush);

            KeLeaveCriticalRegionThread (CurrentThread);

            ExReleaseRundownProtectionEx (&ReplacedBlock->RundownProtect,
                                          ExFastRefGetUnusedReferences (OldRef) + 1);

        }
        return TRUE;
    } else {
        //
        // The swap failed. Remove the addition references if we had added any.
        //
        if (NewBlock != NULL) {
            ExReleaseRundownProtectionEx (&NewBlock->RundownProtect,
                                          ExFastRefGetAdditionalReferenceCount () + 1);
        }
        return FALSE;
    }
}