[PATCH] server: Implement inherited handles list.

Nikolay Sivov nsivov at codeweavers.com
Tue Aug 25 11:28:41 CDT 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/ntdll/unix/process.c      | 24 ++++++++++++++++++--
 include/wine/server_protocol.h |  4 +++-
 server/handle.c                | 41 +++++++++++++++++++++++++---------
 server/handle.h                |  3 ++-
 server/process.c               | 35 ++++++++++++++++++++++++-----
 server/process.h               |  2 +-
 server/protocol.def            |  2 ++
 server/request.c               |  2 +-
 8 files changed, 92 insertions(+), 21 deletions(-)

diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c
index 37d0af19817..19fb8119577 100644
--- a/dlls/ntdll/unix/process.c
+++ b/dlls/ntdll/unix/process.c
@@ -215,9 +215,11 @@ static inline DWORD append_string( void **ptr, const RTL_USER_PROCESS_PARAMETERS
 /***********************************************************************
  *           create_startup_info
  */
-static startup_info_t *create_startup_info( const RTL_USER_PROCESS_PARAMETERS *params, DWORD *info_size )
+static startup_info_t *create_startup_info( const RTL_USER_PROCESS_PARAMETERS *params,
+        const PS_ATTRIBUTE *handle_list, DWORD *info_size )
 {
     startup_info_t *info;
+    unsigned int i;
     DWORD size;
     void *ptr;
 
@@ -230,6 +232,8 @@ static startup_info_t *create_startup_info( const RTL_USER_PROCESS_PARAMETERS *p
     size += params->Desktop.Length;
     size += params->ShellInfo.Length;
     size += params->RuntimeInfo.Length;
+    if (handle_list)
+        size += sizeof(obj_handle_t) * handle_list->Size / sizeof(HANDLE);
     size = (size + 1) & ~1;
     *info_size = size;
 
@@ -260,6 +264,17 @@ static startup_info_t *create_startup_info( const RTL_USER_PROCESS_PARAMETERS *p
     info->desktop_len = append_string( &ptr, params, &params->Desktop );
     info->shellinfo_len = append_string( &ptr, params, &params->ShellInfo );
     info->runtime_len = append_string( &ptr, params, &params->RuntimeInfo );
+
+    if (handle_list)
+    {
+        obj_handle_t *dst = ptr;
+        HANDLE *src = handle_list->ValuePtr;
+
+        info->handle_count = handle_list->Size / sizeof(HANDLE);
+
+        for (i = 0; i < info->handle_count; ++i)
+            dst[i] = wine_server_obj_handle( src[i] );
+    }
     return info;
 }
 
@@ -799,6 +814,7 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
     HANDLE parent = 0, debug = 0, token = 0;
     UNICODE_STRING path = {0};
     SIZE_T i, attr_count = (attr->TotalLength - sizeof(attr->TotalLength)) / sizeof(PS_ATTRIBUTE);
+    const PS_ATTRIBUTE *handle_list = NULL;
 
     for (i = 0; i < attr_count; i++)
     {
@@ -817,6 +833,10 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
         case PS_ATTRIBUTE_TOKEN:
             token = attr->Attributes[i].ValuePtr;
             break;
+        case PS_ATTRIBUTE_HANDLE_LIST:
+            if (process_flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES)
+                handle_list = &attr->Attributes[i];
+            break;
         default:
             if (attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT)
                 FIXME( "unhandled input attribute %lx\n", attr->Attributes[i].Attribute );
@@ -840,7 +860,7 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
         }
         goto done;
     }
-    if (!(startup_info = create_startup_info( params, &startup_info_size ))) goto done;
+    if (!(startup_info = create_startup_info( params, handle_list, &startup_info_size ))) goto done;
     env_size = get_env_size( params, &winedebug );
 
     if ((status = alloc_object_attributes( process_attr, &objattr, &attr_len ))) goto done;
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index af3353eae33..644e1f976cf 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -227,6 +227,8 @@ typedef struct
     data_size_t  desktop_len;
     data_size_t  shellinfo_len;
     data_size_t  runtime_len;
+    unsigned int handle_count;
+
 
 
 
@@ -6333,7 +6335,7 @@ union generic_reply
 
 /* ### protocol_version begin ### */
 
-#define SERVER_PROTOCOL_VERSION 638
+#define SERVER_PROTOCOL_VERSION 639
 
 /* ### protocol_version end ### */
 
diff --git a/server/handle.c b/server/handle.c
index 9ae99cd0c63..51e2bffc514 100644
--- a/server/handle.c
+++ b/server/handle.c
@@ -353,9 +353,10 @@ static void shrink_handle_table( struct handle_table *table )
     table->entries = new_entries;
 }
 
-/* copy the handle table of the parent process */
+/* copy the whole handle table of the parent process, or a subset if specified */
 /* return 1 if OK, 0 on error */
-struct handle_table *copy_handle_table( struct process *process, struct process *parent )
+struct handle_table *copy_handle_table( struct process *process, struct process *parent,
+        const obj_handle_t *handles, unsigned int count )
 {
     struct handle_table *parent_table = parent->handles;
     struct handle_table *table;
@@ -364,20 +365,40 @@ struct handle_table *copy_handle_table( struct process *process, struct process
     assert( parent_table );
     assert( parent_table->obj.ops == &handle_table_ops );
 
-    if (!(table = alloc_handle_table( process, parent_table->count )))
+    if (!(table = alloc_handle_table( process, count ? count : parent_table->count )))
         return NULL;
 
-    if ((table->last = parent_table->last) >= 0)
+    if (handles)
     {
-        struct handle_entry *ptr = table->entries;
-        memcpy( ptr, parent_table->entries, (table->last + 1) * sizeof(struct handle_entry) );
-        for (i = 0; i <= table->last; i++, ptr++)
+        struct handle_entry *dst, *src;
+        int j;
+
+        dst = table->entries;
+        memset( dst, 0, count * sizeof(*dst) );
+
+        for (i = 0, j = 0; i < count; i++)
+        {
+            src = get_handle( parent, handles[i] );
+            if (!src || !(src->access & RESERVED_INHERIT)) continue;
+            grab_object_for_handle( src->ptr );
+            dst[j++] = *src;
+        }
+    }
+    else
+    {
+        if ((table->last = parent_table->last) >= 0)
         {
-            if (!ptr->ptr) continue;
-            if (ptr->access & RESERVED_INHERIT) grab_object_for_handle( ptr->ptr );
-            else ptr->ptr = NULL; /* don't inherit this entry */
+            struct handle_entry *ptr = table->entries;
+            memcpy( ptr, parent_table->entries, (table->last + 1) * sizeof(struct handle_entry) );
+            for (i = 0; i <= table->last; i++, ptr++)
+            {
+                if (!ptr->ptr) continue;
+                if (ptr->access & RESERVED_INHERIT) grab_object_for_handle( ptr->ptr );
+                else ptr->ptr = NULL; /* don't inherit this entry */
+            }
         }
     }
+
     /* attempt to shrink the table */
     shrink_handle_table( table );
     return table;
diff --git a/server/handle.h b/server/handle.h
index f1deb79fb5f..736fd360173 100644
--- a/server/handle.h
+++ b/server/handle.h
@@ -52,7 +52,8 @@ extern obj_handle_t enumerate_handles( struct process *process, const struct obj
                                        unsigned int *index );
 extern void close_process_handles( struct process *process );
 extern struct handle_table *alloc_handle_table( struct process *process, int count );
-extern struct handle_table *copy_handle_table( struct process *process, struct process *parent );
+extern struct handle_table *copy_handle_table( struct process *process, struct process *parent,
+                                               const obj_handle_t *handles, unsigned int handle_count );
 extern unsigned int get_handle_table_count( struct process *process);
 
 #endif  /* __WINE_SERVER_HANDLE_H */
diff --git a/server/process.c b/server/process.c
index c1bdb591f60..8aadd31bb87 100644
--- a/server/process.c
+++ b/server/process.c
@@ -500,7 +500,7 @@ static void start_sigkill_timer( struct process *process )
 /* create a new process */
 /* if the function fails the fd is closed */
 struct process *create_process( int fd, struct process *parent, int inherit_all,
-                                const struct security_descriptor *sd )
+                                const struct security_descriptor *sd, const struct startup_info *info )
 {
     struct process *process;
 
@@ -573,8 +573,33 @@ struct process *create_process( int fd, struct process *parent, int inherit_all,
     else
     {
         process->parent_id = parent->id;
-        process->handles = inherit_all ? copy_handle_table( process, parent )
-                                       : alloc_handle_table( process, 0 );
+        if (!inherit_all)
+        {
+            process->handles = alloc_handle_table( process, 0 );
+        }
+        else
+        {
+            /* No explicit handle list */
+            if (!info->data->handle_count)
+            {
+                process->handles = copy_handle_table( process, parent, NULL, 0 );
+            }
+            else
+            {
+                const char *ptr = (const char *)(info->data + 1);
+
+                ptr += info->data->curdir_len;
+                ptr += info->data->dllpath_len;
+                ptr += info->data->imagepath_len;
+                ptr += info->data->cmdline_len;
+                ptr += info->data->title_len;
+                ptr += info->data->desktop_len;
+                ptr += info->data->shellinfo_len;
+                ptr += info->data->runtime_len;
+
+                process->handles = copy_handle_table( process, parent, (obj_handle_t *)ptr, info->data->handle_count );
+            }
+        }
         /* Note: for security reasons, starting a new process does not attempt
          * to use the current impersonation token for the new process */
         process->token = token_duplicate( parent->token, TRUE, 0, NULL );
@@ -1199,7 +1224,7 @@ DECL_HANDLER(new_process)
 #undef FIXUP_LEN
     }
 
-    if (!(process = create_process( socket_fd, parent, req->inherit_all, sd ))) goto done;
+    if (!(process = create_process( socket_fd, parent, req->inherit_all, sd, info ))) goto done;
 
     process->startup_info = (struct startup_info *)grab_object( info );
 
@@ -1294,7 +1319,7 @@ DECL_HANDLER(exec_process)
         close( socket_fd );
         return;
     }
-    if (!(process = create_process( socket_fd, NULL, 0, NULL ))) return;
+    if (!(process = create_process( socket_fd, NULL, 0, NULL, NULL ))) return;
     create_thread( -1, process, NULL );
     release_object( process );
 }
diff --git a/server/process.h b/server/process.h
index 0fdf070b78e..58e0b6b6a1b 100644
--- a/server/process.h
+++ b/server/process.h
@@ -109,7 +109,7 @@ extern unsigned int alloc_ptid( void *ptr );
 extern void free_ptid( unsigned int id );
 extern void *get_ptid_entry( unsigned int id );
 extern struct process *create_process( int fd, struct process *parent, int inherit_all,
-                                       const struct security_descriptor *sd );
+                                       const struct security_descriptor *sd, const struct startup_info *info );
 extern data_size_t init_process( struct thread *thread );
 extern struct thread *get_process_first_thread( struct process *process );
 extern struct process *get_process_from_id( process_id_t id );
diff --git a/server/protocol.def b/server/protocol.def
index 75888ea9a22..bc19fcb96b8 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -243,6 +243,7 @@ typedef struct
     data_size_t  desktop_len;
     data_size_t  shellinfo_len;
     data_size_t  runtime_len;
+    unsigned int handle_count;
     /* VARARG(curdir,unicode_str,curdir_len); */
     /* VARARG(dllpath,unicode_str,dllpath_len); */
     /* VARARG(imagepath,unicode_str,imagepath_len); */
@@ -251,6 +252,7 @@ typedef struct
     /* VARARG(desktop,unicode_str,desktop_len); */
     /* VARARG(shellinfo,unicode_str,shellinfo_len); */
     /* VARARG(runtime,unicode_str,runtime_len); */
+    /* obj_handle_t handle_list[handle_count]; */
 } startup_info_t;
 
 /* structure returned in the list of window properties */
diff --git a/server/request.c b/server/request.c
index 4c1f30a5fe7..321bb6cfa81 100644
--- a/server/request.c
+++ b/server/request.c
@@ -582,7 +582,7 @@ static void master_socket_poll_event( struct fd *fd, int event )
         int client = accept( get_unix_fd( master_socket->fd ), (struct sockaddr *) &dummy, &len );
         if (client == -1) return;
         fcntl( client, F_SETFL, O_NONBLOCK );
-        if ((process = create_process( client, NULL, 0, NULL )))
+        if ((process = create_process( client, NULL, 0, NULL, NULL )))
         {
             create_thread( -1, process, NULL );
             release_object( process );
-- 
2.28.0




More information about the wine-devel mailing list