NTSTATUS NTAPI NtCreateIoCompletion(OUT PHANDLE IoCompletionHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG NumberOfConcurrentThreads) { PKQUEUE Queue; HANDLE hIoCompletionHandle; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status; PAGED_CODE(); /* Check if this was a user-mode call */ if (PreviousMode != KernelMode) { /* Wrap probing in SEH */ _SEH2_TRY { /* Probe the handle */ ProbeForWriteHandle(IoCompletionHandle); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
/* * @implemented */ NTSTATUS NTAPI NtCreateEvent(OUT PHANDLE EventHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN EVENT_TYPE EventType, IN BOOLEAN InitialState) { KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); PKEVENT Event; HANDLE hEvent; NTSTATUS Status; PAGED_CODE(); DPRINT("NtCreateEvent(0x%p, 0x%x, 0x%p)\n", EventHandle, DesiredAccess, ObjectAttributes); /* Check if we were called from user-mode */ if (PreviousMode != KernelMode) { /* Enter SEH Block */ _SEH2_TRY { /* Check handle pointer */ ProbeForWriteHandle(EventHandle); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
/* * @unimplemented */ NTSTATUS NTAPI NtCreateJobObject ( PHANDLE JobHandle, ACCESS_MASK DesiredAccess, POBJECT_ATTRIBUTES ObjectAttributes ) { HANDLE hJob; PEJOB Job; KPROCESSOR_MODE PreviousMode; PEPROCESS CurrentProcess; NTSTATUS Status; PAGED_CODE(); PreviousMode = ExGetPreviousMode(); CurrentProcess = PsGetCurrentProcess(); /* check for valid buffers */ if (PreviousMode != KernelMode) { _SEH2_TRY { ProbeForWriteHandle(JobHandle); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
/* * @implemented */ NTSTATUS NTAPI NtOpenProcessTokenEx(IN HANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, IN ULONG HandleAttributes, OUT PHANDLE TokenHandle) { PACCESS_TOKEN Token; HANDLE hToken; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status; PAGED_CODE(); PSTRACE(PS_SECURITY_DEBUG, "Process: %p DesiredAccess: %lx\n", ProcessHandle, DesiredAccess); /* Check if caller was user-mode */ if (PreviousMode != KernelMode) { /* Enter SEH for probing */ _SEH2_TRY { /* Probe the token handle */ ProbeForWriteHandle(TokenHandle); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
NTSTATUS NTAPI NtCreateEventPair(OUT PHANDLE EventPairHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes) { PKEVENT_PAIR EventPair; HANDLE hEventPair; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status; PAGED_CODE(); DPRINT("NtCreateEventPair: 0x%p\n", EventPairHandle); /* Check if we were called from user-mode */ if (PreviousMode != KernelMode) { /* Enter SEH Block */ _SEH2_TRY { /* Check handle pointer */ ProbeForWriteHandle(EventPairHandle); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
/* * @implemented */ NTSTATUS NTAPI NtCreateSemaphore(OUT PHANDLE SemaphoreHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN LONG InitialCount, IN LONG MaximumCount) { PKSEMAPHORE Semaphore; HANDLE hSemaphore; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); NTSTATUS Status; PAGED_CODE(); /* Check if we were called from user-mode */ if (PreviousMode != KernelMode) { /* Enter SEH Block */ _SEH2_TRY { /* Check handle pointer */ ProbeForWriteHandle(SemaphoreHandle); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Return the exception code */ _SEH2_YIELD(return _SEH2_GetExceptionCode()); } _SEH2_END; }
NTSTATUS NtAcceptConnectPort ( OUT PHANDLE PortHandle, IN PVOID PortContext OPTIONAL, IN PPORT_MESSAGE ConnectionRequest, IN BOOLEAN AcceptConnection, IN OUT PPORT_VIEW ServerView OPTIONAL, OUT PREMOTE_PORT_VIEW ClientView OPTIONAL ) /*++ Routine Description: A server process can accept or reject a client connection request using the NtAcceptConnectPort service. The ConnectionRequest parameter must specify a connection request returned by a previous call to the NtListenPort service. This service will either complete the connection if the AcceptConnection parameter is TRUE, or reject the connection request if the AcceptConnection parameter is FALSE. In either case, the contents of the data portion of the connection request is the data to return to the caller of NtConnectPort. If the connection request is accepted, then two communication port objects will be created and connected together. One will be inserted in the client process' handle table and returned to the client via the PortHandle parameter it specified on the NtConnectPort service. The other will be inserted in the server process' handle table and returned via the PortHandle parameter specified on the NtCompleteConnectPort service. In addition the two communication ports (client and server) will be linked together. If the connection request is accepted, and the ServerView parameter was specified, then the section handle is examined. If it is valid, 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 server's address space will be returned in the ViewBase field. The address in the client's 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. Communication port objects are temporary objects that have no names and cannot be inherited. When either the client or server process calls the !f NtClose service for a communication port, the port will be deleted since there can never be more than one outstanding handle for each communication port. The port object type specific delete procedure will then be invoked. This delete procedure will examine the communication port, and if it is connected to another communication port, it will queue an LPC_PORT_CLOSED datagram to that port's message queue. This will allow both the client and server processes to notice when a port becomes disconnected, either because of an explicit call to NtClose or an implicit call due to process termination. In addition, the delete procedure will scan the message queue of the port being closed and for each message still in the queue, it will return an ERROR_PORT_CLOSED status to any thread that is waiting for a reply to the message. Arguments: PortHandle - A pointer to a variable that will receive the server communication port object handle value. PortContext - An uninterpreted pointer that is stored in the server communication port. This pointer is returned whenever a message is received for this port. ConnectionRequest - A pointer to a structure that describes the connection request being accepted or rejected: The ConnectionRequest structure ULONG Length - Specifies the size of this data structure in bytes. CLIENT_ID ClientId - Specifies a structure that contains the client identifier (CLIENT_ID) of the thread that sent the request. The ClientId Structure ULONG UniqueProcessId - A unique value for each process in the system. ULONG UniqueThreadId - A unique value for each thread in the system. ULONG MessageId - A unique value that identifies the connection request being completed. ULONG PortAttributes - This field has no meaning for this service. ULONG ClientViewSize - This field has no meaning for this service. AcceptConnection - Specifies a boolean value which indicates where the connection request is being accepted or rejected. A value of TRUE means that the connection request is accepted and a server communication port handle will be created and connected to the client's communication port handle. A value of FALSE means that the connection request is not accepted. ServerView - A pointer to a structure that specifies the section that the server process will use to send messages back to the client process connected to this port. The ServerView Structure ULONG Length - Specifies the size of this data structure in bytes. HANDLE SectionHandle - Specifies an open handle to a section object. ULONG 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 ViewSize - Specifies the size of the view, in bytes. PVOID ViewBase - Specifies a field that will receive the base address of the port memory in the server's address space. PVOID ViewRemoteBase - Specifies a field that will receive the base address of the server port's memory in the client's address space. Used to generate pointers that are meaningful to the client. ClientView - An optional pointer to a structure that will receive information about the client process' view in the server's address space. The server process can use this information to validate pointers it receives from the client process. The ClientView Structure ULONG Length - Specifies the size of this data structure in bytes. PVOID ViewBase - Specifies a field that will receive the base address of the client port's memory in the server's address space. ULONG ViewSize - Specifies a field that will receive the size, in bytes, of the client's view in the server's address space. If this field is zero, then client has no view in the server's address space. Return Value: NTSTATUS - An appropriate status value. --*/ { PLPCP_PORT_OBJECT ConnectionPort; PLPCP_PORT_OBJECT ServerPort; PLPCP_PORT_OBJECT ClientPort; PVOID ClientSectionToMap; HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; ULONG ConnectionInfoLength; PLPCP_MESSAGE Msg; PLPCP_CONNECTION_MESSAGE ConnectMsg; PORT_MESSAGE CapturedReplyMessage; PVOID SectionToMap; LARGE_INTEGER SectionOffset; SIZE_T ViewSize; PEPROCESS ClientProcess; PETHREAD ClientThread; PORT_VIEW CapturedServerView; PAGED_CODE(); // // Get previous processor mode and probe output arguments if necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { try { ProbeForWriteHandle( PortHandle ); ProbeForRead( ConnectionRequest, sizeof( *ConnectionRequest ), sizeof( ULONG )); CapturedReplyMessage = *ConnectionRequest; if (ARGUMENT_PRESENT( ServerView )) { CapturedServerView = ProbeAndReadStructure( ServerView, PORT_VIEW ); if (CapturedServerView.Length != sizeof( *ServerView )) { return STATUS_INVALID_PARAMETER; } ProbeForWrite( ServerView, sizeof( *ServerView ), sizeof( ULONG )); } if (ARGUMENT_PRESENT( ClientView )) { if (ProbeAndReadUlong( &ClientView->Length ) != sizeof( *ClientView )) { return STATUS_INVALID_PARAMETER; } ProbeForWrite( ClientView, sizeof( *ClientView ), sizeof( ULONG )); } } except( EXCEPTION_EXECUTE_HANDLER ) { return GetExceptionCode(); } } else {
NTSTATUS NtCreateTimer ( OUT PHANDLE TimerHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN TIMER_TYPE TimerType ) /*++ Routine Description: This function creates an timer object and opens a handle to the object with the specified desired access. Arguments: TimerHandle - Supplies a pointer to a variable that will receive the timer object handle. DesiredAccess - Supplies the desired types of access for the timer object. ObjectAttributes - Supplies a pointer to an object attributes structure. TimerType - Supplies the type of the timer (autoclearing or notification). Return Value: TBS --*/ { PETIMER ExTimer; HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Establish an exception handler, probe the output handle address, and // attempt to create a timer object. If the probe fails, then return the // exception code as the service status. Otherwise return the status value // returned by the object insertion routine. // try { // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWriteHandle(TimerHandle); } // // Check argument validity. // if ((TimerType != NotificationTimer) && (TimerType != SynchronizationTimer)) { return STATUS_INVALID_PARAMETER_4; } // // Allocate timer object. // Status = ObCreateObject(PreviousMode, ExTimerObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(ETIMER), 0, 0, (PVOID *)&ExTimer); // // If the timer object was successfully allocated, then initialize the // timer object and attempt to insert the time object in the current // process' handle table. // if (NT_SUCCESS(Status)) { KeInitializeDpc(&ExTimer->TimerDpc, ExpTimerDpcRoutine, (PVOID)ExTimer); KeInitializeTimerEx(&ExTimer->KeTimer, TimerType); KeInitializeSpinLock(&ExTimer->Lock); ExTimer->ApcAssociated = FALSE; ExTimer->WakeTimer = FALSE; ExTimer->WakeTimerListEntry.Flink = NULL; Status = ObInsertObject((PVOID)ExTimer, NULL, DesiredAccess, 0, (PVOID *)NULL, &Handle); // // If the timer object was successfully inserted in the current // process' handle table, then attempt to write the timer object // handle value. If the write attempt fails, then do not report // an error. When the caller attempts to access the handle value, // an access violation will occur. // if (NT_SUCCESS(Status)) { try { *TimerHandle = Handle; } except(ExSystemExceptionFilter()) { } } } // // If an exception occurs during the probe of the output handle address, // then always handle the exception and return the exception code as the // status value. // } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } // // Return service status. // return Status; }
/* * @implemented */ NTSTATUS NTAPI NtAcceptConnectPort(OUT PHANDLE PortHandle, IN PVOID PortContext OPTIONAL, IN PPORT_MESSAGE ReplyMessage, IN BOOLEAN AcceptConnection, IN PPORT_VIEW ServerView, IN PREMOTE_PORT_VIEW ClientView) { PLPCP_PORT_OBJECT ConnectionPort, ServerPort, ClientPort; PVOID ClientSectionToMap = NULL; HANDLE Handle; KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); NTSTATUS Status; ULONG ConnectionInfoLength; PLPCP_MESSAGE Message; PLPCP_CONNECTION_MESSAGE ConnectMessage; PEPROCESS ClientProcess; PETHREAD ClientThread; LARGE_INTEGER SectionOffset; CLIENT_ID ClientId; ULONG MessageId; PAGED_CODE(); LPCTRACE(LPC_COMPLETE_DEBUG, "Context: %p. Message: %p. Accept: %lx. Views: %p/%p\n", PortContext, ReplyMessage, AcceptConnection, ClientView, ServerView); /* Check if the call comes from user mode */ if (PreviousMode != KernelMode) { /* Enter SEH for probing the parameters */ _SEH2_TRY { ProbeForWriteHandle(PortHandle); /* Probe the basic ReplyMessage structure */ ProbeForRead(ReplyMessage, sizeof(PORT_MESSAGE), sizeof(ULONG)); /* Grab some values */ ClientId = ReplyMessage->ClientId; MessageId = ReplyMessage->MessageId; ConnectionInfoLength = ReplyMessage->u1.s1.DataLength; /* Probe the connection info */ ProbeForRead(ReplyMessage + 1, ConnectionInfoLength, 1); /* The following parameters are optional */ if (ServerView != NULL) { ProbeForWrite(ServerView, sizeof(PORT_VIEW), sizeof(ULONG)); /* Validate the size of the server view */ if (ServerView->Length != sizeof(PORT_VIEW)) { /* Invalid size */ _SEH2_YIELD(return STATUS_INVALID_PARAMETER); } }
NTSTATUS NtOpenProcessToken( IN HANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, OUT PHANDLE TokenHandle ) /*++ Routine Description: Open a token object associated with a process and return a handle that may be used to access that token. Arguments: ProcessHandle - Specifies the process whose token is to be opened. DesiredAccess - Is an access mask indicating which access types are desired to the token. These access types are reconciled with the Discretionary Access Control list of the token to determine whether the accesses will be granted or denied. TokenHandle - Receives the handle of the newly opened token. Return Value: STATUS_SUCCESS - Indicates the operation was successful. --*/ { PVOID Token; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; HANDLE LocalHandle; PAGED_CODE(); PreviousMode = KeGetPreviousMode(); // // Probe parameters // if (PreviousMode != KernelMode) { try { ProbeForWriteHandle(TokenHandle); } except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } // end_try } //end_if // // Valdiate access to the process and obtain a pointer to the // process's token. If successful, this will cause the token's // reference count to be incremented. // Status = PsOpenTokenOfProcess( ProcessHandle, ((PACCESS_TOKEN *)&Token)); if (!NT_SUCCESS(Status)) { return Status; } // // Now try to open the token for the specified desired access // Status = ObOpenObjectByPointer( (PVOID)Token, // Object 0, // HandleAttributes NULL, // AccessState DesiredAccess, // DesiredAccess SepTokenObjectType, // ObjectType PreviousMode, // AccessMode &LocalHandle // Handle ); // // And decrement the reference count of the token to counter // the action performed by PsOpenTokenOfProcess(). If the open // was successful, the handle will have caused the token's // reference count to have been incremented. // ObDereferenceObject( Token ); // // Return the new handle // if (NT_SUCCESS(Status)) { try { *TokenHandle = LocalHandle; } except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } } return Status; }
NTSTATUS NtCreateMutant ( OUT PHANDLE MutantHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN BOOLEAN InitialOwner ) /*++ Routine Description: This function creates a mutant object, sets its initial count to one (signaled), and opens a handle to the object with the specified desired access. Arguments: MutantHandle - Supplies a pointer to a variable that will receive the mutant object handle. DesiredAccess - Supplies the desired types of access for the mutant object. ObjectAttributes - Supplies a pointer to an object attributes structure. InitialOwner - Supplies a boolean value that determines whether the creator of the object desires immediate ownership of the object. Return Value: TBS --*/ { HANDLE Handle; PVOID Mutant; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Establish an exception handler, probe the output handle address, and // attempt to create a mutant object. If the probe fails, then return the // exception code as the service status. Otherwise return the status value // returned by the object insertion routine. // try { // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWriteHandle(MutantHandle); } // // Allocate mutant object. // Status = ObCreateObject(PreviousMode, ExMutantObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(KMUTANT), 0, 0, (PVOID *)&Mutant); // // If the mutant object was successfully allocated, then initialize // the mutant object and attempt to insert the mutant object in the // current process' handle table. // if (NT_SUCCESS(Status)) { KeInitializeMutant((PKMUTANT)Mutant, InitialOwner); Status = ObInsertObject(Mutant, NULL, DesiredAccess, 0, (PVOID *)NULL, &Handle); // // If the mutant object was successfully inserted in the current // process' handle table, then attempt to write the mutant object // handle value. If the write attempt fails, then do not report // an error. When the caller attempts to access the handle value, // an access violation will occur. // if (NT_SUCCESS(Status)) { try { *MutantHandle = Handle; } except(ExSystemExceptionFilter()) { } } } // // If an exception occurs during the probe of the output handle address, // then always handle the exception and return the exception code as the // status value. // } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } // // Return service status. // return Status; }
NTSTATUS NtOpenProcess ( __out PHANDLE ProcessHandle, __in ACCESS_MASK DesiredAccess, __in POBJECT_ATTRIBUTES ObjectAttributes, __in_opt PCLIENT_ID ClientId ) /*++ Routine Description: This function opens a handle to a process object with the specified desired access. The object is located either by name, or by locating a thread whose Client ID matches the specified Client ID and then opening that thread's process. Arguments: ProcessHandle - Supplies a pointer to a variable that will receive the process object handle. DesiredAccess - Supplies the desired types of access for the process object. ObjectAttributes - Supplies a pointer to an object attributes structure. If the ObjectName field is specified, then ClientId must not be specified. ClientId - Supplies a pointer to a ClientId that if supplied specifies the thread whose process is to be opened. If this argument is specified, then ObjectName field of the ObjectAttributes structure must not be specified. Return Value: NTSTATUS - Status of call --*/ { HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; PEPROCESS Process; PETHREAD Thread; CLIENT_ID CapturedCid={0}; BOOLEAN ObjectNamePresent; BOOLEAN ClientIdPresent; ACCESS_STATE AccessState; AUX_ACCESS_DATA AuxData; ULONG Attributes; PAGED_CODE(); // // Make sure that only one of either ClientId or ObjectName is // present. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { // // Since we need to look at the ObjectName field, probe // ObjectAttributes and capture object name present indicator. // try { ProbeForWriteHandle (ProcessHandle); ProbeForReadSmallStructure (ObjectAttributes, sizeof(OBJECT_ATTRIBUTES), sizeof(ULONG)); ObjectNamePresent = (BOOLEAN)ARGUMENT_PRESENT (ObjectAttributes->ObjectName); Attributes = ObSanitizeHandleAttributes (ObjectAttributes->Attributes, UserMode); if (ARGUMENT_PRESENT (ClientId)) { ProbeForReadSmallStructure (ClientId, sizeof (CLIENT_ID), sizeof (ULONG)); CapturedCid = *ClientId; ClientIdPresent = TRUE; } else { ClientIdPresent = FALSE; } } except (EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } } else {
NTSTATUS NtCreateSemaphore ( __out PHANDLE SemaphoreHandle, __in ACCESS_MASK DesiredAccess, __in_opt POBJECT_ATTRIBUTES ObjectAttributes, __in LONG InitialCount, __in LONG MaximumCount ) /*++ Routine Description: This function creates a semaphore object, sets its initial count to the specified value, sets its maximum count to the specified value, and opens a handle to the object with the specified desired access. Arguments: SemaphoreHandle - Supplies a pointer to a variable that will receive the semaphore object handle. DesiredAccess - Supplies the desired types of access for the semaphore object. ObjectAttributes - Supplies a pointer to an object attributes structure. InitialCount - Supplies the initial count of the semaphore object. MaximumCount - Supplies the maximum count of the semaphore object. Return Value: NTSTATUS. --*/ { HANDLE Handle; KPROCESSOR_MODE PreviousMode; PVOID Semaphore; NTSTATUS Status; // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { try { ProbeForWriteHandle(SemaphoreHandle); } except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } } // // Check argument validity. // if ((MaximumCount <= 0) || (InitialCount < 0) || (InitialCount > MaximumCount)) { return STATUS_INVALID_PARAMETER; } // // Allocate semaphore object. // Status = ObCreateObject(PreviousMode, ExSemaphoreObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(KSEMAPHORE), 0, 0, &Semaphore); // // If the semaphore object was successfully allocated, then initialize // the semaphore object and attempt to insert the semaphore object in // the current process' handle table. // if (NT_SUCCESS(Status)) { KeInitializeSemaphore((PKSEMAPHORE)Semaphore, InitialCount, MaximumCount); Status = ObInsertObject(Semaphore, NULL, DesiredAccess, 0, NULL, &Handle); // // If the semaphore object was successfully inserted in the current // process' handle table, then attempt to write the semaphore handle // value. If the write attempt fails, then do not report an error. // When the caller attempts to access the handle value, an access // violation will occur. // if (NT_SUCCESS(Status)) { if (PreviousMode != KernelMode) { try { *SemaphoreHandle = Handle; } except(EXCEPTION_EXECUTE_HANDLER) { NOTHING; } } else { *SemaphoreHandle = Handle; } } }
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 )) {
NTSTATUS NtCreateEvent ( OUT PHANDLE EventHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN EVENT_TYPE EventType, IN BOOLEAN InitialState ) /*++ Routine Description: This function creates an event object, sets it initial state to the specified value, and opens a handle to the object with the specified desired access. Arguments: EventHandle - Supplies a pointer to a variable that will receive the event object handle. DesiredAccess - Supplies the desired types of access for the event object. ObjectAttributes - Supplies a pointer to an object attributes structure. EventType - Supplies the type of the event (autoclearing or notification). InitialState - Supplies the initial state of the event object. Return Value: TBS --*/ { PVOID Event; HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Establish an exception handler, probe the output handle address, and // attempt to create an event object. If the probe fails, then return the // exception code as the service status. Otherwise return the status value // returned by the object insertion routine. // try { // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWriteHandle(EventHandle); } // // Check argument validity. // if ((EventType != NotificationEvent) && (EventType != SynchronizationEvent)) { return STATUS_INVALID_PARAMETER; } // // Allocate event object. // Status = ObCreateObject(PreviousMode, ExEventObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(KEVENT), 0, 0, (PVOID *)&Event); // // If the event object was successfully allocated, then initialize the // event object and attempt to insert the event object in the current // process' handle table. // if (NT_SUCCESS(Status)) { KeInitializeEvent((PKEVENT)Event, EventType, InitialState); Status = ObInsertObject(Event, NULL, DesiredAccess, 0, (PVOID *)NULL, &Handle); // // If the event object was successfully inserted in the current // process' handle table, then attempt to write the event object // handle value. If the write attempt fails, then do not report // an error. When the caller attempts to access the handle value, // an access violation will occur. // if (NT_SUCCESS(Status)) { try { *EventHandle = Handle; } except(ExSystemExceptionFilter()) { } } } // // If an exception occurs during the probe of the output handle address, // then always handle the exception and return the exception code as the // status value. // } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } // // Return service status. // return Status; }
NTSTATUS NtOpenEvent ( OUT PHANDLE EventHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes ) /*++ Routine Description: This function opens a handle to an event object with the specified desired access. Arguments: EventHandle - Supplies a pointer to a variable that will receive the event object handle. DesiredAccess - Supplies the desired types of access for the event object. ObjectAttributes - Supplies a pointer to an object attributes structure. Return Value: TBS --*/ { HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Establish an exception handler, probe the output handle address, and // attempt to open the event object. If the probe fails, then return the // exception code as the service status. Otherwise return the status value // returned by the object open routine. // try { // // Get previous processor mode and probe output handle address // if necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWriteHandle(EventHandle); } // // Open handle to the event object with the specified desired access. // Status = ObOpenObjectByName(ObjectAttributes, ExEventObjectType, PreviousMode, NULL, DesiredAccess, NULL, &Handle); // // If the open was successful, then attempt to write the event object // handle value. If the write attempt fails, then do not report an // error. When the caller attempts to access the handle value, an // access violation will occur. // if (NT_SUCCESS(Status)) { try { *EventHandle = Handle; } except(ExSystemExceptionFilter()) { } } // // If an exception occurs during the probe of the output event handle, // then always handle the exception and return the exception code as the // status value. // } except(ExSystemExceptionFilter()) { return GetExceptionCode(); } // // Return service status. // return Status; }
NTSTATUS NtOpenThreadToken( IN HANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN BOOLEAN OpenAsSelf, OUT PHANDLE TokenHandle ) /*++ Routine Description: Open a token object associated with a thread and return a handle that may be used to access that token. Arguments: ThreadHandle - Specifies the thread whose token is to be opened. DesiredAccess - Is an access mask indicating which access types are desired to the token. These access types are reconciled with the Discretionary Access Control list of the token to determine whether the accesses will be granted or denied. OpenAsSelf - Is a boolean value indicating whether the access should be made using the calling thread's current security context, which may be that of a client if impersonating, or using the caller's process-level security context. A value of FALSE indicates the caller's current context should be used un-modified. A value of TRUE indicates the request should be fulfilled using the process level security context. This parameter is necessary to allow a server process to open a client's token when the client specified IDENTIFICATION level impersonation. In this case, the caller would not be able to open the client's token using the client's context (because you can't create executive level objects using IDENTIFICATION level impersonation). TokenHandle - Receives the handle of the newly opened token. Return Value: STATUS_SUCCESS - Indicates the operation was successful. STATUS_NO_TOKEN - Indicates an attempt has been made to open a token associated with a thread that is not currently impersonating a client. STATUS_CANT_OPEN_ANONYMOUS - Indicates the client requested anonymous impersonation level. An anonymous token can not be openned. --*/ { KPROCESSOR_MODE PreviousMode; NTSTATUS Status; PVOID Token; PTOKEN NewToken = NULL; BOOLEAN CopyOnOpen; BOOLEAN EffectiveOnly; SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; SE_IMPERSONATION_STATE DisabledImpersonationState; BOOLEAN RestoreImpersonationState = FALSE; HANDLE LocalHandle; SECURITY_DESCRIPTOR SecurityDescriptor; OBJECT_ATTRIBUTES ObjectAttributes; PACL NewAcl = NULL; PETHREAD Thread; PETHREAD OriginalThread = NULL; PACCESS_TOKEN PrimaryToken; SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; PAGED_CODE(); PreviousMode = KeGetPreviousMode(); // // Probe parameters // if (PreviousMode != KernelMode) { try { ProbeForWriteHandle(TokenHandle); } except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } // end_try } //end_if // // Valdiate access to the thread and obtain a pointer to the // thread's token (if there is one). If successful, this will // cause the token's reference count to be incremented. // // This routine disabled impersonation as necessary to properly // honor the OpenAsSelf flag. // Status = SepOpenTokenOfThread( ThreadHandle, OpenAsSelf, ((PACCESS_TOKEN *)&Token), &OriginalThread, &CopyOnOpen, &EffectiveOnly, &ImpersonationLevel ); if (!NT_SUCCESS(Status)) { return Status; } // // The token was successfully referenced. // // // We need to create and/or open a token object, so disable impersonation // if necessary. // if (OpenAsSelf) { RestoreImpersonationState = PsDisableImpersonation( PsGetCurrentThread(), &DisabledImpersonationState ); } // // If the CopyOnOpen flag is not set, then the token can be // opened directly. Otherwise, the token must be duplicated, // and a handle to the duplicate returned. // if (CopyOnOpen) { // // Create the new security descriptor for the token. // // We must obtain the correct SID to put into the Dacl. Do this // by finding the process associated with the passed thread // and grabbing the User SID out of that process's token. // If we just use the current SubjectContext, we'll get the // SID of whoever is calling us, which isn't what we want. // Status = ObReferenceObjectByHandle( ThreadHandle, THREAD_ALL_ACCESS, PsThreadType, KernelMode, (PVOID)&Thread, NULL ); // // Verify that the handle is still pointer to the same thread\ // BUGBUG: wrong error code. // if (NT_SUCCESS(Status) && (Thread != OriginalThread)) { Status = STATUS_OBJECT_TYPE_MISMATCH; } if (NT_SUCCESS(Status)) { PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess); Status = SepCreateImpersonationTokenDacl( (PTOKEN)Token, PrimaryToken, &NewAcl ); PsDereferencePrimaryToken( PrimaryToken ); if (NT_SUCCESS( Status )) { if (NewAcl != NULL) { // // There exist tokens that either do not have security descriptors at all, // or have security descriptors, but do not have DACLs. In either case, do // nothing. // Status = RtlCreateSecurityDescriptor ( &SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION ); ASSERT( NT_SUCCESS( Status )); Status = RtlSetDaclSecurityDescriptor ( &SecurityDescriptor, TRUE, NewAcl, FALSE ); ASSERT( NT_SUCCESS( Status )); } InitializeObjectAttributes( &ObjectAttributes, NULL, 0L, NULL, NewAcl == NULL ? NULL : &SecurityDescriptor ); // // Open a copy of the token // Status = SepDuplicateToken( (PTOKEN)Token, // ExistingToken &ObjectAttributes, // ObjectAttributes EffectiveOnly, // EffectiveOnly TokenImpersonation, // TokenType ImpersonationLevel, // ImpersonationLevel KernelMode, // RequestorMode must be kernel mode &NewToken ); if (NT_SUCCESS( Status )) { // // Reference the token so it doesn't go away // ObReferenceObject(NewToken); // // Insert the new token // Status = ObInsertObject( NewToken, NULL, DesiredAccess, 0, (PVOID *)NULL, &LocalHandle ); } } } } else { // // We do not have to modify the security on the token in the static case, // because in all the places in the system where impersonation takes place // over a secure transport (e.g., LPC), CopyOnOpen is set. The only reason // we'be be here is if the impersonation is taking place because someone did // an NtSetInformationThread and passed in a token. // // In that case, we absolutely do not want to give the caller guaranteed // access, because that would allow anyone who has access to a thread to // impersonate any of that thread's clients for any access. // // // Open the existing token // Status = ObOpenObjectByPointer( (PVOID)Token, // Object 0, // HandleAttributes NULL, // AccessState DesiredAccess, // DesiredAccess SepTokenObjectType, // ObjectType PreviousMode, // AccessMode &LocalHandle // Handle ); } if (NewAcl != NULL) { ExFreePool( NewAcl ); } if (RestoreImpersonationState) { PsRestoreImpersonation( PsGetCurrentThread(), &DisabledImpersonationState ); } // // And decrement the reference count of the existing token to counter // the action performed by PsOpenTokenOfThread. If the open // was successful, the handle will have caused the token's // reference count to have been incremented. // ObDereferenceObject( Token ); if (NT_SUCCESS( Status ) && CopyOnOpen) { // // Assign the newly duplicated token to the thread. // PsImpersonateClient( Thread, NewToken, FALSE, // turn off CopyOnOpen flag EffectiveOnly, ImpersonationLevel ); } // // We've impersonated the token so let go of oure reference // if (NewToken != NULL) { ObDereferenceObject( NewToken ); } if (CopyOnOpen && (Thread != NULL)) { ObDereferenceObject( Thread ); } if (OriginalThread != NULL) { ObDereferenceObject(OriginalThread); } // // Return the new handle // if (NT_SUCCESS(Status)) { try { *TokenHandle = LocalHandle; } except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } } return Status; }
NTSTATUS NtCreateEvent ( __out PHANDLE EventHandle, __in ACCESS_MASK DesiredAccess, __in_opt POBJECT_ATTRIBUTES ObjectAttributes, __in EVENT_TYPE EventType, __in BOOLEAN InitialState ) /*++ Routine Description: This function creates an event object, sets it initial state to the specified value, and opens a handle to the object with the specified desired access. Arguments: EventHandle - Supplies a pointer to a variable that will receive the event object handle. DesiredAccess - Supplies the desired types of access for the event object. ObjectAttributes - Supplies a pointer to an object attributes structure. EventType - Supplies the type of the event (autoclearing or notification). InitialState - Supplies the initial state of the event object. Return Value: NTSTATUS. --*/ { PVOID Event; HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { try { ProbeForWriteHandle(EventHandle); } except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } } // // Check argument validity. // if ((EventType != NotificationEvent) && (EventType != SynchronizationEvent)) { return STATUS_INVALID_PARAMETER; } // // Allocate event object. // Status = ObCreateObject(PreviousMode, ExEventObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(KEVENT), 0, 0, &Event); // // If the event object was successfully allocated, then initialize the // event object and attempt to insert the event object in the current // process' handle table. // if (NT_SUCCESS(Status)) { KeInitializeEvent((PKEVENT)Event, EventType, InitialState); Status = ObInsertObject(Event, NULL, DesiredAccess, 0, NULL, &Handle); // // If the event object was successfully inserted in the current // process' handle table, then attempt to write the event object // handle value. If the write attempt fails, then do not report // an error. When the caller attempts to access the handle value, // an access violation will occur. // if (NT_SUCCESS(Status)) { if (PreviousMode != KernelMode) { try { *EventHandle = Handle; } except(EXCEPTION_EXECUTE_HANDLER) { NOTHING; } } else { *EventHandle = Handle; } } }
NTSTATUS NtOpenIoCompletion ( __out PHANDLE IoCompletionHandle, __in ACCESS_MASK DesiredAccess, __in POBJECT_ATTRIBUTES ObjectAttributes ) /*++ Routine Description: This function opens a handle to an I/O completion object with the specified desired access. Arguments: IoCompletionHandle - Supplies a pointer to a variable that receives the completion object handle. DesiredAccess - Supplies the desired types of access for the I/O completion object. ObjectAttributes - Supplies a pointer to an object attributes structure. Return Value: STATUS_SUCCESS is returned if the function is success. Otherwise, an error status is returned. --*/ { HANDLE Handle; KPROCESSOR_MODE PreviousMode; NTSTATUS Status; // // Establish an exception handler, probe the output handle address, // and attempt to open an I/O completion object. If the probe fails, // then return the exception code as the service status. Otherwise, // return the status value returned by the object open routine. // try { // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWriteHandle(IoCompletionHandle); } // // Open handle to the completion object with the specified desired // access. // Status = ObOpenObjectByName(ObjectAttributes, IoCompletionObjectType, PreviousMode, NULL, DesiredAccess, NULL, &Handle); // // If the open was successful, then attempt to write the I/O // completion object handle value. If the write attempt fails, // then do not report an error. When the caller attempts to // access the handle value, an access violation will occur. // if (NT_SUCCESS(Status)) { try { *IoCompletionHandle = Handle; } except(ExSystemExceptionFilter()) { NOTHING; } } // // If an exception occurs during the probe of the output handle address, // then always handle the exception and return the exception code as the // status value. // } except(ExSystemExceptionFilter()) { Status = GetExceptionCode(); } // // Return service status. // return Status; }
NTSTATUS NtCreateIoCompletion ( __out PHANDLE IoCompletionHandle, __in ACCESS_MASK DesiredAccess, __in_opt POBJECT_ATTRIBUTES ObjectAttributes, __in ULONG Count OPTIONAL ) /*++ Routine Description: This function creates an I/O completion object, sets the maximum target concurrent thread count to the specified value, and opens a handle to the object with the specified desired access. Arguments: IoCompletionHandle - Supplies a pointer to a variable that receives the I/O completion object handle. DesiredAccess - Supplies the desired types of access for the I/O completion object. ObjectAttributes - Supplies a pointer to an object attributes structure. Count - Supplies the target maximum number of threads that should be concurrently active. If this parameter is not specified, then the number of processors is used. Return Value: STATUS_SUCCESS is returned if the function is success. Otherwise, an error status is returned. --*/ { HANDLE Handle; KPROCESSOR_MODE PreviousMode; PVOID IoCompletion; NTSTATUS Status; // // Establish an exception handler, probe the output handle address, and // attempt to create an I/O completion object. If the probe fails, then // return the exception code as the service status. Otherwise, return the // status value returned by the object insertion routine. // try { // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWriteHandle(IoCompletionHandle); } // // Allocate I/O completion object. // Status = ObCreateObject(PreviousMode, IoCompletionObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(KQUEUE), 0, 0, (PVOID *)&IoCompletion); // // If the I/O completion object was successfully allocated, then // initialize the object and attempt to insert it in the handle // table of the current process. // if (NT_SUCCESS(Status)) { KeInitializeQueue((PKQUEUE)IoCompletion, Count); Status = ObInsertObject(IoCompletion, NULL, DesiredAccess, 0, (PVOID *)NULL, &Handle); // // If the I/O completion object was successfully inserted in // the handle table of the current process, then attempt to // write the handle value. If the write attempt fails, then // do not report an error. When the caller attempts to access // the handle value, an access violation will occur. // if (NT_SUCCESS(Status)) { try { *IoCompletionHandle = Handle; } except(ExSystemExceptionFilter()) { NOTHING; } } } // // If an exception occurs during the probe of the output handle address, // then always handle the exception and return the exception code as the // status value. // } except(ExSystemExceptionFilter()) { Status = GetExceptionCode(); } // // Return service status. // return Status; }
NTSTATUS NtCreateSymbolicLinkObject( OUT PHANDLE LinkHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN PUNICODE_STRING LinkTarget ) /*++ Routine Description: This function creates a symbolic link object, sets it initial value to value specified in the LinkTarget parameter, and opens a handle to the object with the specified desired access. Arguments: LinkHandle - Supplies a pointer to a variable that will receive the symbolic link object handle. DesiredAccess - Supplies the desired types of access for the symbolic link object. ObjectAttributes - Supplies a pointer to an object attributes structure. LinkTarget - Supplies the target name for the symbolic link object. Return Value: TBS --*/ { KPROCESSOR_MODE PreviousMode; NTSTATUS Status; POBJECT_SYMBOLIC_LINK SymbolicLink; PVOID Object; HANDLE Handle; UNICODE_STRING CapturedLinkTarget; UNICODE_STRING CapturedLinkName; ULONG CapturedAttributes; PAGED_CODE(); // // Get previous processor mode and probe output arguments if necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { try { CapturedAttributes = ObjectAttributes->Attributes; CapturedLinkName = *(ObjectAttributes->ObjectName); ProbeForRead( LinkTarget, sizeof( *LinkTarget ), sizeof( UCHAR ) ); CapturedLinkTarget = *LinkTarget; ProbeForRead( CapturedLinkTarget.Buffer, CapturedLinkTarget.MaximumLength, sizeof( UCHAR ) ); ProbeForWriteHandle( LinkHandle ); } except( EXCEPTION_EXECUTE_HANDLER ) { return( GetExceptionCode() ); } } else {