- Completely reimplement NtWaitForMultipleObjects:

- Check for invalid Objectcount and wait type
    - Don't use 2.6KB of stack space (kernel threads only get 4...)
    - Don't call ObReferenceObjectByHandle since it does a lot of superflous checks, continous locking/unlocking and makes us extremly slow for a large wait and also doesn't give us the full flexibility we need.
    - Detect if a Waitall is being done with the same object duplicated.
    - Protect wait with SEH.
- General fixes for all NtWaitXXX:
    - Use DefaultObject from Object Header and remove all previous associated hacks, including the IO_TYPE hack. The DefaultObject will either be NULL, an offset to an internal Object Event, or a pointer to a default event. We handle all three.
    - Guard the KeWaitXXX call with SEH since it can raise exceptions.
- Fix all object type intiailizers regarding DefaultObject.

svn path=/trunk/; revision=17179
This commit is contained in:
Alex Ionescu 2005-08-07 21:29:51 +00:00
parent a6b3bd07b6
commit 4c1eb86320
12 changed files with 350 additions and 271 deletions

View file

@ -91,7 +91,6 @@ ExpInitializeCallbacks(VOID)
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(CALLBACK_OBJECT); ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(CALLBACK_OBJECT);
ObjectTypeInitializer.GenericMapping = ExpCallbackMapping; ObjectTypeInitializer.GenericMapping = ExpCallbackMapping;
ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.UseDefaultObject = TRUE;
Status = ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExCallbackObjectType); Status = ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExCallbackObjectType);

View file

@ -50,7 +50,6 @@ ExpInitializeEventImplementation(VOID)
ObjectTypeInitializer.GenericMapping = ExpEventMapping; ObjectTypeInitializer.GenericMapping = ExpEventMapping;
ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.ValidAccessMask = EVENT_ALL_ACCESS; ObjectTypeInitializer.ValidAccessMask = EVENT_ALL_ACCESS;
ObjectTypeInitializer.UseDefaultObject = TRUE;
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExEventObjectType); ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExEventObjectType);
} }

View file

@ -68,7 +68,6 @@ ExpInitializeMutantImplementation(VOID)
ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.DeleteProcedure = ExpDeleteMutant; ObjectTypeInitializer.DeleteProcedure = ExpDeleteMutant;
ObjectTypeInitializer.ValidAccessMask = MUTANT_ALL_ACCESS; ObjectTypeInitializer.ValidAccessMask = MUTANT_ALL_ACCESS;
ObjectTypeInitializer.UseDefaultObject = TRUE;
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExMutantObjectType); ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExMutantObjectType);
} }

View file

@ -94,7 +94,6 @@ ExpInitializeProfileImplementation(VOID)
ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.DeleteProcedure = ExpDeleteProfile; ObjectTypeInitializer.DeleteProcedure = ExpDeleteProfile;
ObjectTypeInitializer.ValidAccessMask = STANDARD_RIGHTS_ALL; ObjectTypeInitializer.ValidAccessMask = STANDARD_RIGHTS_ALL;
ObjectTypeInitializer.UseDefaultObject = TRUE;
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExProfileObjectType); ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExProfileObjectType);
} }

View file

@ -133,7 +133,6 @@ ExpWin32kInit(VOID)
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
ObjectTypeInitializer.GenericMapping = ExpWindowStationMapping; ObjectTypeInitializer.GenericMapping = ExpWindowStationMapping;
ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.UseDefaultObject = TRUE;
ObjectTypeInitializer.OpenProcedure = ExpWinStaObjectOpen; ObjectTypeInitializer.OpenProcedure = ExpWinStaObjectOpen;
ObjectTypeInitializer.DeleteProcedure = ExpWinStaObjectDelete; ObjectTypeInitializer.DeleteProcedure = ExpWinStaObjectDelete;
ObjectTypeInitializer.ParseProcedure = ExpWinStaObjectParse; ObjectTypeInitializer.ParseProcedure = ExpWinStaObjectParse;

View file

@ -8,6 +8,13 @@ extern LARGE_INTEGER ExpTimeZoneBias;
extern ULONG ExpTimeZoneId; extern ULONG ExpTimeZoneId;
extern POBJECT_TYPE ExEventPairObjectType; extern POBJECT_TYPE ExEventPairObjectType;
#define EX_OBJ_TO_HDR(eob) ((POBJECT_HEADER)((ULONG_PTR)(eob) & \
~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
EX_HANDLE_ENTRY_AUDITONCLOSE)))
#define EX_HTE_TO_HDR(hte) ((POBJECT_HEADER)((ULONG_PTR)((hte)->u1.Object) & \
~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
EX_HANDLE_ENTRY_AUDITONCLOSE)))
/* INITIALIZATION FUNCTIONS *************************************************/ /* INITIALIZATION FUNCTIONS *************************************************/
VOID VOID

View file

@ -18,8 +18,6 @@
#include <ndk/ntndk.h> #include <ndk/ntndk.h>
#include <ndk/sysguid.h> #include <ndk/sysguid.h>
#include <ndk/asm.h> #include <ndk/asm.h>
#undef IO_TYPE_FILE
#define IO_TYPE_FILE 0x0F5L /* Temp Hack */
/* FIXME: Temporary until CC Ros is gone */ /* FIXME: Temporary until CC Ros is gone */
#include <ccros.h> #include <ccros.h>

View file

@ -217,6 +217,7 @@ IoInit (VOID)
ObjectTypeInitializer.DeleteProcedure = IopDeleteFile; ObjectTypeInitializer.DeleteProcedure = IopDeleteFile;
ObjectTypeInitializer.SecurityProcedure = IopSecurityFile; ObjectTypeInitializer.SecurityProcedure = IopSecurityFile;
ObjectTypeInitializer.QueryNameProcedure = IopQueryNameFile; ObjectTypeInitializer.QueryNameProcedure = IopQueryNameFile;
ObjectTypeInitializer.UseDefaultObject = FALSE;
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &IoFileObjectType); ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &IoFileObjectType);
/* /*

View file

@ -225,22 +225,6 @@ KeWaitForSingleObject(PVOID Object,
/* Get the Current Object */ /* Get the Current Object */
CurrentObject = (PDISPATCHER_HEADER)Object; CurrentObject = (PDISPATCHER_HEADER)Object;
/* FIXME:
* Temporary hack until my Object Manager re-write. Basically some objects, like
* the File Object, but also LPCs and others, are actually waitable on their event.
* The Object Manager sets this up in The ObjectTypeInformation->DefaultObject member,
* by using pretty much the same kind of hack as us. Normal objects point to themselves
* in that pointer. Then, NtWaitForXXX will populate the WaitList that gets sent to us by
* using ->DefaultObject, so the proper actual objects will be sent to us. Until then however,
* I will keep this hack here, since there's no need to make an interim hack until the rewrite
* -- Alex Ionescu 24/02/05
*/
if (CurrentObject->Type == IO_TYPE_FILE) {
DPRINT1("Hack used: %x\n", &((PFILE_OBJECT)CurrentObject)->Event);
CurrentObject = (PDISPATCHER_HEADER)(&((PFILE_OBJECT)CurrentObject)->Event);
}
/* Check if the Object is Signaled */ /* Check if the Object is Signaled */
if (KiIsObjectSignaled(CurrentObject, CurrentThread)) { if (KiIsObjectSignaled(CurrentObject, CurrentThread)) {
@ -441,21 +425,6 @@ KeWaitForMultipleObjects(ULONG Count,
/* Get the Current Object */ /* Get the Current Object */
CurrentObject = (PDISPATCHER_HEADER)Object[WaitIndex]; CurrentObject = (PDISPATCHER_HEADER)Object[WaitIndex];
/* FIXME:
* Temporary hack until my Object Manager re-write. Basically some objects, like
* the File Object, but also LPCs and others, are actually waitable on their event.
* The Object Manager sets this up in The ObjectTypeInformation->DefaultObject member,
* by using pretty much the same kind of hack as us. Normal objects point to themselves
* in that pointer. Then, NtWaitForXXX will populate the WaitList that gets sent to us by
* using ->DefaultObject, so the proper actual objects will be sent to us. Until then however,
* I will keep this hack here, since there's no need to make an interim hack until the rewrite
* -- Alex Ionescu 24/02/05
*/
if (CurrentObject->Type == IO_TYPE_FILE) {
CurrentObject = (PDISPATCHER_HEADER)(&((PFILE_OBJECT)CurrentObject)->Event);
}
/* Check if the Object is Signaled */ /* Check if the Object is Signaled */
if (KiIsObjectSignaled(CurrentObject, CurrentThread)) { if (KiIsObjectSignaled(CurrentObject, CurrentThread)) {
@ -807,31 +776,6 @@ KiIsObjectSignaled(PDISPATCHER_HEADER Object,
return (!Object->SignalState <= 0); return (!Object->SignalState <= 0);
} }
BOOL
inline
FASTCALL
KiIsObjectWaitable(PVOID Object)
{
POBJECT_HEADER Header;
Header = BODY_TO_HEADER(Object);
if (Header->Type == ExEventObjectType ||
Header->Type == IoCompletionType ||
Header->Type == ExMutantObjectType ||
Header->Type == ExSemaphoreObjectType ||
Header->Type == ExTimerType ||
Header->Type == PsProcessType ||
Header->Type == PsThreadType ||
Header->Type == IoFileObjectType) {
return TRUE;
} else {
return FALSE;
}
}
VOID VOID
inline inline
FASTCALL FASTCALL

View file

@ -33,13 +33,6 @@
#define NDEBUG #define NDEBUG
#include <internal/debug.h> #include <internal/debug.h>
#define EX_OBJ_TO_HDR(eob) ((POBJECT_HEADER)((ULONG_PTR)(eob) & \
~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
EX_HANDLE_ENTRY_AUDITONCLOSE)))
#define EX_HTE_TO_HDR(hte) ((POBJECT_HEADER)((ULONG_PTR)((hte)->u1.Object) & \
~(EX_HANDLE_ENTRY_PROTECTFROMCLOSE | EX_HANDLE_ENTRY_INHERITABLE | \
EX_HANDLE_ENTRY_AUDITONCLOSE)))
#define GENERIC_ANY (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL) #define GENERIC_ANY (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
/* GLOBALS *****************************************************************/ /* GLOBALS *****************************************************************/

View file

@ -4,7 +4,7 @@
* FILE: ntoskrnl/ob/wait.c * FILE: ntoskrnl/ob/wait.c
* PURPOSE: Handles Waiting on Objects * PURPOSE: Handles Waiting on Objects
* *
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created file * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
* David Welch (welch@mcmail.com) * David Welch (welch@mcmail.com)
*/ */
@ -14,188 +14,322 @@
#define NDEBUG #define NDEBUG
#include <internal/debug.h> #include <internal/debug.h>
#define TAG_WAIT TAG('W', 'a', 'i', 't')
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
BOOL inline FASTCALL KiIsObjectWaitable(PVOID Object); NTSTATUS
STDCALL
NTSTATUS STDCALL
NtWaitForMultipleObjects(IN ULONG ObjectCount, NtWaitForMultipleObjects(IN ULONG ObjectCount,
IN PHANDLE ObjectsArray, IN PHANDLE HandleArray,
IN WAIT_TYPE WaitType, IN WAIT_TYPE WaitType,
IN BOOLEAN Alertable, IN BOOLEAN Alertable,
IN PLARGE_INTEGER TimeOut OPTIONAL) IN PLARGE_INTEGER TimeOut OPTIONAL)
{ {
KWAIT_BLOCK WaitBlockArray[MAXIMUM_WAIT_OBJECTS]; PKWAIT_BLOCK WaitBlockArray = NULL;
HANDLE SafeObjectsArray[MAXIMUM_WAIT_OBJECTS]; HANDLE Handles[MAXIMUM_WAIT_OBJECTS];
PVOID ObjectPtrArray[MAXIMUM_WAIT_OBJECTS]; PVOID Objects[MAXIMUM_WAIT_OBJECTS];
ULONG i, j; PVOID WaitObjects[MAXIMUM_WAIT_OBJECTS];
KPROCESSOR_MODE PreviousMode; ULONG i = 0, ReferencedObjects = 0, j;
LARGE_INTEGER SafeTimeOut; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status = STATUS_SUCCESS; LARGE_INTEGER SafeTimeOut;
BOOLEAN LockInUse;
PHANDLE_TABLE_ENTRY HandleEntry;
POBJECT_HEADER ObjectHeader;
PHANDLE_TABLE HandleTable;
ACCESS_MASK GrantedAccess;
LONG ExHandle;
PVOID DefaultObject;
NTSTATUS Status = STATUS_SUCCESS;
DPRINT("NtWaitForMultipleObjects(ObjectCount %lu ObjectsArray[] %x, Alertable %d, " DPRINT("NtWaitForMultipleObjects(ObjectCount %lu HandleArray[] %x, Alertable %d, "
"TimeOut %x)\n", ObjectCount,ObjectsArray,Alertable,TimeOut); "TimeOut %x)\n", ObjectCount, HandleArray, Alertable, TimeOut);
PreviousMode = ExGetPreviousMode(); /* Enter a critical region since we'll play with handles */
LockInUse = TRUE;
KeEnterCriticalRegion();
if (ObjectCount > MAXIMUM_WAIT_OBJECTS) /* Check for valid Object Count */
return STATUS_UNSUCCESSFUL; if ((ObjectCount > MAXIMUM_WAIT_OBJECTS) || !ObjectCount)
if (0 == ObjectCount) {
return STATUS_INVALID_PARAMETER; Status = STATUS_INVALID_PARAMETER_1;
DPRINT1("No object count, or too many objects\n");
goto Quickie;
}
if(PreviousMode != KernelMode) /* Check for valid Wait Type */
{ if ((WaitType != WaitAll) && (WaitType != WaitAny))
_SEH_TRY {
{ Status = STATUS_INVALID_PARAMETER_3;
ProbeForRead(ObjectsArray, DPRINT1("Invalid wait type\n");
ObjectCount * sizeof(ObjectsArray[0]), goto Quickie;
sizeof(ULONG)); }
/* make a copy so we don't have to guard with SEH later and keep track of
what objects we referenced in case dereferencing pointers suddenly fails */
RtlCopyMemory(SafeObjectsArray, ObjectsArray, ObjectCount * sizeof(ObjectsArray[0]));
ObjectsArray = SafeObjectsArray;
if(TimeOut != NULL) /* Capture arguments */
{ _SEH_TRY
ProbeForRead(TimeOut, {
sizeof(LARGE_INTEGER), if(PreviousMode != KernelMode)
sizeof(ULONG)); {
/* make a local copy of the timeout on the stack */ ProbeForRead(HandleArray,
SafeTimeOut = *TimeOut; ObjectCount * sizeof(HANDLE),
TimeOut = &SafeTimeOut; sizeof(HANDLE));
}
} if(TimeOut)
_SEH_HANDLE {
{ ProbeForRead(TimeOut,
Status = _SEH_GetExceptionCode(); sizeof(LARGE_INTEGER),
} sizeof(ULONG));
_SEH_END;
if(!NT_SUCCESS(Status)) /* Make a local copy of the timeout on the stack */
{ SafeTimeOut = *TimeOut;
return Status; TimeOut = &SafeTimeOut;
} }
} }
/* reference all objects */ /*
for (i = 0; i < ObjectCount; i++) * Make a copy so we don't have to guard with SEH later and keep
{ * track of what objects we referenced if dereferencing pointers
Status = ObReferenceObjectByHandle(ObjectsArray[i], * suddenly fails
SYNCHRONIZE, */
NULL, RtlCopyMemory(Handles,
PreviousMode, HandleArray,
&ObjectPtrArray[i], ObjectCount * sizeof(HANDLE));
NULL); }
if (!NT_SUCCESS(Status) || !KiIsObjectWaitable(ObjectPtrArray[i])) _SEH_HANDLE
{ {
if (NT_SUCCESS(Status)) Status = _SEH_GetExceptionCode();
{ }
DPRINT1("Waiting for object type '%wZ' is not supported\n", _SEH_END;
&BODY_TO_HEADER(ObjectPtrArray[i])->Type->Name);
Status = STATUS_INVALID_HANDLE;
i++;
}
/* dereference all referenced objects */
for (j = 0; j < i; j++)
{
ObDereferenceObject(ObjectPtrArray[j]);
}
return(Status); if(!NT_SUCCESS(Status)) goto Quickie;
}
}
Status = KeWaitForMultipleObjects(ObjectCount, /* Check if we can use the internal Wait Array */
ObjectPtrArray, if (ObjectCount > THREAD_WAIT_OBJECTS)
WaitType, {
UserRequest, /* Allocate from Pool */
PreviousMode, WaitBlockArray = ExAllocatePoolWithTag(NonPagedPool,
Alertable, ObjectCount * sizeof(KWAIT_BLOCK),
TimeOut, TAG_WAIT);
WaitBlockArray); }
/* dereference all objects */ /* Start the loop */
for (i = 0; i < ObjectCount; i++) do
{ {
ObDereferenceObject(ObjectPtrArray[i]); /* Use the right Executive Handle */
} if(ObIsKernelHandle(Handles[i], PreviousMode))
{
/* Use the System Handle Table and decode */
HandleTable = ObpKernelHandleTable;
ExHandle = HANDLE_TO_EX_HANDLE(ObKernelHandleToHandle(Handles[i]));
}
else
{
/* Use the Process' Handle table and get the Ex Handle */
HandleTable = PsGetCurrentProcess()->ObjectTable;
ExHandle = HANDLE_TO_EX_HANDLE(Handles[i]);
}
return(Status); /* Get a pointer to it */
if (!(HandleEntry = ExMapHandleToPointer(HandleTable, ExHandle)))
{
DPRINT1("Invalid handle\n");
Status = STATUS_INVALID_HANDLE;
goto Quickie;
}
/* Check for synchronize access */
GrantedAccess = HandleEntry->u2.GrantedAccess;
if ((PreviousMode != KernelMode) && (!(GrantedAccess & SYNCHRONIZE)))
{
/* Unlock the entry and fail */
ExUnlockHandleTableEntry(HandleTable, HandleEntry);
Status = STATUS_ACCESS_DENIED;
DPRINT1("Handle doesn't have SYNCH access\n");
goto Quickie;
}
/* Get the Object Header */
ObjectHeader = EX_HTE_TO_HDR(HandleEntry);
/* Get default Object */
DefaultObject = ObjectHeader->Type->DefaultObject;
/* Check if it's the internal offset */
if ((LONG_PTR)DefaultObject >= 0)
{
/* Increase reference count */
InterlockedIncrement(&ObjectHeader->PointerCount);
ReferencedObjects++;
/* Save the Object and Wait Object, this is a relative offset */
Objects[i] = &ObjectHeader->Body;
WaitObjects[i] = (PVOID)((ULONG_PTR)&ObjectHeader->Body +
(ULONG_PTR)DefaultObject);
}
else
{
/* This is our internal Object */
ReferencedObjects++;
Objects[i] = NULL;
WaitObjects[i] = DefaultObject;
}
/* Unlock the Handle Table Entry */
ExUnlockHandleTableEntry(HandleTable, HandleEntry);
/* Keep looping */
i++;
} while (i < ObjectCount);
/* For a Waitall, we can't have the same object more then once */
if (WaitType == WaitAll)
{
/* Start the loop */
do
{
/* Check the current and forward object */
for (i = 0, j = i + 1; j < ObjectCount; j++)
{
/* Make sure they don't match */
if (WaitObjects[i] == WaitObjects[j])
{
/* Fail */
Status = STATUS_INVALID_PARAMETER_MIX;
DPRINT1("Objects duplicated with WaitAll\n");
goto Quickie;
}
}
/* Keep looping */
i++;
} while (i < ObjectCount);
}
/* Now we can finally wait. Use SEH since it can raise an exception */
_SEH_TRY
{
/* We're done playing with handles */
LockInUse = FALSE;
KeLeaveCriticalRegion();
/* Do the kernel wait */
Status = KeWaitForMultipleObjects(ObjectCount,
WaitObjects,
WaitType,
UserRequest,
PreviousMode,
Alertable,
TimeOut,
WaitBlockArray);
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
Quickie:
/* First derefence */
while (ReferencedObjects)
{
ReferencedObjects--;
if (Objects[ReferencedObjects])
{
ObDereferenceObject(Objects[ReferencedObjects]);
}
}
/* Free wait block array */
if (WaitBlockArray) ExFreePool(WaitBlockArray);
/* Re-enable APCs if needed */
if (LockInUse) KeLeaveCriticalRegion();
/* Return status */
return Status;
} }
/* /*
* @implemented * @implemented
*/ */
NTSTATUS STDCALL NTSTATUS
STDCALL
NtWaitForSingleObject(IN HANDLE ObjectHandle, NtWaitForSingleObject(IN HANDLE ObjectHandle,
IN BOOLEAN Alertable, IN BOOLEAN Alertable,
IN PLARGE_INTEGER TimeOut OPTIONAL) IN PLARGE_INTEGER TimeOut OPTIONAL)
{ {
PVOID ObjectPtr; PVOID Object, WaitableObject;
KPROCESSOR_MODE PreviousMode; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
LARGE_INTEGER SafeTimeOut; LARGE_INTEGER SafeTimeOut;
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
DPRINT("NtWaitForSingleObject(ObjectHandle %x, Alertable %d, TimeOut %x)\n", DPRINT("NtWaitForSingleObject(ObjectHandle %x, Alertable %d, TimeOut %x)\n",
ObjectHandle,Alertable,TimeOut); ObjectHandle,Alertable,TimeOut);
PreviousMode = ExGetPreviousMode(); /* Capture timeout */
if(TimeOut && PreviousMode != KernelMode)
{
_SEH_TRY
{
ProbeForRead(TimeOut,
sizeof(LARGE_INTEGER),
sizeof(ULONG));
/* Make a copy on the stack */
SafeTimeOut = *TimeOut;
TimeOut = &SafeTimeOut;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if(TimeOut != NULL && PreviousMode != KernelMode) if(!NT_SUCCESS(Status)) return Status;
{ }
_SEH_TRY
{
ProbeForRead(TimeOut,
sizeof(LARGE_INTEGER),
sizeof(ULONG));
/* make a copy on the stack */
SafeTimeOut = *TimeOut;
TimeOut = &SafeTimeOut;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if(!NT_SUCCESS(Status)) /* Get the Object */
{ Status = ObReferenceObjectByHandle(ObjectHandle,
return Status; SYNCHRONIZE,
} NULL,
} PreviousMode,
&Object,
NULL);
if (NT_SUCCESS(Status))
{
/* Get the Waitable Object */
WaitableObject = BODY_TO_HEADER(Object)->Type->DefaultObject;
Status = ObReferenceObjectByHandle(ObjectHandle, /* Is it an offset for internal objects? */
SYNCHRONIZE, if ((LONG_PTR)WaitableObject >= 0)
NULL, {
PreviousMode, /* Turn it into a pointer */
&ObjectPtr, WaitableObject = (PVOID)((ULONG_PTR)Object +
NULL); (ULONG_PTR)WaitableObject);
if (!NT_SUCCESS(Status)) }
{
return(Status);
}
if (!KiIsObjectWaitable(ObjectPtr))
{
DPRINT1("Waiting for object type '%wZ' is not supported\n",
&BODY_TO_HEADER(ObjectPtr)->Type->Name);
Status = STATUS_INVALID_HANDLE;
}
else
{
Status = KeWaitForSingleObject(ObjectPtr,
UserRequest,
PreviousMode,
Alertable,
TimeOut);
}
ObDereferenceObject(ObjectPtr); /* Now wait. Also SEH this since it can also raise an exception */
_SEH_TRY
{
Status = KeWaitForSingleObject(WaitableObject,
UserRequest,
PreviousMode,
Alertable,
TimeOut);
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
return(Status); /* Dereference the Object */
ObDereferenceObject(Object);
}
/* Return the status */
return Status;
} }
NTSTATUS NTSTATUS
STDCALL STDCALL
NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal, NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal,
@ -204,15 +338,17 @@ NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal,
IN PLARGE_INTEGER TimeOut OPTIONAL) IN PLARGE_INTEGER TimeOut OPTIONAL)
{ {
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PDISPATCHER_HEADER Header; POBJECT_TYPE Type;
PVOID SignalObj; PVOID SignalObj;
PVOID WaitObj; PVOID WaitObj;
PVOID WaitableObject;
LARGE_INTEGER SafeTimeOut; LARGE_INTEGER SafeTimeOut;
OBJECT_HANDLE_INFORMATION HandleInfo; OBJECT_HANDLE_INFORMATION HandleInfo;
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
/* Capture timeout */ /* Capture timeout */
if(!TimeOut && PreviousMode != KernelMode) DPRINT("NtSignalAndWaitForSingleObject\n");
if(TimeOut && PreviousMode != KernelMode)
{ {
_SEH_TRY _SEH_TRY
{ {
@ -257,58 +393,65 @@ NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal,
return Status; return Status;
} }
/* FIXME: Use DefaultObject from ObjectHeader */ /* Get the real waitable object */
Header = (PDISPATCHER_HEADER)SignalObj; WaitableObject = BODY_TO_HEADER(WaitObj)->Type->DefaultObject;
/* Check dispatcher type */ /* Handle internal offset */
/* FIXME: Check Object Type instead! */ if ((LONG_PTR)WaitableObject >= 0)
switch (Header->Type)
{ {
case EventNotificationObject: /* Get real pointer */
case EventSynchronizationObject: WaitableObject = (PVOID)((ULONG_PTR)WaitObj +
/* Set the Event */ (ULONG_PTR)WaitableObject);
/* FIXME: Check permissions */ }
KeSetEvent(SignalObj, EVENT_INCREMENT, TRUE);
break; /* Check Signal Object Type */
Type = BODY_TO_HEADER(WaitObj)->Type;
case MutantObject: if (Type == ExEventObjectType)
/* Release the Mutant. This can raise an exception*/ {
_SEH_TRY /* Set the Event */
{ /* FIXME: Check permissions */
KeReleaseMutant(SignalObj, MUTANT_INCREMENT, FALSE, TRUE); KeSetEvent(SignalObj, EVENT_INCREMENT, TRUE);
} }
_SEH_HANDLE else if (Type == ExMutantObjectType)
{ {
Status = _SEH_GetExceptionCode(); /* Release the Mutant. This can raise an exception*/
goto Quickie; _SEH_TRY
} {
_SEH_END; KeReleaseMutant(SignalObj, MUTANT_INCREMENT, FALSE, TRUE);
break; }
_SEH_HANDLE
case SemaphoreObject: {
/* Release the Semaphore. This can raise an exception*/ Status = _SEH_GetExceptionCode();
/* FIXME: Check permissions */
_SEH_TRY
{
KeReleaseSemaphore(SignalObj, SEMAPHORE_INCREMENT, 1, TRUE);
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
goto Quickie;
}
_SEH_END;
break;
default:
Status = STATUS_OBJECT_TYPE_MISMATCH;
goto Quickie; goto Quickie;
}
_SEH_END;
}
else if (Type == ExSemaphoreObjectType)
{
/* Release the Semaphore. This can raise an exception*/
/* FIXME: Check permissions */
_SEH_TRY
{
KeReleaseSemaphore(SignalObj, SEMAPHORE_INCREMENT, 1, TRUE);
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
goto Quickie;
}
_SEH_END;
}
else
{
Status = STATUS_OBJECT_TYPE_MISMATCH;
DPRINT1("Waiting on invalid object type\n");
goto Quickie;
} }
/* Now wait. Also SEH this since it can also raise an exception */ /* Now wait. Also SEH this since it can also raise an exception */
_SEH_TRY _SEH_TRY
{ {
Status = KeWaitForSingleObject(WaitObj, Status = KeWaitForSingleObject(WaitableObject,
UserRequest, UserRequest,
PreviousMode, PreviousMode,
Alertable, Alertable,

View file

@ -97,7 +97,6 @@ PsInitThreadManagment(VOID)
ObjectTypeInitializer.GenericMapping = PiThreadMapping; ObjectTypeInitializer.GenericMapping = PiThreadMapping;
ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.ValidAccessMask = THREAD_ALL_ACCESS; ObjectTypeInitializer.ValidAccessMask = THREAD_ALL_ACCESS;
ObjectTypeInitializer.UseDefaultObject = TRUE;
ObjectTypeInitializer.DeleteProcedure = PspDeleteThread; ObjectTypeInitializer.DeleteProcedure = PspDeleteThread;
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &PsThreadType); ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &PsThreadType);
@ -138,7 +137,6 @@ PsInitProcessManagment(VOID)
ObjectTypeInitializer.GenericMapping = PiProcessMapping; ObjectTypeInitializer.GenericMapping = PiProcessMapping;
ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.ValidAccessMask = PROCESS_ALL_ACCESS; ObjectTypeInitializer.ValidAccessMask = PROCESS_ALL_ACCESS;
ObjectTypeInitializer.UseDefaultObject = TRUE;
ObjectTypeInitializer.DeleteProcedure = PspDeleteProcess; ObjectTypeInitializer.DeleteProcedure = PspDeleteProcess;
ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &PsProcessType); ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &PsProcessType);