server: Implement inherited handles list.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
1683206425
commit
c58a10c163
|
@ -4102,7 +4102,6 @@ static void test_handle_list_attribute(BOOL child, HANDLE handle1, HANDLE handle
|
||||||
CloseHandle(handle1);
|
CloseHandle(handle1);
|
||||||
|
|
||||||
ret = GetHandleInformation(handle2, &flags);
|
ret = GetHandleInformation(handle2, &flags);
|
||||||
todo_wine
|
|
||||||
ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Unexpected return value, error %d.\n", GetLastError());
|
ok(!ret && GetLastError() == ERROR_INVALID_HANDLE, "Unexpected return value, error %d.\n", GetLastError());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -812,6 +812,28 @@ done:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NTSTATUS alloc_handle_list( const PS_ATTRIBUTE *handles_attr, obj_handle_t **handles, data_size_t *handles_len )
|
||||||
|
{
|
||||||
|
SIZE_T count, i;
|
||||||
|
HANDLE *src;
|
||||||
|
|
||||||
|
*handles = NULL;
|
||||||
|
*handles_len = 0;
|
||||||
|
|
||||||
|
if (!handles_attr) return STATUS_SUCCESS;
|
||||||
|
|
||||||
|
count = handles_attr->Size / sizeof(HANDLE);
|
||||||
|
|
||||||
|
if (!(*handles = calloc( sizeof(**handles), count ))) return STATUS_NO_MEMORY;
|
||||||
|
|
||||||
|
src = handles_attr->ValuePtr;
|
||||||
|
for (i = 0; i < count; ++i)
|
||||||
|
(*handles)[i] = wine_server_obj_handle( src[i] );
|
||||||
|
|
||||||
|
*handles_len = count * sizeof(**handles);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* NtCreateUserProcess (NTDLL.@)
|
* NtCreateUserProcess (NTDLL.@)
|
||||||
|
@ -837,6 +859,9 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
|
||||||
HANDLE parent = 0, debug = 0, token = 0;
|
HANDLE parent = 0, debug = 0, token = 0;
|
||||||
UNICODE_STRING path = {0};
|
UNICODE_STRING path = {0};
|
||||||
SIZE_T i, attr_count = (attr->TotalLength - sizeof(attr->TotalLength)) / sizeof(PS_ATTRIBUTE);
|
SIZE_T i, attr_count = (attr->TotalLength - sizeof(attr->TotalLength)) / sizeof(PS_ATTRIBUTE);
|
||||||
|
const PS_ATTRIBUTE *handles_attr = NULL;
|
||||||
|
data_size_t handles_size;
|
||||||
|
obj_handle_t *handles;
|
||||||
|
|
||||||
for (i = 0; i < attr_count; i++)
|
for (i = 0; i < attr_count; i++)
|
||||||
{
|
{
|
||||||
|
@ -855,6 +880,10 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
|
||||||
case PS_ATTRIBUTE_TOKEN:
|
case PS_ATTRIBUTE_TOKEN:
|
||||||
token = attr->Attributes[i].ValuePtr;
|
token = attr->Attributes[i].ValuePtr;
|
||||||
break;
|
break;
|
||||||
|
case PS_ATTRIBUTE_HANDLE_LIST:
|
||||||
|
if (process_flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES)
|
||||||
|
handles_attr = &attr->Attributes[i];
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT)
|
if (attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT)
|
||||||
FIXME( "unhandled input attribute %lx\n", attr->Attributes[i].Attribute );
|
FIXME( "unhandled input attribute %lx\n", attr->Attributes[i].Attribute );
|
||||||
|
@ -883,12 +912,19 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
|
||||||
|
|
||||||
if ((status = alloc_object_attributes( process_attr, &objattr, &attr_len ))) goto done;
|
if ((status = alloc_object_attributes( process_attr, &objattr, &attr_len ))) goto done;
|
||||||
|
|
||||||
|
if ((status = alloc_handle_list( handles_attr, &handles, &handles_size )))
|
||||||
|
{
|
||||||
|
free( objattr );
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* create the socket for the new process */
|
/* create the socket for the new process */
|
||||||
|
|
||||||
if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
|
if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
|
||||||
{
|
{
|
||||||
status = STATUS_TOO_MANY_OPENED_FILES;
|
status = STATUS_TOO_MANY_OPENED_FILES;
|
||||||
free( objattr );
|
free( objattr );
|
||||||
|
free( handles );
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
#ifdef SO_PASSCRED
|
#ifdef SO_PASSCRED
|
||||||
|
@ -914,7 +950,9 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
|
||||||
req->access = process_access;
|
req->access = process_access;
|
||||||
req->cpu = pe_info.cpu;
|
req->cpu = pe_info.cpu;
|
||||||
req->info_size = startup_info_size;
|
req->info_size = startup_info_size;
|
||||||
|
req->handles_size = handles_size;
|
||||||
wine_server_add_data( req, objattr, attr_len );
|
wine_server_add_data( req, objattr, attr_len );
|
||||||
|
wine_server_add_data( req, handles, handles_size );
|
||||||
wine_server_add_data( req, startup_info, startup_info_size );
|
wine_server_add_data( req, startup_info, startup_info_size );
|
||||||
wine_server_add_data( req, params->Environment, env_size );
|
wine_server_add_data( req, params->Environment, env_size );
|
||||||
if (!(status = wine_server_call( req )))
|
if (!(status = wine_server_call( req )))
|
||||||
|
@ -926,6 +964,7 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
free( objattr );
|
free( objattr );
|
||||||
|
free( handles );
|
||||||
|
|
||||||
if (status)
|
if (status)
|
||||||
{
|
{
|
||||||
|
|
|
@ -781,10 +781,11 @@ struct new_process_request
|
||||||
unsigned int access;
|
unsigned int access;
|
||||||
client_cpu_t cpu;
|
client_cpu_t cpu;
|
||||||
data_size_t info_size;
|
data_size_t info_size;
|
||||||
|
data_size_t handles_size;
|
||||||
/* VARARG(objattr,object_attributes); */
|
/* VARARG(objattr,object_attributes); */
|
||||||
|
/* VARARG(handles,uints,handles_size); */
|
||||||
/* VARARG(info,startup_info,info_size); */
|
/* VARARG(info,startup_info,info_size); */
|
||||||
/* VARARG(env,unicode_str); */
|
/* VARARG(env,unicode_str); */
|
||||||
char __pad_44[4];
|
|
||||||
};
|
};
|
||||||
struct new_process_reply
|
struct new_process_reply
|
||||||
{
|
{
|
||||||
|
@ -6282,7 +6283,7 @@ union generic_reply
|
||||||
|
|
||||||
/* ### protocol_version begin ### */
|
/* ### protocol_version begin ### */
|
||||||
|
|
||||||
#define SERVER_PROTOCOL_VERSION 643
|
#define SERVER_PROTOCOL_VERSION 644
|
||||||
|
|
||||||
/* ### protocol_version end ### */
|
/* ### protocol_version end ### */
|
||||||
|
|
||||||
|
|
|
@ -355,7 +355,8 @@ static void shrink_handle_table( struct handle_table *table )
|
||||||
|
|
||||||
/* copy the handle table of the parent process */
|
/* copy the handle table of the parent process */
|
||||||
/* return 1 if OK, 0 on error */
|
/* 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 handle_count )
|
||||||
{
|
{
|
||||||
struct handle_table *parent_table = parent->handles;
|
struct handle_table *parent_table = parent->handles;
|
||||||
struct handle_table *table;
|
struct handle_table *table;
|
||||||
|
@ -367,6 +368,26 @@ struct handle_table *copy_handle_table( struct process *process, struct process
|
||||||
if (!(table = alloc_handle_table( process, parent_table->count )))
|
if (!(table = alloc_handle_table( process, parent_table->count )))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (handles)
|
||||||
|
{
|
||||||
|
struct handle_entry *dst, *src;
|
||||||
|
int index;
|
||||||
|
|
||||||
|
dst = table->entries;
|
||||||
|
memset( dst, 0, parent_table->count * sizeof(*dst) );
|
||||||
|
|
||||||
|
for (i = 0; i < handle_count; i++)
|
||||||
|
{
|
||||||
|
src = get_handle( parent, handles[i] );
|
||||||
|
if (!src || !(src->access & RESERVED_INHERIT)) continue;
|
||||||
|
grab_object_for_handle( src->ptr );
|
||||||
|
index = handle_to_index( handles[i] );
|
||||||
|
dst[index] = *src;
|
||||||
|
table->last = max( table->last, index );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if ((table->last = parent_table->last) >= 0)
|
if ((table->last = parent_table->last) >= 0)
|
||||||
{
|
{
|
||||||
struct handle_entry *ptr = table->entries;
|
struct handle_entry *ptr = table->entries;
|
||||||
|
@ -378,6 +399,7 @@ struct handle_table *copy_handle_table( struct process *process, struct process
|
||||||
else ptr->ptr = NULL; /* don't inherit this entry */
|
else ptr->ptr = NULL; /* don't inherit this entry */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/* attempt to shrink the table */
|
/* attempt to shrink the table */
|
||||||
shrink_handle_table( table );
|
shrink_handle_table( table );
|
||||||
return table;
|
return table;
|
||||||
|
|
|
@ -50,7 +50,8 @@ extern obj_handle_t open_object( struct process *process, obj_handle_t parent, u
|
||||||
extern obj_handle_t find_inherited_handle( struct process *process, const struct object_ops *ops );
|
extern obj_handle_t find_inherited_handle( struct process *process, const struct object_ops *ops );
|
||||||
extern void close_process_handles( struct process *process );
|
extern void close_process_handles( struct process *process );
|
||||||
extern struct handle_table *alloc_handle_table( struct process *process, int count );
|
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);
|
extern unsigned int get_handle_table_count( struct process *process);
|
||||||
|
|
||||||
#endif /* __WINE_SERVER_HANDLE_H */
|
#endif /* __WINE_SERVER_HANDLE_H */
|
||||||
|
|
|
@ -500,7 +500,8 @@ static void start_sigkill_timer( struct process *process )
|
||||||
/* create a new process */
|
/* create a new process */
|
||||||
/* if the function fails the fd is closed */
|
/* if the function fails the fd is closed */
|
||||||
struct process *create_process( int fd, struct process *parent, int inherit_all,
|
struct process *create_process( int fd, struct process *parent, int inherit_all,
|
||||||
const struct security_descriptor *sd )
|
const struct security_descriptor *sd, const obj_handle_t *handles,
|
||||||
|
unsigned int handle_count )
|
||||||
{
|
{
|
||||||
struct process *process;
|
struct process *process;
|
||||||
|
|
||||||
|
@ -573,7 +574,7 @@ struct process *create_process( int fd, struct process *parent, int inherit_all,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
process->parent_id = parent->id;
|
process->parent_id = parent->id;
|
||||||
process->handles = inherit_all ? copy_handle_table( process, parent )
|
process->handles = inherit_all ? copy_handle_table( process, parent, handles, handle_count )
|
||||||
: alloc_handle_table( process, 0 );
|
: alloc_handle_table( process, 0 );
|
||||||
/* Note: for security reasons, starting a new process does not attempt
|
/* Note: for security reasons, starting a new process does not attempt
|
||||||
* to use the current impersonation token for the new process */
|
* to use the current impersonation token for the new process */
|
||||||
|
@ -1101,6 +1102,7 @@ DECL_HANDLER(new_process)
|
||||||
struct process *parent;
|
struct process *parent;
|
||||||
struct thread *parent_thread = current;
|
struct thread *parent_thread = current;
|
||||||
int socket_fd = thread_get_inflight_fd( current, req->socket_fd );
|
int socket_fd = thread_get_inflight_fd( current, req->socket_fd );
|
||||||
|
const obj_handle_t *handles = NULL;
|
||||||
|
|
||||||
if (socket_fd == -1)
|
if (socket_fd == -1)
|
||||||
{
|
{
|
||||||
|
@ -1162,6 +1164,19 @@ DECL_HANDLER(new_process)
|
||||||
info->data = NULL;
|
info->data = NULL;
|
||||||
|
|
||||||
info_ptr = get_req_data_after_objattr( objattr, &info->data_size );
|
info_ptr = get_req_data_after_objattr( objattr, &info->data_size );
|
||||||
|
|
||||||
|
if ((req->handles_size & 3) || req->handles_size > info->data_size)
|
||||||
|
{
|
||||||
|
set_error( STATUS_INVALID_PARAMETER );
|
||||||
|
close( socket_fd );
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (req->handles_size)
|
||||||
|
{
|
||||||
|
handles = info_ptr;
|
||||||
|
info_ptr = (const char *)info_ptr + req->handles_size;
|
||||||
|
info->data_size -= req->handles_size;
|
||||||
|
}
|
||||||
info->info_size = min( req->info_size, info->data_size );
|
info->info_size = min( req->info_size, info->data_size );
|
||||||
|
|
||||||
if (req->info_size < sizeof(*info->data))
|
if (req->info_size < sizeof(*info->data))
|
||||||
|
@ -1202,7 +1217,8 @@ DECL_HANDLER(new_process)
|
||||||
#undef FIXUP_LEN
|
#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, handles, req->handles_size / sizeof(*handles) )))
|
||||||
|
goto done;
|
||||||
|
|
||||||
process->startup_info = (struct startup_info *)grab_object( info );
|
process->startup_info = (struct startup_info *)grab_object( info );
|
||||||
|
|
||||||
|
@ -1297,7 +1313,7 @@ DECL_HANDLER(exec_process)
|
||||||
close( socket_fd );
|
close( socket_fd );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!(process = create_process( socket_fd, NULL, 0, NULL ))) return;
|
if (!(process = create_process( socket_fd, NULL, 0, NULL, NULL, 0 ))) return;
|
||||||
create_thread( -1, process, NULL );
|
create_thread( -1, process, NULL );
|
||||||
release_object( process );
|
release_object( process );
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,8 @@ extern unsigned int alloc_ptid( void *ptr );
|
||||||
extern void free_ptid( unsigned int id );
|
extern void free_ptid( unsigned int id );
|
||||||
extern void *get_ptid_entry( unsigned int id );
|
extern void *get_ptid_entry( unsigned int id );
|
||||||
extern struct process *create_process( int fd, struct process *parent, int inherit_all,
|
extern struct process *create_process( int fd, struct process *parent, int inherit_all,
|
||||||
const struct security_descriptor *sd );
|
const struct security_descriptor *sd, const obj_handle_t *handles,
|
||||||
|
unsigned int handle_count );
|
||||||
extern data_size_t init_process( struct thread *thread );
|
extern data_size_t init_process( struct thread *thread );
|
||||||
extern struct thread *get_process_first_thread( struct process *process );
|
extern struct thread *get_process_first_thread( struct process *process );
|
||||||
extern struct process *get_process_from_id( process_id_t id );
|
extern struct process *get_process_from_id( process_id_t id );
|
||||||
|
|
|
@ -795,7 +795,9 @@ struct rawinput_device
|
||||||
unsigned int access; /* access rights for process object */
|
unsigned int access; /* access rights for process object */
|
||||||
client_cpu_t cpu; /* CPU that the new process will use */
|
client_cpu_t cpu; /* CPU that the new process will use */
|
||||||
data_size_t info_size; /* size of startup info */
|
data_size_t info_size; /* size of startup info */
|
||||||
|
data_size_t handles_size; /* length of explicit handles list */
|
||||||
VARARG(objattr,object_attributes); /* object attributes */
|
VARARG(objattr,object_attributes); /* object attributes */
|
||||||
|
VARARG(handles,uints,handles_size); /* handles list */
|
||||||
VARARG(info,startup_info,info_size); /* startup information */
|
VARARG(info,startup_info,info_size); /* startup information */
|
||||||
VARARG(env,unicode_str); /* environment for new process */
|
VARARG(env,unicode_str); /* environment for new process */
|
||||||
@REPLY
|
@REPLY
|
||||||
|
|
|
@ -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 );
|
int client = accept( get_unix_fd( master_socket->fd ), (struct sockaddr *) &dummy, &len );
|
||||||
if (client == -1) return;
|
if (client == -1) return;
|
||||||
fcntl( client, F_SETFL, O_NONBLOCK );
|
fcntl( client, F_SETFL, O_NONBLOCK );
|
||||||
if ((process = create_process( client, NULL, 0, NULL )))
|
if ((process = create_process( client, NULL, 0, NULL, NULL, 0 )))
|
||||||
{
|
{
|
||||||
create_thread( -1, process, NULL );
|
create_thread( -1, process, NULL );
|
||||||
release_object( process );
|
release_object( process );
|
||||||
|
|
|
@ -725,6 +725,7 @@ 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, access) == 32 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct new_process_request, cpu) == 36 );
|
C_ASSERT( FIELD_OFFSET(struct new_process_request, cpu) == 36 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 40 );
|
C_ASSERT( FIELD_OFFSET(struct new_process_request, info_size) == 40 );
|
||||||
|
C_ASSERT( FIELD_OFFSET(struct new_process_request, handles_size) == 44 );
|
||||||
C_ASSERT( sizeof(struct new_process_request) == 48 );
|
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, info) == 8 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct new_process_reply, pid) == 12 );
|
C_ASSERT( FIELD_OFFSET(struct new_process_reply, pid) == 12 );
|
||||||
|
|
|
@ -1292,7 +1292,9 @@ static void dump_new_process_request( const struct new_process_request *req )
|
||||||
fprintf( stderr, ", access=%08x", req->access );
|
fprintf( stderr, ", access=%08x", req->access );
|
||||||
dump_client_cpu( ", cpu=", &req->cpu );
|
dump_client_cpu( ", cpu=", &req->cpu );
|
||||||
fprintf( stderr, ", info_size=%u", req->info_size );
|
fprintf( stderr, ", info_size=%u", req->info_size );
|
||||||
|
fprintf( stderr, ", handles_size=%u", req->handles_size );
|
||||||
dump_varargs_object_attributes( ", objattr=", cur_size );
|
dump_varargs_object_attributes( ", objattr=", cur_size );
|
||||||
|
dump_varargs_uints( ", handles=", min(cur_size,req->handles_size) );
|
||||||
dump_varargs_startup_info( ", info=", min(cur_size,req->info_size) );
|
dump_varargs_startup_info( ", info=", min(cur_size,req->info_size) );
|
||||||
dump_varargs_unicode_str( ", env=", cur_size );
|
dump_varargs_unicode_str( ", env=", cur_size );
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue