From dc4e88183499cca1e32a2d95a842b941b3c1af1a Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 4 Feb 2021 14:08:23 +0100 Subject: [PATCH] server: Add support for object counts in the object type information. Signed-off-by: Alexandre Julliard --- dlls/ntdll/unix/file.c | 48 +++++++++++++++++----------------- include/wine/server_protocol.h | 17 +++++++++--- include/winternl.h | 23 +++++++++++++++- server/directory.c | 18 +++++++++++-- server/handle.c | 3 +++ server/object.c | 3 +++ server/object.h | 4 +++ server/protocol.def | 14 ++++++++-- server/request.h | 3 +-- server/trace.c | 26 ++++++++++++++++-- 10 files changed, 122 insertions(+), 37 deletions(-) diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index d6533fedfdd..c41d6bbfa6c 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -6596,37 +6596,37 @@ NTSTATUS WINAPI NtQueryObject( HANDLE handle, OBJECT_INFORMATION_CLASS info_clas case ObjectTypeInformation: { OBJECT_TYPE_INFORMATION *p = ptr; + char buffer[sizeof(struct object_type_info) + 64]; + struct object_type_info *info = (struct object_type_info *)buffer; SERVER_START_REQ( get_object_type ) { req->handle = wine_server_obj_handle( handle ); - if (len > sizeof(*p)) wine_server_set_reply( req, p + 1, len - sizeof(*p) ); + wine_server_set_reply( req, buffer, sizeof(buffer) ); status = wine_server_call( req ); - if (status == STATUS_SUCCESS) - { - if (!reply->total) /* no name */ - { - if (sizeof(*p) > len) status = STATUS_INFO_LENGTH_MISMATCH; - else memset( p, 0, sizeof(*p) ); - if (used_len) *used_len = sizeof(*p); - } - else if (sizeof(*p) + reply->total + sizeof(WCHAR) > len) - { - if (used_len) *used_len = sizeof(*p) + reply->total + sizeof(WCHAR); - status = STATUS_INFO_LENGTH_MISMATCH; - } - else - { - ULONG res = wine_server_reply_size( reply ); - p->TypeName.Buffer = (WCHAR *)(p + 1); - p->TypeName.Length = res; - p->TypeName.MaximumLength = res + sizeof(WCHAR); - p->TypeName.Buffer[res / sizeof(WCHAR)] = 0; - if (used_len) *used_len = sizeof(*p) + p->TypeName.MaximumLength; - } - } } SERVER_END_REQ; + if (status) break; + if (sizeof(*p) + info->name_len + sizeof(WCHAR) <= len) + { + memset( p, 0, sizeof(*p) ); + p->TypeName.Buffer = (WCHAR *)(p + 1); + p->TypeName.Length = info->name_len; + p->TypeName.MaximumLength = info->name_len + sizeof(WCHAR); + p->TotalNumberOfObjects = info->obj_count; + p->TotalNumberOfHandles = info->handle_count; + p->HighWaterNumberOfObjects = info->obj_max; + p->HighWaterNumberOfHandles = info->handle_max; + p->TypeIndex = info->index + 2; + memcpy( p->TypeName.Buffer, info + 1, info->name_len ); + p->TypeName.Buffer[info->name_len / sizeof(WCHAR)] = 0; + if (used_len) *used_len = sizeof(*p) + p->TypeName.MaximumLength; + } + else + { + if (used_len) *used_len = sizeof(*p) + info->name_len + sizeof(WCHAR); + status = STATUS_INFO_LENGTH_MISMATCH; + } break; } diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index df6ca01077c..accce0c0ed1 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -399,6 +399,17 @@ struct object_attributes }; +struct object_type_info +{ + data_size_t name_len; + unsigned int index; + unsigned int obj_count; + unsigned int handle_count; + unsigned int obj_max; + unsigned int handle_max; + +}; + struct token_groups { unsigned int count; @@ -4740,9 +4751,7 @@ struct get_object_type_request struct get_object_type_reply { struct reply_header __header; - data_size_t total; - /* VARARG(type,unicode_str); */ - char __pad_12[4]; + /* VARARG(info,object_type_info); */ }; @@ -6234,7 +6243,7 @@ union generic_reply /* ### protocol_version begin ### */ -#define SERVER_PROTOCOL_VERSION 665 +#define SERVER_PROTOCOL_VERSION 666 /* ### protocol_version end ### */ diff --git a/include/winternl.h b/include/winternl.h index c79292b55b0..92004cb8056 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1599,7 +1599,28 @@ typedef struct _OBJECT_NAME_INFORMATION { typedef struct __OBJECT_TYPE_INFORMATION { UNICODE_STRING TypeName; - ULONG Reserved [22]; + ULONG TotalNumberOfObjects; + ULONG TotalNumberOfHandles; + ULONG TotalPagedPoolUsage; + ULONG TotalNonPagedPoolUsage; + ULONG TotalNamePoolUsage; + ULONG TotalHandleTableUsage; + ULONG HighWaterNumberOfObjects; + ULONG HighWaterNumberOfHandles; + ULONG HighWaterPagedPoolUsage; + ULONG HighWaterNonPagedPoolUsage; + ULONG HighWaterNamePoolUsage; + ULONG HighWaterHandleTableUsage; + ULONG InvalidAttributes; + GENERIC_MAPPING GenericMapping; + ULONG ValidAccessMask; + BOOLEAN SecurityRequired; + BOOLEAN MaintainHandleCount; + UCHAR TypeIndex; + CHAR ReservedByte; + ULONG PoolType; + ULONG DefaultPagedPoolCharge; + ULONG DefaultNonPagedPoolCharge; } OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION; typedef struct _PROCESS_BASIC_INFORMATION { diff --git a/server/directory.c b/server/directory.c index e57b97c3ede..16b178085e5 100644 --- a/server/directory.c +++ b/server/directory.c @@ -553,11 +553,25 @@ DECL_HANDLER(get_object_type) { struct object *obj; struct type_descr *type; + struct object_type_info *info; if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL ))) return; type = obj->ops->type; - reply->total = type->name.len; - set_reply_data( type->name.str, min( reply->total, get_reply_max_size() ) ); + if (sizeof(*info) + type->name.len <= get_reply_max_size()) + { + if ((info = set_reply_data_size( sizeof(*info) + type->name.len ))) + { + info->name_len = type->name.len; + info->index = type->index; + info->obj_count = type->obj_count; + info->handle_count = type->handle_count; + info->obj_max = type->obj_max; + info->handle_max = type->handle_max; + memcpy( info + 1, type->name.str, type->name.len ); + } + } + else set_error( STATUS_BUFFER_OVERFLOW ); + release_object( obj ); } diff --git a/server/handle.c b/server/handle.c index 2333107b724..da04d03ad7f 100644 --- a/server/handle.c +++ b/server/handle.c @@ -101,6 +101,8 @@ static inline obj_handle_t handle_global_to_local( obj_handle_t handle ) static struct object *grab_object_for_handle( struct object *obj ) { obj->handle_count++; + obj->ops->type->handle_count++; + obj->ops->type->handle_max = max( obj->ops->type->handle_max, obj->ops->type->handle_count ); return grab_object( obj ); } @@ -108,6 +110,7 @@ static struct object *grab_object_for_handle( struct object *obj ) static void release_object_from_handle( struct object *obj ) { assert( obj->handle_count ); + obj->ops->type->handle_count--; obj->handle_count--; release_object( obj ); } diff --git a/server/object.c b/server/object.c index 56f7b72dfa5..e3014b005fa 100644 --- a/server/object.c +++ b/server/object.c @@ -199,6 +199,8 @@ void *alloc_object( const struct object_ops *ops ) #ifdef DEBUG_OBJECTS list_add_head( &object_list, &obj->obj_list ); #endif + obj->ops->type->obj_count++; + obj->ops->type->obj_max = max( obj->ops->type->obj_max, obj->ops->type->obj_count ); return obj; } return NULL; @@ -208,6 +210,7 @@ void *alloc_object( const struct object_ops *ops ) static void free_object( struct object *obj ) { free( obj->sd ); + obj->ops->type->obj_count--; #ifdef DEBUG_OBJECTS list_remove( &obj->obj_list ); memset( obj, 0xaa, obj->ops->size ); diff --git a/server/object.h b/server/object.h index 8a4ec0660ed..1a204fcbb69 100644 --- a/server/object.h +++ b/server/object.h @@ -58,6 +58,10 @@ struct type_descr { struct unicode_str name; /* type name */ unsigned int index; /* index in global array of types */ + unsigned int obj_count; /* count of objects of this type */ + unsigned int handle_count; /* count of handles of this type */ + unsigned int obj_max; /* max count of objects of this type */ + unsigned int handle_max; /* max count of handles of this type */ }; /* operations valid on all objects */ diff --git a/server/protocol.def b/server/protocol.def index 95a80dede63..42035e5c124 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -415,6 +415,17 @@ struct object_attributes /* VARARG(name,unicode_str); */ }; +struct object_type_info +{ + data_size_t name_len; /* length of the name string */ + unsigned int index; /* type index in global table */ + unsigned int obj_count; /* count of objects of this type */ + unsigned int handle_count; /* count of handles of this type */ + unsigned int obj_max; /* max count of objects of this type */ + unsigned int handle_max; /* max count of handles of this type */ + /* VARARG(name,unicode_str); */ +}; + struct token_groups { unsigned int count; @@ -3309,8 +3320,7 @@ struct handle_info @REQ(get_object_type) obj_handle_t handle; /* handle to the object */ @REPLY - data_size_t total; /* needed size for type name */ - VARARG(type,unicode_str); /* type name */ + VARARG(info,object_type_info); /* type information */ @END diff --git a/server/request.h b/server/request.h index 4c554ce8303..e5345e56ddd 100644 --- a/server/request.h +++ b/server/request.h @@ -2055,8 +2055,7 @@ C_ASSERT( FIELD_OFFSET(struct get_object_info_reply, total) == 20 ); C_ASSERT( sizeof(struct get_object_info_reply) == 24 ); C_ASSERT( FIELD_OFFSET(struct get_object_type_request, handle) == 12 ); C_ASSERT( sizeof(struct get_object_type_request) == 16 ); -C_ASSERT( FIELD_OFFSET(struct get_object_type_reply, total) == 8 ); -C_ASSERT( sizeof(struct get_object_type_reply) == 16 ); +C_ASSERT( sizeof(struct get_object_type_reply) == 8 ); C_ASSERT( FIELD_OFFSET(struct get_token_impersonation_level_request, handle) == 12 ); C_ASSERT( sizeof(struct get_token_impersonation_level_request) == 16 ); C_ASSERT( FIELD_OFFSET(struct get_token_impersonation_level_reply, impersonation_level) == 8 ); diff --git a/server/trace.c b/server/trace.c index cfe9814265b..479969b03fb 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1214,6 +1214,29 @@ static void dump_varargs_object_attributes( const char *prefix, data_size_t size fputc( '}', stderr ); } +static void dump_varargs_object_type_info( const char *prefix, data_size_t size ) +{ + const struct object_type_info *info = cur_data; + + fprintf( stderr,"%s{", prefix ); + if (size) + { + if (size < sizeof(*info) || (size - sizeof(*info) < info->name_len)) + { + fprintf( stderr, "***invalid***}" ); + remove_data( size ); + return; + } + + fprintf( stderr, "index=%u,obj_count=%u,handle_count=%u,obj_max=%u,handle_max=%u,name=L\"", + info->index,info->obj_count, info->handle_count, info->obj_max, info->handle_max ); + dump_strW( (const WCHAR *)(info + 1), info->name_len, stderr, "\"\"" ); + fputc( '\"', stderr ); + remove_data( min( size, sizeof(*info) + ((info->name_len + 2) & ~3 ))); + } + fputc( '}', stderr ); +} + static void dump_varargs_filesystem_event( const char *prefix, data_size_t size ) { static const char * const actions[] = { @@ -4021,8 +4044,7 @@ static void dump_get_object_type_request( const struct get_object_type_request * static void dump_get_object_type_reply( const struct get_object_type_reply *req ) { - fprintf( stderr, " total=%u", req->total ); - dump_varargs_unicode_str( ", type=", cur_size ); + dump_varargs_object_type_info( " info=", cur_size ); } static void dump_get_token_impersonation_level_request( const struct get_token_impersonation_level_request *req )