Exemplo n.º 1
0
VOID
LpcpDeletePort (
    IN PVOID Object
    )

/*++

Routine Description:

    This routine is the callback used for deleting a port object.

Arguments:

    Object - Supplies a pointer to the port object being deleted

Return Value:

    None.

--*/

{
    PETHREAD CurrentThread;
    PLPCP_PORT_OBJECT Port = Object;
    PLPCP_PORT_OBJECT ConnectionPort;
    LPC_CLIENT_DIED_MSG ClientPortClosedDatagram;
    PLPCP_MESSAGE Msg;
    PLIST_ENTRY Head, Next;
    HANDLE CurrentProcessId;
    NTSTATUS Status;
    LARGE_INTEGER RetryInterval = {(ULONG)(-10 * 1000 * 100), -1}; // 100 milliseconds

    PAGED_CODE();

    CurrentThread = PsGetCurrentThread ();

    //
    //  If the port is a server communication port then make sure that if
    //  there is a dangling client thread that we get rid of it.  This
    //  handles the case of someone calling NtAcceptConnectPort and not
    //  calling NtCompleteConnectPort
    //

    if ((Port->Flags & PORT_TYPE) == SERVER_COMMUNICATION_PORT) {

        PETHREAD ClientThread;

        LpcpAcquireLpcpLockByThread(CurrentThread);

        if ((ClientThread = Port->ClientThread) != NULL) {

            Port->ClientThread = NULL;

            LpcpReleaseLpcpLock();

            ObDereferenceObject( ClientThread );

        } else {

            LpcpReleaseLpcpLock();
        }
    }

    //
    //  Send an LPC_PORT_CLOSED datagram to whoever is connected
    //  to this port so they know they are no longer connected.
    //

    if ((Port->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) {

        ClientPortClosedDatagram.PortMsg.u1.s1.TotalLength = sizeof( ClientPortClosedDatagram );
        ClientPortClosedDatagram.PortMsg.u1.s1.DataLength = sizeof( ClientPortClosedDatagram.CreateTime );

        ClientPortClosedDatagram.PortMsg.u2.s2.Type = LPC_PORT_CLOSED;
        ClientPortClosedDatagram.PortMsg.u2.s2.DataInfoOffset = 0;

        ClientPortClosedDatagram.CreateTime = PsGetCurrentProcess()->CreateTime;

        Status = LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram );

        while (Status == STATUS_NO_MEMORY) {

            KeDelayExecutionThread(KernelMode, FALSE, &RetryInterval);

            Status = LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram );
        }
    }

    //
    //  If connected, disconnect the port, and then scan the message queue
    //  for this port and dereference any messages in the queue.
    //

    LpcpDestroyPortQueue( Port, TRUE );

    //
    //  If we had mapped sections into the server or client communication ports,
    //  we need to unmap them in the context of that process.
    //

    if ( (Port->ClientSectionBase != NULL) ||
         (Port->ServerSectionBase != NULL) ) {

        //
        //  If the client has a port memory view, then unmap it
        //

        if (Port->ClientSectionBase != NULL) {

            MmUnmapViewOfSection( Port->MappingProcess,
                                  Port->ClientSectionBase );

        }

        //
        //  If the server has a port memory view, then unmap it
        //

        if (Port->ServerSectionBase != NULL) {

            MmUnmapViewOfSection( Port->MappingProcess,
                                  Port->ServerSectionBase  );

        }

        //
        //  Removing the reference added while mapping the section
        //

        ObDereferenceObject( Port->MappingProcess );

        Port->MappingProcess = NULL;
    }

    //
    //  Dereference the pointer to the connection port if it is not
    //  this port.
    //

    LpcpAcquireLpcpLockByThread(CurrentThread);

    ConnectionPort = Port->ConnectionPort;

    if (ConnectionPort) {

        CurrentProcessId = CurrentThread->Cid.UniqueProcess;

        Head = &ConnectionPort->LpcDataInfoChainHead;
        Next = Head->Flink;

        while (Next != Head) {

            Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry );
            Next = Next->Flink;
            
            if (Port == ConnectionPort) {

                //
                //  If the Connection port is going away free all queued messages
                //

                RemoveEntryList( &Msg->Entry );
                InitializeListHead( &Msg->Entry );

                LpcpFreeToPortZone( Msg, LPCP_MUTEX_OWNED );

                //
                //  In LpcpFreeToPortZone the LPC lock is released and reacquired.
                //  Another thread might free the LPC message captured above
                //  in Next. We need to restart the search at the list head.
                //

                Next = Head->Flink;

            } else if ((Msg->Request.ClientId.UniqueProcess == CurrentProcessId)
                    &&
                ((Msg->SenderPort == Port) 
                        || 
                 (Msg->SenderPort == Port->ConnectedPort) 
                        || 
                 (Msg->SenderPort == ConnectionPort))) {

                //
                //  Test whether the message come from the same port and process
                //

                LpcpTrace(( "%s Freeing DataInfo Message %lx (%u.%u)  Port: %lx\n",
                            PsGetCurrentProcess()->ImageFileName,
                            Msg,
                            Msg->Request.MessageId,
                            Msg->Request.CallbackId,
                            ConnectionPort ));

                RemoveEntryList( &Msg->Entry );
                InitializeListHead( &Msg->Entry );

                LpcpFreeToPortZone( Msg, LPCP_MUTEX_OWNED );

                //
                //  In LpcpFreeToPortZone the LPC lock is released and reacquired.
                //  Another thread might free the LPC message captured above
                //  in Next. We need to restart the search at the list head.
                //

                Next = Head->Flink;
            }
        }

        LpcpReleaseLpcpLock();

        if (ConnectionPort != Port) {

            ObDereferenceObject( ConnectionPort );
        }

    } else {

        LpcpReleaseLpcpLock();
    }

    if (((Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) &&
        (ConnectionPort->ServerProcess != NULL)) {

        ObDereferenceObject( ConnectionPort->ServerProcess );

        ConnectionPort->ServerProcess = NULL;
    }

    //
    //  Free any static client security context
    //

    LpcpFreePortClientSecurity( Port );

    //
    //  And return to our caller
    //

    return;
}
Exemplo n.º 2
0
/*
 * FUNCTION: Terminates the current thread
 * See "Windows Internals" - Chapter 13, Page 50-53
 */
VOID
NTAPI
PspExitThread(IN NTSTATUS ExitStatus)
{
    CLIENT_DIED_MSG TerminationMsg;
    NTSTATUS Status;
    PTEB Teb;
    PEPROCESS CurrentProcess;
    PETHREAD Thread, OtherThread, PreviousThread = NULL;
    PVOID DeallocationStack;
    SIZE_T Dummy;
    BOOLEAN Last = FALSE;
    PTERMINATION_PORT TerminationPort, NextPort;
    PLIST_ENTRY FirstEntry, CurrentEntry;
    PKAPC Apc;
    PTOKEN PrimaryToken;
    PAGED_CODE();
    PSTRACE(PS_KILL_DEBUG, "ExitStatus: %d\n", ExitStatus);

    /* Get the Current Thread and Process */
    Thread = PsGetCurrentThread();
    CurrentProcess = Thread->ThreadsProcess;
    ASSERT((Thread) == PsGetCurrentThread());

    /* Can't terminate a thread if it attached another process */
    if (KeIsAttachedProcess())
    {
        /* Bugcheck */
        KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
                     (ULONG_PTR)CurrentProcess,
                     (ULONG_PTR)Thread->Tcb.ApcState.Process,
                     (ULONG_PTR)Thread->Tcb.ApcStateIndex,
                     (ULONG_PTR)Thread);
    }

    /* Lower to Passive Level */
    KeLowerIrql(PASSIVE_LEVEL);

    /* Can't be a worker thread */
    if (Thread->ActiveExWorker)
    {
        /* Bugcheck */
        KeBugCheckEx(ACTIVE_EX_WORKER_THREAD_TERMINATION,
                     (ULONG_PTR)Thread,
                     0,
                     0,
                     0);
    }

    /* Can't have pending APCs */
    if (Thread->Tcb.CombinedApcDisable != 0)
    {
        /* Bugcheck */
        KeBugCheckEx(KERNEL_APC_PENDING_DURING_EXIT,
                     0,
                     Thread->Tcb.CombinedApcDisable,
                     0,
                     1);
    }

    /* Lock the thread */
    ExWaitForRundownProtectionRelease(&Thread->RundownProtect);

    /* Cleanup the power state */
    PopCleanupPowerState((PPOWER_STATE)&Thread->Tcb.PowerState);

    /* Call the WMI Callback for Threads */
    //WmiTraceThread(Thread, NULL, FALSE);

    /* Run Thread Notify Routines before we desintegrate the thread */
    PspRunCreateThreadNotifyRoutines(Thread, FALSE);

    /* Lock the Process before we modify its thread entries */
    KeEnterCriticalRegion();
    ExAcquirePushLockExclusive(&CurrentProcess->ProcessLock);

    /* Decrease the active thread count, and check if it's 0 */
    if (!(--CurrentProcess->ActiveThreads))
    {
        /* Set the delete flag */
        InterlockedOr((PLONG)&CurrentProcess->Flags, PSF_PROCESS_DELETE_BIT);

        /* Remember we are last */
        Last = TRUE;

        /* Check if this termination is due to the thread dying */
        if (ExitStatus == STATUS_THREAD_IS_TERMINATING)
        {
            /* Check if the last thread was pending */
            if (CurrentProcess->ExitStatus == STATUS_PENDING)
            {
                /* Use the last exit status */
                CurrentProcess->ExitStatus = CurrentProcess->
                                             LastThreadExitStatus;
            }
        }
        else
        {
            /* Just a normal exit, write the code */
            CurrentProcess->ExitStatus = ExitStatus;
        }

        /* 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)
    {
        /* Write down the exit status of the last thread to get killed */
        CurrentProcess->LastThreadExitStatus = ExitStatus;
    }

    /* Unlock the Process */
    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))
    {
        /* Notify the Debug API. */
        Last ? DbgkExitProcess(CurrentProcess->ExitStatus) :
               DbgkExitThread(ExitStatus);
    }

    /* Check if this is a Critical Thread */
    if ((KdDebuggerEnabled) && (Thread->BreakOnTermination))
    {
        /* Break to debugger */
        PspCatchCriticalBreak("Critical thread 0x%p (in %s) exited\n",
                              Thread,
                              CurrentProcess->ImageFileName);
    }

    /* Check if it's the last thread and this is a Critical Process */
    if ((Last) && (CurrentProcess->BreakOnTermination))
    {
        /* Check if a debugger is here to handle this */
        if (KdDebuggerEnabled)
        {
            /* Break to debugger */
            PspCatchCriticalBreak("Critical  process 0x%p (in %s) exited\n",
                                  CurrentProcess,
                                  CurrentProcess->ImageFileName);
        }
        else
        {
            /* Bugcheck, we can't allow this */
            KeBugCheckEx(CRITICAL_PROCESS_DIED,
                         (ULONG_PTR)CurrentProcess,
                         0,
                         0,
                         0);
        }
    }

    /* Sanity check */
    ASSERT(Thread->Tcb.CombinedApcDisable == 0);

    /* Process the Termination Ports */
    TerminationPort = Thread->TerminationPort;
    if (TerminationPort)
    {
        /* Setup the message header */
        TerminationMsg.h.u2.ZeroInit = 0;
        TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED;
        TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg);
        TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) -
                                            sizeof(PORT_MESSAGE);

        /* Loop each port */
        do
        {
            /* Save the Create Time */
            TerminationMsg.CreateTime = Thread->CreateTime;

            /* Loop trying to send message */
            while (TRUE)
            {
                /* 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 */
            ObDereferenceObject(TerminationPort->Port);

            /* Move to the next one */
            NextPort = TerminationPort->Next;

            /* Free the Termination Port Object */
            ExFreePoolWithTag(TerminationPort, '=TsP');

            /* Keep looping as long as there is a port */
            TerminationPort = NextPort;
        } while (TerminationPort);
    }
    else if (((ExitStatus == STATUS_THREAD_IS_TERMINATING) &&
              (Thread->DeadThread)) ||
             !(Thread->DeadThread))
    {
        /*
         * This case is special and deserves some extra comments. What
         * basically happens here is that this thread doesn't have a termination
         * port, which means that it died before being fully created. Since we
         * still have to notify an LPC Server, we'll use the exception port,
         * which we know exists. However, we need to know how far the thread
         * actually got created. We have three possibilities:
         *
         *  - NtCreateThread returned an error really early: DeadThread is set.
         *  - NtCreateThread managed to create the thread: DeadThread is off.
         *  - NtCreateThread was creating the thread (with DeadThread set,
         *    but the thread got killed prematurely: STATUS_THREAD_IS_TERMINATING
         *    is our exit code.)
         *
         * For the 2 & 3rd scenarios, the thread has been created far enough to
         * warrant notification to the LPC Server.
         */

        /* Setup the message header */
        TerminationMsg.h.u2.ZeroInit = 0;
        TerminationMsg.h.u2.s2.Type = LPC_CLIENT_DIED;
        TerminationMsg.h.u1.s1.TotalLength = sizeof(TerminationMsg);
        TerminationMsg.h.u1.s1.DataLength = sizeof(TerminationMsg) -
                                            sizeof(PORT_MESSAGE);

        /* Make sure the process has an exception port */
        if (CurrentProcess->ExceptionPort)
        {
            /* Save the Create Time */
            TerminationMsg.CreateTime = Thread->CreateTime;

            /* Loop trying to send message */
            while (TRUE)
            {
                /* 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;
            }
        }
    }

    /* Rundown Win32 Thread if there is one */
    if (Thread->Tcb.Win32Thread) PspW32ThreadCallout(Thread,
                                                     PsW32ThreadCalloutExit);

    /* If we are the last thread and have a W32 Process */
    if ((Last) && (CurrentProcess->Win32Process))
    {
        /* Run it down too */
        PspW32ProcessCallout(CurrentProcess, FALSE);
    }

    /* Make sure Stack Swap is enabled */
    if (!Thread->Tcb.EnableStackSwap)
    {
        /* Stack swap really shouldn't be disabled during exit! */
        KeBugCheckEx(KERNEL_STACK_LOCKED_AT_EXIT, 0, 0, 0, 0);
    }

    /* Cancel I/O for the thread. */
    IoCancelThreadIo(Thread);

    /* Rundown Timers */
    ExTimerRundown();

    /* FIXME: Rundown Registry Notifications (NtChangeNotify)
    CmNotifyRunDown(Thread); */

    /* Rundown Mutexes */
    KeRundownThread();

    /* Check if we have a TEB */
    Teb = Thread->Tcb.Teb;
    if (Teb)
    {
        /* Check if the thread is still alive */
        if (!Thread->DeadThread)
        {
            /* 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 debug handle */
            if (Teb->DbgSsReserved[1]) ObCloseHandle(Teb->DbgSsReserved[1],
                                                     UserMode);
        }

        /* Decommit the TEB */
        MmDeleteTeb(CurrentProcess, Teb);
        Thread->Tcb.Teb = NULL;
    }

    /* Free LPC Data */
    LpcExitThread(Thread);

    /* Save the exit status and exit time */
    Thread->ExitStatus = ExitStatus;
    KeQuerySystemTime(&Thread->ExitTime);

    /* Sanity check */
    ASSERT(Thread->Tcb.CombinedApcDisable == 0);

    /* Check if this is the final thread or not */
    if (Last)
    {
        /* Set the process exit time */
        CurrentProcess->ExitTime = Thread->ExitTime;

        /* Exit the process */
        PspExitProcess(TRUE, CurrentProcess);

        /* Get the process token and check if we need to audit */
        PrimaryToken = PsReferencePrimaryToken(CurrentProcess);
        if (SeDetailedAuditingWithToken(PrimaryToken))
        {
            /* Audit the exit */
            SeAuditProcessExit(CurrentProcess);
        }

        /* Dereference the process token */
        ObFastDereferenceObject(&CurrentProcess->Token, PrimaryToken);

        /* Check if this is a VDM Process and rundown the VDM DPCs if so */
        if (CurrentProcess->VdmObjects) { /* VdmRundownDpcs(CurrentProcess); */ }

        /* Kill the process in the Object Manager */
        ObKillProcess(CurrentProcess);

        /* Check if we have a section object */
        if (CurrentProcess->SectionObject)
        {
            /* Dereference and clear the Section Object */
            ObDereferenceObject(CurrentProcess->SectionObject);
            CurrentProcess->SectionObject = NULL;
        }

        /* Check if the process is part of a job */
        if (CurrentProcess->Job)
        {
            /* Remove the process from the job */
            PspExitProcessFromJob(CurrentProcess->Job, CurrentProcess);
        }
    }

    /* Disable APCs */
    KeEnterCriticalRegion();

    /* Disable APC queueing, force a resumption */
    Thread->Tcb.ApcQueueable = FALSE;
    KeForceResumeThread(&Thread->Tcb);

    /* Re-enable APCs */
    KeLeaveCriticalRegion();

    /* Flush the User APCs */
    FirstEntry = KeFlushQueueApc(&Thread->Tcb, UserMode);
    if (FirstEntry)
    {
        /* Start with the first entry */
        CurrentEntry = FirstEntry;
        do
        {
           /* Get the APC */
           Apc = CONTAINING_RECORD(CurrentEntry, KAPC, ApcListEntry);

           /* Move to the next one */
           CurrentEntry = CurrentEntry->Flink;

           /* Rundown the APC or de-allocate it */
           if (Apc->RundownRoutine)
           {
              /* Call its own routine */
              Apc->RundownRoutine(Apc);
           }
           else
           {
              /* Do it ourselves */
              ExFreePool(Apc);
           }
        }
        while (CurrentEntry != FirstEntry);
    }

    /* Clean address space if this was the last thread */
    if (Last) MmCleanProcessAddressSpace(CurrentProcess);

    /* Call the Lego routine */
    if (Thread->Tcb.LegoData) PspRunLegoRoutine(&Thread->Tcb);

    /* Flush the APC queue, which should be empty */
    FirstEntry = KeFlushQueueApc(&Thread->Tcb, KernelMode);
    if ((FirstEntry) || (Thread->Tcb.CombinedApcDisable != 0))
    {
        /* Bugcheck time */
        KeBugCheckEx(KERNEL_APC_PENDING_DURING_EXIT,
                     (ULONG_PTR)FirstEntry,
                     Thread->Tcb.CombinedApcDisable,
                     KeGetCurrentIrql(),
                     0);
    }

    /* Signal the process if this was the last thread */
    if (Last) KeSetProcess(&CurrentProcess->Pcb, 0, FALSE);

    /* Terminate the Thread from the Scheduler */
    KeTerminateThread(0);
}
Exemplo n.º 3
0
/*
 * Function copied from ntdll/csr/connect.c::CsrClientCallServer
 * and adapted for kernel-mode.
 *
 * NOTE: This is really a co_* function!
 */
NTSTATUS
NTAPI
CsrClientCallServer(IN OUT PCSR_API_MESSAGE ApiMessage,
                    IN OUT PCSR_CAPTURE_BUFFER CaptureBuffer OPTIONAL,
                    IN CSR_API_NUMBER ApiNumber,
                    IN ULONG DataLength)
{
    NTSTATUS Status;
#if 0
    ULONG PointerCount;
    PULONG_PTR OffsetPointer;
#endif

    /* Do we have a connection to CSR yet? */
    if (!CsrApiPort)
        return STATUS_INVALID_PORT_HANDLE;

    /* Fill out the Port Message Header */
    ApiMessage->Header.u2.ZeroInit = 0;
    ApiMessage->Header.u1.s1.TotalLength = DataLength +
        sizeof(CSR_API_MESSAGE) - sizeof(ApiMessage->Data); // FIELD_OFFSET(CSR_API_MESSAGE, Data) + DataLength;
    ApiMessage->Header.u1.s1.DataLength = DataLength +
        FIELD_OFFSET(CSR_API_MESSAGE, Data) - sizeof(ApiMessage->Header); // ApiMessage->Header.u1.s1.TotalLength - sizeof(PORT_MESSAGE);

    /* Fill out the CSR Header */
    ApiMessage->ApiNumber = ApiNumber;
    ApiMessage->CsrCaptureData = NULL;

    TRACE("API: %lx, u1.s1.DataLength: %x, u1.s1.TotalLength: %x\n",
          ApiNumber,
          ApiMessage->Header.u1.s1.DataLength,
          ApiMessage->Header.u1.s1.TotalLength);

#if 0
    /* Check if we got a Capture Buffer */
    if (CaptureBuffer)
    {
        /*
         * We have to convert from our local (client) view
         * to the remote (server) view.
         */
        ApiMessage->CsrCaptureData = (PCSR_CAPTURE_BUFFER)
            ((ULONG_PTR)CaptureBuffer + CsrPortMemoryDelta);

        /* Lock the buffer. */
        CaptureBuffer->BufferEnd = NULL;

        /*
         * Each client pointer inside the CSR message is converted into
         * a server pointer, and each pointer to these message pointers
         * is converted into an offset.
         */
        PointerCount  = CaptureBuffer->PointerCount;
        OffsetPointer = CaptureBuffer->PointerOffsetsArray;
        while (PointerCount--)
        {
            if (*OffsetPointer != 0)
            {
                *(PULONG_PTR)*OffsetPointer += CsrPortMemoryDelta;
                *OffsetPointer -= (ULONG_PTR)ApiMessage;
            }
            ++OffsetPointer;
        }
    }
#endif

    UserLeaveCo();

    /* Send the LPC Message */

    // The wait logic below is subject to change in the future. One can
    // imagine adding an external parameter to CsrClientCallServer, or write
    // two versions of CsrClientCallServer, synchronous and asynchronous.
    if (PsGetCurrentProcess() == gpepCSRSS)
    {
        Status = LpcRequestPort(CsrApiPort,
                                &ApiMessage->Header);
    }
    else
    {
        Status = LpcRequestWaitReplyPort(CsrApiPort,
                                         &ApiMessage->Header,
                                         &ApiMessage->Header);
    }

    UserEnterCo();

#if 0
    /* Check if we got a Capture Buffer */
    if (CaptureBuffer)
    {
        /*
         * We have to convert back from the remote (server) view
         * to our local (client) view.
         */
        ApiMessage->CsrCaptureData = (PCSR_CAPTURE_BUFFER)
            ((ULONG_PTR)ApiMessage->CsrCaptureData - CsrPortMemoryDelta);

        /*
         * Convert back the offsets into pointers to CSR message
         * pointers, and convert back these message server pointers
         * into client pointers.
         */
        PointerCount  = CaptureBuffer->PointerCount;
        OffsetPointer = CaptureBuffer->PointerOffsetsArray;
        while (PointerCount--)
        {
            if (*OffsetPointer != 0)
            {
                *OffsetPointer += (ULONG_PTR)ApiMessage;
                *(PULONG_PTR)*OffsetPointer -= CsrPortMemoryDelta;
            }
            ++OffsetPointer;
        }
    }
#endif

    /* Check for success */
    if (!NT_SUCCESS(Status))
    {
        /* We failed. Overwrite the return value with the failure. */
        ERR("LPC Failed: %lx\n", Status);
        ApiMessage->Status = Status;
    }

    /* Return the CSR Result */
    TRACE("Got back: 0x%lx\n", ApiMessage->Status);
    return ApiMessage->Status;
}
Exemplo n.º 4
0
VOID
NTAPI
LpcpDeletePort(IN PVOID ObjectBody)
{
    LARGE_INTEGER Timeout;
    PETHREAD Thread;
    PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)ObjectBody;
    PLPCP_PORT_OBJECT ConnectionPort;
    PLPCP_MESSAGE Message;
    PLIST_ENTRY ListHead, NextEntry;
    HANDLE Pid;
    CLIENT_DIED_MSG ClientDiedMsg;

    PAGED_CODE();
    LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);

    Timeout.QuadPart = -1000000;

    /* Check if this is a communication port */
    if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_COMMUNICATION_PORT)
    {
        /* Acquire the lock */
        KeAcquireGuardedMutex(&LpcpLock);

        /* Get the thread */
        Thread = Port->ClientThread;
        if (Thread)
        {
            /* Clear it */
            Port->ClientThread = NULL;

            /* Release the lock and dereference */
            KeReleaseGuardedMutex(&LpcpLock);
            ObDereferenceObject(Thread);
        }
        else
        {
            /* Release the lock */
            KeReleaseGuardedMutex(&LpcpLock);
        }
    }

    /* Check if this is a client-side port */
    if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
    {
        /* Setup the client died message */
        ClientDiedMsg.h.u1.s1.TotalLength = sizeof(ClientDiedMsg);
        ClientDiedMsg.h.u1.s1.DataLength = sizeof(ClientDiedMsg.CreateTime);
        ClientDiedMsg.h.u2.ZeroInit = 0;
        ClientDiedMsg.h.u2.s2.Type = LPC_PORT_CLOSED;
        ClientDiedMsg.CreateTime = PsGetCurrentProcess()->CreateTime;

        /* Send it */
        for (;;)
        {
            /* Send the message */
            if (LpcRequestPort(Port, &ClientDiedMsg.h) != STATUS_NO_MEMORY)
                break;

            /* Wait until trying again */
            KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
        }
    }

    /* Destroy the port queue */
    LpcpDestroyPortQueue(Port, TRUE);

    /* Check if we had views */
    if ((Port->ClientSectionBase) || (Port->ServerSectionBase))
    {
        /* Check if we had a client view */
        if (Port->ClientSectionBase)
        {
            /* Unmap it */
            MmUnmapViewOfSection(Port->MappingProcess,
                                 Port->ClientSectionBase);
        }

        /* Check for a server view */
        if (Port->ServerSectionBase)
        {
            /* Unmap it */
            MmUnmapViewOfSection(Port->MappingProcess,
                                 Port->ServerSectionBase);
        }

        /* Dereference the mapping process */
        ObDereferenceObject(Port->MappingProcess);
        Port->MappingProcess = NULL;
    }

    /* Acquire the lock */
    KeAcquireGuardedMutex(&LpcpLock);

    /* Get the connection port */
    ConnectionPort = Port->ConnectionPort;
    if (ConnectionPort)
    {
        /* Get the PID */
        Pid = PsGetCurrentProcessId();

        /* Loop the data lists */
        ListHead = &ConnectionPort->LpcDataInfoChainHead;
        NextEntry = ListHead->Flink;
        while (NextEntry != ListHead)
        {
            /* Get the message */
            Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
            NextEntry = NextEntry->Flink;

            /* Check if this is the connection port */
            if (Port == ConnectionPort)
            {
                /* Free queued messages */
                RemoveEntryList(&Message->Entry);
                InitializeListHead(&Message->Entry);
                LpcpFreeToPortZone(Message, LPCP_LOCK_HELD);

                /* Restart at the head */
                NextEntry = ListHead->Flink;
            }
            else if ((Message->Request.ClientId.UniqueProcess == Pid) &&
                     ((Message->SenderPort == Port) ||
                      (Message->SenderPort == Port->ConnectedPort) ||
                      (Message->SenderPort == ConnectionPort)))
            {
                /* Remove it */
                RemoveEntryList(&Message->Entry);
                InitializeListHead(&Message->Entry);
                LpcpFreeToPortZone(Message, LPCP_LOCK_HELD);

                /* Restart at the head */
                NextEntry = ListHead->Flink;
            }
        }

        /* Release the lock */
        KeReleaseGuardedMutex(&LpcpLock);

        /* Dereference the object unless it's the same port */
        if (ConnectionPort != Port) ObDereferenceObject(ConnectionPort);

        /* Check if this is a connection port with a server process */
        if (((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT) &&
            (ConnectionPort->ServerProcess))
        {
            /* Dereference the server process */
            ObDereferenceObject(ConnectionPort->ServerProcess);
            ConnectionPort->ServerProcess = NULL;
        }
    }
    else
    {
        /* Release the lock */
        KeReleaseGuardedMutex(&LpcpLock);
    }

    /* Free client security */
    LpcpFreePortClientSecurity(Port);
    LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p deleted\n", Port);
}
Exemplo n.º 5
0
BOOL xxxActivateDebugger(
    UINT fsModifiers)
{
    ULONG ArgLength;
    USER_API_MSG m;
    PACTIVATEDEBUGGERMSG a = &m.u.ActivateDebugger;
    PEPROCESS Process;
    HANDLE hDebugPort;
    NTSTATUS Status;

    if (fsModifiers & MOD_CONTROL) {
#ifdef DEBUG
        if (RipOutput(0, RIP_WARNING, "User debugger", 0, "Debug prompt", NULL)) {
            DbgBreakPoint();
        }
#endif
        return FALSE;
    } else if (fsModifiers & MOD_SHIFT) {

        /*
         * Bail out if the process is not being debugged.
         */
        if (gpepCSRSS->DebugPort == NULL)
            return FALSE;

        a->ClientId.UniqueProcess = gpepCSRSS->UniqueProcessId;
    } else {

        if ((gpqForeground == NULL) || (gpqForeground->ptiKeyboard == NULL))
            return FALSE;

        a->ClientId = gpqForeground->ptiKeyboard->Thread->Cid;

        /*
         * Bail out if the process is not being debugged.
         */
        if (!NT_SUCCESS(LockProcessByClientId(a->ClientId.UniqueProcess,
                &Process)))
            return FALSE;
        hDebugPort = Process->DebugPort;
        UnlockProcess(Process);

        if (hDebugPort == NULL)
            return FALSE;
    }

    /*
     * Send the datagram to CSR
     */
    if (CsrApiPort != NULL) {
        ArgLength = sizeof(*a);
        ArgLength |= (ArgLength << 16);
        ArgLength +=     ((sizeof( CSR_API_MSG ) - sizeof( m.u )) << 16) |
                        (FIELD_OFFSET( CSR_API_MSG, u ) - sizeof( m.h ));
        m.h.u1.Length = ArgLength;
        m.h.u2.ZeroInit = 0;
        m.CaptureBuffer = NULL;
        m.ApiNumber = CSR_MAKE_API_NUMBER( USERSRV_SERVERDLL_INDEX,
                                           UserpActivateDebugger);
        LeaveCrit();
        Status = LpcRequestPort(CsrApiPort, (PPORT_MESSAGE)&m);
        EnterCrit();
        UserAssert(NT_SUCCESS(Status));
    }

    /*
     * Don't eat this event unless we are breaking into CSR! Since we have
     * choosen an arbitrary hot key like F12 for the debug key, we need to
     * pass on the key to the application, or apps that want this key would
     * never see it. If we had an api for installing a debug hot key
     * (export or MOD_DEBUG flag to RegisterHotKey()), then it would be ok
     * to eat because the user selected the hot key. But it is not ok to
     * eat it as long as we've picked an arbitrary hot key. scottlu.
     */
    if (fsModifiers & MOD_SHIFT)
        return TRUE;
    else
        return FALSE;
}
Exemplo n.º 6
0
VOID
LpcpDeletePort(
    IN PVOID Object
    )
{
    PLPCP_PORT_OBJECT Port = Object;
    PLPCP_PORT_OBJECT ConnectionPort;
    LPC_CLIENT_DIED_MSG ClientPortClosedDatagram;
    PLPCP_MESSAGE Msg;
    PLIST_ENTRY Head, Next;
    HANDLE CurrentProcessId;

    PAGED_CODE();
    //
    // Send an LPC_PORT_CLOSED datagram to whoever is connected
    // to this port so they know they are no longer connected.
    //
    if ((Port->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) {
        ClientPortClosedDatagram.PortMsg.u1.s1.TotalLength = sizeof( ClientPortClosedDatagram );
        ClientPortClosedDatagram.PortMsg.u1.s1.DataLength = sizeof( ClientPortClosedDatagram.CreateTime );
        ClientPortClosedDatagram.PortMsg.u2.s2.Type = LPC_PORT_CLOSED;
        ClientPortClosedDatagram.PortMsg.u2.s2.DataInfoOffset = 0;
        ClientPortClosedDatagram.CreateTime = PsGetCurrentProcess()->CreateTime;
        LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram );
        }


    //
    // If connected, disconnect the port, and then scan the message queue
    // for this port and dereference any messages in the queue.
    //

    LpcpDestroyPortQueue( Port, TRUE );

    //
    // If the client has a port memory view, then unmap it
    //

    if (Port->ClientSectionBase != NULL) {
        ZwUnmapViewOfSection( NtCurrentProcess(),
                              Port->ClientSectionBase
                            );
        }

    //
    // If the server has a port memory view, then unmap it
    //

    if (Port->ServerSectionBase != NULL) {
        ZwUnmapViewOfSection( NtCurrentProcess(),
                              Port->ServerSectionBase
                            );
        }

    //
    // Dereference the pointer to the connection port if it is not
    // this port.
    //

    if (ConnectionPort = Port->ConnectionPort) {
        CurrentProcessId = PsGetCurrentThread()->Cid.UniqueProcess;
        ExAcquireFastMutex( &LpcpLock );
        Head = &ConnectionPort->LpcDataInfoChainHead;
        Next = Head->Flink;
        while (Next != Head) {
            Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry );
            Next = Next->Flink;
            if (Msg->Request.ClientId.UniqueProcess == CurrentProcessId) {
                LpcpTrace(( "%s Freeing DataInfo Message %lx (%u.%u)  Port: %lx\n",
                            PsGetCurrentProcess()->ImageFileName,
                            Msg,
                            Msg->Request.MessageId,
                            Msg->Request.CallbackId,
                            ConnectionPort
                         ));
                RemoveEntryList( &Msg->Entry );
                LpcpFreeToPortZone( Msg, TRUE );
                }
            }
        ExReleaseFastMutex( &LpcpLock );

        if (ConnectionPort != Port) {
            ObDereferenceObject( ConnectionPort );
            }
        }

    //
    // Free any static client security context
    //

    LpcpFreePortClientSecurity( Port );
}
Exemplo n.º 7
0
VOID
LpcpDeletePort (
    IN PVOID Object
    )

/*++

Routine Description:

    This routine is the callback used for deleting a port object.

Arguments:

    Object - Supplies a pointer to the port object being deleted

Return Value:

    None.

--*/

{
    PLPCP_PORT_OBJECT Port = Object;
    PLPCP_PORT_OBJECT ConnectionPort;
    LPC_CLIENT_DIED_MSG ClientPortClosedDatagram;
    PLPCP_MESSAGE Msg;
    PLIST_ENTRY Head, Next;
    HANDLE CurrentProcessId;

    PAGED_CODE();

    //
    //  If the port is a server communication port then make sure that if
    //  there is a dangling client thread that we get rid of it.  This
    //  handles the case of someone calling NtAcceptConnectPort and not
    //  calling NtCompleteConnectPort
    //

    LpcpPortExtraDataDestroy( Port );

    if ((Port->Flags & PORT_TYPE) == SERVER_COMMUNICATION_PORT) {

        PETHREAD ClientThread;

        LpcpAcquireLpcpLock();

        if ((ClientThread = Port->ClientThread) != NULL) {

            Port->ClientThread = NULL;

            LpcpReleaseLpcpLock();

            ObDereferenceObject( ClientThread );

        } else {

            LpcpReleaseLpcpLock();
        }
    }

    //
    //  Send an LPC_PORT_CLOSED datagram to whoever is connected
    //  to this port so they know they are no longer connected.
    //

    if ((Port->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) {

        ClientPortClosedDatagram.PortMsg.u1.s1.TotalLength = sizeof( ClientPortClosedDatagram );
        ClientPortClosedDatagram.PortMsg.u1.s1.DataLength = sizeof( ClientPortClosedDatagram.CreateTime );

        ClientPortClosedDatagram.PortMsg.u2.s2.Type = LPC_PORT_CLOSED;
        ClientPortClosedDatagram.PortMsg.u2.s2.DataInfoOffset = 0;

        ClientPortClosedDatagram.CreateTime = PsGetCurrentProcess()->CreateTime;

        LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram );
    }

    //
    //  If connected, disconnect the port, and then scan the message queue
    //  for this port and dereference any messages in the queue.
    //

    LpcpDestroyPortQueue( Port, TRUE );

    //
    //  If the client has a port memory view, then unmap it
    //

    if (Port->ClientSectionBase != NULL) {

        MmUnmapViewOfSection( PsGetCurrentProcess(),
                              Port->ClientSectionBase );

    }

    //
    //  If the server has a port memory view, then unmap it
    //

    if (Port->ServerSectionBase != NULL) {

        MmUnmapViewOfSection( PsGetCurrentProcess(),
                              Port->ServerSectionBase  );

    }

    //
    //  Dereference the pointer to the connection port if it is not
    //  this port.
    //

    if (ConnectionPort = Port->ConnectionPort) {

        CurrentProcessId = PsGetCurrentThread()->Cid.UniqueProcess;

        LpcpAcquireLpcpLock();

        Head = &ConnectionPort->LpcDataInfoChainHead;
        Next = Head->Flink;

        while (Next != Head) {

            Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry );
            Next = Next->Flink;

            if (Msg->Request.ClientId.UniqueProcess == CurrentProcessId) {

                LpcpTrace(( "%s Freeing DataInfo Message %lx (%u.%u)  Port: %lx\n",
                            PsGetCurrentProcess()->ImageFileName,
                            Msg,
                            Msg->Request.MessageId,
                            Msg->Request.CallbackId,
                            ConnectionPort ));

                RemoveEntryList( &Msg->Entry );

                LpcpFreeToPortZone( Msg, TRUE );
            }
        }

        LpcpReleaseLpcpLock();

        if (ConnectionPort != Port) {

            ObDereferenceObject( ConnectionPort );
        }
    }

    if (((Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) &&
        (ConnectionPort->ServerProcess != NULL)) {

        ObDereferenceObject( ConnectionPort->ServerProcess );

        ConnectionPort->ServerProcess = NULL;
    }

    //
    //  Free any static client security context
    //

    LpcpFreePortClientSecurity( Port );

    //
    //  And return to our caller
    //

    return;
}