From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/ntdll/unix/sync.c | 42 +++++++++++++++++++++++++++++++++++++++--- server/inproc_sync.c | 1 + server/protocol.def | 3 ++- server/thread.c | 2 +- server/thread.h | 1 + 5 files changed, 44 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index acdb7b3d9f8..2894e75d6f2 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -309,9 +309,10 @@ static unsigned int validate_open_object_attributes( const OBJECT_ATTRIBUTES *at
struct inproc_sync { - int fd; - unsigned int access; - unsigned int type : 2; + int fd; /* unix file descriptor */ + unsigned int access; /* handle access rights */ + unsigned short type; /* enum inproc_sync_type as short to save space */ + unsigned short internal; /* sync is internal and cannot be signaled */ };
static void release_inproc_sync( struct inproc_sync *sync ) @@ -339,6 +340,7 @@ static NTSTATUS get_inproc_sync( HANDLE handle, ACCESS_MASK desired_access, stru assert( wine_server_ptr_handle(fd_handle) == handle ); sync->access = reply->access; sync->type = reply->type; + sync->internal = reply->internal; } } SERVER_END_REQ; @@ -355,6 +357,21 @@ static NTSTATUS get_inproc_sync( HANDLE handle, ACCESS_MASK desired_access, stru return STATUS_SUCCESS; }
+extern unsigned int check_signal_access( struct inproc_sync *sync ) +{ + if (sync->internal) return STATUS_OBJECT_TYPE_MISMATCH; + + switch (sync->type) + { + case INPROC_SYNC_EVENT: + if (!(sync->access & EVENT_MODIFY_STATE)) return STATUS_ACCESS_DENIED; + return STATUS_SUCCESS; + } + + assert( 0 ); + return STATUS_OBJECT_TYPE_MISMATCH; +} + static NTSTATUS inproc_release_semaphore( HANDLE handle, ULONG count, ULONG *prev_count ) { if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; @@ -429,7 +446,26 @@ static NTSTATUS inproc_wait( DWORD count, const HANDLE *handles, BOOLEAN wait_an static NTSTATUS inproc_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { + struct inproc_sync stack_signal, stack_wait, *signal_sync = &stack_signal, *wait_sync = &stack_wait; + NTSTATUS ret; + if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; + + if ((ret = get_inproc_sync( signal, 0, signal_sync ))) return ret; + if ((ret = check_signal_access( signal_sync ))) + { + release_inproc_sync( signal_sync ); + return ret; + } + + if ((ret = get_inproc_sync( wait, SYNCHRONIZE, wait_sync ))) + { + release_inproc_sync( signal_sync ); + return ret; + } + + release_inproc_sync( signal_sync ); + release_inproc_sync( wait_sync ); return STATUS_NOT_IMPLEMENTED; }
diff --git a/server/inproc_sync.c b/server/inproc_sync.c index 4615a5b3335..5c7dc1ae770 100644 --- a/server/inproc_sync.c +++ b/server/inproc_sync.c @@ -182,6 +182,7 @@ DECL_HANDLER(get_inproc_sync_fd) if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL ))) return;
reply->access = get_handle_access( current->process, req->handle ); + reply->internal = check_signal_access( obj, reply->access ) == STATUS_OBJECT_TYPE_MISMATCH;
if ((fd = get_inproc_sync_fd( obj, &reply->type )) < 0) set_error( STATUS_NOT_IMPLEMENTED ); else send_client_fd( current->process, fd, req->handle ); diff --git a/server/protocol.def b/server/protocol.def index 59c6436fa88..f6f0324054d 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -4135,5 +4135,6 @@ enum inproc_sync_type obj_handle_t handle; /* handle to the object */ @REPLY int type; /* inproc sync type */ - unsigned int access; /* handle access rights */ + int internal; /* sync is an internal event sync */ + unsigned int access; /* handle access rights */ @END diff --git a/server/thread.c b/server/thread.c index b6d6d2230d1..a725800fb42 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1258,7 +1258,7 @@ static void thread_timeout( void *ptr ) }
/* check if an event flag, a semaphore or a mutex can be signaled */ -static unsigned int check_signal_access( struct object *obj, unsigned int access ) +unsigned int check_signal_access( struct object *obj, unsigned int access ) { if (!obj->ops->type->signal_access) return STATUS_OBJECT_TYPE_MISMATCH; if (!(access & obj->ops->type->signal_access)) return STATUS_ACCESS_DENIED; diff --git a/server/thread.h b/server/thread.h index b33a00d9f26..9b6e0c2a03b 100644 --- a/server/thread.h +++ b/server/thread.h @@ -117,6 +117,7 @@ extern void set_wait_status( struct wait_queue_entry *entry, int status ); extern void stop_thread( struct thread *thread ); extern int wake_thread( struct thread *thread ); extern int wake_thread_queue_entry( struct wait_queue_entry *entry ); +extern unsigned int check_signal_access( struct object *obj, unsigned int access ); extern int add_queue( struct object *obj, struct wait_queue_entry *entry ); extern void remove_queue( struct object *obj, struct wait_queue_entry *entry ); extern void kill_thread( struct thread *thread, int violent_death );