server: Keep track of mapped memory views.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2017-09-26 14:11:49 +02:00
parent d82321006d
commit a557934c76
9 changed files with 225 additions and 7 deletions

View File

@ -1329,8 +1329,8 @@ static NTSTATUS stat_mapping_file( struct file_view *view, struct stat *st )
*
* Map an executable (PE format) image into memory.
*/
static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_size, SIZE_T mask,
SIZE_T header_size, int shared_fd, HANDLE dup_mapping, PVOID *addr_ptr )
static NTSTATUS map_image( HANDLE hmapping, ACCESS_MASK access, int fd, char *base, SIZE_T total_size,
SIZE_T mask, SIZE_T header_size, int shared_fd, HANDLE dup_mapping, PVOID *addr_ptr )
{
IMAGE_DOS_HEADER *dos;
IMAGE_NT_HEADERS *nt;
@ -1537,6 +1537,19 @@ static NTSTATUS map_image( HANDLE hmapping, int fd, char *base, SIZE_T total_siz
done:
view->mapping = dup_mapping;
SERVER_START_REQ( map_view )
{
req->mapping = wine_server_obj_handle( hmapping );
req->access = access;
req->base = wine_server_client_ptr( view->base );
req->size = view->size;
req->start = 0;
status = wine_server_call( req );
}
SERVER_END_REQ;
if (status) goto error;
VIRTUAL_DEBUG_DUMP_VIEW( view );
server_leave_uninterrupted_section( &csVirtual, &sigset );
@ -2930,14 +2943,14 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
if ((res = server_get_unix_fd( shared_file, FILE_READ_DATA|FILE_WRITE_DATA,
&shared_fd, &shared_needs_close, NULL, NULL ))) goto done;
res = map_image( handle, unix_handle, base, size, mask, image_info.header_size,
res = map_image( handle, access, unix_handle, base, size, mask, image_info.header_size,
shared_fd, dup_mapping, addr_ptr );
if (shared_needs_close) close( shared_fd );
close_handle( shared_file );
}
else
{
res = map_image( handle, unix_handle, base, size, mask, image_info.header_size,
res = map_image( handle, access, unix_handle, base, size, mask, image_info.header_size,
-1, dup_mapping, addr_ptr );
}
if (needs_close) close( unix_handle );
@ -2988,6 +3001,20 @@ NTSTATUS WINAPI NtMapViewOfSection( HANDLE handle, HANDLE process, PVOID *addr_p
handle, size, offset.u.HighPart, offset.u.LowPart );
res = map_file_into_view( view, unix_handle, 0, size, offset.QuadPart, vprot, !dup_mapping );
if (res == STATUS_SUCCESS)
{
SERVER_START_REQ( map_view )
{
req->mapping = wine_server_obj_handle( handle );
req->access = access;
req->base = wine_server_client_ptr( view->base );
req->size = size;
req->start = offset.QuadPart;
res = wine_server_call( req );
}
SERVER_END_REQ;
}
if (res == STATUS_SUCCESS)
{
*addr_ptr = view->base;
@ -3039,8 +3066,13 @@ NTSTATUS WINAPI NtUnmapViewOfSection( HANDLE process, PVOID addr )
server_enter_uninterrupted_section( &csVirtual, &sigset );
if ((view = VIRTUAL_FindView( addr, 0 )) && !is_view_valloc( view ))
{
delete_view( view );
status = STATUS_SUCCESS;
SERVER_START_REQ( unmap_view )
{
req->base = wine_server_client_ptr( view->base );
status = wine_server_call( req );
}
SERVER_END_REQ;
if (!status) delete_view( view );
}
server_leave_uninterrupted_section( &csVirtual, &sigset );
return status;

View File

@ -2228,6 +2228,36 @@ struct get_mapping_info_reply
struct map_view_request
{
struct request_header __header;
obj_handle_t mapping;
unsigned int access;
char __pad_20[4];
client_ptr_t base;
mem_size_t size;
file_pos_t start;
};
struct map_view_reply
{
struct reply_header __header;
};
struct unmap_view_request
{
struct request_header __header;
char __pad_12[4];
client_ptr_t base;
};
struct unmap_view_reply
{
struct reply_header __header;
};
struct get_mapping_committed_range_request
{
struct request_header __header;
@ -5626,6 +5656,8 @@ enum request
REQ_create_mapping,
REQ_open_mapping,
REQ_get_mapping_info,
REQ_map_view,
REQ_unmap_view,
REQ_get_mapping_committed_range,
REQ_add_mapping_committed_range,
REQ_create_snapshot,
@ -5917,6 +5949,8 @@ union generic_request
struct create_mapping_request create_mapping_request;
struct open_mapping_request open_mapping_request;
struct get_mapping_info_request get_mapping_info_request;
struct map_view_request map_view_request;
struct unmap_view_request unmap_view_request;
struct get_mapping_committed_range_request get_mapping_committed_range_request;
struct add_mapping_committed_range_request add_mapping_committed_range_request;
struct create_snapshot_request create_snapshot_request;
@ -6206,6 +6240,8 @@ union generic_reply
struct create_mapping_reply create_mapping_reply;
struct open_mapping_reply open_mapping_reply;
struct get_mapping_info_reply get_mapping_info_reply;
struct map_view_reply map_view_reply;
struct unmap_view_reply unmap_view_reply;
struct get_mapping_committed_range_reply get_mapping_committed_range_reply;
struct add_mapping_committed_range_reply add_mapping_committed_range_reply;
struct create_snapshot_reply create_snapshot_reply;
@ -6408,6 +6444,6 @@ union generic_reply
struct terminate_job_reply terminate_job_reply;
};
#define SERVER_PROTOCOL_VERSION 537
#define SERVER_PROTOCOL_VERSION 538
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -150,6 +150,7 @@ extern struct mapping *get_mapping_obj( struct process *process, obj_handle_t ha
extern obj_handle_t open_mapping_file( struct process *process, struct mapping *mapping,
unsigned int access, unsigned int sharing );
extern struct mapping *grab_mapping_unless_removable( struct mapping *mapping );
extern void free_mapped_views( struct process *process );
extern int get_page_size(void);
/* device functions */

View File

@ -55,6 +55,16 @@ struct ranges
} ranges[1];
};
/* memory view mapped in client address space */
struct memory_view
{
struct list entry; /* entry in per-process view list */
unsigned int flags; /* SEC_* flags */
client_ptr_t base; /* view base address (in process addr space) */
mem_size_t size; /* view size */
file_pos_t start; /* start offset in mapping */
};
struct mapping
{
struct object obj; /* object header */
@ -196,6 +206,33 @@ static int create_temp_file( file_pos_t size )
return fd;
}
/* find a memory view from its base address */
static struct memory_view *find_mapped_view( struct process *process, client_ptr_t base )
{
struct memory_view *view;
LIST_FOR_EACH_ENTRY( view, &process->views, struct memory_view, entry )
if (view->base == base) return view;
set_error( STATUS_NOT_MAPPED_VIEW );
return NULL;
}
static void free_memory_view( struct memory_view *view )
{
list_remove( &view->entry );
free( view );
}
/* free all mapped views at process exit */
void free_mapped_views( struct process *process )
{
struct list *ptr;
while ((ptr = list_head( &process->views )))
free_memory_view( LIST_ENTRY( ptr, struct memory_view, entry ));
}
/* find the shared PE mapping for a given mapping */
static struct file *get_shared_file( struct mapping *mapping )
{
@ -776,6 +813,66 @@ DECL_HANDLER(get_mapping_info)
release_object( mapping );
}
/* add a memory view in the current process */
DECL_HANDLER(map_view)
{
struct mapping *mapping = NULL;
struct memory_view *view;
if (!req->size || (req->base & page_mask) || req->base + req->size < req->base) /* overflow */
{
set_error( STATUS_INVALID_PARAMETER );
return;
}
/* make sure we don't already have an overlapping view */
LIST_FOR_EACH_ENTRY( view, &current->process->views, struct memory_view, entry )
{
if (view->base + view->size <= req->base) continue;
if (view->base >= req->base + req->size) continue;
set_error( STATUS_INVALID_PARAMETER );
return;
}
if (!(mapping = get_mapping_obj( current->process, req->mapping, req->access ))) return;
if (mapping->flags & SEC_IMAGE)
{
if (req->start || req->size > mapping->image.map_size)
{
set_error( STATUS_INVALID_PARAMETER );
goto done;
}
}
else if (req->start >= mapping->size ||
req->start + req->size < req->start ||
req->start + req->size > ((mapping->size + page_mask) & ~(mem_size_t)page_mask))
{
set_error( STATUS_INVALID_PARAMETER );
goto done;
}
if ((view = mem_alloc( sizeof(*view) )))
{
view->base = req->base;
view->size = req->size;
view->start = req->start;
view->flags = mapping->flags;
list_add_tail( &current->process->views, &view->entry );
}
done:
release_object( mapping );
}
/* unmap a memory view from the current process */
DECL_HANDLER(unmap_view)
{
struct memory_view *view = find_mapped_view( current->process, req->base );
if (view) free_memory_view( view );
}
/* get a range of committed pages in a file mapping */
DECL_HANDLER(get_mapping_committed_range)
{

View File

@ -537,6 +537,7 @@ struct thread *create_process( int fd, struct thread *parent_thread, int inherit
list_init( &process->locks );
list_init( &process->asyncs );
list_init( &process->classes );
list_init( &process->views );
list_init( &process->dlls );
list_init( &process->rawinput_devices );
@ -871,6 +872,7 @@ static void process_killed( struct process *process )
free( dll );
}
destroy_process_classes( process );
free_mapped_views( process );
free_process_user_handles( process );
remove_process_locks( process );
set_process_startup_state( process, STARTUP_ABORTED );

View File

@ -88,6 +88,7 @@ struct process
obj_handle_t winstation; /* main handle to process window station */
obj_handle_t desktop; /* handle to desktop to use for new threads */
struct token *token; /* security token associated with this process */
struct list views; /* list of memory views */
struct list dlls; /* list of loaded dlls */
client_ptr_t peb; /* PEB address in client address space */
client_ptr_t ldt_copy; /* pointer to LDT copy in client addr space */

View File

@ -1726,6 +1726,22 @@ enum char_info_mode
@END
/* Add a memory view in the current process */
@REQ(map_view)
obj_handle_t mapping; /* file mapping handle */
unsigned int access; /* wanted access rights */
client_ptr_t base; /* view base address (page-aligned) */
mem_size_t size; /* view size */
file_pos_t start; /* start offset in mapping */
@END
/* Unmap a memory view from the current process */
@REQ(unmap_view)
client_ptr_t base; /* view base address */
@END
/* Get a range of committed pages in a file mapping */
@REQ(get_mapping_committed_range)
obj_handle_t handle; /* handle to the mapping */

View File

@ -196,6 +196,8 @@ DECL_HANDLER(read_change);
DECL_HANDLER(create_mapping);
DECL_HANDLER(open_mapping);
DECL_HANDLER(get_mapping_info);
DECL_HANDLER(map_view);
DECL_HANDLER(unmap_view);
DECL_HANDLER(get_mapping_committed_range);
DECL_HANDLER(add_mapping_committed_range);
DECL_HANDLER(create_snapshot);
@ -486,6 +488,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_create_mapping,
(req_handler)req_open_mapping,
(req_handler)req_get_mapping_info,
(req_handler)req_map_view,
(req_handler)req_unmap_view,
(req_handler)req_get_mapping_committed_range,
(req_handler)req_add_mapping_committed_range,
(req_handler)req_create_snapshot,
@ -1266,6 +1270,14 @@ C_ASSERT( FIELD_OFFSET(struct get_mapping_info_reply, flags) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_mapping_info_reply, mapping) == 20 );
C_ASSERT( FIELD_OFFSET(struct get_mapping_info_reply, shared_file) == 24 );
C_ASSERT( sizeof(struct get_mapping_info_reply) == 32 );
C_ASSERT( FIELD_OFFSET(struct map_view_request, mapping) == 12 );
C_ASSERT( FIELD_OFFSET(struct map_view_request, access) == 16 );
C_ASSERT( FIELD_OFFSET(struct map_view_request, base) == 24 );
C_ASSERT( FIELD_OFFSET(struct map_view_request, size) == 32 );
C_ASSERT( FIELD_OFFSET(struct map_view_request, start) == 40 );
C_ASSERT( sizeof(struct map_view_request) == 48 );
C_ASSERT( FIELD_OFFSET(struct unmap_view_request, base) == 16 );
C_ASSERT( sizeof(struct unmap_view_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct get_mapping_committed_range_request, handle) == 12 );
C_ASSERT( FIELD_OFFSET(struct get_mapping_committed_range_request, offset) == 16 );
C_ASSERT( sizeof(struct get_mapping_committed_range_request) == 24 );

View File

@ -2243,6 +2243,20 @@ static void dump_get_mapping_info_reply( const struct get_mapping_info_reply *re
dump_varargs_pe_image_info( ", image=", cur_size );
}
static void dump_map_view_request( const struct map_view_request *req )
{
fprintf( stderr, " mapping=%04x", req->mapping );
fprintf( stderr, ", access=%08x", req->access );
dump_uint64( ", base=", &req->base );
dump_uint64( ", size=", &req->size );
dump_uint64( ", start=", &req->start );
}
static void dump_unmap_view_request( const struct unmap_view_request *req )
{
dump_uint64( " base=", &req->base );
}
static void dump_get_mapping_committed_range_request( const struct get_mapping_committed_range_request *req )
{
fprintf( stderr, " handle=%04x", req->handle );
@ -4553,6 +4567,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_create_mapping_request,
(dump_func)dump_open_mapping_request,
(dump_func)dump_get_mapping_info_request,
(dump_func)dump_map_view_request,
(dump_func)dump_unmap_view_request,
(dump_func)dump_get_mapping_committed_range_request,
(dump_func)dump_add_mapping_committed_range_request,
(dump_func)dump_create_snapshot_request,
@ -4840,6 +4856,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_create_mapping_reply,
(dump_func)dump_open_mapping_reply,
(dump_func)dump_get_mapping_info_reply,
NULL,
NULL,
(dump_func)dump_get_mapping_committed_range_reply,
NULL,
(dump_func)dump_create_snapshot_reply,
@ -5127,6 +5145,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"create_mapping",
"open_mapping",
"get_mapping_info",
"map_view",
"unmap_view",
"get_mapping_committed_range",
"add_mapping_committed_range",
"create_snapshot",
@ -5407,6 +5427,7 @@ static const struct
{ "NOT_A_DIRECTORY", STATUS_NOT_A_DIRECTORY },
{ "NOT_FOUND", STATUS_NOT_FOUND },
{ "NOT_IMPLEMENTED", STATUS_NOT_IMPLEMENTED },
{ "NOT_MAPPED_VIEW", STATUS_NOT_MAPPED_VIEW },
{ "NOT_REGISTRY_FILE", STATUS_NOT_REGISTRY_FILE },
{ "NOT_SUPPORTED", STATUS_NOT_SUPPORTED },
{ "NO_DATA_DETECTED", STATUS_NO_DATA_DETECTED },