Signed-off-by: Nikolay Sivov nsivov@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, ¶ms->Desktop ); info->shellinfo_len = append_string( &ptr, params, ¶ms->ShellInfo ); info->runtime_len = append_string( &ptr, params, ¶ms->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 );