From 4d40a736740ec865c3beee3cfa321477a1faca49 Mon Sep 17 00:00:00 2001
From: Zebediah Figura <z.figura12@gmail.com>
Date: Sun, 10 Jun 2018 16:11:54 -0500
Subject: [PATCH 32/83] server, ntdll: Also store the esync type in the server.

And validate it there while we're at it.

We need to do this because CreateEvent() ignores the passed-in parameter
when opening an existing event.
---
 dlls/ntdll/esync.c  | 23 +++++++++++++++--------
 server/esync.c      | 28 ++++++++++++++++++++++++----
 server/protocol.def |  2 ++
 3 files changed, 41 insertions(+), 12 deletions(-)

diff --git a/dlls/ntdll/esync.c b/dlls/ntdll/esync.c
index 130357ce6..2b4555959 100644
--- a/dlls/ntdll/esync.c
+++ b/dlls/ntdll/esync.c
@@ -235,8 +235,10 @@ NTSTATUS esync_close( HANDLE handle )
     return STATUS_INVALID_HANDLE;
 }
 
-static NTSTATUS create_esync(int *fd, HANDLE *handle, ACCESS_MASK access,
-    const OBJECT_ATTRIBUTES *attr, int initval, int flags)
+/* type is an in-out parameter; if the object already existed it returns the
+ * actual type. */
+static NTSTATUS create_esync(enum esync_type *type, int *fd, HANDLE *handle,
+    ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, int initval, int flags)
 {
     NTSTATUS ret;
     data_size_t len;
@@ -254,11 +256,13 @@ static NTSTATUS create_esync(int *fd, HANDLE *handle, ACCESS_MASK access,
         req->access  = access;
         req->initval = initval;
         req->flags   = flags;
+        req->type    = *type;
         wine_server_add_data( req, objattr, len );
         ret = wine_server_call( req );
         if (!ret || ret == STATUS_OBJECT_NAME_EXISTS)
         {
             *handle = wine_server_ptr_handle( reply->handle );
+            *type = reply->type;
             *fd = receive_fd( &fd_handle );
             assert( wine_server_ptr_handle(fd_handle) == *handle );
         }
@@ -275,6 +279,7 @@ static NTSTATUS create_esync(int *fd, HANDLE *handle, ACCESS_MASK access,
 NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
     const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max)
 {
+    enum esync_type type = ESYNC_SEMAPHORE;
     struct semaphore *semaphore;
     NTSTATUS ret;
     int fd = -1;
@@ -282,7 +287,7 @@ NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
     TRACE("name %s, initial %d, max %d.\n",
         attr ? debugstr_us(attr->ObjectName) : "<no name>", initial, max);
 
-    ret = create_esync( &fd, handle, access, attr, initial, EFD_SEMAPHORE );
+    ret = create_esync( &type, &fd, handle, access, attr, initial, EFD_SEMAPHORE );
     if (!ret || ret == STATUS_OBJECT_NAME_EXISTS)
     {
         semaphore = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*semaphore) );
@@ -321,24 +326,25 @@ NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev )
 }
 
 NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access,
-    const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial )
+    const OBJECT_ATTRIBUTES *attr, EVENT_TYPE event_type, BOOLEAN initial )
 {
+    enum esync_type type = (event_type == SynchronizationEvent ? ESYNC_AUTO_EVENT : ESYNC_MANUAL_EVENT);
     struct event *event;
     NTSTATUS ret;
     int fd;
 
     TRACE("name %s, %s-reset, initial %d.\n",
         attr ? debugstr_us(attr->ObjectName) : "<no name>",
-        type == NotificationEvent ? "manual" : "auto", initial);
+        event_type == NotificationEvent ? "manual" : "auto", initial);
 
-    ret = create_esync( &fd, handle, access, attr, initial, 0 );
+    ret = create_esync( &type, &fd, handle, access, attr, initial, 0 );
     if (!ret || ret == STATUS_OBJECT_NAME_EXISTS)
     {
         event = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*event) );
         if (!event)
             return STATUS_NO_MEMORY;
 
-        event->obj.type = (type == NotificationEvent ? ESYNC_MANUAL_EVENT : ESYNC_AUTO_EVENT);
+        event->obj.type = type; /* note that the server might give us the real type */
         event->obj.fd = fd;
 
         add_to_list( *handle, &event->obj);
@@ -417,6 +423,7 @@ NTSTATUS esync_pulse_event( HANDLE handle, LONG *prev )
 NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access,
     const OBJECT_ATTRIBUTES *attr, BOOLEAN initial )
 {
+    enum esync_type type = ESYNC_MUTEX;
     struct mutex *mutex;
     NTSTATUS ret;
     int fd;
@@ -424,7 +431,7 @@ NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access,
     TRACE("name %s, initial %d.\n",
         attr ? debugstr_us(attr->ObjectName) : "<no name>", initial);
 
-    ret = create_esync( &fd, handle, access, attr, initial ? 0 : 1, 0 );
+    ret = create_esync( &type, &fd, handle, access, attr, initial ? 0 : 1, 0 );
     if (!ret || ret == STATUS_OBJECT_NAME_EXISTS)
     {
         mutex = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*mutex) );
diff --git a/server/esync.c b/server/esync.c
index 1f8c0d516..9ff1a847b 100644
--- a/server/esync.c
+++ b/server/esync.c
@@ -56,6 +56,7 @@ struct esync
 {
     struct object   obj;    /* object header */
     int             fd;     /* eventfd file descriptor */
+    enum esync_type type;
 };
 
 static void esync_dump( struct object *obj, int verbose );
@@ -98,9 +99,16 @@ static void esync_destroy( struct object *obj )
     close( esync->fd );
 }
 
-struct esync *create_esync( struct object *root, const struct unicode_str *name,
-                            unsigned int attr, int initval, int flags,
-                            const struct security_descriptor *sd )
+static int type_matches( enum esync_type type1, enum esync_type type2 )
+{
+    return (type1 == type2) ||
+           ((type1 == ESYNC_AUTO_EVENT || type1 == ESYNC_MANUAL_EVENT) &&
+            (type2 == ESYNC_AUTO_EVENT || type2 == ESYNC_MANUAL_EVENT));
+}
+
+static struct esync *create_esync( struct object *root, const struct unicode_str *name,
+    unsigned int attr, int initval, int flags, enum esync_type type,
+    const struct security_descriptor *sd )
 {
 #ifdef HAVE_SYS_EVENTFD_H
     struct esync *esync;
@@ -118,6 +126,17 @@ struct esync *create_esync( struct object *root, const struct unicode_str *name,
                 release_object( esync );
                 return NULL;
             }
+            esync->type = type;
+        }
+        else
+        {
+            /* validate the type */
+            if (!type_matches( type, esync->type ))
+            {
+                release_object( &esync->obj );
+                set_error( STATUS_OBJECT_TYPE_MISMATCH );
+                return NULL;
+            }
         }
     }
     return esync;
@@ -200,7 +219,7 @@ DECL_HANDLER(create_esync)
 
     if (!objattr) return;
 
-    if ((esync = create_esync( root, &name, objattr->attributes, req->initval, req->flags, sd )))
+    if ((esync = create_esync( root, &name, objattr->attributes, req->initval, req->flags, req->type, sd )))
     {
         if (get_error() == STATUS_OBJECT_NAME_EXISTS)
             reply->handle = alloc_handle( current->process, esync, req->access, objattr->attributes );
@@ -208,6 +227,7 @@ DECL_HANDLER(create_esync)
             reply->handle = alloc_handle_no_access_check( current->process, esync,
                                                           req->access, objattr->attributes );
 
+        reply->type = esync->type;
         send_client_fd( current->process, esync->fd, reply->handle );
         release_object( esync );
     }
diff --git a/server/protocol.def b/server/protocol.def
index 721ffb96d..50735ee78 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -4047,9 +4047,11 @@ struct handle_info
     unsigned int access;        /* wanted access rights */
     int          initval;       /* initial value */
     int          flags;         /* flags (EFD_SEMAPHORE or 0) */
+    int          type;          /* type of esync object (see below) */
     VARARG(objattr,object_attributes); /* object attributes */
 @REPLY
     obj_handle_t handle;        /* handle to the object */
+    int          type;          /* type of esync object (see below) */
 @END
 
 /* Retrieve the esync fd for an object. */
-- 
2.20.1

