Example #1
0
/*
 * @implemented
 */
NTSTATUS
NTAPI
NtReplyPort(IN HANDLE PortHandle,
            IN PPORT_MESSAGE ReplyMessage)
{
    PLPCP_PORT_OBJECT Port;
    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
    NTSTATUS Status;
    PLPCP_MESSAGE Message;
    PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
    //PORT_MESSAGE CapturedReplyMessage;

    PAGED_CODE();
    LPCTRACE(LPC_REPLY_DEBUG,
             "Handle: %p. Message: %p.\n",
             PortHandle,
             ReplyMessage);

    if (KeGetPreviousMode() == UserMode)
    {
        _SEH2_TRY
        {
            ProbeForRead(ReplyMessage, sizeof(PORT_MESSAGE), sizeof(ULONG));
            /*RtlCopyMemory(&CapturedReplyMessage, ReplyMessage, sizeof(PORT_MESSAGE));
            ReplyMessage = &CapturedReplyMessage;*/
        }
        _SEH2_EXCEPT(ExSystemExceptionFilter())
        {
            DPRINT1("SEH crash [1]\n");
            DbgBreakPoint();
            _SEH2_YIELD(return _SEH2_GetExceptionCode());
        }
        _SEH2_END;
    }
Example #2
0
/*
 * @implemented
 */
NTSTATUS
NTAPI
NtQueryDefaultUILanguage(OUT LANGID* LanguageId)
{
    NTSTATUS Status = STATUS_SUCCESS;
    PAGED_CODE();

    /* Enter SEH for probing */
    _SEH2_TRY
    {
        /* Check if we came from user mode */
        if (KeGetPreviousMode() != KernelMode)
        {
            /* Probe the Language ID */
            ProbeForWriteLangid(LanguageId);
        }

        /* Call the executive helper routine */
        Status = ExpGetCurrentUserUILanguage(L"MultiUILanguageId", LanguageId);
        if (NT_SUCCESS(Status))
        {
            /* Success, return the language */
            *LanguageId = PsInstallUILanguageId;
        }
    }
    _SEH2_EXCEPT(ExSystemExceptionFilter())
    {
        /* Get exception code */
        Status = _SEH2_GetExceptionCode();
    }
    _SEH2_END;

    /* Return status */
    return Status;
}
Example #3
0
/*
 * @implemented
 */
NTSTATUS
NTAPI
NtQueryInstallUILanguage(OUT LANGID* LanguageId)
{
    NTSTATUS Status = STATUS_SUCCESS;
    PAGED_CODE();

    /* Enter SEH for probing */
    _SEH2_TRY
    {
        /* Check if we came from user mode */
        if (KeGetPreviousMode() != KernelMode)
        {
            /* Probe the Language ID */
            ProbeForWriteLangid(LanguageId);
        }

        /* Return it */
        *LanguageId = PsInstallUILanguageId;
    }
    _SEH2_EXCEPT(ExSystemExceptionFilter())
    {
        /* Get exception code */
        Status = _SEH2_GetExceptionCode();
    }
    _SEH2_END;

    /* Return status */
    return Status;
}
Example #4
0
/*
 * @implemented
 */
NTSTATUS
NTAPI
NtReplyPort(IN HANDLE PortHandle,
            IN PPORT_MESSAGE ReplyMessage)
{
    NTSTATUS Status;
    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
    PORT_MESSAGE CapturedReplyMessage;
    PLPCP_PORT_OBJECT Port;
    PLPCP_MESSAGE Message;
    PETHREAD Thread = PsGetCurrentThread(), WakeupThread;

    PAGED_CODE();
    LPCTRACE(LPC_REPLY_DEBUG,
             "Handle: %p. Message: %p.\n",
             PortHandle,
             ReplyMessage);

    /* Check if the call comes from user mode */
    if (PreviousMode != KernelMode)
    {
        _SEH2_TRY
        {
            ProbeForRead(ReplyMessage, sizeof(*ReplyMessage), sizeof(ULONG));
            CapturedReplyMessage = *(volatile PORT_MESSAGE*)ReplyMessage;
        }
        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
        {
            _SEH2_YIELD(return _SEH2_GetExceptionCode());
        }
        _SEH2_END;
    }
Example #5
0
CCHAR
PsGetCurrentThreadPreviousMode(
    VOID
    )
{
    return KeGetPreviousMode();
}
Example #6
0
int
ExSystemExceptionFilter( VOID )
{
    return( KeGetPreviousMode() != KernelMode ? EXCEPTION_EXECUTE_HANDLER
                                            : EXCEPTION_CONTINUE_SEARCH
          );
}
Example #7
0
NTKERNELAPI
KPROCESSOR_MODE
ExGetPreviousMode(
    VOID
    )
/*++

Routine Description:

    Returns previous mode.  This routine is exported from the kernel so
    that drivers can call it, as they may have to do probing of
    embedded pointers to user structures on IOCTL calls that the I/O
    system can't probe for them on the FastIo path, which does not pass
    previous mode via the FastIo parameters.

Arguments:

    None.

Return Value:

    Either KernelMode or UserMode

--*/

{
    return KeGetPreviousMode();
}
Example #8
0
NTSTATUS
NtAllocateLocallyUniqueId (
    __out PLUID Luid
    )

/*++

Routine Description:

    This function returns an LUID value that is unique since the system
    was last rebooted.  It is unique on the system it is generated on
    only (not network wide).

    There are no restrictions on who can allocate LUIDs.  The LUID space
    is large enough that this will never present a problem.  If one LUID
    is allocated every 100ns, they will not be exhausted for roughly
    15,000 years (100ns * 2^63).

Arguments:

    Luid - Supplies the address of a variable that will receive the
        new LUID.

Return Value:

    STATUS_SUCCESS is returned if the service is successfully executed.

    STATUS_ACCESS_VIOLATION is returned if the output parameter for the
        LUID cannot be written.

--*/

{

    KPROCESSOR_MODE PreviousMode;

    //
    // Get previous processor mode and probe argument if necessary.
    //

    try {
        PreviousMode = KeGetPreviousMode();
        if (PreviousMode != KernelMode) {
            ProbeForWriteSmallStructure((PVOID)Luid, sizeof(LUID), sizeof(ULONG));
        }

        //
        // Allocate and store a locally unique Id.
        //

        ExAllocateLocallyUniqueId(Luid);

    } except (ExSystemExceptionFilter()) {
        return GetExceptionCode();
    }

    return STATUS_SUCCESS;
}
Example #9
0
NTSTATUS
NTAPI
NtQueryInformationPort(
    IN HANDLE PortHandle OPTIONAL,
    IN PORT_INFORMATION_CLASS PortInformationClass,
    OUT PVOID PortInformation,
    IN ULONG Length,
    OUT PULONG ReturnLength OPTIONAL
    )
{
    KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;
    PLPCP_PORT_OBJECT PortObject;

    PAGED_CODE();

    //
    // Get previous processor mode and probe output argument if necessary.
    //

    PreviousMode = KeGetPreviousMode();
    if (PreviousMode != KernelMode) {
        try {
            ProbeForWrite( PortInformation,
                           Length,
                           sizeof( ULONG )
                         );

            if (ARGUMENT_PRESENT( ReturnLength )) {
                ProbeForWriteUlong( ReturnLength );
                }
            }
        except( EXCEPTION_EXECUTE_HANDLER ) {
            return( GetExceptionCode() );
            }
        }

    if (ARGUMENT_PRESENT( PortHandle )) {
        Status = ObReferenceObjectByHandle( PortHandle,
                                            GENERIC_READ,
                                            LpcPortObjectType,
                                            PreviousMode,
                                            &PortObject,
                                            NULL
                                          );
        if (!NT_SUCCESS( Status )) {
            return( Status );
            }

        ObDereferenceObject( PortObject );
        return STATUS_SUCCESS;
        }
    else {
        return STATUS_INVALID_INFO_CLASS;
        }
}
Example #10
0
/*
 * @implemented
 */
NTSTATUS
NTAPI
NtRequestWaitReplyPort(IN HANDLE PortHandle,
                       IN PPORT_MESSAGE LpcRequest,
                       IN OUT PPORT_MESSAGE LpcReply)
{
    PORT_MESSAGE LocalLpcRequest;
    ULONG NumberOfDataEntries;
    PLPCP_PORT_OBJECT Port, QueuePort, ReplyPort, ConnectionPort = NULL;
    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
    NTSTATUS Status;
    PLPCP_MESSAGE Message;
    PETHREAD Thread = PsGetCurrentThread();
    BOOLEAN Callback;
    PKSEMAPHORE Semaphore;
    ULONG MessageType;
    PLPCP_DATA_INFO DataInfo;
    PAGED_CODE();
    LPCTRACE(LPC_SEND_DEBUG,
             "Handle: %p. Messages: %p/%p. Type: %lx\n",
             PortHandle,
             LpcRequest,
             LpcReply,
             LpcpGetMessageType(LpcRequest));

    /* Check if the thread is dying */
    if (Thread->LpcExitThreadCalled) return STATUS_THREAD_IS_TERMINATING;

    /* Check for user mode access */
    if (PreviousMode != KernelMode)
    {
        _SEH2_TRY
        {
            /* Probe the full request message and copy the base structure */
            ProbeForRead(LpcRequest, sizeof(*LpcRequest), sizeof(ULONG));
            ProbeForRead(LpcRequest, LpcRequest->u1.s1.TotalLength, sizeof(ULONG));
            LocalLpcRequest = *LpcRequest;

            /* Probe the reply message for write */
            ProbeForWrite(LpcReply, sizeof(*LpcReply), sizeof(ULONG));

            /* Make sure the data entries in the request message are valid */
            Status = LpcpVerifyMessageDataInfo(LpcRequest, &NumberOfDataEntries);
            if (!NT_SUCCESS(Status))
            {
                DPRINT1("LpcpVerifyMessageDataInfo failed\n");
                return Status;
            }
        }
        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
        {
            DPRINT1("Got exception\n");
            return _SEH2_GetExceptionCode();
        }
        _SEH2_END;
    }
Example #11
0
NTSTATUS
NtClearEvent (
    __in HANDLE EventHandle
    )

/*++

Routine Description:

    This function sets an event object to a Not-Signaled state.

Arguments:

    EventHandle - Supplies a handle to an event object.

Return Value:

    NTSTATUS.

--*/

{

    PVOID Event;
    NTSTATUS Status;

    //
    // Reference event object by handle.
    //

    Status = ObReferenceObjectByHandle(EventHandle,
                                       EVENT_MODIFY_STATE,
                                       ExEventObjectType,
                                       KeGetPreviousMode(),
                                       &Event,
                                       NULL);

    //
    // If the reference was successful, then set the state of the event
    // object to Not-Signaled and dereference event object.
    //

    if (NT_SUCCESS(Status)) {
        PERFINFO_DECLARE_OBJECT(Event);
        KeClearEvent((PKEVENT)Event);
        ObDereferenceObject(Event);
    }

    //
    // Return service status.
    //

    return Status;
}
Example #12
0
NTSTATUS
NtAlertThread(
    IN HANDLE ThreadHandle
    )

/*++

Routine Description:

    This function alerts the target thread using the previous mode
    as the mode of the alert.

Arguments:

    ThreadHandle - Supplies an open handle to the thread to be alerted

Return Value:

    TBD

--*/

{
    PETHREAD Thread;
    NTSTATUS st;
    KPROCESSOR_MODE Mode;

    PAGED_CODE();

    Mode = KeGetPreviousMode();

    st = ObReferenceObjectByHandle(
            ThreadHandle,
            THREAD_ALERT,
            PsThreadType,
            Mode,
            (PVOID *)&Thread,
            NULL
            );

    if ( !NT_SUCCESS(st) ) {
        return st;
    }

    (VOID) KeAlertThread(&Thread->Tcb,Mode);

    ObDereferenceObject(Thread);

    return STATUS_SUCCESS;

}
Example #13
0
NTSTATUS
NTAPI
KiRaiseException(IN PEXCEPTION_RECORD ExceptionRecord,
                 IN PCONTEXT Context,
                 IN PKEXCEPTION_FRAME ExceptionFrame,
                 IN PKTRAP_FRAME TrapFrame,
                 IN BOOLEAN SearchFrames)
{
    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
    CONTEXT LocalContext;
    EXCEPTION_RECORD LocalExceptionRecord;
    ULONG ParameterCount, Size;

    /* Check if we need to probe */
    if (PreviousMode != KernelMode)
    {
        /* Set up SEH */
        _SEH2_TRY
        {
            /* Probe the context */
            ProbeForRead(Context, sizeof(CONTEXT), sizeof(ULONG));

            /* Probe the Exception Record */
            ProbeForRead(ExceptionRecord,
                         FIELD_OFFSET(EXCEPTION_RECORD, NumberParameters) +
                         sizeof(ULONG),
                         sizeof(ULONG));

            /* Validate the maximum parameters */
            if ((ParameterCount = ExceptionRecord->NumberParameters) >
                EXCEPTION_MAXIMUM_PARAMETERS)
            {
                /* Too large */
                _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
            }

            /* Probe the entire parameters now*/
            Size = (sizeof(EXCEPTION_RECORD) - 
                    ((EXCEPTION_MAXIMUM_PARAMETERS - ParameterCount) * sizeof(ULONG)));
            ProbeForRead(ExceptionRecord, Size, sizeof(ULONG));

            /* Now make copies in the stack */
            RtlCopyMemory(&LocalContext, Context, sizeof(CONTEXT));
            RtlCopyMemory(&LocalExceptionRecord, ExceptionRecord, Size);
            Context = &LocalContext;
            ExceptionRecord = &LocalExceptionRecord;

            /* Update the parameter count */
            ExceptionRecord->NumberParameters = ParameterCount;
        }
Example #14
0
NTSTATUS
NTAPI
KiContinue(IN PCONTEXT Context,
           IN PKEXCEPTION_FRAME ExceptionFrame,
           IN PKTRAP_FRAME TrapFrame)
{
    NTSTATUS Status = STATUS_SUCCESS;
    KIRQL OldIrql = APC_LEVEL;
    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();

    /* Raise to APC_LEVEL, only if needed */
    if (KeGetCurrentIrql() < APC_LEVEL) KeRaiseIrql(APC_LEVEL, &OldIrql);

    /* Set up SEH to validate the context */
    _SEH2_TRY
    {
        /* Check the previous mode */
        if (PreviousMode != KernelMode)
        {
            /* Validate from user-mode */
            KiContinuePreviousModeUser(Context,
                                       ExceptionFrame,
                                       TrapFrame);
        }
        else
        {
            /* Convert the context into Exception/Trap Frames */
            KeContextToTrapFrame(Context,
                                 ExceptionFrame,
                                 TrapFrame,
                                 Context->ContextFlags,
                                 KernelMode);
        }
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
        /* Save the exception code */
        Status = _SEH2_GetExceptionCode();
    }
    _SEH2_END;

    /* Lower the IRQL if needed */
    if (OldIrql < APC_LEVEL) KeLowerIrql(OldIrql);

    /* Return status */
    return Status;
}
Example #15
0
NTSTATUS
NTAPI
NtQueryDefaultLocale(IN BOOLEAN UserProfile,
                     OUT PLCID DefaultLocaleId)
{
    NTSTATUS Status = STATUS_SUCCESS;
    PAGED_CODE();

    /* Enter SEH for probing */
    _SEH2_TRY
    {
        /* Check if we came from user mode */
        if (KeGetPreviousMode() != KernelMode)
        {
            /* Probe the language ID */
            ProbeForWriteLangid(DefaultLocaleId);
        }

        /* Check if we have a user profile */
        if (UserProfile)
        {
            /* Return session wide thread locale */
            *DefaultLocaleId = MmGetSessionLocaleId();
        }
        else
        {
            /* Return system locale */
            *DefaultLocaleId = PsDefaultSystemLocaleId;
        }
    }
    _SEH2_EXCEPT(ExSystemExceptionFilter())
    {
        /* Get exception code */
        Status = _SEH2_GetExceptionCode();
    }
    _SEH2_END;

    /* Return status */
    return Status;
}
Example #16
0
NTSTATUS
NTAPI
NtRegisterThreadTerminatePort(IN HANDLE PortHandle)
{
    NTSTATUS Status;
    PTERMINATION_PORT TerminationPort;
    PVOID TerminationLpcPort;
    PETHREAD Thread;
    PAGED_CODE();
    PSTRACE(PS_KILL_DEBUG, "PortHandle: %p\n", PortHandle);

    /* Get the Port */
    Status = ObReferenceObjectByHandle(PortHandle,
                                       PORT_ALL_ACCESS,
                                       LpcPortObjectType,
                                       KeGetPreviousMode(),
                                       &TerminationLpcPort,
                                       NULL);
    if (!NT_SUCCESS(Status)) return(Status);

    /* Allocate the Port and make sure it suceeded */
    TerminationPort = ExAllocatePoolWithTag(NonPagedPool,
                                            sizeof(TERMINATION_PORT),
                                            '=TsP');
    if(TerminationPort)
    {
        /* Associate the Port */
        Thread = PsGetCurrentThread();
        TerminationPort->Port = TerminationLpcPort;
        TerminationPort->Next = Thread->TerminationPort;
        Thread->TerminationPort = TerminationPort;

        /* Return success */
        return STATUS_SUCCESS;
    }

    /* Dereference and Fail */
    ObDereferenceObject(TerminationLpcPort);
    return STATUS_INSUFFICIENT_RESOURCES;
}
Example #17
0
NTSTATUS
NtTestAlert(
    VOID
    )

/*++

Routine Description:

    This function tests the alert flag inside the current thread. If
    an alert is pending for the previous mode, then the alerted status
    is returned, pending APC's may also be delivered at this time.

Arguments:

    None

Return Value:

    STATUS_ALERTED - An alert was pending for the current thread at the
        time this function was called.

    STATUS_SUCCESS - No alert was pending for this thread.

--*/

{

    PAGED_CODE();

    if ( KeTestAlertThread(KeGetPreviousMode()) ) {
        return STATUS_ALERTED;
    } else {
        return STATUS_SUCCESS;
    }
}
Example #18
0
NTSYSAPI
NTSTATUS
NTAPI
NtQueueApcThread(
    IN HANDLE ThreadHandle,
    IN PPS_APC_ROUTINE ApcRoutine,
    IN PVOID ApcArgument1,
    IN PVOID ApcArgument2,
    IN PVOID ApcArgument3
    )

/*++

Routine Description:

    This function is used to queue a user-mode APC to the specified thread. The APC
    will fire when the specified thread does an alertable wait

Arguments:

    ThreadHandle - Supplies a handle to a thread object.  The caller
        must have THREAD_SET_CONTEXT access to the thread.

    ApcRoutine - Supplies the address of the APC routine to execute when the
        APC fires.

    ApcArgument1 - Supplies the first PVOID passed to the APC

    ApcArgument2 - Supplies the second PVOID passed to the APC

    ApcArgument3 - Supplies the third PVOID passed to the APC

Return Value:

    Returns an NT Status code indicating success or failure of the API

--*/

{
    PETHREAD Thread;
    NTSTATUS st;
    KPROCESSOR_MODE Mode;
    KIRQL Irql;
    PKAPC Apc;

    PAGED_CODE();

    Mode = KeGetPreviousMode();

    st = ObReferenceObjectByHandle(
            ThreadHandle,
            THREAD_SET_CONTEXT,
            PsThreadType,
            Mode,
            (PVOID *)&Thread,
            NULL
            );

    if ( NT_SUCCESS(st) ) {
        st = STATUS_SUCCESS;
        if ( IS_SYSTEM_THREAD(Thread) ) {
            st = STATUS_INVALID_HANDLE;
            }
        else {
            Apc = ExAllocatePoolWithQuotaTag(
                    (NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE),
                    sizeof(*Apc),
                    'pasP'
                    );

            if ( !Apc ) {
                st = STATUS_NO_MEMORY;
                }
            else {
                KeInitializeApc(
                    Apc,
                    &Thread->Tcb,
                    OriginalApcEnvironment,
                    PspQueueApcSpecialApc,
                    NULL,
                    (PKNORMAL_ROUTINE)ApcRoutine,
                    UserMode,
                    ApcArgument1
                    );

                if ( !KeInsertQueueApc(Apc,ApcArgument2,ApcArgument3,0) ) {
                    ExFreePool(Apc);
                    st = STATUS_UNSUCCESSFUL;
                    }
                }
            }
        ObDereferenceObject(Thread);
        }

    return st;
}
Example #19
0
NTSTATUS
NtImpersonateThread(
    __in HANDLE ServerThreadHandle,
    __in HANDLE ClientThreadHandle,
    __in PSECURITY_QUALITY_OF_SERVICE SecurityQos
    )

/*++

Routine Description:

    This routine is used to cause the server thread to impersonate the client
    thread.  The impersonation is done according to the specified quality
    of service parameters.



Arguments:

    ServerThreadHandle - Is a handle to the server thread (the impersonator, or
        doing the impersonation).  This handle must be open for
        THREAD_IMPERSONATE access.

    ClientThreadHandle - Is a handle to the Client thread (the impersonatee, or
        one being impersonated).   This handle must be open for
        THREAD_DIRECT_IMPERSONATION access.


    SecurityQos - A pointer to security quality of service information
        indicating what form of impersonation is to be performed.



Return Value:

    STATUS_SUCCESS - Indicates the call completed successfully.


--*/

{


    KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;
    PETHREAD ClientThread, ServerThread;
    SECURITY_QUALITY_OF_SERVICE CapturedQos;
    SECURITY_CLIENT_CONTEXT ClientSecurityContext;

    //
    // Get previous processor mode and probe and capture arguments if necessary
    //

    PreviousMode = KeGetPreviousMode();

    try {

        if (PreviousMode != KernelMode) {
            ProbeForReadSmallStructure (SecurityQos,
                                        sizeof (SECURITY_QUALITY_OF_SERVICE),
                                        sizeof (ULONG));
        }
        CapturedQos = *SecurityQos;

    } except (ExSystemExceptionFilter ()) {
        return GetExceptionCode ();
    }



    //
    // Reference the client thread, checking for appropriate access.
    //

    Status = ObReferenceObjectByHandle (ClientThreadHandle,           // Handle
                                        THREAD_DIRECT_IMPERSONATION,  // DesiredAccess
                                        PsThreadType,                 // ObjectType
                                        PreviousMode,                 // AccessMode
                                        &ClientThread,                // Object
                                        NULL);                        // GrantedAccess

    if (!NT_SUCCESS (Status)) {
        return Status;
    }

    //
    // Reference the client thread, checking for appropriate access.
    //

    Status = ObReferenceObjectByHandle (ServerThreadHandle,           // Handle
                                        THREAD_IMPERSONATE,           // DesiredAccess
                                        PsThreadType,                 // ObjectType
                                        PreviousMode,                 // AccessMode
                                        &ServerThread,                // Object
                                        NULL);                        // GrantedAccess

    if (!NT_SUCCESS (Status)) {
        ObDereferenceObject (ClientThread);
        return Status;
    }


    //
    // Get the client's security context
    //

    Status = SeCreateClientSecurity (ClientThread,             // ClientThread
                                     &CapturedQos,             // SecurityQos
                                     FALSE,                    // ServerIsRemote
                                     &ClientSecurityContext);  // ClientContext

    if (!NT_SUCCESS (Status)) {
        ObDereferenceObject (ServerThread);
        ObDereferenceObject (ClientThread);
        return Status;
    }


    //
    // Impersonate the client
    //

    Status = SeImpersonateClientEx (&ClientSecurityContext, ServerThread);

    SeDeleteClientSecurity (&ClientSecurityContext);

    //
    // Done.
    //


    ObDereferenceObject (ServerThread);
    ObDereferenceObject (ClientThread);

    return Status ;
}
Example #20
0
/*
 * @implemented
 */
NTSTATUS
NTAPI
NtRequestWaitReplyPort(IN HANDLE PortHandle,
                       IN PPORT_MESSAGE LpcRequest,
                       IN OUT PPORT_MESSAGE LpcReply)
{
    PLPCP_PORT_OBJECT Port, QueuePort, ReplyPort, ConnectionPort = NULL;
    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
    NTSTATUS Status;
    PLPCP_MESSAGE Message;
    PETHREAD Thread = PsGetCurrentThread();
    BOOLEAN Callback;
    PKSEMAPHORE Semaphore;
    ULONG MessageType;
    PAGED_CODE();
    LPCTRACE(LPC_SEND_DEBUG,
             "Handle: %lx. Messages: %p/%p. Type: %lx\n",
             PortHandle,
             LpcRequest,
             LpcReply,
             LpcpGetMessageType(LpcRequest));

    /* Check if the thread is dying */
    if (Thread->LpcExitThreadCalled) return STATUS_THREAD_IS_TERMINATING;

    /* Check if this is an LPC Request */
    if (LpcpGetMessageType(LpcRequest) == LPC_REQUEST)
    {
        /* Then it's a callback */
        Callback = TRUE;
    }
    else if (LpcpGetMessageType(LpcRequest))
    {
        /* This is a not kernel-mode message */
        return STATUS_INVALID_PARAMETER;
    }
    else
    {
        /* This is a kernel-mode message without a callback */
        LpcRequest->u2.s2.Type |= LPC_REQUEST;
        Callback = FALSE;
    }

    /* Get the message type */
    MessageType = LpcRequest->u2.s2.Type;

    /* Validate the length */
    if (((ULONG)LpcRequest->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
            (ULONG)LpcRequest->u1.s1.TotalLength)
    {
        /* Fail */
        return STATUS_INVALID_PARAMETER;
    }

    /* Reference the object */
    Status = ObReferenceObjectByHandle(PortHandle,
                                       0,
                                       LpcPortObjectType,
                                       PreviousMode,
                                       (PVOID*)&Port,
                                       NULL);
    if (!NT_SUCCESS(Status)) return Status;

    /* Validate the message length */
    if (((ULONG)LpcRequest->u1.s1.TotalLength > Port->MaxMessageLength) ||
            ((ULONG)LpcRequest->u1.s1.TotalLength <= (ULONG)LpcRequest->u1.s1.DataLength))
    {
        /* Fail */
        ObDereferenceObject(Port);
        return STATUS_PORT_MESSAGE_TOO_LONG;
    }

    /* Allocate a message from the port zone */
    Message = LpcpAllocateFromPortZone();
    if (!Message)
    {
        /* Fail if we couldn't allocate a message */
        ObDereferenceObject(Port);
        return STATUS_NO_MEMORY;
    }

    /* Check if this is a callback */
    if (Callback)
    {
        /* FIXME: TODO */
        Semaphore = NULL; // we'd use the Thread Semaphore here
        ASSERT(FALSE);
    }
    else
    {
        /* No callback, just copy the message */
        _SEH2_TRY
        {
            /* Copy it */
            LpcpMoveMessage(&Message->Request,
            LpcRequest,
            LpcRequest + 1,
            MessageType,
            &Thread->Cid);
        }
        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
        {
            /* Fail */
            LpcpFreeToPortZone(Message, 0);
            ObDereferenceObject(Port);
            _SEH2_YIELD(return _SEH2_GetExceptionCode());
        }
        _SEH2_END;

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

        /* Right now clear the port context */
        Message->PortContext = NULL;

        /* Check if this is a not connection port */
        if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
        {
            /* We want the connected port */
            QueuePort = Port->ConnectedPort;
            if (!QueuePort)
            {
                /* We have no connected port, fail */
                LpcpFreeToPortZone(Message, 3);
                ObDereferenceObject(Port);
                return STATUS_PORT_DISCONNECTED;
            }

            /* This will be the rundown port */
            ReplyPort = QueuePort;

            /* Check if this is a communication port */
            if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
            {
                /* Copy the port context and use the connection port */
                Message->PortContext = QueuePort->PortContext;
                ConnectionPort = QueuePort = Port->ConnectionPort;
                if (!ConnectionPort)
                {
                    /* Fail */
                    LpcpFreeToPortZone(Message, 3);
                    ObDereferenceObject(Port);
                    return STATUS_PORT_DISCONNECTED;
                }
            }
            else if ((Port->Flags & LPCP_PORT_TYPE_MASK) !=
                     LPCP_COMMUNICATION_PORT)
            {
                /* Use the connection port for anything but communication ports */
                ConnectionPort = QueuePort = Port->ConnectionPort;
                if (!ConnectionPort)
                {
                    /* Fail */
                    LpcpFreeToPortZone(Message, 3);
                    ObDereferenceObject(Port);
                    return STATUS_PORT_DISCONNECTED;
                }
            }

            /* Reference the connection port if it exists */
            if (ConnectionPort) ObReferenceObject(ConnectionPort);
        }
        else
        {
            /* Otherwise, for a connection port, use the same port object */
            QueuePort = ReplyPort = Port;
        }

        /* No reply thread */
        Message->RepliedToThread = NULL;
        Message->SenderPort = Port;

        /* Generate the Message ID and set it */
        Message->Request.MessageId =  LpcpNextMessageId++;
        if (!LpcpNextMessageId) LpcpNextMessageId = 1;
        Message->Request.CallbackId = 0;

        /* Set the message ID for our thread now */
        Thread->LpcReplyMessageId = Message->Request.MessageId;
        Thread->LpcReplyMessage = NULL;

        /* Insert the message in our chain */
        InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
        InsertTailList(&ReplyPort->LpcReplyChainHead, &Thread->LpcReplyChain);
        LpcpSetPortToThread(Thread, Port);

        /* Release the lock and get the semaphore we'll use later */
        KeEnterCriticalRegion();
        KeReleaseGuardedMutex(&LpcpLock);
        Semaphore = QueuePort->MsgQueue.Semaphore;

        /* If this is a waitable port, wake it up */
        if (QueuePort->Flags & LPCP_WAITABLE_PORT)
        {
            /* Wake it */
            KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
        }
    }

    /* Now release the semaphore */
    LpcpCompleteWait(Semaphore);
    KeLeaveCriticalRegion();

    /* And let's wait for the reply */
    LpcpReplyWait(&Thread->LpcReplySemaphore, PreviousMode);

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

    /* Get the LPC Message and clear our thread's reply data */
    Message = LpcpGetMessageFromThread(Thread);
    Thread->LpcReplyMessage = NULL;
    Thread->LpcReplyMessageId = 0;

    /* Check if we have anything on the reply chain*/
    if (!IsListEmpty(&Thread->LpcReplyChain))
    {
        /* Remove this thread and reinitialize the list */
        RemoveEntryList(&Thread->LpcReplyChain);
        InitializeListHead(&Thread->LpcReplyChain);
    }

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

    /* Check if we got a reply */
    if (Status == STATUS_SUCCESS)
    {
        /* Check if we have a valid message */
        if (Message)
        {
            LPCTRACE(LPC_SEND_DEBUG,
                     "Reply Messages: %p/%p\n",
                     &Message->Request,
                     (&Message->Request) + 1);

            /* Move the message */
            _SEH2_TRY
            {
                LpcpMoveMessage(LpcReply,
                &Message->Request,
                (&Message->Request) + 1,
                0,
                NULL);
            }
            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
            {
                Status = _SEH2_GetExceptionCode();
            }
            _SEH2_END;

            /* Check if this is an LPC request with data information */
            if ((LpcpGetMessageType(&Message->Request) == LPC_REQUEST) &&
                    (Message->Request.u2.s2.DataInfoOffset))
            {
                /* Save the data information */
                LpcpSaveDataInfoMessage(Port, Message, 0);
            }
            else
            {
                /* Otherwise, just free it */
                LpcpFreeToPortZone(Message, 0);
            }
        }
        else
        {
            /* We don't have a reply */
            Status = STATUS_LPC_REPLY_LOST;
        }
    }
Example #21
0
NTSTATUS
NtGetContextThread(
    IN HANDLE ThreadHandle,
    IN OUT PCONTEXT ThreadContext
    )

/*++

Routine Description:

    This function returns the usermode context of the specified thread. This
    function will fail if the specified thread is a system thread. It will
    return the wrong answer if the thread is a non-system thread that does
    not execute in user-mode.

Arguments:

    ThreadHandle - Supplies an open handle to the thread object from
                   which to retrieve context information.  The handle
                   must allow THREAD_GET_CONTEXT access to the thread.

    ThreadContext - Supplies the address of a buffer that will receive
                    the context of the specified thread.

Return Value:

    None.

--*/

{

    ULONG Alignment;
    ULONG ContextFlags;
    GETSETCONTEXT ContextFrame;
    ULONG ContextLength;
    KIRQL Irql;
    KPROCESSOR_MODE Mode;
    NTSTATUS Status;
    PETHREAD Thread;

    PAGED_CODE();

    //
    // Get previous mode and reference specified thread.
    //

    Mode = KeGetPreviousMode();
    Status = ObReferenceObjectByHandle(ThreadHandle,
                                   THREAD_GET_CONTEXT,
                                   PsThreadType,
                                   Mode,
                                   (PVOID *)&Thread,
                                   NULL);

    //
    // If the reference was successful, the check if the specified thread
    // is a system thread.
    //

    if (NT_SUCCESS(Status)) {

        //
        // If the thread is not a system thread, then attempt to get the
        // context of the thread.
        //

        if (IS_SYSTEM_THREAD(Thread) == FALSE) {

            //
            // Attempt to get the context of the specified thread.
            //

            try {

                //
                // Set the default alignment, capture the context flags,
                // and set the default size of the context record.
                //

                Alignment = CONTEXT_ALIGN;
                ContextFlags = ProbeAndReadUlong(&ThreadContext->ContextFlags);
                ContextLength = sizeof(CONTEXT);

#if defined(_X86_)
                //
                // CONTEXT_EXTENDED_REGISTERS is SET, then we want sizeof(CONTEXT) set above
                // otherwise (not set) we only want the old part of the context record.
                //
                if ((ContextFlags & CONTEXT_EXTENDED_REGISTERS) != CONTEXT_EXTENDED_REGISTERS) {
                    ContextLength = FIELD_OFFSET(CONTEXT, ExtendedRegisters);
                }
#endif

#if defined(_MIPS_)

                //
                // The following code is included for backward compatibility
                // with old code that does not understand extended context
                // records on MIPS systems.
                //

                if ((ContextFlags & CONTEXT_EXTENDED_INTEGER) != CONTEXT_EXTENDED_INTEGER) {
                    Alignment = sizeof(ULONG);
                    ContextLength = FIELD_OFFSET(CONTEXT, ContextFlags) + 4;
                }

#endif

                if (Mode != KernelMode) {
                    ProbeForWrite(ThreadContext, ContextLength, Alignment);
                }

            } except(EXCEPTION_EXECUTE_HANDLER) {
                Status = GetExceptionCode();
            }

            //
            // If an exception did not occur during the probe of the thread
            // context, then get the context of the target thread.
            //

            if (NT_SUCCESS(Status)) {
                KeInitializeEvent(&ContextFrame.OperationComplete,
                                  NotificationEvent,
                                  FALSE);

                ContextFrame.Context.ContextFlags = ContextFlags;

                ContextFrame.Mode = Mode;
                if (Thread == PsGetCurrentThread()) {
                    ContextFrame.Apc.SystemArgument1 = NULL;
                    ContextFrame.Apc.SystemArgument2 = Thread;
                    KeRaiseIrql(APC_LEVEL, &Irql);
                    PspGetSetContextSpecialApc(&ContextFrame.Apc,
                                               NULL,
                                               NULL,
                                               &ContextFrame.Apc.SystemArgument1,
                                               &ContextFrame.Apc.SystemArgument2);

                    KeLowerIrql(Irql);

                    //
                    // Move context to specfied context record. If an exception
                    // occurs, then silently handle it and return success.
                    //

                    try {
                        RtlMoveMemory(ThreadContext,
                                      &ContextFrame.Context,
                                      ContextLength);

                    } except(EXCEPTION_EXECUTE_HANDLER) {
                    }

                } else {
                    KeInitializeApc(&ContextFrame.Apc,
                                    &Thread->Tcb,
                                    OriginalApcEnvironment,
                                    PspGetSetContextSpecialApc,
                                    NULL,
                                    NULL,
                                    KernelMode,
                                    NULL);

                    if (!KeInsertQueueApc(&ContextFrame.Apc, NULL, Thread, 2)) {
                        Status = STATUS_UNSUCCESSFUL;

                    } else {
                        KeWaitForSingleObject(&ContextFrame.OperationComplete,
                                              Executive,
                                              KernelMode,
                                              FALSE,
                                              NULL);
                        //
                        // Move context to specfied context record. If an
                        // exception occurs, then silently handle it and
                        // return success.
                        //

                        try {
                            RtlMoveMemory(ThreadContext,
                                          &ContextFrame.Context,
                                          ContextLength);

                        } except(EXCEPTION_EXECUTE_HANDLER) {
                        }
                    }
                }
            }

        } else {
Example #22
0
/*
 * @implemented
 */
NTSTATUS
NTAPI
LpcRequestPort(IN PVOID PortObject,
               IN PPORT_MESSAGE LpcMessage)
{
    PLPCP_PORT_OBJECT Port = PortObject, QueuePort, ConnectionPort = NULL;
    ULONG MessageType;
    PLPCP_MESSAGE Message;
    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
    PAGED_CODE();
    LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", Port, LpcMessage);

    /* Check if this is a non-datagram message */
    if (LpcMessage->u2.s2.Type)
    {
        /* Get the message type */
        MessageType = LpcpGetMessageType(LpcMessage);

        /* Validate it */
        if ((MessageType < LPC_DATAGRAM) || (MessageType > LPC_CLIENT_DIED))
        {
            /* Fail */
            return STATUS_INVALID_PARAMETER;
        }

        /* Mark this as a kernel-mode message only if we really came from it */
        if ((PreviousMode == KernelMode) &&
                (LpcMessage->u2.s2.Type & LPC_KERNELMODE_MESSAGE))
        {
            /* We did, this is a kernel mode message */
            MessageType |= LPC_KERNELMODE_MESSAGE;
        }
    }
    else
    {
        /* This is a datagram */
        MessageType = LPC_DATAGRAM;
    }

    /* Can't have data information on this type of call */
    if (LpcMessage->u2.s2.DataInfoOffset) return STATUS_INVALID_PARAMETER;

    /* Validate message sizes */
    if (((ULONG)LpcMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
            ((ULONG)LpcMessage->u1.s1.TotalLength <= (ULONG)LpcMessage->u1.s1.DataLength))
    {
        /* Fail */
        return STATUS_PORT_MESSAGE_TOO_LONG;
    }

    /* Allocate a new message */
    Message = LpcpAllocateFromPortZone();
    if (!Message) return STATUS_NO_MEMORY;

    /* Clear the context */
    Message->RepliedToThread = NULL;
    Message->PortContext = NULL;

    /* Copy the message */
    LpcpMoveMessage(&Message->Request,
                    LpcMessage,
                    LpcMessage + 1,
                    MessageType,
                    &PsGetCurrentThread()->Cid);

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

    /* Check if this is anything but a connection port */
    if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
    {
        /* The queue port is the connected port */
        QueuePort = Port->ConnectedPort;
        if (QueuePort)
        {
            /* Check if this is a client port */
            if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
            {
                /* Then copy the context */
                Message->PortContext = QueuePort->PortContext;
                ConnectionPort = QueuePort = Port->ConnectionPort;
                if (!ConnectionPort)
                {
                    /* Fail */
                    LpcpFreeToPortZone(Message, 3);
                    return STATUS_PORT_DISCONNECTED;
                }
            }
            else if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
            {
                /* Any other kind of port, use the connection port */
                ConnectionPort = QueuePort = Port->ConnectionPort;
                if (!ConnectionPort)
                {
                    /* Fail */
                    LpcpFreeToPortZone(Message, 3);
                    return STATUS_PORT_DISCONNECTED;
                }
            }

            /* If we have a connection port, reference it */
            if (ConnectionPort) ObReferenceObject(ConnectionPort);
        }
    }
    else
    {
        /* For connection ports, use the port itself */
        QueuePort = PortObject;
    }

    /* Make sure we have a port */
    if (QueuePort)
    {
        /* Generate the Message ID and set it */
        Message->Request.MessageId =  LpcpNextMessageId++;
        if (!LpcpNextMessageId) LpcpNextMessageId = 1;
        Message->Request.CallbackId = 0;

        /* No Message ID for the thread */
        PsGetCurrentThread()->LpcReplyMessageId = 0;

        /* Insert the message in our chain */
        InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);

        /* Release the lock and release the semaphore */
        KeEnterCriticalRegion();
        KeReleaseGuardedMutex(&LpcpLock);
        LpcpCompleteWait(QueuePort->MsgQueue.Semaphore);

        /* If this is a waitable port, wake it up */
        if (QueuePort->Flags & LPCP_WAITABLE_PORT)
        {
            /* Wake it */
            KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
        }

        /* We're done */
        KeLeaveCriticalRegion();
        if (ConnectionPort) ObDereferenceObject(ConnectionPort);
        LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", QueuePort, Message);
        return STATUS_SUCCESS;
    }

    /* If we got here, then free the message and fail */
    LpcpFreeToPortZone(Message, 3);
    if (ConnectionPort) ObDereferenceObject(ConnectionPort);
    return STATUS_PORT_DISCONNECTED;
}
Example #23
0
/*
 * @implemented
 */
NTSTATUS
NTAPI
NtRequestPort(IN HANDLE PortHandle,
              IN PPORT_MESSAGE LpcRequest)
{
    PLPCP_PORT_OBJECT Port, QueuePort, ConnectionPort = NULL;
    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
    NTSTATUS Status;
    PLPCP_MESSAGE Message;
    PETHREAD Thread = PsGetCurrentThread();

    PKSEMAPHORE Semaphore;
    ULONG MessageType;
    PAGED_CODE();
    LPCTRACE(LPC_SEND_DEBUG,
             "Handle: %lx. Message: %p. Type: %lx\n",
             PortHandle,
             LpcRequest,
             LpcpGetMessageType(LpcRequest));

    /* Get the message type */
    MessageType = LpcRequest->u2.s2.Type | LPC_DATAGRAM;

    /* Can't have data information on this type of call */
    if (LpcRequest->u2.s2.DataInfoOffset) return STATUS_INVALID_PARAMETER;

    /* Validate the length */
    if (((ULONG)LpcRequest->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
            (ULONG)LpcRequest->u1.s1.TotalLength)
    {
        /* Fail */
        return STATUS_INVALID_PARAMETER;
    }

    /* Reference the object */
    Status = ObReferenceObjectByHandle(PortHandle,
                                       0,
                                       LpcPortObjectType,
                                       PreviousMode,
                                       (PVOID*)&Port,
                                       NULL);
    if (!NT_SUCCESS(Status)) return Status;

    /* Validate the message length */
    if (((ULONG)LpcRequest->u1.s1.TotalLength > Port->MaxMessageLength) ||
            ((ULONG)LpcRequest->u1.s1.TotalLength <= (ULONG)LpcRequest->u1.s1.DataLength))
    {
        /* Fail */
        ObDereferenceObject(Port);
        return STATUS_PORT_MESSAGE_TOO_LONG;
    }

    /* Allocate a message from the port zone */
    Message = LpcpAllocateFromPortZone();
    if (!Message)
    {
        /* Fail if we couldn't allocate a message */
        ObDereferenceObject(Port);
        return STATUS_NO_MEMORY;
    }

    /* No callback, just copy the message */
    _SEH2_TRY
    {
        /* Copy it */
        LpcpMoveMessage(&Message->Request,
        LpcRequest,
        LpcRequest + 1,
        MessageType,
        &Thread->Cid);
    }
    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
    {
        /* Fail */
        LpcpFreeToPortZone(Message, 0);
        ObDereferenceObject(Port);
        _SEH2_YIELD(return _SEH2_GetExceptionCode());
    }
    _SEH2_END;

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

    /* Right now clear the port context */
    Message->PortContext = NULL;

    /* Check if this is a not connection port */
    if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
    {
        /* We want the connected port */
        QueuePort = Port->ConnectedPort;
        if (!QueuePort)
        {
            /* We have no connected port, fail */
            LpcpFreeToPortZone(Message, 3);
            ObDereferenceObject(Port);
            return STATUS_PORT_DISCONNECTED;
        }

        /* Check if this is a communication port */
        if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
        {
            /* Copy the port context and use the connection port */
            Message->PortContext = QueuePort->PortContext;
            ConnectionPort = QueuePort = Port->ConnectionPort;
            if (!ConnectionPort)
            {
                /* Fail */
                LpcpFreeToPortZone(Message, 3);
                ObDereferenceObject(Port);
                return STATUS_PORT_DISCONNECTED;
            }
        }
        else if ((Port->Flags & LPCP_PORT_TYPE_MASK) !=
                 LPCP_COMMUNICATION_PORT)
        {
            /* Use the connection port for anything but communication ports */
            ConnectionPort = QueuePort = Port->ConnectionPort;
            if (!ConnectionPort)
            {
                /* Fail */
                LpcpFreeToPortZone(Message, 3);
                ObDereferenceObject(Port);
                return STATUS_PORT_DISCONNECTED;
            }
        }

        /* Reference the connection port if it exists */
        if (ConnectionPort) ObReferenceObject(ConnectionPort);
    }
    else
    {
        /* Otherwise, for a connection port, use the same port object */
        QueuePort = Port;
    }

    /* Reference QueuePort if we have it */
    if (QueuePort && ObReferenceObjectSafe(QueuePort))
    {
        /* Set sender's port */
        Message->SenderPort = Port;

        /* Generate the Message ID and set it */
        Message->Request.MessageId =  LpcpNextMessageId++;
        if (!LpcpNextMessageId) LpcpNextMessageId = 1;
        Message->Request.CallbackId = 0;

        /* No Message ID for the thread */
        PsGetCurrentThread()->LpcReplyMessageId = 0;

        /* Insert the message in our chain */
        InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);

        /* Release the lock and get the semaphore we'll use later */
        KeEnterCriticalRegion();
        KeReleaseGuardedMutex(&LpcpLock);

        /* Now release the semaphore */
        Semaphore = QueuePort->MsgQueue.Semaphore;
        LpcpCompleteWait(Semaphore);

        /* If this is a waitable port, wake it up */
        if (QueuePort->Flags & LPCP_WAITABLE_PORT)
        {
            /* Wake it */
            KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
        }

        KeLeaveCriticalRegion();

        /* Dereference objects */
        if (ConnectionPort) ObDereferenceObject(ConnectionPort);
        ObDereferenceObject(QueuePort);
        ObDereferenceObject(Port);
        LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", QueuePort, Message);
        return STATUS_SUCCESS;
    }

    Status = STATUS_PORT_DISCONNECTED;

    /* All done with a failure*/
    LPCTRACE(LPC_SEND_DEBUG,
             "Port: %p. Status: %p\n",
             Port,
             Status);

    /* The wait failed, free the message */
    if (Message) LpcpFreeToPortZone(Message, 3);

    ObDereferenceObject(Port);
    if (ConnectionPort) ObDereferenceObject(ConnectionPort);
    return Status;
}
Example #24
0
NTSTATUS
NtReplyPort (
    IN HANDLE PortHandle,
    IN PPORT_MESSAGE ReplyMessage
    )

/*++

Routine Description:

    A client and server process can send a reply to a previous request
    message with the NtReplyPort service:

    The Type field of the message is set to LPC_REPLY by the service.  If the
    MapInfoOffset field of the reply message is non-zero, then the
    PORT_MAP_INFORMATION structure it points to will be processed and the
    relevant pages in the caller's address space will be unmapped.

    The ClientId and MessageId fields of the ReplyMessage structure are used
    to identify the thread waiting for this reply.  If the target thread is
    in fact waiting for this reply message, then the reply message is copied
    into the thread's message buffer and the thread's wait is satisfied.

    If the thread is not waiting for a reply or is waiting for a reply to
    some other MessageId, then the message is placed in the message queue of
    the port that is connected to the communication port specified by the
    PortHandle parameter and the Type field of the message is set to
    LPC_LOST_REPLY.

Arguments:

    PortHandle - Specifies the handle of the communication port that the
        original message was received from.

    ReplyMessage - Specifies a pointer to the reply message to be sent.
        The ClientId and MessageId fields determine which thread will
        get the reply.

Return Value:

    Status code that indicates whether or not the operation was
    successful.

--*/

{
    KPROCESSOR_MODE PreviousMode;
    PLPCP_PORT_OBJECT PortObject;
    PORT_MESSAGE CapturedReplyMessage;
    NTSTATUS Status;
    PLPCP_MESSAGE Msg;
    PETHREAD CurrentThread;
    PETHREAD WakeupThread;

    PAGED_CODE();

    CurrentThread = PsGetCurrentThread();

    //
    //  Get previous processor mode and probe output arguments if necessary.
    //

    PreviousMode = KeGetPreviousMode();

    if (PreviousMode != KernelMode) {

        try {

            ProbeForRead( ReplyMessage,
                          sizeof( *ReplyMessage ),
                          sizeof( ULONG ));

            CapturedReplyMessage = *ReplyMessage;

        } except( EXCEPTION_EXECUTE_HANDLER ) {

            return GetExceptionCode();
        }

    } else {
Example #25
0
/*
* @implemented
*/
NTSTATUS
NTAPI
LpcRequestWaitReplyPort(IN PVOID PortObject,
                        IN PPORT_MESSAGE LpcRequest,
                        OUT PPORT_MESSAGE LpcReply)
{
    PLPCP_PORT_OBJECT Port, QueuePort, ReplyPort, ConnectionPort = NULL;
    KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
    NTSTATUS Status = STATUS_SUCCESS;
    PLPCP_MESSAGE Message;
    PETHREAD Thread = PsGetCurrentThread();
    BOOLEAN Callback = FALSE;
    PKSEMAPHORE Semaphore;
    USHORT MessageType;
    PAGED_CODE();

    Port = (PLPCP_PORT_OBJECT)PortObject;

    LPCTRACE(LPC_SEND_DEBUG,
             "Port: %p. Messages: %p/%p. Type: %lx\n",
             Port,
             LpcRequest,
             LpcReply,
             LpcpGetMessageType(LpcRequest));

    /* Check if the thread is dying */
    if (Thread->LpcExitThreadCalled) return STATUS_THREAD_IS_TERMINATING;

    /* Check if this is an LPC Request */
    MessageType = LpcpGetMessageType(LpcRequest);
    switch (MessageType)
    {
    /* No type */
    case 0:

        /* Assume LPC request */
        MessageType = LPC_REQUEST;
        break;

    /* LPC request callback */
    case LPC_REQUEST:

        /* This is a callback */
        Callback = TRUE;
        break;

    /* Anything else */
    case LPC_CLIENT_DIED:
    case LPC_PORT_CLOSED:
    case LPC_EXCEPTION:
    case LPC_DEBUG_EVENT:
    case LPC_ERROR_EVENT:

        /* Nothing to do */
        break;

    default:

        /* Invalid message type */
        return STATUS_INVALID_PARAMETER;
    }

    /* Set the request type */
    LpcRequest->u2.s2.Type = MessageType;

    /* Validate the message length */
    if (((ULONG)LpcRequest->u1.s1.TotalLength > Port->MaxMessageLength) ||
            ((ULONG)LpcRequest->u1.s1.TotalLength <= (ULONG)LpcRequest->u1.s1.DataLength))
    {
        /* Fail */
        return STATUS_PORT_MESSAGE_TOO_LONG;
    }

    /* Allocate a message from the port zone */
    Message = LpcpAllocateFromPortZone();
    if (!Message)
    {
        /* Fail if we couldn't allocate a message */
        return STATUS_NO_MEMORY;
    }

    /* Check if this is a callback */
    if (Callback)
    {
        /* FIXME: TODO */
        Semaphore = NULL; // we'd use the Thread Semaphore here
        ASSERT(FALSE);
        return STATUS_NOT_IMPLEMENTED;
    }
    else
    {
        /* No callback, just copy the message */
        LpcpMoveMessage(&Message->Request,
                        LpcRequest,
                        LpcRequest + 1,
                        0,
                        &Thread->Cid);

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

        /* Right now clear the port context */
        Message->PortContext = NULL;

        /* Check if this is a not connection port */
        if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
        {
            /* We want the connected port */
            QueuePort = Port->ConnectedPort;
            if (!QueuePort)
            {
                /* We have no connected port, fail */
                LpcpFreeToPortZone(Message, 3);
                return STATUS_PORT_DISCONNECTED;
            }

            /* This will be the rundown port */
            ReplyPort = QueuePort;

            /* Check if this is a communication port */
            if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
            {
                /* Copy the port context and use the connection port */
                Message->PortContext = QueuePort->PortContext;
                ConnectionPort = QueuePort = Port->ConnectionPort;
                if (!ConnectionPort)
                {
                    /* Fail */
                    LpcpFreeToPortZone(Message, 3);
                    return STATUS_PORT_DISCONNECTED;
                }
            }
            else if ((Port->Flags & LPCP_PORT_TYPE_MASK) !=
                     LPCP_COMMUNICATION_PORT)
            {
                /* Use the connection port for anything but communication ports */
                ConnectionPort = QueuePort = Port->ConnectionPort;
                if (!ConnectionPort)
                {
                    /* Fail */
                    LpcpFreeToPortZone(Message, 3);
                    return STATUS_PORT_DISCONNECTED;
                }
            }

            /* Reference the connection port if it exists */
            if (ConnectionPort) ObReferenceObject(ConnectionPort);
        }
        else
        {
            /* Otherwise, for a connection port, use the same port object */
            QueuePort = ReplyPort = Port;
        }

        /* No reply thread */
        Message->RepliedToThread = NULL;
        Message->SenderPort = Port;

        /* Generate the Message ID and set it */
        Message->Request.MessageId =  LpcpNextMessageId++;
        if (!LpcpNextMessageId) LpcpNextMessageId = 1;
        Message->Request.CallbackId = 0;

        /* Set the message ID for our thread now */
        Thread->LpcReplyMessageId = Message->Request.MessageId;
        Thread->LpcReplyMessage = NULL;

        /* Insert the message in our chain */
        InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
        InsertTailList(&ReplyPort->LpcReplyChainHead, &Thread->LpcReplyChain);
        LpcpSetPortToThread(Thread, Port);

        /* Release the lock and get the semaphore we'll use later */
        KeEnterCriticalRegion();
        KeReleaseGuardedMutex(&LpcpLock);
        Semaphore = QueuePort->MsgQueue.Semaphore;

        /* If this is a waitable port, wake it up */
        if (QueuePort->Flags & LPCP_WAITABLE_PORT)
        {
            /* Wake it */
            KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
        }
    }

    /* Now release the semaphore */
    LpcpCompleteWait(Semaphore);
    KeLeaveCriticalRegion();

    /* And let's wait for the reply */
    LpcpReplyWait(&Thread->LpcReplySemaphore, PreviousMode);

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

    /* Get the LPC Message and clear our thread's reply data */
    Message = LpcpGetMessageFromThread(Thread);
    Thread->LpcReplyMessage = NULL;
    Thread->LpcReplyMessageId = 0;

    /* Check if we have anything on the reply chain*/
    if (!IsListEmpty(&Thread->LpcReplyChain))
    {
        /* Remove this thread and reinitialize the list */
        RemoveEntryList(&Thread->LpcReplyChain);
        InitializeListHead(&Thread->LpcReplyChain);
    }

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

    /* Check if we got a reply */
    if (Status == STATUS_SUCCESS)
    {
        /* Check if we have a valid message */
        if (Message)
        {
            LPCTRACE(LPC_SEND_DEBUG,
                     "Reply Messages: %p/%p\n",
                     &Message->Request,
                     (&Message->Request) + 1);

            /* Move the message */
            LpcpMoveMessage(LpcReply,
                            &Message->Request,
                            (&Message->Request) + 1,
                            0,
                            NULL);

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

            /* Check if we replied to a thread */
            if (Message->RepliedToThread)
            {
                /* Dereference */
                ObDereferenceObject(Message->RepliedToThread);
                Message->RepliedToThread = NULL;
            }


            /* Free the message */
            LpcpFreeToPortZone(Message, 3);
        }
        else
        {
            /* We don't have a reply */
            Status = STATUS_LPC_REPLY_LOST;
        }
    }
    else
    {
        /* The wait failed, free the message */
        if (Message) LpcpFreeToPortZone(Message, 0);
    }

    /* All done */
    LPCTRACE(LPC_SEND_DEBUG,
             "Port: %p. Status: %p\n",
             Port,
             Status);

    /* Dereference the connection port */
    if (ConnectionPort) ObDereferenceObject(ConnectionPort);
    return Status;
}
Example #26
0
NTSTATUS
KeUserModeCallback (
    IN ULONG ApiNumber,
    IN PVOID InputBuffer,
    IN ULONG InputLength,
    OUT PVOID *OutputBuffer,
    IN PULONG OutputLength
    )

/*++

Routine Description:

    This function call out from kernel mode to a user mode function.

Arguments:

    ApiNumber - Supplies the API number.

    InputBuffer - Supplies a pointer to a structure that is copied
        to the user stack.

    InputLength - Supplies the length of the input structure.

    Outputbuffer - Supplies a pointer to a variable that receives
        the address of the output buffer.

    Outputlength - Supplies a pointer to a variable that receives
        the length of the output buffer.

Return Value:

    If the callout cannot be executed, then an error status is
    returned. Otherwise, the status returned by the callback function
    is returned.

--*/

{
    PUCALLOUT_FRAME CalloutFrame;
    ULONGLONG OldStack;
    ULONGLONG NewStack;
    ULONGLONG OldStIFS;
    PKTRAP_FRAME TrapFrame;
    NTSTATUS Status;
    ULONG Length;
    SHORT BsFrameSize;
    USHORT TearPointOffset;

    ASSERT(KeGetPreviousMode() == UserMode);

    //
    // Get the user mode stack pointer and attempt to copy input buffer
    // to the user stack.
    //

    TrapFrame = KeGetCurrentThread()->TrapFrame;
    OldStack = TrapFrame->IntSp;
    OldStIFS = TrapFrame->StIFS;

    try {

        //
        // Compute new user mode stack address, probe for writability,
        // and copy the input buffer to the user stack.
        //
        // N.B. EM requires stacks to be 16-byte aligned, therefore
        //      the input length must be rounded up to a 16-byte boundary.
        //

        Length =  (InputLength + 16 - 1 + sizeof(UCALLOUT_FRAME) + STACK_SCRATCH_AREA) & ~(16 - 1);
        NewStack = OldStack - Length;
        CalloutFrame = (PUCALLOUT_FRAME)(NewStack + STACK_SCRATCH_AREA);
        ProbeForWrite((PVOID)NewStack, Length, sizeof(QUAD));
        RtlCopyMemory(CalloutFrame + 1, InputBuffer, InputLength);

        //
        // Fill in the callout arguments.
        //

        CalloutFrame->Buffer = (PVOID)(CalloutFrame + 1);
        CalloutFrame->Length = InputLength;
        CalloutFrame->ApiNumber = ApiNumber;
        CalloutFrame->IntSp = OldStack;
        CalloutFrame->RsPFS = TrapFrame->StIFS;
        CalloutFrame->BrRp = TrapFrame->BrRp;

      if (PsGetCurrentProcess()->DebugPort != NULL) {
        KiFlushRse();
        BsFrameSize = (SHORT)(TrapFrame->RsBSP - TrapFrame->RsBSPSTORE);
        if (BsFrameSize) {

            ULONGLONG TopBound, BottomBound;
            ULONGLONG UserRnats1, UserRnats2;
            ULONGLONG Mask;
            ULONGLONG CurrentRNAT = 0;
            SHORT RNatSaveIndex;

            //
            // Copy the dirty stacked registers back into the
            // user backing store
            //

            TearPointOffset = (USHORT) TrapFrame->RsBSPSTORE & 0x1F8;
            RtlCopyMemory((PVOID)(TrapFrame->RsBSPSTORE),
                         (PVOID)(PCR->InitialBStore + TearPointOffset),
                         BsFrameSize);

            TopBound = TrapFrame->RsBSP | RNAT_ALIGNMENT;
            BottomBound = TrapFrame->RsBSPSTORE | RNAT_ALIGNMENT;

            RNatSaveIndex = TearPointOffset >> 3;
            Mask = (((1ULL << (NAT_BITS_PER_RNAT_REG - RNatSaveIndex)) - 1) << RNatSaveIndex);
            UserRnats1 = TrapFrame->RsRNAT & ((1ULL << RNatSaveIndex) - 1);

            if (TopBound > BottomBound) {

                //
                // user dirty stacked GR span across at least one RNAT
                // boundary; need to deposit the valid RNAT bits from
                // the trap frame into the kernel backing store.  Also,
                // the RNAT field in the trap frame has to be updated.
                //

                UserRnats2 = *(PULONGLONG)BottomBound & Mask;
                *(PULONGLONG)BottomBound = UserRnats1 | UserRnats2;
                TrapFrame->RsRNAT = CurrentRNAT;
                
            } else {

                //
                // user stacked register region does not span across an
                // RNAT boundary; combine the RNAT fields from both the
                // trap frame and the context frame.
                //

                UserRnats2 = CurrentRNAT & Mask;
                TrapFrame->RsRNAT = UserRnats1 | UserRnats2;

            }

            TrapFrame->RsBSPSTORE = TrapFrame->RsBSP;
        }
      }

    //
    // If an exception occurs during the probe of the user stack, then
    // always handle the exception and return the exception code as the
    // status value.
    //

    } except (EXCEPTION_EXECUTE_HANDLER) {
Example #27
0
NTSTATUS
NtSuspendThread(
    IN HANDLE ThreadHandle,
    OUT PULONG PreviousSuspendCount OPTIONAL
    )

/*++

Routine Description:

    This function suspends the target thread, and optionally
    returns the previous suspend count.

Arguments:

    ThreadHandle - Supplies a handle to the thread object to suspend.

    PreviousSuspendCount - An optional parameter, that if specified
        points to a variable that receives the thread's previous suspend
        count.

Return Value:

    return-value - Description of conditions needed to return value. - or -
    None.

--*/

{
    PETHREAD Thread;
    NTSTATUS st;
    ULONG LocalPreviousSuspendCount;
    KPROCESSOR_MODE Mode;

    PAGED_CODE();

    try {

        Mode = KeGetPreviousMode();

        if ( Mode != KernelMode ) {
            if (ARGUMENT_PRESENT(PreviousSuspendCount)) {
                ProbeForWriteUlong(PreviousSuspendCount);
            }
        }
    } except (EXCEPTION_EXECUTE_HANDLER) {

        return GetExceptionCode();
    }

    st = ObReferenceObjectByHandle(
            ThreadHandle,
            THREAD_SUSPEND_RESUME,
            PsThreadType,
            Mode,
            (PVOID *)&Thread,
            NULL
            );

    if ( !NT_SUCCESS(st) ) {
        return st;
    }

    try {

        if ( Thread != PsGetCurrentThread() ) {
            if ( Thread->HasTerminated ) {
                ObDereferenceObject(Thread);
                return STATUS_THREAD_IS_TERMINATING;
            }

            LocalPreviousSuspendCount = (ULONG) KeSuspendThread(&Thread->Tcb);

        } else {
            LocalPreviousSuspendCount = (ULONG) KeSuspendThread(&Thread->Tcb);
        }

        ObDereferenceObject(Thread);

        if (ARGUMENT_PRESENT(PreviousSuspendCount))
            *PreviousSuspendCount = LocalPreviousSuspendCount;

    } except (EXCEPTION_EXECUTE_HANDLER) {

        st = GetExceptionCode();

        //
        // Either the suspend, or the store could cause an
        // exception. The store is a partial success, while the
        // suspend exception is an error
        //

        if ( st == STATUS_SUSPEND_COUNT_EXCEEDED ) {
            ObDereferenceObject(Thread);
        } else {
            st = STATUS_SUCCESS;
        }

        return st;
    }

    return STATUS_SUCCESS;

}
Example #28
0
NTSTATUS
NtSignalAndWaitForSingleObject(
    IN HANDLE SignalHandle,
    IN HANDLE WaitHandle,
    IN BOOLEAN Alertable,
    IN PLARGE_INTEGER Timeout OPTIONAL
    )

/*++

Routine Description:

    This function atomically signals the specified signal object and then
    waits until the specified wait object attains a state of Signaled. An
    optional timeout can also be specified. If a timeout is not specified,
    then the wait will not be satisfied until the wait object attains a
    state of Signaled. If a timeout is specified, and the wait object has
    not attained a state of Signaled when the timeout expires, then the
    wait is automatically satisfied. If an explicit timeout value of zero
    is specified, then no wait will occur if the wait cannot be satisfied
    immediately. The wait can also be specified as alertable.

Arguments:

    SignalHandle - supplies the handle of the signal object.

    WaitHandle  - Supplies the handle for the wait object.

    Alertable - Supplies a boolean value that specifies whether the wait
        is alertable.

    Timeout - Supplies an pointer to an absolute or relative time over
        which the wait is to occur.

Return Value:

    The wait completion status. A value of STATUS_TIMEOUT is returned if a
    timeout occurred. A value of STATUS_SUCCESS is returned if the specified
    object satisfied the wait. A value of STATUS_ALERTED is returned if the
    wait was aborted to deliver an alert to the current thread. A value of
    STATUS_USER_APC is returned if the wait was aborted to deliver a user
    APC to the current thread.

--*/

{

    OBJECT_HANDLE_INFORMATION HandleInformation;
    KPROCESSOR_MODE PreviousMode;
    PVOID RealObject;
    PVOID SignalObject;
    POBJECT_HEADER SignalObjectHeader;
    NTSTATUS Status;
    LARGE_INTEGER TimeoutValue;
    PVOID WaitObject;
    POBJECT_HEADER WaitObjectHeader;

    //
    // Establish an exception handler and probe the specified timeout value
    // if necessary. If the probe fails, then return the exception code as
    // the service status.
    //

    PreviousMode = KeGetPreviousMode();
    if ((ARGUMENT_PRESENT(Timeout)) && (PreviousMode != KernelMode)) {
        try {
            TimeoutValue = ProbeAndReadLargeInteger(Timeout);
            Timeout = &TimeoutValue;

        } except(EXCEPTION_EXECUTE_HANDLER) {
            return GetExceptionCode();
        }
    }

    //
    // Reference the signal object by handle.
    //

    Status = ObReferenceObjectByHandle(SignalHandle,
                                       0,
                                       NULL,
                                       PreviousMode,
                                       &SignalObject,
                                       &HandleInformation);

    //
    // If the reference was successful, then reference the wait object by
    // handle.
    //

    if (NT_SUCCESS(Status)) {
        Status = ObReferenceObjectByHandle(WaitHandle,
                                           SYNCHRONIZE,
                                           NULL,
                                           PreviousMode,
                                           &WaitObject,
                                           NULL);

        //
        // If the reference was successful, then determine the real wait
        // object, check the signal object access, signal the signal object,
        // and wait for the real wait object.
        //

        if (NT_SUCCESS(Status)) {
            WaitObjectHeader = OBJECT_TO_OBJECT_HEADER(WaitObject);
            RealObject = WaitObjectHeader->Type->DefaultObject;
            if ((LONG)RealObject >= 0) {
                RealObject = (PVOID)((PCHAR)WaitObject + (ULONG)RealObject);
            }

            //
            // If the signal object is an event, then check for modify access
            // and set the event. Otherwise, if the signal object is a mutant,
            // then attempt to release ownership of the mutant. Otherwise, if
            // the object is a semaphore, then check for modify access and
            // release the semaphore. Otherwise, the signal objet is invalid.
            //

            SignalObjectHeader = OBJECT_TO_OBJECT_HEADER(SignalObject);
            Status = STATUS_ACCESS_DENIED;
            if (SignalObjectHeader->Type == ExEventObjectType) {

                //
                // Check for access to the specified event object,
                //

                if ((PreviousMode != KernelMode) &&
                    (SeComputeDeniedAccesses(HandleInformation.GrantedAccess,
                                             EVENT_MODIFY_STATE) != 0)) {
                    goto WaitExit;
                }

                //
                // If the wait object is also an event, the wait is not
                // alertable, and no timeout was specified, then the event
                // pair path can be used. Otherwise, set the event and wait
                // atomically.
                //

                if ((WaitObjectHeader->Type == ExEventObjectType) &&
                    (Alertable == FALSE) &&
                    (Timeout == NULL)) {
                    Status = KiSetServerWaitClientEvent((PKEVENT)SignalObject,
                                                        (PKEVENT)RealObject,
                                                        PreviousMode);

                    goto WaitExit;
                }

                //
                // Set the specified event and wait atomically.
                //

                KeSetEvent((PKEVENT)SignalObject, EVENT_INCREMENT, TRUE);

            } else if (SignalObjectHeader->Type == ExMutantObjectType) {

                //
                // Release the specified mutant and wait atomically.
                //
                // N.B. The release will only be successful if the current
                //      thread is the owner of the mutant.
                //

                try {
                    KeReleaseMutant((PKMUTANT)SignalObject,
                                    MUTANT_INCREMENT,
                                    FALSE,
                                    TRUE);

                } except(EXCEPTION_EXECUTE_HANDLER) {
                    Status = GetExceptionCode();
                    goto WaitExit;
                }

            } else if (SignalObjectHeader->Type == ExSemaphoreObjectType) {

                //
                // Check for access to the specified semaphore object,
                //

                if ((PreviousMode != KernelMode) &&
                    (SeComputeDeniedAccesses(HandleInformation.GrantedAccess,
                                             SEMAPHORE_MODIFY_STATE) != 0)) {
                    goto WaitExit;
                }

                //
                // Release the specified semaphore and wait atomically.
                //

                try {

                    //
                    // If the wait object is also a semaphore, the wait is
                    // not alertable, and no timeout was specified, then
                    // the semaphore path can be used. Otherwise, release
                    // the semaphore and wait atomically.
                    //

                    if ((WaitObjectHeader->Type == ExSemaphoreObjectType) &&
                        (Alertable == FALSE) &&
                        (Timeout == NULL)) {
                        Status = KeReleaseWaitForSemaphore((PKSEMAPHORE)SignalObject,
                                                           (PKSEMAPHORE)RealObject,
                                                           UserRequest,
                                                           PreviousMode);

                        goto WaitExit;
                    }

                    //
                    // Release the specified semaphore and wait atomically.
                    //

                    KeReleaseSemaphore((PKSEMAPHORE)SignalObject,
                                       SEMAPHORE_INCREMENT,
                                       1,
                                       TRUE);

                } except(EXCEPTION_EXECUTE_HANDLER) {
                    Status = GetExceptionCode();
                    goto WaitExit;
                }

            } else {
                Status =
                STATUS_OBJECT_TYPE_MISMATCH;
                goto WaitExit;
            }

            Status = KeWaitForSingleObject(RealObject,
                                           UserRequest,
                                           PreviousMode,
                                           Alertable,
                                           Timeout);

        WaitExit:
            ObDereferenceObject(WaitObject);
        }
Example #29
0
NTSTATUS
NTAPI
NtTerminateThread(IN HANDLE ThreadHandle,
                  IN NTSTATUS ExitStatus)
{
    PETHREAD Thread;
    PETHREAD CurrentThread = PsGetCurrentThread();
    NTSTATUS Status;
    PAGED_CODE();
    PSTRACE(PS_KILL_DEBUG,
            "ThreadHandle: %p ExitStatus: %d\n", ThreadHandle, ExitStatus);

    /* Handle the special NULL case */
    if (!ThreadHandle)
    {
        /* Check if we're the only thread left */
        if (PsGetCurrentProcess()->ActiveThreads == 1)
        {
            /* This is invalid */
            return STATUS_CANT_TERMINATE_SELF;
        }

        /* Terminate us directly */
        goto TerminateSelf;
    }
    else if (ThreadHandle == NtCurrentThread())
    {
TerminateSelf:
        /* Terminate this thread */
        return PspTerminateThreadByPointer(CurrentThread,
                                           ExitStatus,
                                           TRUE);
    }

    /* We are terminating another thread, get the Thread Object */
    Status = ObReferenceObjectByHandle(ThreadHandle,
                                       THREAD_TERMINATE,
                                       PsThreadType,
                                       KeGetPreviousMode(),
                                       (PVOID*)&Thread,
                                       NULL);
    if (!NT_SUCCESS(Status)) return Status;

    /* Check to see if we're running in the same thread */
    if (Thread != CurrentThread)
    {
        /* Terminate it */
        Status = PspTerminateThreadByPointer(Thread, ExitStatus, FALSE);

        /* Dereference the Thread and return */
        ObDereferenceObject(Thread);
    }
    else
    {
        /* Dereference the thread and terminate ourselves */
        ObDereferenceObject(Thread);
        goto TerminateSelf;
    }

    /* Return status */
    return Status;
}
Example #30
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;
}