[PATCH v3 2/4] ntdll: Support creating processes with specified parent.

Paul Gofman gofmanp at gmail.com
Thu Dec 12 05:18:31 CST 2019


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47817
Signed-off-by: Paul Gofman <gofmanp at gmail.com>
---
    v2:
        - don't use arbitrary thread as parent;
    v3:
        - don't check for current process pseudo handle value in RtlCreateUserProcess().

 dlls/kernel32/tests/process.c  |  4 ++--
 dlls/ntdll/process.c           |  5 +++--
 include/wine/server_protocol.h |  4 +++-
 server/console.c               | 32 ++++++++++++++++----------------
 server/process.c               | 30 ++++++++++++++++++++++++------
 server/process.h               |  3 ++-
 server/protocol.def            |  1 +
 server/request.h               | 17 +++++++++--------
 server/trace.c                 |  3 ++-
 server/user.h                  |  3 ++-
 server/winstation.c            | 24 ++++++++++++++++--------
 11 files changed, 80 insertions(+), 46 deletions(-)

diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c
index 3efbfa2402..6d7a9a74c3 100644
--- a/dlls/kernel32/tests/process.c
+++ b/dlls/kernel32/tests/process.c
@@ -3874,14 +3874,14 @@ void test_parent_process_attribute(unsigned int level, HANDLE read_pipe)
 
         memset(&parent_data, 0, sizeof(parent_data));
         ret = ReadFile(read_pipe, &parent_data, sizeof(parent_data), &size, NULL);
-        todo_wine_if(level == 2) ok((level == 2 && ret) || (level == 1 && !ret && GetLastError() == ERROR_INVALID_HANDLE),
+        ok((level == 2 && ret) || (level == 1 && !ret && GetLastError() == ERROR_INVALID_HANDLE),
                 "Got unexpected ret %#x, level %u, GetLastError() %u.\n",
                 ret, level, GetLastError());
     }
 
     if (level == 2)
     {
-        todo_wine ok(parent_id == parent_data.parent_id, "Got parent id %u, parent_data.parent_id %u.\n",
+        ok(parent_id == parent_data.parent_id, "Got parent id %u, parent_data.parent_id %u.\n",
                 parent_id, parent_data.parent_id);
         return;
     }
diff --git a/dlls/ntdll/process.c b/dlls/ntdll/process.c
index 52d7ea429e..a4a2f17b4f 100644
--- a/dlls/ntdll/process.c
+++ b/dlls/ntdll/process.c
@@ -1667,8 +1667,8 @@ NTSTATUS WINAPI RtlCreateUserProcess( UNICODE_STRING *path, ULONG attributes,
 
     RtlNormalizeProcessParams( params );
 
-    TRACE( "%s image %s cmdline %s\n", debugstr_us( path ),
-           debugstr_us( &params->ImagePathName ), debugstr_us( &params->CommandLine ));
+    TRACE("path %s, image %s, cmdline %s, parent %p.\n", debugstr_us(path),
+           debugstr_us(&params->ImagePathName), debugstr_us(&params->CommandLine), parent);
 
     if ((status = get_pe_file_info( path, attributes, &file_handle, &pe_info )))
     {
@@ -1709,6 +1709,7 @@ NTSTATUS WINAPI RtlCreateUserProcess( UNICODE_STRING *path, ULONG attributes,
 
     SERVER_START_REQ( new_process )
     {
+        req->parent_process = wine_server_obj_handle(parent);
         req->inherit_all    = inherit;
         req->create_flags   = params->DebugFlags; /* hack: creation flags stored in DebugFlags for now */
         req->socket_fd      = socketfd[1];
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index aaa5fd2e33..98ecd98b08 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -769,6 +769,7 @@ struct rawinput_device
 struct new_process_request
 {
     struct request_header __header;
+    obj_handle_t parent_process;
     int          inherit_all;
     unsigned int create_flags;
     int          socket_fd;
@@ -779,6 +780,7 @@ struct new_process_request
     /* VARARG(objattr,object_attributes); */
     /* VARARG(info,startup_info,info_size); */
     /* VARARG(env,unicode_str); */
+    char __pad_44[4];
 };
 struct new_process_reply
 {
@@ -6702,6 +6704,6 @@ union generic_reply
     struct resume_process_reply resume_process_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 593
+#define SERVER_PROTOCOL_VERSION 594
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/server/console.c b/server/console.c
index 59f8843a75..691a0bf05a 100644
--- a/server/console.c
+++ b/server/console.c
@@ -504,37 +504,37 @@ int free_console( struct process *process )
  *	2/ parent is a renderer which launches process, and process should attach to the console
  *	   rendered by parent
  */
-void inherit_console(struct thread *parent_thread, struct process *process, obj_handle_t hconin)
+void inherit_console(struct thread *parent_thread, struct process *parent, struct process *process,
+        obj_handle_t hconin)
 {
     int done = 0;
-    struct process* parent = parent_thread->process;
 
     /* if parent is a renderer, then attach current process to its console
      * a bit hacky....
      */
-    if (hconin)
+    if (hconin && parent_thread)
     {
-	struct console_input* console;
+        struct console_input *console;
 
         /* FIXME: should we check some access rights ? */
-        if ((console = (struct console_input*)get_handle_obj( parent, hconin,
-                                                              0, &console_input_ops )))
-	{
+        if ((console = (struct console_input *)get_handle_obj( parent, hconin,
+                0, &console_input_ops )))
+        {
             if (console->renderer == parent_thread)
-	    {
-		process->console = (struct console_input*)grab_object( console );
-		process->console->num_proc++;
-		done = 1;
-	    }
-	    release_object( console );
-	}
+            {
+                process->console = (struct console_input*)grab_object( console );
+                process->console->num_proc++;
+                done = 1;
+            }
+            release_object( console );
+        }
         else clear_error();  /* ignore error */
     }
     /* otherwise, if parent has a console, attach child to this console */
     if (!done && parent->console)
     {
-	process->console = (struct console_input*)grab_object( parent->console );
-	process->console->num_proc++;
+        process->console = (struct console_input*)grab_object( parent->console );
+        process->console->num_proc++;
     }
 }
 
diff --git a/server/process.c b/server/process.c
index 16bb5d57e7..00ea45b068 100644
--- a/server/process.c
+++ b/server/process.c
@@ -1117,6 +1117,7 @@ DECL_HANDLER(new_process)
     const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL );
     struct process *process = NULL;
     struct process *parent = current->process;
+    struct thread *parent_thread = current;
     int socket_fd = thread_get_inflight_fd( current, req->socket_fd );
 
     if (socket_fd == -1)
@@ -1148,11 +1149,26 @@ DECL_HANDLER(new_process)
         return;
     }
 
+    if (req->parent_process)
+    {
+        if (!(parent = get_process_from_handle( req->parent_process, PROCESS_CREATE_PROCESS)))
+        {
+            set_error(STATUS_INVALID_HANDLE);
+            close(socket_fd);
+            return;
+        }
+        parent_thread = NULL;
+    }
+
     if (parent->job && (req->create_flags & CREATE_BREAKAWAY_FROM_JOB) &&
         !(parent->job->limit_flags & (JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)))
     {
         set_error( STATUS_ACCESS_DENIED );
         close( socket_fd );
+
+        if (req->parent_process)
+            release_object(parent);
+
         return;
     }
 
@@ -1222,7 +1238,7 @@ DECL_HANDLER(new_process)
     }
 
     /* connect to the window station */
-    connect_process_winstation( process, current );
+    connect_process_winstation( process, parent_thread, parent );
 
     /* set the process console */
     if (!(req->create_flags & (DETACHED_PROCESS | CREATE_NEW_CONSOLE)))
@@ -1231,7 +1247,7 @@ DECL_HANDLER(new_process)
          * like if hConOut and hConIn are console handles, then they should be on the same
          * physical console
          */
-        inherit_console( current, process, req->inherit_all ? info->data->hstdin : 0 );
+        inherit_console( parent_thread, parent, process, req->inherit_all ? info->data->hstdin : 0 );
     }
 
     if (!req->inherit_all && !(req->create_flags & CREATE_NEW_CONSOLE))
@@ -1246,16 +1262,15 @@ DECL_HANDLER(new_process)
         if (get_error() == STATUS_INVALID_HANDLE ||
             get_error() == STATUS_OBJECT_TYPE_MISMATCH) clear_error();
     }
-
     /* attach to the debugger if requested */
     if (req->create_flags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS))
     {
         set_process_debugger( process, current );
         process->debug_children = !(req->create_flags & DEBUG_ONLY_THIS_PROCESS);
     }
-    else if (parent->debugger && parent->debug_children)
+    else if (current->process->debugger && current->process->debug_children)
     {
-        set_process_debugger( process, parent->debugger );
+        set_process_debugger( process, current->process->debugger );
         /* debug_children is set to 1 by default */
     }
 
@@ -1265,9 +1280,12 @@ DECL_HANDLER(new_process)
     info->process = (struct process *)grab_object( process );
     reply->info = alloc_handle( current->process, info, SYNCHRONIZE, 0 );
     reply->pid = get_process_id( process );
-    reply->handle = alloc_handle_no_access_check( parent, process, req->access, objattr->attributes );
+    reply->handle = alloc_handle_no_access_check( current->process, process, req->access, objattr->attributes );
 
  done:
+    if (req->parent_process)
+        release_object(parent);
+
     if (process) release_object( process );
     release_object( info );
 }
diff --git a/server/process.h b/server/process.h
index 20ff6beda6..d8453eeaf2 100644
--- a/server/process.h
+++ b/server/process.h
@@ -141,7 +141,8 @@ extern struct process_snapshot *process_snap( int *count );
 extern void enum_processes( int (*cb)(struct process*, void*), void *user);
 
 /* console functions */
-extern void inherit_console(struct thread *parent_thread, struct process *process, obj_handle_t hconin);
+extern void inherit_console(struct thread *parent_thread, struct process *parent,
+        struct process *process, obj_handle_t hconin);
 extern int free_console( struct process *process );
 extern struct thread *console_get_renderer( struct console_input *console );
 
diff --git a/server/protocol.def b/server/protocol.def
index 1cb1fea602..7f9ec3a149 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -783,6 +783,7 @@ struct rawinput_device
 
 /* Create a new process from the context of the parent */
 @REQ(new_process)
+    obj_handle_t parent_process; /* parent process */
     int          inherit_all;    /* inherit all handles from parent */
     unsigned int create_flags;   /* creation flags */
     int          socket_fd;      /* file descriptor for process socket */
diff --git a/server/request.h b/server/request.h
index 90a3180a6c..9f36bcb711 100644
--- a/server/request.h
+++ b/server/request.h
@@ -745,14 +745,15 @@ C_ASSERT( sizeof(unsigned char) == 1 );
 C_ASSERT( sizeof(unsigned int) == 4 );
 C_ASSERT( sizeof(unsigned short) == 2 );
 C_ASSERT( sizeof(user_handle_t) == 4 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, inherit_all) == 12 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, create_flags) == 16 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, socket_fd) == 20 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, exe_file) == 24 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, access) == 28 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, cpu) == 32 );
-C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 36 );
-C_ASSERT( sizeof(struct new_process_request) == 40 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, parent_process) == 12 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, inherit_all) == 16 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, create_flags) == 20 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, socket_fd) == 24 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, exe_file) == 28 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, access) == 32 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, cpu) == 36 );
+C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 40 );
+C_ASSERT( sizeof(struct new_process_request) == 48 );
 C_ASSERT( FIELD_OFFSET(struct new_process_reply, info) == 8 );
 C_ASSERT( FIELD_OFFSET(struct new_process_reply, pid) == 12 );
 C_ASSERT( FIELD_OFFSET(struct new_process_reply, handle) == 16 );
diff --git a/server/trace.c b/server/trace.c
index 5b1d3ddea9..47f66b582c 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1243,7 +1243,8 @@ typedef void (*dump_func)( const void *req );
 
 static void dump_new_process_request( const struct new_process_request *req )
 {
-    fprintf( stderr, " inherit_all=%d", req->inherit_all );
+    fprintf( stderr, " parent_process=%04x", req->parent_process );
+    fprintf( stderr, ", inherit_all=%d", req->inherit_all );
     fprintf( stderr, ", create_flags=%08x", req->create_flags );
     fprintf( stderr, ", socket_fd=%d", req->socket_fd );
     fprintf( stderr, ", exe_file=%04x", req->exe_file );
diff --git a/server/user.h b/server/user.h
index eb1b7ce1e4..35184d8780 100644
--- a/server/user.h
+++ b/server/user.h
@@ -183,7 +183,8 @@ extern client_ptr_t get_class_client_ptr( struct window_class *class );
 extern struct desktop *get_desktop_obj( struct process *process, obj_handle_t handle, unsigned int access );
 extern struct winstation *get_process_winstation( struct process *process, unsigned int access );
 extern struct desktop *get_thread_desktop( struct thread *thread, unsigned int access );
-extern void connect_process_winstation( struct process *process, struct thread *parent );
+extern void connect_process_winstation( struct process *process, struct thread *parent_thread,
+        struct process *parent_process );
 extern void set_process_default_desktop( struct process *process, struct desktop *desktop,
                                          obj_handle_t handle );
 extern void close_process_desktop( struct process *process );
diff --git a/server/winstation.c b/server/winstation.c
index a09ca03e3b..f7932a9dc6 100644
--- a/server/winstation.c
+++ b/server/winstation.c
@@ -372,7 +372,8 @@ void set_process_default_desktop( struct process *process, struct desktop *deskt
 }
 
 /* connect a process to its window station */
-void connect_process_winstation( struct process *process, struct thread *parent )
+void connect_process_winstation( struct process *process, struct thread *parent_thread,
+        struct process *parent_process)
 {
     struct winstation *winstation = NULL;
     struct desktop *desktop = NULL;
@@ -383,9 +384,9 @@ void connect_process_winstation( struct process *process, struct thread *parent
     {
         winstation = (struct winstation *)get_handle_obj( process, handle, 0, &winstation_ops );
     }
-    else if (parent && parent->process->winstation)
+    else if (parent_process->winstation)
     {
-        handle = duplicate_handle( parent->process, parent->process->winstation,
+        handle = duplicate_handle( parent_process, parent_process->winstation,
                                    process, 0, 0, DUP_HANDLE_SAME_ACCESS );
         winstation = (struct winstation *)get_handle_obj( process, handle, 0, &winstation_ops );
     }
@@ -397,14 +398,21 @@ void connect_process_winstation( struct process *process, struct thread *parent
         desktop = get_desktop_obj( process, handle, 0 );
         if (!desktop || desktop->winstation != winstation) goto done;
     }
-    else if (parent && parent->desktop)
+    else
     {
-        desktop = get_desktop_obj( parent->process, parent->desktop, 0 );
+        if (parent_thread && parent_thread->desktop)
+            handle = parent_thread->desktop;
+        else if (parent_process->desktop)
+            handle = parent_process->desktop;
+        else
+            goto done;
+
+        desktop = get_desktop_obj( parent_process, handle, 0 );
+
         if (!desktop || desktop->winstation != winstation) goto done;
-        handle = duplicate_handle( parent->process, parent->desktop,
-                                   process, 0, 0, DUP_HANDLE_SAME_ACCESS );
-    }
 
+        handle = duplicate_handle( parent_process, handle, process, 0, 0, DUP_HANDLE_SAME_ACCESS );
+    }
     if (handle) set_process_default_desktop( process, desktop, handle );
 
 done:
-- 
2.23.0




More information about the wine-devel mailing list