mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
648 lines
12 KiB
648 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
miscsvc.c
|
|
|
|
Abstract:
|
|
|
|
This module contains miscellaneous SPUD services.
|
|
|
|
Author:
|
|
|
|
Keith Moore (keithmo) 09-Feb-1998
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "spudp.h"
|
|
|
|
|
|
//
|
|
// Private prototypes.
|
|
//
|
|
|
|
NTSTATUS
|
|
SpudpOpenSelfHandle(
|
|
OUT PHANDLE SelfHandle
|
|
);
|
|
|
|
NTSTATUS
|
|
SpudpCloseSelfHandle(
|
|
IN HANDLE SelfHandle
|
|
);
|
|
|
|
NTSTATUS
|
|
SpudpInitCompletionPort(
|
|
IN HANDLE CompletionPort
|
|
);
|
|
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, SPUDInitialize )
|
|
#pragma alloc_text( PAGE, SPUDTerminate )
|
|
#pragma alloc_text( PAGE, SPUDCancel )
|
|
#pragma alloc_text( PAGE, SPUDGetCounts )
|
|
#pragma alloc_text( PAGE, SpudpOpenSelfHandle )
|
|
#pragma alloc_text( PAGE, SpudpCloseSelfHandle )
|
|
#endif
|
|
#if 0
|
|
NOT PAGEABLE -- SpudpInitCompletionPort
|
|
#endif
|
|
|
|
|
|
//
|
|
// Public functions.
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
SPUDInitialize(
|
|
ULONG Version,
|
|
HANDLE hPort
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs per-process SPUD initialization.
|
|
|
|
Arguments:
|
|
|
|
Version - The SPUD interface version the user-mode client is expecting.
|
|
|
|
hPort - The handle to the user-mode code's I/O completion port.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
HANDLE selfHandle;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
status = SPUD_ENTER_SERVICE( "SPUDInitialize", FALSE );
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Setup locals so we know how to cleanup on exit.
|
|
//
|
|
|
|
selfHandle = NULL;
|
|
|
|
//
|
|
// SPUD doesn't support kernel-mode callers. In fact, we don't
|
|
// even build the "system stubs" necessary to invoke SPUD from
|
|
// kernel-mode.
|
|
//
|
|
|
|
ASSERT( ExGetPreviousMode() == UserMode );
|
|
|
|
//
|
|
// Ensure we got the SPUD interface version number we're expecting.
|
|
//
|
|
|
|
if( Version != SPUD_VERSION ) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Open an exclusive handle to ourselves.
|
|
//
|
|
|
|
if( NT_SUCCESS(status) ) {
|
|
status = SpudpOpenSelfHandle( &selfHandle );
|
|
}
|
|
|
|
//
|
|
// Reference the I/O completion port handle so we can use the
|
|
// pointer directly in KeInsertQueue().
|
|
//
|
|
|
|
if( NT_SUCCESS(status) ) {
|
|
status = SpudpInitCompletionPort( hPort );
|
|
}
|
|
|
|
//
|
|
// Remember that we're initialized.
|
|
//
|
|
|
|
if( NT_SUCCESS(status) ) {
|
|
SpudSelfHandle = selfHandle;
|
|
} else {
|
|
|
|
//
|
|
// Fatal error, cleanup our self handle if we managed to
|
|
// open it.
|
|
//
|
|
|
|
if( selfHandle != NULL ) {
|
|
SpudpCloseSelfHandle( selfHandle );
|
|
}
|
|
|
|
}
|
|
|
|
SPUD_LEAVE_SERVICE( "SPUDInitialize", status, FALSE );
|
|
return status;
|
|
|
|
} // SPUDInitialize
|
|
|
|
|
|
NTSTATUS
|
|
SPUDTerminate(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Performs per-process SPUD termination.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
status = SPUD_ENTER_SERVICE( "SPUDTerminate", TRUE );
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// SPUD doesn't support kernel-mode callers. In fact, we don't
|
|
// even build the "system stubs" necessary to invoke SPUD from
|
|
// kernel-mode.
|
|
//
|
|
|
|
ASSERT( ExGetPreviousMode() == UserMode );
|
|
|
|
//
|
|
// Close the handle we opened to ourself. The IRP_MJ_CLOSE handler
|
|
// will dereference the completion port and reset the global variables.
|
|
//
|
|
|
|
ASSERT( SpudSelfHandle != NULL );
|
|
SpudpCloseSelfHandle( SpudSelfHandle );
|
|
SpudSelfHandle = NULL;
|
|
|
|
ASSERT( status == STATUS_SUCCESS );
|
|
SPUD_LEAVE_SERVICE( "SPUDTerminate", status, FALSE );
|
|
return status;
|
|
|
|
} // SPUDTerminate
|
|
|
|
|
|
NTSTATUS
|
|
SPUDCancel(
|
|
IN PSPUD_REQ_CONTEXT reqContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cancels an outstanding XxxAndRecv() request.
|
|
|
|
Arguments:
|
|
|
|
reqContext - The user-mode context associated with the I/O request.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
PSPUD_AFD_REQ_CONTEXT SpudReqContext;
|
|
PIRP irp;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
status = SPUD_ENTER_SERVICE( "SPUDCancel", TRUE );
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// SPUD doesn't support kernel-mode callers. In fact, we don't
|
|
// even build the "system stubs" necessary to invoke SPUD from
|
|
// kernel-mode.
|
|
//
|
|
|
|
ASSERT( ExGetPreviousMode() == UserMode );
|
|
|
|
try {
|
|
|
|
//
|
|
// Make sure we can write to reqContext
|
|
//
|
|
|
|
ProbeForRead(
|
|
reqContext,
|
|
sizeof(SPUD_REQ_CONTEXT),
|
|
sizeof(ULONG)
|
|
);
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
status = GetExceptionCode();
|
|
}
|
|
|
|
//
|
|
// Get the kernel-mode context from the user-mode context.
|
|
//
|
|
|
|
if( NT_SUCCESS(status) ) {
|
|
SpudReqContext = SpudGetRequestContext( reqContext );
|
|
|
|
if( SpudReqContext == NULL ) {
|
|
status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Snag the IRP from the context & cancel the request.
|
|
//
|
|
|
|
if( NT_SUCCESS(status) ) {
|
|
irp = SpudReqContext->Irp;
|
|
if (irp) {
|
|
IoCancelIrp(irp);
|
|
}
|
|
}
|
|
|
|
SPUD_LEAVE_SERVICE( "SPUDCancel", status, FALSE );
|
|
return status;
|
|
|
|
} // SPUDCancel
|
|
|
|
|
|
NTSTATUS
|
|
SPUDGetCounts(
|
|
PSPUD_COUNTERS UserCounters
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Retrieves the SPUD activity counters.
|
|
|
|
Arguments:
|
|
|
|
UserCounters - Receives the counters.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// N.B. We do not perform the usual driver initialization and
|
|
// exclusivity checks here. We *want* SPUDGetCounts to be callable
|
|
// by processes other than the server.
|
|
//
|
|
|
|
//
|
|
// SPUD doesn't support kernel-mode callers. In fact, we don't
|
|
// even build the "system stubs" necessary to invoke SPUD from
|
|
// kernel-mode.
|
|
//
|
|
|
|
ASSERT( ExGetPreviousMode() == UserMode );
|
|
|
|
try {
|
|
|
|
//
|
|
// The SpudCounters parameter must be writable.
|
|
//
|
|
|
|
ProbeForWrite( UserCounters, sizeof(*UserCounters), sizeof(ULONG) );
|
|
|
|
//
|
|
// Copy the counters to the user-mode buffer.
|
|
//
|
|
|
|
RtlCopyMemory(
|
|
UserCounters,
|
|
&SpudCounters,
|
|
sizeof(SpudCounters)
|
|
);
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
status = GetExceptionCode();
|
|
}
|
|
|
|
return status;
|
|
|
|
} // SPUDGetCounts
|
|
|
|
|
|
//
|
|
// Private prototypes.
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
SpudpOpenSelfHandle(
|
|
OUT PHANDLE SelfHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens a handle to \Device\Spud and marks it so that it cannot be
|
|
closed.
|
|
|
|
Arguments:
|
|
|
|
SelfHandle - Pointer to a variable that receives the handle.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
HANDLE selfHandle;
|
|
UNICODE_STRING deviceName;
|
|
OBJECT_ATTRIBUTES objectAttributes;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
OBJECT_HANDLE_FLAG_INFORMATION handleInfo;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Open an exclusive handle to ourselves.
|
|
//
|
|
|
|
RtlInitUnicodeString(
|
|
&deviceName,
|
|
SPUD_DEVICE_NAME
|
|
);
|
|
|
|
InitializeObjectAttributes(
|
|
&objectAttributes, // ObjectAttributes
|
|
&deviceName, // ObjectName
|
|
OBJ_CASE_INSENSITIVE, // Attributes
|
|
NULL, // RootDirectory
|
|
NULL // SecurityDescriptor
|
|
);
|
|
|
|
status = IoCreateFile(
|
|
&selfHandle, // FileHandle
|
|
GENERIC_READ // DesiredAccess
|
|
| SYNCHRONIZE //
|
|
| FILE_READ_ATTRIBUTES, //
|
|
&objectAttributes, // ObjectAttributes
|
|
&ioStatusBlock, // IoStatusBlock
|
|
NULL, // AllocationSize
|
|
0L, // FileAttributes
|
|
0L, // ShareAccess
|
|
FILE_OPEN, // Disposition
|
|
0L, // CreateOptions
|
|
NULL, // EaBuffer
|
|
0, // EaLength
|
|
CreateFileTypeNone, // CreateFileType
|
|
NULL, // ExtraCreateParameters
|
|
IO_NO_PARAMETER_CHECKING // Options
|
|
);
|
|
|
|
if( !NT_SUCCESS(status) ) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Mark the handle so that those pesky user-mode applications
|
|
// can't close it. While we're at it, make the handle not
|
|
// inheritable.
|
|
//
|
|
|
|
handleInfo.ProtectFromClose = TRUE;
|
|
handleInfo.Inherit = FALSE;
|
|
|
|
status = ZwSetInformationObject(
|
|
selfHandle, // Handle
|
|
ObjectHandleFlagInformation, // ObjectInformationClass
|
|
&handleInfo, // ObjectInformation
|
|
sizeof(handleInfo) // ObjectInformationLength
|
|
);
|
|
|
|
//
|
|
// If all went well, then return the handle to the caller. Otherwise,
|
|
// carefully close the handle (avoiding an exception if the user-mode
|
|
// code has already closed it).
|
|
//
|
|
|
|
if( NT_SUCCESS(status) ) {
|
|
*SelfHandle = selfHandle;
|
|
} else {
|
|
if( selfHandle != NULL ) {
|
|
try {
|
|
NtClose( selfHandle );
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
NOTHING;
|
|
}
|
|
}
|
|
}
|
|
|
|
return status;
|
|
|
|
} // SpudpOpenSelfHandle
|
|
|
|
|
|
NTSTATUS
|
|
SpudpCloseSelfHandle(
|
|
IN HANDLE SelfHandle
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Closes the handle opened by SpudpOpenSelfHandle().
|
|
|
|
Arguments:
|
|
|
|
SelfHandle - The handle to close.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
OBJECT_HANDLE_FLAG_INFORMATION handleInfo;
|
|
|
|
//
|
|
// Sanity check.
|
|
//
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Mark the handle so that we can close it.
|
|
//
|
|
|
|
handleInfo.ProtectFromClose = FALSE;
|
|
handleInfo.Inherit = FALSE;
|
|
|
|
status = ZwSetInformationObject(
|
|
SelfHandle, // Handle
|
|
ObjectHandleFlagInformation, // ObjectInformationClass
|
|
&handleInfo, // ObjectInformation
|
|
sizeof(handleInfo) // ObjectInformationLength
|
|
);
|
|
|
|
//
|
|
// Carefully close the handle, even if the above APIs failed.
|
|
//
|
|
|
|
try {
|
|
status = NtClose( SelfHandle );
|
|
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
status = GetExceptionCode();
|
|
}
|
|
|
|
return status;
|
|
|
|
} // SpudpCloseSelfHandle
|
|
|
|
|
|
NTSTATUS
|
|
SpudpInitCompletionPort(
|
|
IN HANDLE CompletionPort
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
References the specified completion port and sets our local reference
|
|
count.
|
|
|
|
N.B. This is a separate routine so that SPUDInitialize() can be pageable.
|
|
|
|
Arguments:
|
|
|
|
CompletionPort - The completion port handle.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
KIRQL oldIrql;
|
|
PVOID completionPort;
|
|
|
|
//
|
|
// Reference the I/O completion port handle so we can use the
|
|
// pointer directly in KeInsertQueue().
|
|
//
|
|
|
|
status = ObReferenceObjectByHandle(
|
|
CompletionPort, // Handle
|
|
IO_COMPLETION_MODIFY_STATE, // DesiredAccess
|
|
NULL, // ObjectType
|
|
UserMode, // AccessMode
|
|
&completionPort, // Object
|
|
NULL // HandleInformation
|
|
);
|
|
|
|
//
|
|
// Remember that we're initialized.
|
|
//
|
|
|
|
if( NT_SUCCESS(status) ) {
|
|
TRACE_OB_REFERENCE( completionPort );
|
|
|
|
KeAcquireSpinLock(
|
|
&SpudCompletionPortLock,
|
|
&oldIrql
|
|
);
|
|
|
|
ASSERT( SpudCompletionPort == NULL );
|
|
ASSERT( SpudCompletionPortRefCount == 0 );
|
|
|
|
SpudCompletionPort = completionPort;
|
|
SpudCompletionPortRefCount = 1;
|
|
|
|
KeReleaseSpinLock(
|
|
&SpudCompletionPortLock,
|
|
oldIrql
|
|
);
|
|
}
|
|
|
|
return status;
|
|
|
|
} // SpudpInitCompletionPort
|
|
|