server: Store pointers to objects created by kernel_object_from_handle in server.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2019-03-25 14:37:39 +01:00 committed by Alexandre Julliard
parent b2a546c92d
commit 134e264ae5
6 changed files with 270 additions and 39 deletions

View File

@ -264,13 +264,27 @@ static void free_kernel_object( void *obj )
HeapFree( GetProcessHeap(), 0, header );
}
void *alloc_kernel_object( POBJECT_TYPE type, SIZE_T size, LONG ref )
void *alloc_kernel_object( POBJECT_TYPE type, HANDLE handle, SIZE_T size, LONG ref )
{
struct object_header *header;
if (!(header = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*header) + size)) )
return NULL;
if (handle)
{
NTSTATUS status;
SERVER_START_REQ( set_kernel_object_ptr )
{
req->manager = wine_server_obj_handle( get_device_manager() );
req->handle = wine_server_obj_handle( handle );
req->user_ptr = wine_server_client_ptr( header + 1 );
status = wine_server_call( req );
}
SERVER_END_REQ;
if (status) FIXME( "set_object_reference failed: %#x\n", status );
}
header->ref = ref;
header->type = type;
return header + 1;
@ -327,51 +341,91 @@ static const POBJECT_TYPE *known_types[] =
&SeTokenObjectType
};
static CRITICAL_SECTION handle_map_cs;
static CRITICAL_SECTION_DEBUG handle_map_critsect_debug =
{
0, 0, &handle_map_cs,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": handle_map_cs") }
};
static CRITICAL_SECTION handle_map_cs = { &handle_map_critsect_debug, -1, 0, 0, 0, 0 };
static NTSTATUS kernel_object_from_handle( HANDLE handle, POBJECT_TYPE type, void **ret )
{
char buf[256];
OBJECT_TYPE_INFORMATION *type_info = (OBJECT_TYPE_INFORMATION *)buf;
ULONG size;
struct object_header *header;
void *obj;
NTSTATUS status;
status = NtQueryObject(handle, ObjectTypeInformation, buf, sizeof(buf), &size);
if (status) return status;
EnterCriticalSection( &handle_map_cs );
if (!type)
SERVER_START_REQ( get_kernel_object_ptr )
{
size_t i;
for (i = 0; i < ARRAY_SIZE(known_types); i++)
{
type = *known_types[i];
if (!RtlCompareUnicodeStrings( type->name, strlenW(type->name), type_info->TypeName.Buffer,
type_info->TypeName.Length / sizeof(WCHAR), FALSE ))
break;
}
if (i == ARRAY_SIZE(known_types))
{
FIXME("Unsupported type %s\n", debugstr_us(&type_info->TypeName));
return STATUS_INVALID_HANDLE;
}
req->manager = wine_server_obj_handle( get_device_manager() );
req->handle = wine_server_obj_handle( handle );
status = wine_server_call( req );
obj = wine_server_get_ptr( reply->user_ptr );
}
SERVER_END_REQ;
if (status)
{
LeaveCriticalSection( &handle_map_cs );
return status;
}
else if (!!RtlCompareUnicodeStrings( type->name, strlenW(type->name), type_info->TypeName.Buffer,
type_info->TypeName.Length / sizeof(WCHAR), FALSE ))
return STATUS_OBJECT_TYPE_MISMATCH;
FIXME( "semi-stub: returning new %s object instance\n", debugstr_w(type->name) );
if (type->constructor)
obj = type->constructor( handle );
if (obj)
{
header = (struct object_header *)obj - 1;
if (type && header->type != type) status = STATUS_OBJECT_TYPE_MISMATCH;
}
else
{
obj = alloc_kernel_object( type, 0, 0 );
FIXME( "No constructor for type %s returning empty %p object\n", debugstr_w(type->name), obj );
}
if (!obj) return STATUS_NO_MEMORY;
char buf[256];
OBJECT_TYPE_INFORMATION *type_info = (OBJECT_TYPE_INFORMATION *)buf;
ULONG size;
TRACE( "%p -> %p\n", handle, obj );
*ret = obj;
return STATUS_SUCCESS;
status = NtQueryObject( handle, ObjectTypeInformation, buf, sizeof(buf), &size );
if (status)
{
LeaveCriticalSection( &handle_map_cs );
return status;
}
if (!type)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(known_types); i++)
{
type = *known_types[i];
if (!RtlCompareUnicodeStrings( type->name, strlenW(type->name), type_info->TypeName.Buffer,
type_info->TypeName.Length / sizeof(WCHAR), FALSE ))
break;
}
if (i == ARRAY_SIZE(known_types))
{
FIXME("Unsupported type %s\n", debugstr_us(&type_info->TypeName));
LeaveCriticalSection( &handle_map_cs );
return STATUS_INVALID_HANDLE;
}
}
else if (RtlCompareUnicodeStrings( type->name, strlenW(type->name), type_info->TypeName.Buffer,
type_info->TypeName.Length / sizeof(WCHAR), FALSE) )
{
LeaveCriticalSection( &handle_map_cs );
return STATUS_OBJECT_TYPE_MISMATCH;
}
if (type->constructor)
obj = type->constructor( handle );
else
{
FIXME( "No constructor for type %s\n", debugstr_w(type->name) );
obj = alloc_kernel_object( type, handle, 0, 0 );
}
if (!obj) status = STATUS_NO_MEMORY;
}
LeaveCriticalSection( &handle_map_cs );
if (!status) *ret = obj;
return status;
}
/***********************************************************************
@ -422,7 +476,7 @@ POBJECT_TYPE IoFileObjectType = &file_type;
static void *create_file_object( HANDLE handle )
{
FILE_OBJECT *file;
if (!(file = alloc_kernel_object( IoFileObjectType, sizeof(*file), 0 ))) return NULL;
if (!(file = alloc_kernel_object( IoFileObjectType, handle, sizeof(*file), 0 ))) return NULL;
file->Type = 5; /* MSDN */
file->Size = sizeof(*file);
return file;
@ -487,7 +541,7 @@ static NTSTATUS dispatch_create( const irp_params_t *params, void *in_buff, ULON
FILE_OBJECT *file;
DEVICE_OBJECT *device = wine_server_get_ptr( params->create.device );
if (!(file = alloc_kernel_object( IoFileObjectType, sizeof(*file), 1 ))) return STATUS_NO_MEMORY;
if (!(file = alloc_kernel_object( IoFileObjectType, NULL, sizeof(*file), 1 ))) return STATUS_NO_MEMORY;
TRACE( "device %p -> file %p\n", device, file );
@ -1298,7 +1352,7 @@ NTSTATUS WINAPI IoCreateDriver( UNICODE_STRING *name, PDRIVER_INITIALIZE init )
TRACE("(%s, %p)\n", debugstr_us(name), init);
if (!(driver = alloc_kernel_object( IoDriverObjectType, sizeof(*driver), 1 )))
if (!(driver = alloc_kernel_object( IoDriverObjectType, NULL, sizeof(*driver), 1 )))
return STATUS_NO_MEMORY;
if ((status = RtlDuplicateUnicodeString( 1, name, &driver->driver_obj.DriverName )))
@ -1379,7 +1433,7 @@ NTSTATUS WINAPI IoCreateDevice( DRIVER_OBJECT *driver, ULONG ext_size,
TRACE( "(%p, %u, %s, %u, %x, %u, %p)\n",
driver, ext_size, debugstr_us(name), type, characteristics, exclusive, ret_device );
if (!(device = alloc_kernel_object( IoDeviceObjectType, sizeof(DEVICE_OBJECT) + ext_size, 1 )))
if (!(device = alloc_kernel_object( IoDeviceObjectType, NULL, sizeof(DEVICE_OBJECT) + ext_size, 1 )))
return STATUS_NO_MEMORY;
SERVER_START_REQ( create_device )

View File

@ -5247,6 +5247,36 @@ struct get_next_device_request_reply
struct get_kernel_object_ptr_request
{
struct request_header __header;
obj_handle_t manager;
obj_handle_t handle;
char __pad_20[4];
};
struct get_kernel_object_ptr_reply
{
struct reply_header __header;
client_ptr_t user_ptr;
};
struct set_kernel_object_ptr_request
{
struct request_header __header;
obj_handle_t manager;
obj_handle_t handle;
char __pad_20[4];
client_ptr_t user_ptr;
};
struct set_kernel_object_ptr_reply
{
struct reply_header __header;
};
struct make_process_system_request
{
struct request_header __header;
@ -5933,6 +5963,8 @@ enum request
REQ_create_device,
REQ_delete_device,
REQ_get_next_device_request,
REQ_get_kernel_object_ptr,
REQ_set_kernel_object_ptr,
REQ_make_process_system,
REQ_get_token_statistics,
REQ_create_completion,
@ -6231,6 +6263,8 @@ union generic_request
struct create_device_request create_device_request;
struct delete_device_request delete_device_request;
struct get_next_device_request_request get_next_device_request_request;
struct get_kernel_object_ptr_request get_kernel_object_ptr_request;
struct set_kernel_object_ptr_request set_kernel_object_ptr_request;
struct make_process_system_request make_process_system_request;
struct get_token_statistics_request get_token_statistics_request;
struct create_completion_request create_completion_request;
@ -6527,6 +6561,8 @@ union generic_reply
struct create_device_reply create_device_reply;
struct delete_device_reply delete_device_reply;
struct get_next_device_request_reply get_next_device_request_reply;
struct get_kernel_object_ptr_reply get_kernel_object_ptr_reply;
struct set_kernel_object_ptr_reply set_kernel_object_ptr_reply;
struct make_process_system_reply make_process_system_reply;
struct get_token_statistics_reply get_token_statistics_reply;
struct create_completion_reply create_completion_reply;
@ -6556,6 +6592,6 @@ union generic_reply
struct terminate_job_reply terminate_job_reply;
};
#define SERVER_PROTOCOL_VERSION 573
#define SERVER_PROTOCOL_VERSION 574
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */

View File

@ -243,6 +243,49 @@ static int compare_kernel_object( const void *k, const struct wine_rb_entry *ent
return memcmp( k, &ptr->user_ptr, sizeof(client_ptr_t) );
}
static struct kernel_object *kernel_object_from_obj( struct device_manager *manager, struct object *obj )
{
struct kernel_object *kernel_object;
struct list *list;
if (!(list = obj->ops->get_kernel_obj_list( obj ))) return NULL;
LIST_FOR_EACH_ENTRY( kernel_object, list, struct kernel_object, list_entry )
{
if (kernel_object->manager != manager) continue;
return kernel_object;
}
return NULL;
}
static client_ptr_t get_kernel_object_ptr( struct device_manager *manager, struct object *obj )
{
struct kernel_object *kernel_object = kernel_object_from_obj( manager, obj );
return kernel_object ? kernel_object->user_ptr : 0;
}
static struct kernel_object *set_kernel_object( struct device_manager *manager, struct object *obj, client_ptr_t user_ptr )
{
struct kernel_object *kernel_object;
struct list *list;
if (!(list = obj->ops->get_kernel_obj_list( obj ))) return NULL;
if (!(kernel_object = malloc( sizeof(*kernel_object) ))) return NULL;
kernel_object->manager = manager;
kernel_object->user_ptr = user_ptr;
kernel_object->object = obj;
if (wine_rb_put( &manager->kernel_objects, &user_ptr, &kernel_object->rb_entry ))
{
/* kernel_object pointer already set */
free( kernel_object );
return NULL;
}
list_add_head( list, &kernel_object->list_entry );
return kernel_object;
}
static void irp_call_dump( struct object *obj, int verbose )
{
struct irp_call *irp = (struct irp_call *)obj;
@ -803,3 +846,47 @@ DECL_HANDLER(set_irp_result)
release_object( irp );
}
}
/* get kernel pointer from server object */
DECL_HANDLER(get_kernel_object_ptr)
{
struct device_manager *manager;
struct object *object = NULL;
if (!(manager = (struct device_manager *)get_handle_obj( current->process, req->manager,
0, &device_manager_ops )))
return;
if ((object = get_handle_obj( current->process, req->handle, 0, NULL )))
{
reply->user_ptr = get_kernel_object_ptr( manager, object );
release_object( object );
}
release_object( manager );
}
/* associate kernel pointer with server object */
DECL_HANDLER(set_kernel_object_ptr)
{
struct device_manager *manager;
struct object *object = NULL;
if (!(manager = (struct device_manager *)get_handle_obj( current->process, req->manager,
0, &device_manager_ops )))
return;
if (!(object = get_handle_obj( current->process, req->handle, 0, NULL )))
{
release_object( manager );
return;
}
if (!set_kernel_object( manager, object, req->user_ptr ))
set_error( STATUS_INVALID_HANDLE );
release_object( object );
release_object( manager );
}

View File

@ -3623,6 +3623,23 @@ struct handle_info
@END
/* Get kernel pointer from server object */
@REQ(get_kernel_object_ptr)
obj_handle_t manager; /* handle to the device manager */
obj_handle_t handle; /* object handle */
@REPLY
client_ptr_t user_ptr; /* kernel object pointer */
@END
/* Associate kernel pointer with server object */
@REQ(set_kernel_object_ptr)
obj_handle_t manager; /* handle to the device manager */
obj_handle_t handle; /* object handle */
client_ptr_t user_ptr; /* kernel object pointer */
@END
/* Make the current process a system process */
@REQ(make_process_system)
@REPLY

View File

@ -376,6 +376,8 @@ DECL_HANDLER(create_device_manager);
DECL_HANDLER(create_device);
DECL_HANDLER(delete_device);
DECL_HANDLER(get_next_device_request);
DECL_HANDLER(get_kernel_object_ptr);
DECL_HANDLER(set_kernel_object_ptr);
DECL_HANDLER(make_process_system);
DECL_HANDLER(get_token_statistics);
DECL_HANDLER(create_completion);
@ -673,6 +675,8 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_create_device,
(req_handler)req_delete_device,
(req_handler)req_get_next_device_request,
(req_handler)req_get_kernel_object_ptr,
(req_handler)req_set_kernel_object_ptr,
(req_handler)req_make_process_system,
(req_handler)req_get_token_statistics,
(req_handler)req_create_completion,
@ -2285,6 +2289,15 @@ C_ASSERT( FIELD_OFFSET(struct get_next_device_request_reply, client_tid) == 40 )
C_ASSERT( FIELD_OFFSET(struct get_next_device_request_reply, in_size) == 44 );
C_ASSERT( FIELD_OFFSET(struct get_next_device_request_reply, out_size) == 48 );
C_ASSERT( sizeof(struct get_next_device_request_reply) == 56 );
C_ASSERT( FIELD_OFFSET(struct get_kernel_object_ptr_request, manager) == 12 );
C_ASSERT( FIELD_OFFSET(struct get_kernel_object_ptr_request, handle) == 16 );
C_ASSERT( sizeof(struct get_kernel_object_ptr_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct get_kernel_object_ptr_reply, user_ptr) == 8 );
C_ASSERT( sizeof(struct get_kernel_object_ptr_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct set_kernel_object_ptr_request, manager) == 12 );
C_ASSERT( FIELD_OFFSET(struct set_kernel_object_ptr_request, handle) == 16 );
C_ASSERT( FIELD_OFFSET(struct set_kernel_object_ptr_request, user_ptr) == 24 );
C_ASSERT( sizeof(struct set_kernel_object_ptr_request) == 32 );
C_ASSERT( sizeof(struct make_process_system_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct make_process_system_reply, event) == 8 );
C_ASSERT( sizeof(struct make_process_system_reply) == 16 );

View File

@ -4298,6 +4298,24 @@ static void dump_get_next_device_request_reply( const struct get_next_device_req
dump_varargs_bytes( ", next_data=", cur_size );
}
static void dump_get_kernel_object_ptr_request( const struct get_kernel_object_ptr_request *req )
{
fprintf( stderr, " manager=%04x", req->manager );
fprintf( stderr, ", handle=%04x", req->handle );
}
static void dump_get_kernel_object_ptr_reply( const struct get_kernel_object_ptr_reply *req )
{
dump_uint64( " user_ptr=", &req->user_ptr );
}
static void dump_set_kernel_object_ptr_request( const struct set_kernel_object_ptr_request *req )
{
fprintf( stderr, " manager=%04x", req->manager );
fprintf( stderr, ", handle=%04x", req->handle );
dump_uint64( ", user_ptr=", &req->user_ptr );
}
static void dump_make_process_system_request( const struct make_process_system_request *req )
{
}
@ -4811,6 +4829,8 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_create_device_request,
(dump_func)dump_delete_device_request,
(dump_func)dump_get_next_device_request_request,
(dump_func)dump_get_kernel_object_ptr_request,
(dump_func)dump_set_kernel_object_ptr_request,
(dump_func)dump_make_process_system_request,
(dump_func)dump_get_token_statistics_request,
(dump_func)dump_create_completion_request,
@ -5105,6 +5125,8 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_create_device_reply,
NULL,
(dump_func)dump_get_next_device_request_reply,
(dump_func)dump_get_kernel_object_ptr_reply,
NULL,
(dump_func)dump_make_process_system_reply,
(dump_func)dump_get_token_statistics_reply,
(dump_func)dump_create_completion_reply,
@ -5399,6 +5421,8 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"create_device",
"delete_device",
"get_next_device_request",
"get_kernel_object_ptr",
"set_kernel_object_ptr",
"make_process_system",
"get_token_statistics",
"create_completion",