[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, ¶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 );
--
2.28.0
More information about the wine-devel
mailing list