From: Jacek Caban Subject: [PATCH 6/8] ntoskrnl.exe: Support creating event objects from server handle. Message-Id: <79860aed-7a47-bc20-f5e6-19439a92fbc9@codeweavers.com> Date: Fri, 15 Mar 2019 15:59:05 +0100 Signed-off-by: Jacek Caban --- dlls/ntoskrnl.exe/ntoskrnl_private.h | 2 + dlls/ntoskrnl.exe/sync.c | 63 ++++++++++++++++++++++------ dlls/ntoskrnl.exe/tests/driver.c | 41 ++++++++++++++++-- server/event.c | 11 ++++- 4 files changed, 101 insertions(+), 16 deletions(-) diff --git a/dlls/ntoskrnl.exe/ntoskrnl_private.h b/dlls/ntoskrnl.exe/ntoskrnl_private.h index 58ecf0cf11..055991c2da 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl_private.h +++ b/dlls/ntoskrnl.exe/ntoskrnl_private.h @@ -27,6 +27,8 @@ struct _OBJECT_TYPE { void (*release)(void*); /* called when the last reference is released */ }; +void *alloc_kernel_object( POBJECT_TYPE type, HANDLE handle, SIZE_T size, LONG ref ); + extern POBJECT_TYPE ExEventObjectType; extern POBJECT_TYPE ExSemaphoreObjectType; extern POBJECT_TYPE IoDeviceObjectType; diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c index 926df056b6..7cb31852da 100644 --- a/dlls/ntoskrnl.exe/sync.c +++ b/dlls/ntoskrnl.exe/sync.c @@ -76,6 +76,13 @@ NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG count, void *pobjs[], EnterCriticalSection( &sync_cs ); for (i = 0; i < count; i++) { + if (objs[i]->WaitListHead.Blink == INVALID_HANDLE_VALUE) + { + FIXME("unsupported on kernel objects\n"); + handles[i] = INVALID_HANDLE_VALUE; + continue; + } + ++*((ULONG_PTR *)&objs[i]->WaitListHead.Flink); if (!objs[i]->WaitListHead.Blink) { @@ -127,6 +134,8 @@ NTSTATUS WINAPI KeWaitForMultipleObjects(ULONG count, void *pobjs[], } } + if (objs[i]->WaitListHead.Blink == INVALID_HANDLE_VALUE) continue; + if (!--*((ULONG_PTR *)&objs[i]->WaitListHead.Flink)) { switch (objs[i]->Type) @@ -186,10 +195,24 @@ void WINAPI KeInitializeEvent( PRKEVENT event, EVENT_TYPE type, BOOLEAN state ) event->Header.WaitListHead.Flink = NULL; } +static void *create_event_object( HANDLE handle ) +{ + EVENT_BASIC_INFORMATION info; + KEVENT *event; + + if (!(event = alloc_kernel_object( ExEventObjectType, handle, sizeof(*event), 0 ))) return NULL; + + if (!NtQueryEvent( handle, EventBasicInformation, &info, sizeof(info), NULL )) + KeInitializeEvent( event, info.EventType, info.EventState ); + event->Header.WaitListHead.Blink = INVALID_HANDLE_VALUE; /* mark as kernel object */ + return event; +} + static const WCHAR event_type_name[] = {'E','v','e','n','t',0}; static struct _OBJECT_TYPE event_type = { event_type_name, + create_event_object }; POBJECT_TYPE ExEventObjectType = &event_type; @@ -200,15 +223,23 @@ POBJECT_TYPE ExEventObjectType = &event_type; LONG WINAPI KeSetEvent( PRKEVENT event, KPRIORITY increment, BOOLEAN wait ) { HANDLE handle; - LONG ret; + ULONG ret = 0; TRACE("event %p, increment %d, wait %u.\n", event, increment, wait); - EnterCriticalSection( &sync_cs ); - ret = InterlockedExchange( &event->Header.SignalState, TRUE ); - if ((handle = event->Header.WaitListHead.Blink)) - SetEvent( handle ); - LeaveCriticalSection( &sync_cs ); + if (event->Header.WaitListHead.Blink != INVALID_HANDLE_VALUE) + { + EnterCriticalSection( &sync_cs ); + ret = InterlockedExchange( &event->Header.SignalState, TRUE ); + if ((handle = event->Header.WaitListHead.Blink)) + SetEvent( handle ); + LeaveCriticalSection( &sync_cs ); + } + else + { + FIXME("unsupported on kernel objects\n"); + event->Header.SignalState = TRUE; + } return ret; } @@ -219,15 +250,23 @@ LONG WINAPI KeSetEvent( PRKEVENT event, KPRIORITY increment, BOOLEAN wait ) LONG WINAPI KeResetEvent( PRKEVENT event ) { HANDLE handle; - LONG ret; + ULONG ret = 0; TRACE("event %p.\n", event); - EnterCriticalSection( &sync_cs ); - ret = InterlockedExchange( &event->Header.SignalState, FALSE ); - if ((handle = event->Header.WaitListHead.Blink)) - ResetEvent( handle ); - LeaveCriticalSection( &sync_cs ); + if (event->Header.WaitListHead.Blink != INVALID_HANDLE_VALUE) + { + EnterCriticalSection( &sync_cs ); + ret = InterlockedExchange( &event->Header.SignalState, FALSE ); + if ((handle = event->Header.WaitListHead.Blink)) + ResetEvent( handle ); + LeaveCriticalSection( &sync_cs ); + } + else + { + FIXME("unsupported on kernel objects\n"); + event->Header.SignalState = FALSE; + } return ret; } diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c index 7f2e68c3de..054020824e 100644 --- a/dlls/ntoskrnl.exe/tests/driver.c +++ b/dlls/ntoskrnl.exe/tests/driver.c @@ -308,6 +308,14 @@ static NTSTATUS wait_multiple(ULONG count, void *objs[], WAIT_TYPE wait_type, UL return KeWaitForMultipleObjects(count, objs, wait_type, Executive, KernelMode, FALSE, &integer, NULL); } +static NTSTATUS wait_single_handle(HANDLE handle, ULONGLONG timeout) +{ + LARGE_INTEGER integer; + + integer.QuadPart = timeout; + return ZwWaitForSingleObject(handle, FALSE, &integer); +} + static void run_thread(PKSTART_ROUTINE proc, void *arg) { OBJECT_ATTRIBUTES attr = {0}; @@ -341,11 +349,13 @@ static void WINAPI mutex_thread(void *arg) static void test_sync(void) { KSEMAPHORE semaphore, semaphore2; - KEVENT manual_event, auto_event; + KEVENT manual_event, auto_event, *event; KTIMER timer; LARGE_INTEGER timeout; + OBJECT_ATTRIBUTES attr; void *objs[2]; NTSTATUS ret; + HANDLE handle; int i; KeInitializeEvent(&manual_event, NotificationEvent, FALSE); @@ -440,6 +450,33 @@ static void test_sync(void) ret = wait_multiple(2, objs, WaitAny, 0); ok(ret == 1, "got %#x\n", ret); + InitializeObjectAttributes(&attr, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + ret = ZwCreateEvent(&handle, SYNCHRONIZE, &attr, NotificationEvent, TRUE); + ok(!ret, "ZwCreateEvent failed: %#x\n", ret); + + ret = ObReferenceObjectByHandle(handle, SYNCHRONIZE, *pExEventObjectType, KernelMode, (void **)&event, NULL); + ok(!ret, "ObReferenceObjectByHandle failed: %#x\n", ret); + + ret = wait_single(event, 0); + todo_wine + ok(ret == 0, "got %#x\n", ret); + KeResetEvent(event); + ret = wait_single(event, 0); + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + ret = wait_single_handle(handle, 0); + todo_wine + ok(ret == STATUS_TIMEOUT, "got %#x\n", ret); + + KeSetEvent(event, 0, FALSE); + ret = wait_single(event, 0); + todo_wine + ok(ret == 0, "got %#x\n", ret); + ret = wait_single_handle(handle, 0); + ok(!ret, "got %#x\n", ret); + + ZwClose(handle); + ObDereferenceObject(event); + /* test semaphores */ KeInitializeSemaphore(&semaphore, 0, 5); @@ -719,14 +756,12 @@ static void test_ob_reference(const WCHAR *test_path) status = ObReferenceObjectByHandle(event_handle, SYNCHRONIZE, *pExEventObjectType, KernelMode, &obj2, NULL); ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status); - todo_wine ok(obj1 == obj2, "obj1 != obj2\n"); ObDereferenceObject(obj2); status = ObReferenceObjectByHandle(event_handle, SYNCHRONIZE, NULL, KernelMode, &obj2, NULL); ok(!status, "ObReferenceObjectByHandle failed: %#x\n", status); - todo_wine ok(obj1 == obj2, "obj1 != obj2\n"); ObDereferenceObject(obj2); diff --git a/server/event.c b/server/event.c index dfe08847f2..6286b4d1eb 100644 --- a/server/event.c +++ b/server/event.c @@ -39,6 +39,7 @@ struct event { struct object obj; /* object header */ + struct list kernel_object; /* list of kernel object pointers */ int manual_reset; /* is it a manual reset event? */ int signaled; /* event has been signaled */ }; @@ -49,6 +50,7 @@ static int event_signaled( struct object *obj, struct wait_queue_entry *entry ); static void event_satisfied( struct object *obj, struct wait_queue_entry *entry ); static unsigned int event_map_access( struct object *obj, unsigned int access ); static int event_signal( struct object *obj, unsigned int access); +static struct list *event_kernel_object( struct object *obj ); static const struct object_ops event_ops = { @@ -68,7 +70,7 @@ static const struct object_ops event_ops = directory_link_name, /* link_name */ default_unlink_name, /* unlink_name */ no_open_file, /* open_file */ - no_kernel_object, /* get_kernel_object */ + event_kernel_object, /* get_kernel_object */ no_close_handle, /* close_handle */ no_destroy /* destroy */ }; @@ -119,6 +121,7 @@ struct event *create_event( struct object *root, const struct unicode_str *name, if (get_error() != STATUS_OBJECT_NAME_EXISTS) { /* initialize it if it didn't already exist */ + list_init( &event->kernel_object ); event->manual_reset = manual_reset; event->signaled = initial_state; } @@ -204,6 +207,12 @@ static int event_signal( struct object *obj, unsigned int access ) return 1; } +static struct list *event_kernel_object( struct object *obj ) +{ + struct event *event = (struct event *)obj; + return &event->kernel_object; +} + struct keyed_event *create_keyed_event( struct object *root, const struct unicode_str *name, unsigned int attr, const struct security_descriptor *sd ) {