Пример #1
0
/*++
* @name NtQuerySecurityObject
* @implemented NT4
*
*     The NtQuerySecurityObject routine <FILLMEIN>
*
* @param Handle
*        <FILLMEIN>
*
* @param SecurityInformation
*        <FILLMEIN>
*
* @param SecurityDescriptor
*        <FILLMEIN>
*
* @param Length
*        <FILLMEIN>
*
* @param ResultLength
*        <FILLMEIN>
*
* @return STATUS_SUCCESS or appropriate error value.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
NtQuerySecurityObject(IN HANDLE Handle,
                      IN SECURITY_INFORMATION SecurityInformation,
                      OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
                      IN ULONG Length,
                      OUT PULONG ResultLength)
{
    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
    PVOID Object;
    POBJECT_HEADER Header;
    POBJECT_TYPE Type;
    ACCESS_MASK DesiredAccess;
    NTSTATUS Status;
    PAGED_CODE();

    /* Check if we came from user mode */
    if (PreviousMode != KernelMode)
    {
        /* Enter SEH */
        _SEH2_TRY
        {
            /* Probe the SD and the length pointer */
            ProbeForWrite(SecurityDescriptor, Length, sizeof(ULONG));
            ProbeForWriteUlong(ResultLength);
        }
        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
        {
            /* Return the exception code */
            _SEH2_YIELD(return _SEH2_GetExceptionCode());
        }
        _SEH2_END;
    }
Пример #2
0
NTSTATUS
NTAPI
NtAlertResumeThread(IN HANDLE ThreadHandle,
                    OUT PULONG SuspendCount)
{
    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
    PETHREAD Thread;
    NTSTATUS Status;
    ULONG PreviousState;

    /* Check if we came from user mode with a suspend count */
    if ((SuspendCount) && (PreviousMode != KernelMode))
    {
        /* Enter SEH for probing */
        _SEH2_TRY
        {
            /* Probe the count */
            ProbeForWriteUlong(SuspendCount);
        }
        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
        {
            /* Return the exception code */
            _SEH2_YIELD(return _SEH2_GetExceptionCode());
        }
        _SEH2_END;
    }
Пример #3
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;
        }
}
Пример #4
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;

}
Пример #5
0
NTSTATUS
NtAlertResumeThread(
    IN HANDLE ThreadHandle,
    OUT PULONG PreviousSuspendCount OPTIONAL
    )

/*++

Routine Description:

    description-of-function.

Arguments:

    argument-name - Supplies | Returns description of argument.
    .
    .

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;
    }

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

    ObDereferenceObject(Thread);

    try {

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

    } except (EXCEPTION_EXECUTE_HANDLER) {

        return STATUS_SUCCESS;
    }

    return STATUS_SUCCESS;
}
Пример #6
0
NTSTATUS
NtQueryEvent (
    IN HANDLE EventHandle,
    IN EVENT_INFORMATION_CLASS EventInformationClass,
    OUT PVOID EventInformation,
    IN ULONG EventInformationLength,
    OUT PULONG ReturnLength OPTIONAL
)

/*++

Routine Description:

    This function queries the state of an event object and returns the
    requested information in the specified record structure.

Arguments:

    EventHandle - Supplies a handle to an event object.

    EventInformationClass - Supplies the class of information being requested.

    EventInformation - Supplies a pointer to a record that is to receive the
        requested information.

    EventInformationLength - Supplies the length of the record that is to
        receive the requested information.

    ReturnLength - Supplies an optional pointer to a variable that is to
        receive the actual length of information that is returned.

Return Value:

    TBS

--*/

{

    PKEVENT Event;
    KPROCESSOR_MODE PreviousMode;
    LONG State;
    NTSTATUS Status;
    EVENT_TYPE EventType;

    //
    // Check argument validity.
    //

    if (EventInformationClass != EventBasicInformation) {
        return STATUS_INVALID_INFO_CLASS;
    }

    if (EventInformationLength != sizeof(EVENT_BASIC_INFORMATION)) {
        return STATUS_INFO_LENGTH_MISMATCH;
    }

    //
    // Establish an exception handler, probe the output arguments, reference
    // the event object, and return the specified information. If the probe
    // fails, then return the exception code as the service status. Otherwise
    // return the status value returned by the reference object by handle
    // routine.
    //

    try {

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

        PreviousMode = KeGetPreviousMode();
        if (PreviousMode != KernelMode) {
            ProbeForWrite(EventInformation,
                          sizeof(EVENT_BASIC_INFORMATION),
                          sizeof(ULONG));

            if (ARGUMENT_PRESENT(ReturnLength)) {
                ProbeForWriteUlong(ReturnLength);
            }
        }

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

        Status = ObReferenceObjectByHandle(EventHandle,
                                           EVENT_QUERY_STATE,
                                           ExEventObjectType,
                                           PreviousMode,
                                           (PVOID *)&Event,
                                           NULL);

        //
        // If the reference was successful, then read the current state of
        // the event object, deference event object, fill in the information
        // structure, and return the length of the information structure if
        // specified. If the write of the event information or the return
        // length fails, then do not report an error. When the caller accesses
        // the information structure or length an access violation will occur.
        //

        if (NT_SUCCESS(Status)) {
            State = KeReadStateEvent(Event);
            EventType = Event->Header.Type;
            ObDereferenceObject(Event);
            try {
                ((PEVENT_BASIC_INFORMATION)EventInformation)->EventType = EventType;
                ((PEVENT_BASIC_INFORMATION)EventInformation)->EventState = State;
                if (ARGUMENT_PRESENT(ReturnLength)) {
                    *ReturnLength = sizeof(EVENT_BASIC_INFORMATION);
                }

            }
            except(ExSystemExceptionFilter()) {
            }
        }

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

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

    //
    // Return service status.
    //

    return Status;
}
Пример #7
0
NTSTATUS
NtQuerySection(
    IN HANDLE SectionHandle,
    IN SECTION_INFORMATION_CLASS SectionInformationClass,
    OUT PVOID SectionInformation,
    IN ULONG SectionInformationLength,
    OUT PULONG ReturnLength OPTIONAL
)

/*++

Routine Description:

   This function returns information about an opened section object.
   This function provides the capability to determine the base address,
   size, granted access, and allocation of an opened section object.

Arguments:

    SectionHandle - Supplies an open handle to a section object.

    SectionInformationClass - The section information class about
        which to retrieve information.

    SectionInformation - A pointer to a buffer that receives the
        specified information.  The format and content of the buffer
        depend on the specified section class.

       SectionInformation Format by Information Class:

       SectionBasicInformation - Data type is PSECTION_BASIC_INFORMATION.

           SECTION_BASIC_INFORMATION Structure

           PVOID BaseAddress - The base virtual address of the
               section if the section is based.

           LARGE_INTEGER MaximumSize - The maximum size of the section in
               bytes.

           ULONG AllocationAttributes - The allocation attributes
               flags.

               AllocationAttributes Flags

               SEC_BASED - The section is a based section.

               SEC_TILE - The section must be allocated in the first
                   512mb of the virtual address space.

               SEC_FILE - The section is backed by a data file.

               SEC_RESERVE - All pages of the section were initially
                   set to the reserved state.

               SEC_COMMIT - All pages of the section were initially
                   to the committed state.

               SEC_IMAGE - The section was mapped as an executable
                   image file.

        SECTION_IMAGE_INFORMATION

    SectionInformationLength - Specifies the length in bytes of the
        section information buffer.

    ReturnLength - An optional pointer which, if specified, receives
        the number of bytes placed in the section information buffer.


Return Value:

    Returns the status

    TBS


--*/

{
    PSECTION Section;
    KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;

    PAGED_CODE();

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

    PreviousMode = KeGetPreviousMode();
    if (PreviousMode != KernelMode) {

        //
        // Check arguments.
        //

        try {

            ProbeForWrite(SectionInformation,
                          SectionInformationLength,
                          sizeof(ULONG));

            if (ARGUMENT_PRESENT (ReturnLength)) {
                ProbeForWriteUlong(ReturnLength);
            }

        }
        except (EXCEPTION_EXECUTE_HANDLER) {

            //
            // If an exception occurs during the probe or capture
            // of the initial values, then handle the exception and
            // return the exception code as the status value.
            //

            return GetExceptionCode();
        }
    }

    //
    // Check argument validity.
    //

    if ((SectionInformationClass != SectionBasicInformation) &&
            (SectionInformationClass != SectionImageInformation)) {
        return STATUS_INVALID_INFO_CLASS;
    }

    if (SectionInformationClass == SectionBasicInformation) {
        if (SectionInformationLength < (ULONG)sizeof(SECTION_BASIC_INFORMATION)) {
            return STATUS_INFO_LENGTH_MISMATCH;
        }
    } else {
        if (SectionInformationLength < (ULONG)sizeof(SECTION_IMAGE_INFORMATION)) {
            return STATUS_INFO_LENGTH_MISMATCH;
        }
    }

    //
    // Reference section object by handle for READ access, get the information
    // from the section object, dereference the section
    // object, fill in information structure, optionally return the length of
    // the information structure, and return service status.
    //

    Status = ObReferenceObjectByHandle(SectionHandle, SECTION_QUERY,
                                       MmSectionObjectType,
                                       PreviousMode, (PVOID *)&Section, NULL);

    if (NT_SUCCESS(Status)) {

        try {

            if (SectionInformationClass == SectionBasicInformation) {
                ((PSECTION_BASIC_INFORMATION)SectionInformation)->BaseAddress =
                    (PVOID)Section->Address.StartingVpn;

                ((PSECTION_BASIC_INFORMATION)SectionInformation)->MaximumSize =
                    Section->SizeOfSection;

                ((PSECTION_BASIC_INFORMATION)SectionInformation)->AllocationAttributes =
                    0;

                if (Section->u.Flags.Image) {
                    ((PSECTION_BASIC_INFORMATION)SectionInformation)->AllocationAttributes =
                        SEC_IMAGE;
                }
                if (Section->u.Flags.Based) {
                    ((PSECTION_BASIC_INFORMATION)SectionInformation)->AllocationAttributes |=
                        SEC_BASED;
                }
                if (Section->u.Flags.File) {
                    ((PSECTION_BASIC_INFORMATION)SectionInformation)->AllocationAttributes |=
                        SEC_FILE;
                }
                if (Section->u.Flags.NoCache) {
                    ((PSECTION_BASIC_INFORMATION)SectionInformation)->AllocationAttributes |=
                        SEC_NOCACHE;
                }
                if (Section->u.Flags.Reserve) {
                    ((PSECTION_BASIC_INFORMATION)SectionInformation)->AllocationAttributes |=
                        SEC_RESERVE;
                }
                if (Section->u.Flags.Commit) {
                    ((PSECTION_BASIC_INFORMATION)SectionInformation)->AllocationAttributes |=
                        SEC_COMMIT;
                }
                if (Section->Segment->ControlArea->u.Flags.GlobalMemory) {
                    ((PSECTION_BASIC_INFORMATION)SectionInformation)->AllocationAttributes |=
                        SEC_GLOBAL;
                }

                if (ARGUMENT_PRESENT(ReturnLength)) {
                    *ReturnLength = sizeof(SECTION_BASIC_INFORMATION);
                }

            } else {

                if (Section->u.Flags.Image == 0) {
                    Status = STATUS_SECTION_NOT_IMAGE;
                }
                else {
                    *((PSECTION_IMAGE_INFORMATION)SectionInformation) =
                        *Section->Segment->ImageInformation;

                    if (ARGUMENT_PRESENT(ReturnLength)) {
                        *ReturnLength = sizeof(SECTION_IMAGE_INFORMATION);
                    }
                }
            }

        }
        except (EXCEPTION_EXECUTE_HANDLER) {

        }

        ObDereferenceObject ((PVOID)Section);
    }
    return Status;
}
Пример #8
0
NTSTATUS
NtQueryTimer (
    IN HANDLE TimerHandle,
    IN TIMER_INFORMATION_CLASS TimerInformationClass,
    OUT PVOID TimerInformation,
    IN ULONG TimerInformationLength,
    OUT PULONG ReturnLength OPTIONAL
    )

/*++

Routine Description:

    This function queries the state of an timer object and returns the
    requested information in the specified record structure.

Arguments:

    TimerHandle - Supplies a handle to an timer object.

    TimerInformationClass - Supplies the class of information being requested.

    TimerInformation - Supplies a pointer to a record that is to receive the
        requested information.

    TimerInformationLength - Supplies the length of the record that is to
        receive the requested information.

    ReturnLength - Supplies an optional pointer to a variable that is to
        receive the actual length of information that is returned.

Return Value:

    TBS

--*/

{

    PETIMER ExTimer;
    PKTIMER KeTimer;
    KPROCESSOR_MODE PreviousMode;
    BOOLEAN State;
    NTSTATUS Status;
    LARGE_INTEGER TimeToGo;

    //
    // Establish an exception handler, probe the output arguments, reference
    // the timer object, and return the specified information. If the probe
    // fails, then return the exception code as the service status. Otherwise
    // return the status value returned by the reference object by handle
    // routine.
    //

    try {

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

        PreviousMode = KeGetPreviousMode();
        if (PreviousMode != KernelMode) {
            ProbeForWrite(TimerInformation,
                          sizeof(TIMER_BASIC_INFORMATION),
                          sizeof(ULONG));

            if (ARGUMENT_PRESENT(ReturnLength)) {
                ProbeForWriteUlong(ReturnLength);
            }
        }

        //
        // Check argument validity.
        //

        if (TimerInformationClass != TimerBasicInformation) {
            return STATUS_INVALID_INFO_CLASS;
        }

        if (TimerInformationLength != sizeof(TIMER_BASIC_INFORMATION)) {
            return STATUS_INFO_LENGTH_MISMATCH;
        }

        //
        // Reference timer object by handle.
        //

        Status = ObReferenceObjectByHandle(TimerHandle,
                                           TIMER_QUERY_STATE,
                                           ExTimerObjectType,
                                           PreviousMode,
                                           (PVOID *)&ExTimer,
                                           NULL);

        //
        // If the reference was successful, then read the current state,
        // compute the time remaining, dereference the timer object, fill in
        // the information structure, and return the length of the information
        // structure if specified. If the write of the time information or the
        // return length fails, then do not report an error. When the caller
        // accesses the information structure or the length, an violation will
        // occur.
        //

        if (NT_SUCCESS(Status)) {
            KeTimer = &ExTimer->KeTimer;
            State = KeReadStateTimer(KeTimer);
            KiQueryInterruptTime(&TimeToGo);
            TimeToGo.QuadPart = KeTimer->DueTime.QuadPart - TimeToGo.QuadPart;
            ObDereferenceObject(ExTimer);
            try {
                ((PTIMER_BASIC_INFORMATION)TimerInformation)->TimerState = State;
                ((PTIMER_BASIC_INFORMATION)TimerInformation)->RemainingTime = TimeToGo;
                if (ARGUMENT_PRESENT(ReturnLength)) {
                    *ReturnLength = sizeof(TIMER_BASIC_INFORMATION);
                }

            } except(ExSystemExceptionFilter()) {
            }
        }

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

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

    //
    // Return service status.
    //

    return Status;
}
Пример #9
0
NTSTATUS
NtReplyWaitReceivePortEx(
    __in HANDLE PortHandle,
    __out_opt PVOID *PortContext,
    __in_opt PPORT_MESSAGE ReplyMessage,
    __out PPORT_MESSAGE ReceiveMessage,
    __in_opt PLARGE_INTEGER Timeout
    )

/*++

Routine Description:

    See NtReplyWaitReceivePort.

Arguments:

    See NtReplyWaitReceivePort.

    Timeout - Supplies an optional timeout value to use when waiting for a
        receive.

Return Value:

    See NtReplyWaitReceivePort.

--*/

{
    PLPCP_PORT_OBJECT PortObject;
    PLPCP_PORT_OBJECT ReceivePort;
    PORT_MESSAGE CapturedReplyMessage;
    KPROCESSOR_MODE PreviousMode;
    KPROCESSOR_MODE WaitMode;
    NTSTATUS Status;
    PLPCP_MESSAGE Msg;
    PETHREAD CurrentThread;
    PETHREAD WakeupThread;
    LARGE_INTEGER TimeoutValue ;
    PLPCP_PORT_OBJECT ConnectionPort = NULL;

    PAGED_CODE();

    CurrentThread = PsGetCurrentThread();

    TimeoutValue.QuadPart = 0 ;

    //
    //  Get previous processor mode
    //

    PreviousMode = KeGetPreviousMode();
    WaitMode = PreviousMode;

    if (PreviousMode != KernelMode) {

        try {

            if (ARGUMENT_PRESENT( PortContext )) {

                ProbeForWriteUlong( (PULONG)PortContext );
            }

            if (ARGUMENT_PRESENT( ReplyMessage)) {

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

                CapturedReplyMessage = *ReplyMessage;
            }

            if (ARGUMENT_PRESENT( Timeout )) {

                TimeoutValue = ProbeAndReadLargeInteger( Timeout );

                Timeout = &TimeoutValue ;
            }

            ProbeForWriteSmallStructure( ReceiveMessage,
                                         sizeof( *ReceiveMessage ),
                                         sizeof( ULONG ));

        } except( EXCEPTION_EXECUTE_HANDLER ) {

            return GetExceptionCode();
        }

    } else {

        //
        //  Kernel mode threads call with wait mode of user so that their
        //  kernel // stacks are swappable. Main consumer of this is
        //  SepRmCommandThread
        //

        if ( IS_SYSTEM_THREAD(CurrentThread) ) {
Пример #10
0
NTSTATUS
NtW32Call (
    IN ULONG ApiNumber,
    IN PVOID InputBuffer,
    IN ULONG InputLength,
    OUT PVOID *OutputBuffer,
    OUT PULONG OutputLength
    )

/*++

Routine Description:

    This function calls a W32 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 recevies the
        output buffer address.

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

Return Value:

    TBS.

--*/

{
    PVOID ValueBuffer;
    ULONG ValueLength;
    NTSTATUS Status;

    ASSERT(KeGetPreviousMode() == UserMode);

    //
    // If the current thread is not a GUI thread, then fail the service
    // since the thread does not have a large stack.
    //

    if (KeGetCurrentThread()->Win32Thread == (PVOID)&KeServiceDescriptorTable[0]) {
        return STATUS_NOT_IMPLEMENTED;
    }

    //
    // Probe the output buffer address and length for writeability.
    //

    try {
        ProbeForWriteUlong((PULONG)OutputBuffer);
        ProbeForWriteUlong(OutputLength);

    //
    // If an exception occurs during the probe of the output buffer or
    // length, then always handle the exception and return the exception
    // code as the status value.
    //

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

    //
    // Call out to user mode specifying the input buffer and API number.
    //

    Status = KeUserModeCallback(ApiNumber,
                                InputBuffer,
                                InputLength,
                                &ValueBuffer,
                                &ValueLength);

    //
    // If the callout is successful, then the output buffer address and
    // length.
    //

    if (NT_SUCCESS(Status)) {
        try {
            *OutputBuffer = ValueBuffer;
            *OutputLength = ValueLength;

        } except(EXCEPTION_EXECUTE_HANDLER) {
        }
    }

    return Status;
}
Пример #11
0
NTSTATUS
NtSystemDebugControl (
    IN SYSDBG_COMMAND Command,
    IN PVOID InputBuffer,
    IN ULONG InputBufferLength,
    OUT PVOID OutputBuffer,
    IN ULONG OutputBufferLength,
    OUT PULONG ReturnLength OPTIONAL
    )

/*++

Routine Description:

    This function controls the system debugger.

Arguments:

    Command - The command to be executed.  One of the following:

        SysDbgQueryTraceInformation
        SysDbgSetTracepoint
        SysDbgSetSpecialCall
        SysDbgClearSpecialCalls
        SysDbgQuerySpecialCalls

    InputBuffer - A pointer to a buffer describing the input data for
        the request, if any.  The structure of this buffer varies
        depending upon Command.

    InputBufferLength - The length in bytes of InputBuffer.

    OutputBuffer - A pointer to a buffer that is to receive the output
        data for the request, if any.  The structure of this buffer
        varies depending upon Command.

    OutputBufferLength - The length in bytes of OutputBuffer.

    ReturnLength - A optional pointer to a ULONG that is to receive the
        output data length for the request.

Return Value:

    Returns one of the following status codes:

        STATUS_SUCCESS - normal, successful completion.

        STATUS_INVALID_INFO_CLASS - The Command parameter did not
            specify a valid value.

        STATUS_INFO_LENGTH_MISMATCH - The value of the Length field in the
            Parameters buffer was not correct.

        STATUS_ACCESS_VIOLATION - Either the Parameters buffer pointer
            or a pointer within the Parameters buffer specified an
            invalid address.

        STATUS_INSUFFICIENT_RESOURCES - Insufficient system resources exist
            for this request to complete.

--*/

{
    NTSTATUS status = STATUS_SUCCESS;
    BOOLEAN releaseModuleResoure = FALSE;
    ULONG length = 0;
    KPROCESSOR_MODE PreviousMode;

    PreviousMode = KeGetPreviousMode();

    if (!SeSinglePrivilegeCheck( SeDebugPrivilege, PreviousMode)) {
        return STATUS_ACCESS_DENIED;
    }

    //
    // Operate within a try block in order to catch errors.
    //

    try {

        //
        // Probe input and output buffers, if previous mode is not
        // kernel.
        //

        if ( PreviousMode != KernelMode ) {

            if ( InputBufferLength != 0 ) {
                ProbeForRead( InputBuffer, InputBufferLength, sizeof(ULONG) );
            }

            if ( OutputBufferLength != 0 ) {
                ProbeForWrite( OutputBuffer, OutputBufferLength, sizeof(ULONG) );
            }

            if ( ARGUMENT_PRESENT(ReturnLength) ) {
                ProbeForWriteUlong( ReturnLength );
            }
        }

        //
        // Switch on the command code.
        //

        switch ( Command ) {

#ifdef _X86_

        case SysDbgQueryTraceInformation:

            status = KdGetTraceInformation(
                        OutputBuffer,
                        OutputBufferLength,
                        &length
                        );

            break;

        case SysDbgSetTracepoint:

            if ( InputBufferLength != sizeof(DBGKD_MANIPULATE_STATE64) ) {
                return STATUS_INFO_LENGTH_MISMATCH;
            }

            KdSetInternalBreakpoint( InputBuffer );

            break;

        case SysDbgSetSpecialCall:

            if ( InputBufferLength != sizeof(PVOID) ) {
                return STATUS_INFO_LENGTH_MISMATCH;
            }

            KdSetSpecialCall( InputBuffer, NULL );

            break;

        case SysDbgClearSpecialCalls:

            KdClearSpecialCalls( );

            break;

        case SysDbgQuerySpecialCalls:

            status = KdQuerySpecialCalls(
                        OutputBuffer,
                        OutputBufferLength,
                        &length
                        );

            break;

#endif

        case SysDbgBreakPoint:
            if (KdDebuggerEnabled) {
                DbgBreakPointWithStatus(DBG_STATUS_DEBUG_CONTROL);
            } else {
                status = STATUS_UNSUCCESSFUL;
            }
            break;

        default:

            //
            // Invalid Command.
            //

            status = STATUS_INVALID_INFO_CLASS;
        }

        if ( ARGUMENT_PRESENT(ReturnLength) ) {
            *ReturnLength = length;
        }
    }

    except ( EXCEPTION_EXECUTE_HANDLER ) {

        if ( releaseModuleResoure ) {
            ExReleaseResource( &PsLoadedModuleResource );
            KeLeaveCriticalRegion();
        }

        status = GetExceptionCode();

    }

    return status;

} // NtSystemDebugControl
Пример #12
0
NTSTATUS
NtQueryMutant (
    IN HANDLE MutantHandle,
    IN MUTANT_INFORMATION_CLASS MutantInformationClass,
    OUT PVOID MutantInformation,
    IN ULONG MutantInformationLength,
    OUT PULONG ReturnLength OPTIONAL
    )

/*++

Routine Description:

    This function queries the state of a mutant object and returns the
    requested information in the specified record structure.

Arguments:

    MutantHandle - Supplies a handle to a mutant object.

    MutantInformationClass - Supplies the class of information being
        requested.

    MutantInformation - Supplies a pointer to a record that is to receive
        the requested information.

    MutantInformationLength - Supplies the length of the record that is
        to receive the requested information.

    ReturnLength - Supplies an optional pointer to a variable that will
        receive the actual length of the information that is returned.

Return Value:

    TBS

--*/

{

    BOOLEAN Abandoned;
    BOOLEAN OwnedByCaller;
    LONG Count;
    PVOID Mutant;
    KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;

    //
    // Establish an exception handler, probe the output arguments, reference
    // the mutant object, and return the specified information. If the probe
    // fails, then return the exception code as the service status. Otherwise
    // return the status value returned by the reference object by handle
    // routine.
    //

    try {

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

        PreviousMode = KeGetPreviousMode();
        if (PreviousMode != KernelMode) {
            ProbeForWrite(MutantInformation,
                          sizeof(MUTANT_BASIC_INFORMATION),
                          sizeof(ULONG));

            if (ARGUMENT_PRESENT(ReturnLength)) {
                ProbeForWriteUlong(ReturnLength);
            }
        }

        //
        // Check argument validity.
        //

        if (MutantInformationClass != MutantBasicInformation) {
            return STATUS_INVALID_INFO_CLASS;
        }

        if (MutantInformationLength != sizeof(MUTANT_BASIC_INFORMATION)) {
            return STATUS_INFO_LENGTH_MISMATCH;
        }

        //
        // Reference mutant object by handle.
        //

        Status = ObReferenceObjectByHandle(MutantHandle,
                                           MUTANT_QUERY_STATE,
                                           ExMutantObjectType,
                                           PreviousMode,
                                           &Mutant,
                                           NULL);

        //
        // If the reference was successful, then read the current state and
        // abandoned status of the mutant object, dereference mutant object,
        // fill in the information structure, and return the length of the
        // information structure if specified. If the write of the mutant
        // information or the return length fails, then do not report an error.
        // When the caller accesses the information structure or length an
        // access violation will occur.
        //

        if (NT_SUCCESS(Status)) {
            Count = KeReadStateMutant((PKMUTANT)Mutant);
            Abandoned = ((PKMUTANT)Mutant)->Abandoned;
            OwnedByCaller = (BOOLEAN)((((PKMUTANT)Mutant)->OwnerThread ==
                                                         KeGetCurrentThread()));

            ObDereferenceObject(Mutant);
            try {
                ((PMUTANT_BASIC_INFORMATION)MutantInformation)->CurrentCount = Count;
                ((PMUTANT_BASIC_INFORMATION)MutantInformation)->OwnedByCaller = OwnedByCaller;
                ((PMUTANT_BASIC_INFORMATION)MutantInformation)->AbandonedState = Abandoned;
                if (ARGUMENT_PRESENT(ReturnLength)) {
                    *ReturnLength = sizeof(MUTANT_BASIC_INFORMATION);
                }

            } except(ExSystemExceptionFilter()) {
            }
        }

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

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

    //
    // Return service status.
    //

    return Status;
}
Пример #13
0
NTSTATUS
NtConnectPort(
    OUT PHANDLE PortHandle,
    IN PUNICODE_STRING PortName,
    IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
    IN OUT PPORT_VIEW ClientView OPTIONAL,
    OUT PREMOTE_PORT_VIEW ServerView OPTIONAL,
    OUT PULONG MaxMessageLength OPTIONAL,
    IN OUT PVOID ConnectionInformation OPTIONAL,
    IN OUT PULONG ConnectionInformationLength OPTIONAL
    )

/*++

Routine Description:

    A client process can connect to a server process by name using the
    NtConnectPort service.

    The PortName parameter specifies the name of the server port to
    connect to.  It must correspond to an object name specified on a
    call to NtCreatePort.  The service sends a connection request to the
    server thread that is listening for them with the NtListenPort
    service.  The client thread then blocks until a server thread
    receives the connection request and responds with a call to the
    NtCompleteConnectPort service.  The server thread receives the ID of
    the client thread, along with any information passed via the
    ConnectionInformation parameter.  The server thread then decides to
    either accept or reject the connection request.

    The server communicates the acceptance or rejection with the
    NtCompleteConnectPort service.  The server can pass back data to the
    client about the acceptance or rejection via the
    ConnectionInformation data block.

    If the server accepts the connection request, then the client
    receives a communication port object in the location pointed to by
    the PortHandle parameter.  This object handle has no name associated
    with it and is private to the client process (i.e.  it cannot be
    inherited by a child process).  The client uses the handle to send
    and receive messages to/from the server process using the
    NtRequestWaitReplyPort service.

    If the ClientView parameter was specified, then the section handle
    is examined.  If it is a valid section handle, then the portion of
    the section described by the SectionOffset and ViewSize fields will
    be mapped into both the client and server process' address spaces.
    The address in client address space will be returned in the ViewBase
    field.  The address in the server address space will be returned in
    the ViewRemoteBase field.  The actual offset and size used to map
    the section will be returned in the SectionOffset and ViewSize
    fields.

    If the server rejects the connection request, then no communication
    port object handle is returned, and the return status indicates an
    error occurred.  The server may optionally return information in the
    ConnectionInformation data block giving the reason the connection
    requests was rejected.

    If the PortName does not exist, or the client process does not have
    sufficient access rights then the returned status will indicate that
    the port was not found.

Arguments:

    PortHandle - A pointer to a variable that will receive the client
        communication port object handle value.

    !f PortName - A pointer to a port name string.  The form of the name
        is [\name...\name]\port_name.

    !f SecurityQos - A pointer to security quality of service information
        to be applied to the server on the client's behalf.

    ClientView - An optional pointer to a structure that specifies the
        section that all client threads will use to send messages to the
        server.

    !b !u ClientView Structure

        ULONG !f Length - Specifies the size of this data structure in
            bytes.

        HANDLE !f SectionHandle - Specifies an open handle to a section
            object.

        ULONG !f SectionOffset - Specifies a field that will receive the
            actual offset, in bytes, from the start of the section.  The
            initial value of this parameter specifies the byte offset
            within the section that the client's view is based.  The
            value is rounded down to the next host page size boundary.

        ULONG !f ViewSize - Specifies a field that will receive the
            actual size, in bytes, of the view.  If the value of this
            parameter is zero, then the client's view of the section
            will be mapped starting at the specified section offset and
            continuing to the end of the section.  Otherwise, the
            initial value of this parameter specifies the size, in
            bytes, of the client's view and is rounded up to the next
            host page size boundary.

        PVOID !f ViewBase - Specifies a field that will receive the base
            address of the section in the client's address space.

        PVOID !f ViewRemoteBase - Specifies a field that will receive
            the base address of the client's section in the server's
            address space.  Used to generate pointers that are
            meaningful to the server.

    ServerView - An optional pointer to a structure that will receive
        information about the server process' view in the client's
        address space.  The client process can use this information
        to validate pointers it receives from the server process.

    !b !u ServerView Structure

        ULONG !f Length - Specifies the size of this data structure in
            bytes.

        PVOID !f ViewBase - Specifies a field that will receive the base
            address of the server's section in the client's address
            space.

        ULONG !f ViewSize - Specifies a field that will receive the
            size, in bytes, of the server's view in the client's address
            space.  If this field is zero, then server has no view in
            the client's address space.

    MaxMessageLength - An optional pointer to a variable that will
        receive maximum length of messages that can be sent to the
        server.  The value of this parameter will not exceed
        MAX_PORTMSG_LENGTH bytes.

    ConnectionInformation - An optional pointer to uninterpreted data.
        This data is intended for clients to pass package, version and
        protocol identification information to the server to allow the
        server to determine if it can satisify the client before
        accepting the connection.  Upon return to the client, the
        ConnectionInformation data block contains any information passed
        back from the server by its call to the NtCompleteConnectPort
        service.  The output data overwrites the input data.

    ConnectionInformationLength - Pointer to the length of the
        ConnectionInformation data block.  The output value is the
        length of the data stored in the ConnectionInformation data
        block by the server's call to the NtCompleteConnectPort
        service.  This parameter is OPTIONAL only if the
        ConnectionInformation parameter is null, otherwise it is
        required.

Return Value:

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

--*/

{
    PLPCP_PORT_OBJECT ConnectionPort;
    PLPCP_PORT_OBJECT ClientPort;
    HANDLE Handle;
    KPROCESSOR_MODE PreviousMode;
    NTSTATUS Status;
    ULONG ConnectionInfoLength;
    PVOID SectionToMap;
    PLPCP_MESSAGE Msg;
    PLPCP_CONNECTION_MESSAGE ConnectMsg;
    PETHREAD CurrentThread = PsGetCurrentThread();
    LARGE_INTEGER SectionOffset;
    PORT_VIEW CapturedClientView;
    SECURITY_QUALITY_OF_SERVICE CapturedQos;

    PAGED_CODE();

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

    PreviousMode = KeGetPreviousMode();
    ConnectionInfoLength = 0;
    if (PreviousMode != KernelMode) {
        try {
            ProbeForWriteHandle( PortHandle );

            if (ARGUMENT_PRESENT( ClientView )) {
                if (ClientView->Length != sizeof( *ClientView )) {
                    return( STATUS_INVALID_PARAMETER );
                    }

                CapturedClientView = *ClientView;
                ProbeForWrite( ClientView,
                               sizeof( *ClientView ),
                               sizeof( ULONG )
                             );
                }

            if (ARGUMENT_PRESENT( ServerView )) {
                if (ServerView->Length != sizeof( *ServerView )) {
                    return( STATUS_INVALID_PARAMETER );
                    }

                ProbeForWrite( ServerView,
                               sizeof( *ServerView ),
                               sizeof( ULONG )
                             );
                }

            if (ARGUMENT_PRESENT( MaxMessageLength )) {
                ProbeForWriteUlong( MaxMessageLength );
                }

            if (ARGUMENT_PRESENT( ConnectionInformationLength )) {
                ProbeForWriteUlong( ConnectionInformationLength );
                ConnectionInfoLength = *ConnectionInformationLength;
                }

            if (ARGUMENT_PRESENT( ConnectionInformation )) {
                ProbeForWrite( ConnectionInformation,
                               ConnectionInfoLength,
                               sizeof( UCHAR )
                             );
                }

            ProbeForRead( SecurityQos,
                          sizeof( SECURITY_QUALITY_OF_SERVICE ),
                          sizeof( ULONG )
                          );
            CapturedQos = *SecurityQos;

            }
        except( EXCEPTION_EXECUTE_HANDLER ) {
            return( GetExceptionCode() );
            }
        }
    else {
        if (ARGUMENT_PRESENT( ClientView )) {
Пример #14
0
NTSTATUS
NtFreeVirtualMemory(
    IN HANDLE ProcessHandle,
    IN OUT PVOID *BaseAddress,
    IN OUT PULONG RegionSize,
    IN ULONG FreeType
     )

/*++

Routine Description:

    This function deletes a region of pages within the virtual address
    space of a subject process.

Arguments:

   ProcessHandle - An open handle to a process object.

   BaseAddress - The base address of the region of pages
        to be freed. This value is rounded down to the
        next host page address boundary.

   RegionSize - A pointer to a variable that will receive
        the actual size in bytes of the freed region of
        pages. The initial value of this argument is
        rounded up to the next host page size boundary.

   FreeType - A set of flags that describe the type of
        free that is to be performed for the specified
        region of pages.


       FreeType Flags


        MEM_DECOMMIT - The specified region of pages is to
             be decommitted.

        MEM_RELEASE - The specified region of pages is to
             be released.


Return Value:

    Returns the status

    TBS


--*/

{
    PMMVAD_SHORT Vad;
    PMMVAD_SHORT NewVad;
    PMMVAD PreviousVad;
    PMMVAD NextVad;
    PEPROCESS Process;
    KPROCESSOR_MODE PreviousMode;
    PVOID StartingAddress;
    PVOID EndingAddress;
    NTSTATUS Status;
    ULONG Attached = FALSE;
    ULONG CapturedRegionSize;
    PVOID CapturedBase;
    PMMPTE StartingPte;
    PMMPTE EndingPte;
    ULONG OldQuota;
    ULONG QuotaCharge;
    ULONG CommitReduction;
    PVOID OldEnd;

    PAGED_CODE();

    //
    // Check to make sure FreeType is good.
    //

    if ((FreeType & ~(MEM_DECOMMIT | MEM_RELEASE)) != 0) {
        return STATUS_INVALID_PARAMETER_4;
    }

    //
    // One of MEM_DECOMMIT or MEM_RELEASE must be specified, but not both.
    //

    if (((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) == 0) ||
        ((FreeType & (MEM_DECOMMIT | MEM_RELEASE)) ==
                            (MEM_DECOMMIT | MEM_RELEASE))) {
        return STATUS_INVALID_PARAMETER_4;
    }

    PreviousMode = KeGetPreviousMode();

    //
    // Establish an exception handler, probe the specified addresses
    // for write access and capture the initial values.
    //

    try {

        if (PreviousMode != KernelMode) {

            ProbeForWriteUlong ((PULONG)BaseAddress);
            ProbeForWriteUlong (RegionSize);
        }

        //
        // Capture the base address.
        //

        CapturedBase = *BaseAddress;

        //
        // Capture the region size.
        //

        CapturedRegionSize = *RegionSize;

    } except (ExSystemExceptionFilter()) {

        //
        // If an exception occurs during the probe or capture
        // of the initial values, then handle the exception and
        // return the exception code as the status value.
        //

        return GetExceptionCode();
    }

#if DBG
    if (MmDebug & MM_DBG_SHOW_NT_CALLS) {
        if ( !MmWatchProcess ) {
            DbgPrint("freevm processhandle %lx base %lx size %lx type %lx\n",
                    ProcessHandle, CapturedBase, CapturedRegionSize, FreeType);
        }
    }
#endif

    //
    // Make sure the specified starting and ending addresses are
    // within the user part of the virtual address space.
    //

    if (CapturedBase > MM_HIGHEST_USER_ADDRESS) {

        //
        // Invalid base address.
        //

        return STATUS_INVALID_PARAMETER_2;
    }

    if ((ULONG)MM_HIGHEST_USER_ADDRESS - (ULONG)CapturedBase <
                                                        CapturedRegionSize) {

        //
        // Invalid region size;
        //

        return STATUS_INVALID_PARAMETER_3;

    }

    EndingAddress = (PVOID)(((ULONG)CapturedBase + CapturedRegionSize - 1) |
                        (PAGE_SIZE - 1));

    StartingAddress = (PVOID)PAGE_ALIGN(CapturedBase);

    if ( ProcessHandle == NtCurrentProcess() ) {
        Process = PsGetCurrentProcess();
    } else {
        //
        // Reference the specified process handle for VM_OPERATION access.
        //

        Status = ObReferenceObjectByHandle ( ProcessHandle,
                                             PROCESS_VM_OPERATION,
                                             PsProcessType,
                                             PreviousMode,
                                             (PVOID *)&Process,
                                             NULL );

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

    //
    // If the specified process is not the current process, attach
    // to the specified process.
    //

    if (PsGetCurrentProcess() != Process) {
        KeAttachProcess (&Process->Pcb);
        Attached = TRUE;
    }

    //
    // Get the address creation mutex to block multiple threads from
    // creating or deleting address space at the same time and
    // get the working set mutex so virtual address descriptors can
    // be inserted and walked.  Block APCs to prevent page faults while
    // we own the working set mutex.
    //

    LOCK_WS_AND_ADDRESS_SPACE (Process);

    //
    // Make sure the address space was not deleted.
    //

    if (Process->AddressSpaceDeleted != 0) {
        Status = STATUS_PROCESS_IS_TERMINATING;
        goto ErrorReturn;
    }

    Vad = (PMMVAD_SHORT)MiLocateAddress (StartingAddress);

    if (Vad == NULL) {

        //
        // No Virtual Address Descriptor located for Base Address.
        //

        Status = STATUS_MEMORY_NOT_ALLOCATED;
        goto ErrorReturn;
    }

    //
    // Found the associated Virtual Address Descriptor.
    //

    if (Vad->EndingVa < EndingAddress) {

        //
        // The entire range to delete is not contained within a single
        // virtual address descriptor.  Return an error.
        //

        Status = STATUS_UNABLE_TO_FREE_VM;
        goto ErrorReturn;
    }

    //
    // Check to ensure this Vad is deletable.  Delete is required
    // for both decommit and release.
    //

    if ((Vad->u.VadFlags.PrivateMemory == 0) ||
        (Vad->u.VadFlags.PhysicalMapping == 1)) {
        Status = STATUS_UNABLE_TO_DELETE_SECTION;
        goto ErrorReturn;
    }

    if (Vad->u.VadFlags.NoChange == 1) {

        //
        // An attempt is being made to delete a secured VAD, check
        // to see if this deletion is allowed.
        //

        if (FreeType & MEM_RELEASE) {

            //
            // Specifiy the whole range, this solves the problem with
            // splitting the VAD and trying to decide where the various
            // secure ranges need to go.
            //

            Status = MiCheckSecuredVad ((PMMVAD)Vad,
                                        Vad->StartingVa,
                                (PCHAR)Vad->EndingVa - (PCHAR)Vad->StartingVa,
                                        MM_SECURE_DELETE_CHECK);

        } else {
            Status = MiCheckSecuredVad ((PMMVAD)Vad,
                                        CapturedBase,
                                        CapturedRegionSize,
                                        MM_SECURE_DELETE_CHECK);
        }
        if (!NT_SUCCESS (Status)) {
            goto ErrorReturn;
        }
    }

    PreviousVad = MiGetPreviousVad (Vad);
    NextVad = MiGetNextVad (Vad);
    if (FreeType & MEM_RELEASE) {

        //
        // *****************************************************************
        // MEM_RELEASE was specified.
        // *****************************************************************
        //

        //
        // The descriptor for the address range is deletable.  Remove or split
        // the descriptor.
        //

        //
        // If the region size is zero, remove the whole VAD.
        //

        if (CapturedRegionSize == 0) {

            //
            // If the region size is specified as 0, the base address
            // must be the starting address for the region.
            //

            if (CapturedBase != Vad->StartingVa) {
                Status = STATUS_FREE_VM_NOT_AT_BASE;
                goto ErrorReturn;
            }

            //
            // This Virtual Address Descriptor has been deleted.
            //

            StartingAddress = Vad->StartingVa;
            EndingAddress = Vad->EndingVa;
            MiRemoveVad ((PMMVAD)Vad);
            ExFreePool (Vad);

        } else {

            //
            // Regions size was not specified as zero, delete the
            // whole VAD or split the VAD.
            //

            if (StartingAddress == Vad->StartingVa) {
                if (EndingAddress == Vad->EndingVa) {

                    //
                    // This Virtual Address Descriptor has been deleted.
                    //

                    MiRemoveVad ((PMMVAD)Vad);
                    ExFreePool (Vad);

                } else {

                    //
                    // This Virtual Address Descriptor has a new starting
                    // address.
                    //

                    CommitReduction = MiCalculatePageCommitment (
                                                            StartingAddress,
                                                            EndingAddress,
                                                            (PMMVAD)Vad,
                                                            Process );

                    Vad->StartingVa = (PVOID)((ULONG)EndingAddress + 1L);
                    Vad->u.VadFlags.CommitCharge -= CommitReduction;
                    ASSERT ((LONG)Vad->u.VadFlags.CommitCharge >= 0);
                    MiReturnPageFileQuota (CommitReduction, Process);
                    MiReturnCommitment (CommitReduction);
                    Process->CommitCharge -= CommitReduction;
                    PreviousVad = (PMMVAD)Vad;
                }

            } else {

                //
                // Starting address is greater than start of VAD.
                //

                if (EndingAddress == Vad->EndingVa) {

                    //
                    // Change the ending address of the VAD.
                    //

                    CommitReduction = MiCalculatePageCommitment (
                                                            StartingAddress,
                                                            EndingAddress,
                                                            (PMMVAD)Vad,
                                                            Process );

                    Vad->u.VadFlags.CommitCharge -= CommitReduction;
                    MiReturnPageFileQuota (CommitReduction, Process);
                    MiReturnCommitment (CommitReduction);
                    Process->CommitCharge -= CommitReduction;

                    Vad->EndingVa = (PVOID)((ULONG)StartingAddress - 1L);
                    PreviousVad = (PMMVAD)Vad;

                } else {

                    //
                    // Split this VAD as the address range is within the VAD.
                    //

                    //
                    // Allocate an new VAD under an exception handler
                    // as there may not be enough quota.
                    //

                    NewVad = ExAllocatePoolWithTag (NonPagedPool,
                                                    sizeof(MMVAD_SHORT),
                                                    'SdaV');
                    if ( NewVad == NULL ) {
                        Status = STATUS_INSUFFICIENT_RESOURCES;
                        goto ErrorReturn;
                    }

                    CommitReduction = MiCalculatePageCommitment (
                                                            StartingAddress,
                                                            EndingAddress,
                                                            (PMMVAD)Vad,
                                                            Process );

                    OldQuota = Vad->u.VadFlags.CommitCharge - CommitReduction;
                    OldEnd = Vad->EndingVa;

                    *NewVad = *Vad;

                    Vad->EndingVa = (PVOID)((ULONG)StartingAddress - 1L);
                    NewVad->StartingVa = (PVOID)((ULONG)EndingAddress + 1L);

                    //
                    // Set the commit charge to zero so MiInsertVad will
                    // not charge committment for splitting the VAD.
                    //

                    NewVad->u.VadFlags.CommitCharge = 0;

                    try {

                        //
                        // Insert the VAD, this could get an exception
                        // on charging quota.
                        //

                        MiInsertVad ((PMMVAD)NewVad);

                    } except (EXCEPTION_EXECUTE_HANDLER) {

                        //
                        // Inserting the Vad failed, reset the original
                        // VAD, free new vad and return an error.
                        //

                        Vad->EndingVa = OldEnd;

                        ExFreePool (NewVad);
                        Status = GetExceptionCode();
                        goto ErrorReturn;
                    }

                    Vad->u.VadFlags.CommitCharge -= CommitReduction;
                    MiReturnPageFileQuota (CommitReduction, Process);
                    MiReturnCommitment (CommitReduction);
                    Process->CommitCharge -= CommitReduction;

                    //
                    // As we have split the original VAD into 2 seperate VADs
                    // there is know way of knowing what the commit charge
                    // is for each VAD.  Calculate the charge and reset
                    // each VAD.  Note that we also use the previous value
                    // to make sure the books stay balanced.
                    //

                    QuotaCharge = MiCalculatePageCommitment (Vad->StartingVa,
                                                             Vad->EndingVa,
                                                             (PMMVAD)Vad,
                                                             Process );

                    Vad->u.VadFlags.CommitCharge = QuotaCharge;

                    //
                    // Give the remaining charge to the new VAD.
                    //

                    NewVad->u.VadFlags.CommitCharge = OldQuota - QuotaCharge;
                    PreviousVad = (PMMVAD)Vad;
                    NextVad = (PMMVAD)NewVad;
                }
            }
        }

        //
        // Return commitment for page table pages if possibible.
        //

        MiReturnPageTablePageCommitment (StartingAddress,
                                         EndingAddress,
                                         Process,
                                         PreviousVad,
                                         NextVad);

        //
        // Get the PFN mutex so the MiDeleteVirtualAddresses can be called.
        //

        MiDeleteFreeVm (StartingAddress, EndingAddress);
        UNLOCK_WS (Process);

        CapturedRegionSize = 1 + (ULONG)EndingAddress - (ULONG)StartingAddress;

        //
        // Update the virtual size in the process header.
        //

        Process->VirtualSize -= CapturedRegionSize;

        UNLOCK_ADDRESS_SPACE (Process);

        if (Attached) {
            KeDetachProcess();
        }

        if ( ProcessHandle != NtCurrentProcess() ) {
            ObDereferenceObject (Process);
        }
        //
        // Establish an exception handler and write the size and base
        // address.
        //

        try {

            *RegionSize = CapturedRegionSize;
            *BaseAddress = StartingAddress;

        } except (EXCEPTION_EXECUTE_HANDLER) {

            //
            // An exception occurred, don't take any action (just handle
            // the exception and return success.

        }

#if DBG
    if (MmDebug & MM_DBG_SHOW_NT_CALLS) {
        if ( MmWatchProcess ) {
            if ( MmWatchProcess == PsGetCurrentProcess() ) {
                DbgPrint("\n--- FREE Type 0x%lx Base %lx Size %lx\n",
                        FreeType, StartingAddress, CapturedRegionSize);
                MmFooBar();
            }
        }
    }
#endif

#if DBG
        if (RtlAreLogging( RTL_EVENT_CLASS_VM )) {
            RtlLogEvent( MiFreeVmEventId,
                         RTL_EVENT_CLASS_VM,
                         StartingAddress,
                         CapturedRegionSize,
                         FreeType
                       );

        }
#endif // DBG

        return STATUS_SUCCESS;
    }

    //
    // **************************************************************
    //
    // MEM_DECOMMIT was specified.
    //
    // **************************************************************
    //

    //
    // Check to ensure the complete range of pages is already committed.
    //

    if (CapturedRegionSize == 0) {

        if (CapturedBase != Vad->StartingVa) {
            Status = STATUS_FREE_VM_NOT_AT_BASE;
            goto ErrorReturn;
        }
        EndingAddress = Vad->EndingVa;
    }

#if 0
    if (FreeType & MEM_CHECK_COMMIT_STATE) {
        if ( !MiIsEntireRangeCommitted(StartingAddress,
                                       EndingAddress,
                                       Vad,
                                       Process)) {

            //
            // The entire range to be decommited is not committed,
            // return an errror.
            //

            Status = STATUS_UNABLE_TO_DECOMMIT_VM;
            goto ErrorReturn;
        }
    }
#endif //0

    //
    // The address range is entirely committed, decommit it now.
    //

    //
    // Calculate the initial quotas and commit charges for this VAD.
    //

    StartingPte = MiGetPteAddress (StartingAddress);
    EndingPte = MiGetPteAddress (EndingAddress);

    CommitReduction = 1 + EndingPte - StartingPte;

    //
    // Check to see if the entire range can be decommitted by
    // just updating the virtual address descriptor.
    //

    CommitReduction -= MiDecommitPages (StartingAddress,
                                        EndingPte,
                                        Process,
                                        Vad);

    //
    // Adjust the quota charges.
    //

    ASSERT ((LONG)CommitReduction >= 0);
    MiReturnPageFileQuota (CommitReduction, Process);
    MiReturnCommitment (CommitReduction);
    Vad->u.VadFlags.CommitCharge -= CommitReduction;
    Process->CommitCharge -= CommitReduction;
    ASSERT ((LONG)Vad->u.VadFlags.CommitCharge >= 0);

    UNLOCK_WS (Process);

    UNLOCK_ADDRESS_SPACE (Process);

    if (Attached) {
        KeDetachProcess();
    }
    if ( ProcessHandle != NtCurrentProcess() ) {
        ObDereferenceObject (Process);
    }

    //
    // Establish an exception handler and write the size and base
    // address.
    //

    try {

        *RegionSize = 1 + (ULONG)EndingAddress - (ULONG)StartingAddress;
        *BaseAddress = StartingAddress;

    } except (EXCEPTION_EXECUTE_HANDLER) {
        NOTHING;
    }

#if DBG
    if (RtlAreLogging( RTL_EVENT_CLASS_VM )) {
        RtlLogEvent( MiFreeVmEventId,
                     RTL_EVENT_CLASS_VM,
                     StartingAddress,
                     1 + (ULONG)EndingAddress - (ULONG)StartingAddress,
                     FreeType
                   );

    }
#endif // DBG

    return STATUS_SUCCESS;

ErrorReturn:
       UNLOCK_WS (Process);
       UNLOCK_ADDRESS_SPACE (Process);

       if (Attached) {
           KeDetachProcess();
       }

       if ( ProcessHandle != NtCurrentProcess() ) {
           ObDereferenceObject (Process);
       }
       return Status;
}