reference counts

This commit is contained in:
lhodges1 2023-10-12 22:27:40 +11:00
parent 2ebeb8a055
commit a4fe653d44
4 changed files with 79 additions and 13 deletions

View file

@ -49,6 +49,28 @@ EnumHandleCallback(
#pragma alloc_text(PAGE, ExUnlockHandleTableEntry)
#endif
/*
* Its important on unload we dereference any objects to ensure the kernels reference
* count remains correct.
*/
VOID
CleanupProcessListFreeCallback(
_In_ PPROCESS_LIST_ENTRY ProcessListEntry
)
{
ObDereferenceObject(ProcessListEntry->parent);
ObDereferenceObject(ProcessListEntry->process);
}
VOID
CleanupThreadListFreeCallback(
_In_ PTHREAD_LIST_ENTRY ThreadListEntry
)
{
ObDereferenceObject(ThreadListEntry->thread);
ObDereferenceObject(ThreadListEntry->owning_process);
}
VOID
CleanupProcessListOnDriverUnload()
{
@ -57,7 +79,7 @@ CleanupProcessListOnDriverUnload()
for (;;)
{
if (!ListFreeFirstEntry(&process_list->start, &process_list->lock))
if (!ListFreeFirstEntry(&process_list->start, &process_list->lock, CleanupProcessListFreeCallback))
{
ExFreePoolWithTag(process_list, POOL_TAG_THREAD_LIST);
return;
@ -73,7 +95,7 @@ CleanupThreadListOnDriverUnload()
for (;;)
{
if (!ListFreeFirstEntry(&thread_list->start, &thread_list->lock))
if (!ListFreeFirstEntry(&thread_list->start, &thread_list->lock, CleanupThreadListFreeCallback))
{
ExFreePoolWithTag(thread_list, POOL_TAG_THREAD_LIST);
return;
@ -81,10 +103,6 @@ CleanupThreadListOnDriverUnload()
}
}
/*
* Important to remember the callback function will run at irql = DISPATCH_LEVEL since
* we hold the spinlock during enumeration.
*/
_IRQL_requires_max_(APC_LEVEL)
_Acquires_lock_(_Lock_kind_mutex_)
_Releases_lock_(_Lock_kind_mutex_)
@ -256,6 +274,9 @@ ProcessCreateNotifyRoutine(
if (!entry)
return;
ObReferenceObject(parent);
ObReferenceObject(process);
entry->parent = parent;
entry->process = process;
@ -268,6 +289,9 @@ ProcessCreateNotifyRoutine(
if (!entry)
return;
ObDereferenceObject(entry->parent);
ObDereferenceObject(entry->process);
ListRemoveEntry(&process_list->start, entry, &process_list->lock);
}
}
@ -300,6 +324,9 @@ ThreadCreateNotifyRoutine(
if (!entry)
return;
ObReferenceObject(thread);
ObReferenceObject(process);
entry->thread = thread;
entry->owning_process = process;
entry->apc = NULL;
@ -314,6 +341,9 @@ ThreadCreateNotifyRoutine(
if (!entry)
return;
ObDereferenceObject(entry->thread);
ObDereferenceObject(entry->owning_process);
ListRemoveEntry(&thread_list->start, entry, &thread_list->lock);
}
}
@ -658,7 +688,7 @@ EnumerateProcessHandles(
_In_opt_ PVOID Context
)
{
/* Handles are paged out so we need to be at an IRQL that allows paging */
/* Handles are stored in paged memory */
PAGED_CODE();
UNREFERENCED_PARAMETER(Context);

View file

@ -350,8 +350,8 @@ MapDiskImageIntoVirtualAddressSpace(
NTSTATUS status;
HANDLE file_handle;
OBJECT_ATTRIBUTES object_attributes;
PIO_STATUS_BLOCK pio_block;
OBJECT_ATTRIBUTES object_attributes = { 0 };
PIO_STATUS_BLOCK pio_block = NULL;
UNICODE_STRING path;
*Section = NULL;
@ -977,8 +977,8 @@ ParseSMBIOSTable(
ULONG firmware_table_buffer_size = NULL;
ULONG bytes_returned;
PRAW_SMBIOS_DATA smbios_data;
PSMBIOS_TABLE_HEADER smbios_table_header;
PRAW_SMBIOS_TABLE_01 smbios_baseboard_information;
PSMBIOS_TABLE_HEADER smbios_table_header = NULL;
PRAW_SMBIOS_TABLE_01 smbios_baseboard_information = NULL;
status = ExGetSystemFirmwareTable(
SMBIOS_TABLE,

View file

@ -304,6 +304,26 @@ end:
return STATUS_SUCCESS;
}
/*
* Simple thread safe linked list implementation. All structures should begin
* with a SINGLE_LIST_ENTRY structure provided by the windows API. for example:
*
* typedef struct _LIST_ENTRY_STRUCTURE
* {
* SINGLE_LIST_ENTRY list;
* PVOID address;
* UINT32 data;
* ...
* };
*
* This common structure layout allows us to pass in a callback routine when freeing
* allowing immense flexibility to ensure we can free and/or deference any objects
* that are referenced in said object.
*
* I've opted to use a mutex rather then a spinlock since there are many times we
* enumerate the list for extended periods aswell as queue up many insertions at
* once.
*/
VOID
ListInit(
_Inout_ PSINGLE_LIST_ENTRY Head,
@ -333,12 +353,19 @@ ListInsert(
KeReleaseGuardedMutex(Lock);
}
/*
* Assuming the SINGLE_LIST_ENTRY is the first item in the structure, we
* can pass a callback routine to be called before the free occurs. This
* allows us to dereference/free structure specific items whilst still allowing
* the list to remain flexible.
*/
_Acquires_lock_(_Lock_kind_mutex_)
_Releases_lock_(_Lock_kind_mutex_)
BOOLEAN
ListFreeFirstEntry(
_Inout_ PSINGLE_LIST_ENTRY Head,
_In_ PKGUARDED_MUTEX Lock
_In_ PKGUARDED_MUTEX Lock,
_In_opt_ PVOID CallbackRoutine
)
{
BOOLEAN result = FALSE;
@ -347,6 +374,10 @@ ListFreeFirstEntry(
if (Head->Next)
{
PSINGLE_LIST_ENTRY entry = Head->Next;
VOID(*callback_function_ptr)(PVOID) = CallbackRoutine;
(*callback_function_ptr)(entry);
Head->Next = Head->Next->Next;
ExFreePoolWithTag(entry, POOL_TAG_THREAD_LIST);
result = TRUE;
@ -356,6 +387,10 @@ ListFreeFirstEntry(
return result;
}
/*
* If we are removing a specific entry, its assumed we have freed and/or dereferenced
* any fields in the structure.
*/
_Acquires_lock_(_Lock_kind_mutex_)
_Releases_lock_(_Lock_kind_mutex_)
VOID

View file

@ -100,7 +100,8 @@ _Releases_lock_(_Lock_kind_mutex_)
BOOLEAN
ListFreeFirstEntry(
_Inout_ PSINGLE_LIST_ENTRY Head,
_In_ PKGUARDED_MUTEX Lock
_In_ PKGUARDED_MUTEX Lock,
_In_opt_ PVOID CallbackRoutine
);
_Acquires_lock_(_Lock_kind_mutex_)