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

Paul Gofman gofmanp at gmail.com
Fri Dec 6 15:53:23 CST 2019


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47817
Signed-off-by: Paul Gofman <gofmanp at gmail.com>
---
 dlls/kernel32/tests/process.c  |  4 ++--
 dlls/ntdll/process.c           | 11 +++++++++--
 include/wine/server_protocol.h |  4 +++-
 server/process.c               | 30 ++++++++++++++++++++++++------
 server/protocol.def            |  1 +
 server/request.h               | 17 +++++++++--------
 server/trace.c                 |  3 ++-
 7 files changed, 50 insertions(+), 20 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..5d75a27e97 100644
--- a/dlls/ntdll/process.c
+++ b/dlls/ntdll/process.c
@@ -1667,8 +1667,14 @@ 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( "%s image %s cmdline %s, parent %p.\n", debugstr_us( path ),
+           debugstr_us( &params->ImagePathName ), debugstr_us( &params->CommandLine ), parent);
+
+    if (parent == INVALID_HANDLE_VALUE)
+    {
+        memset(info, 0, sizeof(*info));
+        return STATUS_INVALID_HANDLE;
+    }
 
     if ((status = get_pe_file_info( path, attributes, &file_handle, &pe_info )))
     {
@@ -1709,6 +1715,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/process.c b/server/process.c
index 16bb5d57e7..195f54fa79 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 = get_process_first_thread(parent);
+    }
+
     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 );
 
     /* 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, 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/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 411369a4f6..026aba9c50 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 );
-- 
2.23.0




More information about the wine-devel mailing list