Example #1
0
NTSTATUS
NTAPI
PsSuspendProcess(IN PEPROCESS Process)
{
    PETHREAD Thread;
    PAGED_CODE();

    /* Lock the Process */
    if (!ExAcquireRundownProtection(&Process->RundownProtect))
    {
        /* Process is terminating */
        return STATUS_PROCESS_IS_TERMINATING;
    }

    /* Get the first thread */
    Thread = PsGetNextProcessThread(Process, NULL);
    while (Thread)
    {
        /* Resume it */
        PsSuspendThread(Thread, NULL);

        /* Move to the next thread */
        Thread = PsGetNextProcessThread(Process, Thread);
    }

    /* Unlock the process */
    ExReleaseRundownProtection(&Process->RundownProtect);
    return STATUS_SUCCESS;
}
Example #2
0
/* KphProtectAddEntry
 * 
 * Protects the specified process.
 * 
 * Thread safety: Full
 * IRQL: <= DISPATCH_LEVEL
 */
PKPH_PROCESS_ENTRY KphProtectAddEntry(
    __in PEPROCESS Process,
    __in HANDLE Tag,
    __in LOGICAL AllowKernelMode,
    __in ACCESS_MASK ProcessAllowMask,
    __in ACCESS_MASK ThreadAllowMask
    )
{
    KIRQL oldIrql;
    PKPH_PROCESS_ENTRY entry;
    
    /* Prevent the lookaside list from being freed. */
    if (!ExAcquireRundownProtection(&ProtectedProcessRundownProtect))
        return NULL;
    
    entry = ExAllocateFromNPagedLookasideList(&ProtectedProcessLookasideList);
    /* Lookaside list no longer needed. */
    ExReleaseRundownProtection(&ProtectedProcessRundownProtect);
    
    if (!entry)
        return NULL;
    
    entry->Process = Process;
    entry->CreatorProcess = PsGetCurrentProcess();
    entry->Tag = Tag;
    entry->AllowKernelMode = AllowKernelMode;
    entry->ProcessAllowMask = ProcessAllowMask;
    entry->ThreadAllowMask = ThreadAllowMask;
    
    KeAcquireSpinLock(&ProtectedProcessListLock, &oldIrql);
    InsertHeadList(&ProtectedProcessListHead, &entry->ListEntry);
    KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql);
    
    return entry;
}
Example #3
0
NTSTATUS EVhdNotifyRecoveryStatus(ParserInstance *parser, RecoveryStatusCompletionRoutine pfnCompletionCb, void *pInterface)
{
	PDEVICE_OBJECT pDeviceObject = NULL;
	if (parser->bResiliencyEnabled)
	{
		if (!ExAcquireRundownProtection(&parser->RecoveryRundownProtection))
			return STATUS_UNSUCCESSFUL;

		parser->pfnRecoveryStatusCallback = pfnCompletionCb;
		parser->pRecoveryStatusInterface = pInterface;

		IoReuseIrp(parser->pRecoveryStatusIrp, STATUS_PENDING);
		parser->pRecoveryStatusIrp->Tail.Overlay.Thread = (PETHREAD)__readgsqword(0x188);				// Pointer to calling thread control block
		PIO_STACK_LOCATION pStackFrame = IoGetNextIrpStackLocation(parser->pRecoveryStatusIrp);
		pDeviceObject = IoGetRelatedDeviceObject(parser->pVhdmpFileObject);
		pStackFrame->FileObject = parser->pVhdmpFileObject;
		pStackFrame->DeviceObject = pDeviceObject;
		pStackFrame->Parameters.DeviceIoControl.IoControlCode = IOCTL_STORAGE_VHD_NOTIFY_RECOVERY_STATUS;
		pStackFrame->Parameters.DeviceIoControl.InputBufferLength = 0;
		pStackFrame->Parameters.DeviceIoControl.OutputBufferLength = 0;
		pStackFrame->MajorFunction = IRP_MJ_DEVICE_CONTROL;
		pStackFrame->MinorFunction = 0;
		pStackFrame->Flags = 0;
		pStackFrame->Control = SL_INVOKE_ON_CANCEL | SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
		pStackFrame->Context = parser;
		pStackFrame->CompletionRoutine = EvhdRecoveryStatusCompletionRoutine;
		IoCallDriver(pDeviceObject, parser->pRecoveryStatusIrp);
		return STATUS_PENDING;
	}
	else
		return STATUS_UNSUCCESSFUL;
}
Example #4
0
NTSTATUS
PsReferenceProcessFilePointer (
    IN PEPROCESS Process,
    OUT PVOID *OutFileObject
    )

/*++

Routine Description:

    This routine returns a referenced pointer to the FilePointer of Process.  
    This is a rundown protected wrapper around MmGetFileObjectForSection.

Arguments:

    Process - Supplies the process to query.

    OutFileObject - Returns the file object backing the requested section if
                    success is returned.

Return Value:

    NTSTATUS.
    
Environment:

    Kernel mode, PASSIVE_LEVEL.

--*/

{
    PFILE_OBJECT FileObject;

    PAGED_CODE();
    
    if (!ExAcquireRundownProtection (&Process->RundownProtect)) {
        return STATUS_UNSUCCESSFUL;
    }

    if (Process->SectionObject == NULL) {
        ExReleaseRundownProtection (&Process->RundownProtect);
        return STATUS_UNSUCCESSFUL;
    }

    FileObject = MmGetFileObjectForSection ((PVOID)Process->SectionObject);

    *OutFileObject = FileObject;

    ObReferenceObject (FileObject);

    ExReleaseRundownProtection (&Process->RundownProtect);

    return STATUS_SUCCESS;
}
Example #5
0
/* KphNewOpenProcedure60
 * 
 * New process/thread open procedure for NT 6.0 and 6.1.
 */
NTSTATUS NTAPI KphNewOpenProcedure60(
    __in OB_OPEN_REASON OpenReason,
    __in KPROCESSOR_MODE AccessMode,
    __in PEPROCESS Process,
    __in PVOID Object,
    __in ACCESS_MASK GrantedAccess,
    __in ULONG HandleCount
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    BOOLEAN accessAllowed = TRUE;
    
    /* Prevent the driver from unloading while this routine is executing. */
    if (!ExAcquireRundownProtection(&ProtectedProcessRundownProtect))
    {
        /* Should never happen. */
        return STATUS_INTERNAL_ERROR;
    }
    
    accessAllowed = KphpIsAccessAllowed(
        Object,
        AccessMode,
        /* Assume worst case if granted access not available. */
        !GrantedAccess ? (ACCESS_MASK)-1 : GrantedAccess
        );
    
    if (accessAllowed)
    {
        POBJECT_TYPE objectType = KphGetObjectTypeNt(Object);
        
        /* Call the original open procedure. There shouldn't be any for Windows XP, 
         * while on Windows Vista and 7 it is used for implementing protected 
         * processes (Big Content's DRM protection, not KProcessHacker's protection).
         */
        status = KphObOpenCall(
            objectType == *PsProcessType ? &ProcessOpenHook : &ThreadOpenHook,
            OpenReason,
            AccessMode,
            Process,
            Object,
            GrantedAccess,
            HandleCount
            );
    }
    else
    {
        dprintf("KphNewOpenProcedure60: Access denied.\n");
        status = STATUS_ACCESS_DENIED;
    }
    
    ExReleaseRundownProtection(&ProtectedProcessRundownProtect);
    
    return status;
}
Example #6
0
/* KphpProtectRemoveEntry
 * 
 * Removes and frees process protection data.
 * 
 * Thread safety: Full
 * IRQL: <= DISPATCH_LEVEL
 */
VOID KphpProtectRemoveEntry(
    __in PKPH_PROCESS_ENTRY Entry
    )
{
    KIRQL oldIrql;
    
    KeAcquireSpinLock(&ProtectedProcessListLock, &oldIrql);
    RemoveEntryList(&Entry->ListEntry);
    
    /* Prevent the lookaside list from being destroyed. */
    ExAcquireRundownProtection(&ProtectedProcessRundownProtect);
    ExFreeToNPagedLookasideList(
        &ProtectedProcessLookasideList,
        Entry
        );
    ExReleaseRundownProtection(&ProtectedProcessRundownProtect);
    
    KeReleaseSpinLock(&ProtectedProcessListLock, oldIrql);
}
Example #7
0
/*
 * @implemented
 */
NTSTATUS
NTAPI
NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL,
                   IN NTSTATUS ExitStatus)
{
    NTSTATUS Status;
    PEPROCESS Process, CurrentProcess = PsGetCurrentProcess();
    PETHREAD Thread, CurrentThread = PsGetCurrentThread();
    BOOLEAN KillByHandle;
    PAGED_CODE();
    PSTRACE(PS_KILL_DEBUG,
            "ProcessHandle: %p ExitStatus: %d\n", ProcessHandle, ExitStatus);

    /* Were we passed a process handle? */
    if (ProcessHandle)
    {
        /* Yes we were, use it */
        KillByHandle = TRUE;
    }
    else
    {
        /* We weren't... we assume this is suicide */
        KillByHandle = FALSE;
        ProcessHandle = NtCurrentProcess();
    }

    /* Get the Process Object */
    Status = ObReferenceObjectByHandle(ProcessHandle,
                                       PROCESS_TERMINATE,
                                       PsProcessType,
                                       KeGetPreviousMode(),
                                       (PVOID*)&Process,
                                       NULL);
    if (!NT_SUCCESS(Status)) return(Status);

    /* Check if this is a Critical Process, and Bugcheck */
    if (Process->BreakOnTermination)
    {
        /* Break to debugger */
        PspCatchCriticalBreak("Terminating critical process 0x%p (%s)\n",
                              Process,
                              Process->ImageFileName);
    }

    /* Lock the Process */
    if (!ExAcquireRundownProtection(&Process->RundownProtect))
    {
        /* Failed to lock, fail */
        ObDereferenceObject(Process);
        return STATUS_PROCESS_IS_TERMINATING;
    }

    /* Set the delete flag, unless the process is comitting suicide */
    if (KillByHandle) PspSetProcessFlag(Process, PSF_PROCESS_DELETE_BIT);

    /* Get the first thread */
    Status = STATUS_NOTHING_TO_TERMINATE;
    Thread = PsGetNextProcessThread(Process, NULL);
    if (Thread)
    {
        /* We know we have at least a thread */
        Status = STATUS_SUCCESS;

        /* Loop and kill the others */
        do
        {
            /* Ensure it's not ours*/
            if (Thread != CurrentThread)
            {
                /* Kill it */
                PspTerminateThreadByPointer(Thread, ExitStatus, FALSE);
            }

            /* Move to the next thread */
            Thread = PsGetNextProcessThread(Process, Thread);
        } while (Thread);
    }

    /* Unlock the process */
    ExReleaseRundownProtection(&Process->RundownProtect);

    /* Check if we are killing ourselves */
    if (Process == CurrentProcess)
    {
        /* Also make sure the caller gave us our handle */
        if (KillByHandle)
        {
            /* Dereference the process */
            ObDereferenceObject(Process);

            /* Terminate ourselves */
            PspTerminateThreadByPointer(CurrentThread, ExitStatus, TRUE);
        }
    }
    else if (ExitStatus == DBG_TERMINATE_PROCESS)
    {
        /* Disable debugging on this process */
        DbgkClearProcessDebugObject(Process, NULL);
    }

    /* Check if there was nothing to terminate, or if we have a Debug Port */
    if ((Status == STATUS_NOTHING_TO_TERMINATE) ||
        ((Process->DebugPort) && (KillByHandle)))
    {
        /* Clear the handle table */
        ObClearProcessHandleTable(Process);

        /* Return status now */
        Status = STATUS_SUCCESS;
    }

    /* Decrease the reference count we added */
    ObDereferenceObject(Process);

    /* Return status */
    return Status;
}
Example #8
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 from the untrusted ThreadContext */
        _SEH2_TRY
        {
            Thread->StartAddress = (PVOID)KeGetContextPc(ThreadContext);
            Thread->Win32StartAddress = (PVOID)KeGetContextReturnRegister(ThreadContext);
        }
        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
        {
            Status = _SEH2_GetExceptionCode();
        }
        _SEH2_END;

        /* Let the kernel intialize the Thread */
        if (NT_SUCCESS(Status))
        {
            Status = KeInitThread(&Thread->Tcb,
                                  NULL,
                                  PspUserThreadStartup,
                                  NULL,
                                  Thread->StartAddress,
                                  ThreadContext,
                                  TebBase,
                                  &Process->Pcb);
        }
    }
    else
    {
Example #9
0
File: job.c Project: RPG-7/reactos
/*
 * @unimplemented
 */
NTSTATUS
NTAPI
NtAssignProcessToJobObject (
    HANDLE JobHandle,
    HANDLE ProcessHandle)
{
    PEPROCESS Process;
    KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;

    PAGED_CODE();

    PreviousMode = ExGetPreviousMode();

    /* make sure we're having a handle with enough rights, especially the to
    terminate the process. otherwise one could abuse the job objects to
    terminate processes without having rights granted to do so! The reason
    I open the process handle before the job handle is that a simple test showed
    that it first complains about a invalid process handle! The other way around
    would be simpler though... */
    Status = ObReferenceObjectByHandle(
        ProcessHandle,
        PROCESS_TERMINATE,
        PsProcessType,
        PreviousMode,
        (PVOID*)&Process,
        NULL);
    if(NT_SUCCESS(Status))
    {
        if(Process->Job == NULL)
        {
            PEJOB Job;

            Status = ObReferenceObjectByHandle(
                JobHandle,
                JOB_OBJECT_ASSIGN_PROCESS,
                PsJobType,
                PreviousMode,
                (PVOID*)&Job,
                NULL);
            if(NT_SUCCESS(Status))
            {
                /* lock the process so we can safely assign the process. Note that in the
                meanwhile another thread could have assigned this process to a job! */

                ExAcquireRundownProtection(&Process->RundownProtect);
                if(NT_SUCCESS(Status))
                {
                    if(Process->Job == NULL && PsGetProcessSessionId(Process) == Job->SessionId)
                    {
                        /* Just store the pointer to the job object in the process, we'll
                        assign it later. The reason we can't do this here is that locking
                        the job object might require it to wait, which is a bad thing
                        while holding the process lock! */
                        Process->Job = Job;
                    }
                    else
                    {
                        /* process is already assigned to a job or session id differs! */
                        Status = STATUS_ACCESS_DENIED;
                    }
                    ExReleaseRundownProtection(&Process->RundownProtect);

                    if(NT_SUCCESS(Status))
                    {
                        /* let's actually assign the process to the job as we're not holding
                        the process lock anymore! */
                        Status = PspAssignProcessToJob(Process, Job);
                    }
                }

                ObDereferenceObject(Job);
            }
        }
        else
        {
            /* process is already assigned to a job or session id differs! */
            Status = STATUS_ACCESS_DENIED;
        }

        ObDereferenceObject(Process);
    }

    return Status;
}
Example #10
0
NTSTATUS
NTAPI
PsSuspendThread(IN PETHREAD Thread,
                OUT PULONG PreviousCount OPTIONAL)
{
    NTSTATUS Status;
    ULONG OldCount = 0;
    PAGED_CODE();

    /* Guard with SEH because KeSuspendThread can raise an exception */
    _SEH2_TRY
    {
        /* Check if we're suspending ourselves */
        if (Thread == PsGetCurrentThread())
        {
            /* Do the suspend */
            OldCount = KeSuspendThread(&Thread->Tcb);

            /* We are done */
            Status = STATUS_SUCCESS;
        }
        else
        {
            /* Acquire rundown */
            if (ExAcquireRundownProtection(&Thread->RundownProtect))
            {
                /* Make sure the thread isn't terminating */
                if (Thread->Terminated)
                {
                    /* Fail */
                    Status = STATUS_THREAD_IS_TERMINATING;
                }
                else
                {
                    /* Otherwise, do the suspend */
                    OldCount = KeSuspendThread(&Thread->Tcb);

                    /* Check if it terminated during the suspend */
                    if (Thread->Terminated)
                    {
                        /* Wake it back up and fail */
                        KeForceResumeThread(&Thread->Tcb);
                        Status = STATUS_THREAD_IS_TERMINATING;
                        OldCount = 0;
                    }
                }

                /* Release rundown protection */
                ExReleaseRundownProtection(&Thread->RundownProtect);

                /* We are done */
                Status = STATUS_SUCCESS;
            }
            else
            {
                /* Thread is terminating */
                Status = STATUS_THREAD_IS_TERMINATING;
            }
        }
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
        /* Get the exception code */
        Status = _SEH2_GetExceptionCode();

        /* Don't fail if we merely couldn't write the handle back */
        if (Status != STATUS_SUSPEND_COUNT_EXCEEDED) Status = STATUS_SUCCESS;
    }
    _SEH2_END;

    /* Write back the previous count */
    if (PreviousCount) *PreviousCount = OldCount;
    return Status;
}
Example #11
0
NTSTATUS
NTAPI
PspWriteTebImpersonationInfo(IN PETHREAD Thread,
                             IN PETHREAD CurrentThread)
{
    PEPROCESS Process;
    PTEB Teb;
    BOOLEAN Attached = FALSE;
    BOOLEAN IsImpersonating;
    KAPC_STATE ApcState;
    PAGED_CODE();
    PSTRACE(PS_SECURITY_DEBUG, "Thread: %p\n", Thread);

    /* Sanity check */
    ASSERT(CurrentThread == PsGetCurrentThread());

    /* Get process and TEB */
    Process = Thread->ThreadsProcess;
    Teb = Thread->Tcb.Teb;
    if (Teb)
    {
        /* Check if we're not in the right process */
        if (Thread->Tcb.ApcState.Process != &Process->Pcb)
        {
            /* Attach to the process */
            KeStackAttachProcess(&Process->Pcb, &ApcState);
            Attached = TRUE;
        }

        /* Check if we're in a different thread or acquire rundown */
        if ((Thread == CurrentThread) ||
            (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 we're in a different thread */
        if (Thread != CurrentThread)
        {
            /* Release protection */
            ExReleaseRundownProtection(&Thread->RundownProtect);
        }

        /* Detach */
        if (Attached) KeUnstackDetachProcess(&ApcState);
    }

    /* Return to caller */
    return STATUS_SUCCESS;
}
Example #12
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;
}
Example #13
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
    {