mirror of
https://github.com/reactos/reactos.git
synced 2024-07-08 21:55:08 +00:00
![George Bișoc](/assets/img/avatar_default.png)
In addition to that, here are some stuff done in this commit whilst testing: - ICIF_QUERY_SIZE_VARIABLE and friends were badly misused, they should be used only when an information class whose information length size is dyanmic and not fixed. By removing such flags from erroneous classes, this fixes the STATUS_INFO_LENGTH_MISMATCH testcases. - Use CHAR instead of UCHAR for classes that do not need alignment probing, as every other class in the table do, for the sake of consistency. - ProcessEnableAlignmentFaultFixup uses BOOLEAN as type size, not CHAR. This fixes a testcase failure on ROS. - Check for information length size before proceeding further on querying the process' cookie information. - ProcessHandleTracing wants an alignment of a ULONG, not CHAR. - Move PROCESS_LDT_INFORMATION and PROCESS_LDT_SIZE outside of NTOS_MODE_USER macro case. This fixes a compilation issue when enabling the alignment probing. My mistake of having them inside NTOS_MODE_USER case, sorry. - On functions like NtQueryInformationThread and the Process equivalent, complete probing is not done at the beginning of the function, complete probing including if the buffer is writable alongside with datatype misalignment check that is. Instead such check is done on each information class case basis. With that said, we have to explicitly tell DefaultQueryInfoBufferCheck if we want a complete probing or not initially.
546 lines
15 KiB
C
546 lines
15 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Kernel
|
|
* FILE: ntoskrnl/ex/event.c
|
|
* PURPOSE: Event support
|
|
* PROGRAMMERS: Alex Ionescu(alex@relsoft.net)
|
|
* Thomas Weidenmueller
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
POBJECT_TYPE ExEventObjectType = NULL;
|
|
|
|
GENERIC_MAPPING ExpEventMapping =
|
|
{
|
|
STANDARD_RIGHTS_READ | EVENT_QUERY_STATE,
|
|
STANDARD_RIGHTS_WRITE | EVENT_MODIFY_STATE,
|
|
STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
|
|
EVENT_ALL_ACCESS
|
|
};
|
|
|
|
static const INFORMATION_CLASS_INFO ExEventInfoClass[] =
|
|
{
|
|
/* EventBasicInformation */
|
|
IQS_SAME(EVENT_BASIC_INFORMATION, ULONG, ICIF_QUERY),
|
|
};
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
NTAPI
|
|
ExpInitializeEventImplementation(VOID)
|
|
{
|
|
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
|
|
UNICODE_STRING Name;
|
|
NTSTATUS Status;
|
|
DPRINT("Creating Event Object Type\n");
|
|
|
|
/* Create the Event Object Type */
|
|
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
|
RtlInitUnicodeString(&Name, L"Event");
|
|
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
|
|
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KEVENT);
|
|
ObjectTypeInitializer.GenericMapping = ExpEventMapping;
|
|
ObjectTypeInitializer.PoolType = NonPagedPool;
|
|
ObjectTypeInitializer.ValidAccessMask = EVENT_ALL_ACCESS;
|
|
ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
|
|
Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExEventObjectType);
|
|
if (!NT_SUCCESS(Status)) return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtClearEvent(IN HANDLE EventHandle)
|
|
{
|
|
PKEVENT Event;
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
|
|
/* Reference the Object */
|
|
Status = ObReferenceObjectByHandle(EventHandle,
|
|
EVENT_MODIFY_STATE,
|
|
ExEventObjectType,
|
|
ExGetPreviousMode(),
|
|
(PVOID*)&Event,
|
|
NULL);
|
|
|
|
/* Check for Success */
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
/* Clear the Event and Dereference */
|
|
KeClearEvent(Event);
|
|
ObDereferenceObject(Event);
|
|
}
|
|
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @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;
|
|
}
|
|
|
|
/* Create the Object */
|
|
Status = ObCreateObject(PreviousMode,
|
|
ExEventObjectType,
|
|
ObjectAttributes,
|
|
PreviousMode,
|
|
NULL,
|
|
sizeof(KEVENT),
|
|
0,
|
|
0,
|
|
(PVOID*)&Event);
|
|
|
|
/* Check for Success */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Initialize the Event */
|
|
KeInitializeEvent(Event,
|
|
EventType,
|
|
InitialState);
|
|
|
|
/* Insert it */
|
|
Status = ObInsertObject((PVOID)Event,
|
|
NULL,
|
|
DesiredAccess,
|
|
0,
|
|
NULL,
|
|
&hEvent);
|
|
|
|
/* Check for success */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Enter SEH for return */
|
|
_SEH2_TRY
|
|
{
|
|
/* Return the handle to the caller */
|
|
*EventHandle = hEvent;
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
/* Get the exception code */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
}
|
|
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtOpenEvent(OUT PHANDLE EventHandle,
|
|
IN ACCESS_MASK DesiredAccess,
|
|
IN POBJECT_ATTRIBUTES ObjectAttributes)
|
|
{
|
|
HANDLE hEvent;
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
DPRINT("NtOpenEvent(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;
|
|
}
|
|
|
|
/* Open the Object */
|
|
Status = ObOpenObjectByName(ObjectAttributes,
|
|
ExEventObjectType,
|
|
PreviousMode,
|
|
NULL,
|
|
DesiredAccess,
|
|
NULL,
|
|
&hEvent);
|
|
|
|
/* Check for success */
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Enter SEH for return */
|
|
_SEH2_TRY
|
|
{
|
|
/* Return the handle to the caller */
|
|
*EventHandle = hEvent;
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
/* Get the exception code */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
|
|
/* Return status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtPulseEvent(IN HANDLE EventHandle,
|
|
OUT PLONG PreviousState OPTIONAL)
|
|
{
|
|
PKEVENT Event;
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
DPRINT("NtPulseEvent(EventHandle 0%p PreviousState 0%p)\n",
|
|
EventHandle, PreviousState);
|
|
|
|
/* Check if we were called from user-mode */
|
|
if((PreviousState) && (PreviousMode != KernelMode))
|
|
{
|
|
/* Entry SEH Block */
|
|
_SEH2_TRY
|
|
{
|
|
/* Make sure the state pointer is valid */
|
|
ProbeForWriteLong(PreviousState);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
/* Return the exception code */
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
|
|
/* Open the Object */
|
|
Status = ObReferenceObjectByHandle(EventHandle,
|
|
EVENT_MODIFY_STATE,
|
|
ExEventObjectType,
|
|
PreviousMode,
|
|
(PVOID*)&Event,
|
|
NULL);
|
|
|
|
/* Check for success */
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
/* Pulse the Event */
|
|
LONG Prev = KePulseEvent(Event, EVENT_INCREMENT, FALSE);
|
|
ObDereferenceObject(Event);
|
|
|
|
/* Check if caller wants the old state back */
|
|
if(PreviousState)
|
|
{
|
|
/* Entry SEH Block for return */
|
|
_SEH2_TRY
|
|
{
|
|
/* Return previous state */
|
|
*PreviousState = Prev;
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
/* Get the exception code */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
}
|
|
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtQueryEvent(IN HANDLE EventHandle,
|
|
IN EVENT_INFORMATION_CLASS EventInformationClass,
|
|
OUT PVOID EventInformation,
|
|
IN ULONG EventInformationLength,
|
|
OUT PULONG ReturnLength OPTIONAL)
|
|
{
|
|
PKEVENT Event;
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
NTSTATUS Status;
|
|
PEVENT_BASIC_INFORMATION BasicInfo =
|
|
(PEVENT_BASIC_INFORMATION)EventInformation;
|
|
PAGED_CODE();
|
|
DPRINT("NtQueryEvent(0x%p, 0x%x)\n", EventHandle, EventInformationClass);
|
|
|
|
/* Check buffers and class validity */
|
|
Status = DefaultQueryInfoBufferCheck(EventInformationClass,
|
|
ExEventInfoClass,
|
|
sizeof(ExEventInfoClass) /
|
|
sizeof(ExEventInfoClass[0]),
|
|
EventInformation,
|
|
EventInformationLength,
|
|
ReturnLength,
|
|
NULL,
|
|
PreviousMode,
|
|
TRUE);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
/* Invalid buffers */
|
|
DPRINT("NtQuerySemaphore() failed, Status: 0x%x\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Get the Object */
|
|
Status = ObReferenceObjectByHandle(EventHandle,
|
|
EVENT_QUERY_STATE,
|
|
ExEventObjectType,
|
|
PreviousMode,
|
|
(PVOID*)&Event,
|
|
NULL);
|
|
|
|
/* Check for success */
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
/* Entry SEH Block */
|
|
_SEH2_TRY
|
|
{
|
|
/* Return Event Type and State */
|
|
BasicInfo->EventType = Event->Header.Type;
|
|
BasicInfo->EventState = KeReadStateEvent(Event);
|
|
|
|
/* Return length */
|
|
if(ReturnLength) *ReturnLength = sizeof(EVENT_BASIC_INFORMATION);
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
/* Get the exception code */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
|
|
/* Dereference the Object */
|
|
ObDereferenceObject(Event);
|
|
}
|
|
|
|
/* Return status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtResetEvent(IN HANDLE EventHandle,
|
|
OUT PLONG PreviousState OPTIONAL)
|
|
{
|
|
PKEVENT Event;
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
DPRINT("NtResetEvent(EventHandle 0%p PreviousState 0%p)\n",
|
|
EventHandle, PreviousState);
|
|
|
|
/* Check if we were called from user-mode */
|
|
if ((PreviousState) && (PreviousMode != KernelMode))
|
|
{
|
|
/* Entry SEH Block */
|
|
_SEH2_TRY
|
|
{
|
|
/* Make sure the state pointer is valid */
|
|
ProbeForWriteLong(PreviousState);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
/* Return the exception code */
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
|
|
/* Open the Object */
|
|
Status = ObReferenceObjectByHandle(EventHandle,
|
|
EVENT_MODIFY_STATE,
|
|
ExEventObjectType,
|
|
PreviousMode,
|
|
(PVOID*)&Event,
|
|
NULL);
|
|
|
|
/* Check for success */
|
|
if(NT_SUCCESS(Status))
|
|
{
|
|
/* Reset the Event */
|
|
LONG Prev = KeResetEvent(Event);
|
|
ObDereferenceObject(Event);
|
|
|
|
/* Check if caller wants the old state back */
|
|
if(PreviousState)
|
|
{
|
|
/* Entry SEH Block for return */
|
|
_SEH2_TRY
|
|
{
|
|
/* Return previous state */
|
|
*PreviousState = Prev;
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
/* Get the exception code */
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
}
|
|
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtSetEvent(IN HANDLE EventHandle,
|
|
OUT PLONG PreviousState OPTIONAL)
|
|
{
|
|
PKEVENT Event;
|
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
DPRINT("NtSetEvent(EventHandle 0%p PreviousState 0%p)\n",
|
|
EventHandle, PreviousState);
|
|
|
|
/* Check if we were called from user-mode */
|
|
if ((PreviousState) && (PreviousMode != KernelMode))
|
|
{
|
|
/* Entry SEH Block */
|
|
_SEH2_TRY
|
|
{
|
|
/* Make sure the state pointer is valid */
|
|
ProbeForWriteLong(PreviousState);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
/* Return the exception code */
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
|
|
/* Open the Object */
|
|
Status = ObReferenceObjectByHandle(EventHandle,
|
|
EVENT_MODIFY_STATE,
|
|
ExEventObjectType,
|
|
PreviousMode,
|
|
(PVOID*)&Event,
|
|
NULL);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Set the Event */
|
|
LONG Prev = KeSetEvent(Event, EVENT_INCREMENT, FALSE);
|
|
ObDereferenceObject(Event);
|
|
|
|
/* Check if caller wants the old state back */
|
|
if (PreviousState)
|
|
{
|
|
/* Entry SEH Block for return */
|
|
_SEH2_TRY
|
|
{
|
|
/* Return previous state */
|
|
*PreviousState = Prev;
|
|
}
|
|
_SEH2_EXCEPT(ExSystemExceptionFilter())
|
|
{
|
|
Status = _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
}
|
|
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
NtSetEventBoostPriority(IN HANDLE EventHandle)
|
|
{
|
|
PKEVENT Event;
|
|
NTSTATUS Status;
|
|
PAGED_CODE();
|
|
|
|
/* Open the Object */
|
|
Status = ObReferenceObjectByHandle(EventHandle,
|
|
EVENT_MODIFY_STATE,
|
|
ExEventObjectType,
|
|
ExGetPreviousMode(),
|
|
(PVOID*)&Event,
|
|
NULL);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* Set the Event */
|
|
KeSetEventBoostPriority(Event, NULL);
|
|
ObDereferenceObject(Event);
|
|
}
|
|
|
|
/* Return Status */
|
|
return Status;
|
|
}
|
|
|
|
/* EOF */
|