mirror-ac/driver/queue.c

355 lines
7.1 KiB
C
Raw Normal View History

2023-08-20 16:12:04 +02:00
#include "queue.h"
2023-09-02 10:54:04 +02:00
#include "callbacks.h"
#include "driver.h"
#include "queue.h"
#include "pool.h"
#include "thread.h"
2023-08-30 18:29:44 +02:00
#include "common.h"
2023-09-02 10:54:04 +02:00
/*
* This mutex is to prevent a new item being pushed to the queue
* while the HandlePeriodicCallbackReportQueue is iterating through
* the objects. This can be an issue because the spinlock is released
* after each report is placed in the IRP buffer which means a new report
* can be pushed into the queue before the next iteration can take ownership
* of the spinlock.
*/
typedef struct _REPORT_QUEUE_CONFIGURATION
{
QUEUE_HEAD head;
KGUARDED_MUTEX lock;
2023-10-05 08:27:17 +02:00
}REPORT_QUEUE_CONFIGURATION, * PREPORT_QUEUE_CONFIGURATION;
2023-09-02 10:54:04 +02:00
REPORT_QUEUE_CONFIGURATION report_queue_config = { 0 };
2023-10-05 08:27:17 +02:00
VOID
2023-09-27 06:22:14 +02:00
InitialiseGlobalReportQueue(
2023-09-02 10:54:04 +02:00
_In_ PBOOLEAN Status
)
{
report_queue_config.head.start = NULL;
report_queue_config.head.end = NULL;
report_queue_config.head.entries = 0;
2023-10-05 08:27:17 +02:00
KeInitializeSpinLock(&report_queue_config.head.lock);
KeInitializeGuardedMutex(&report_queue_config.lock);
2023-09-02 10:54:04 +02:00
*Status = TRUE;
}
2023-08-21 11:45:00 +02:00
//PQUEUE_HEAD QueueCreate()
//{
2023-08-22 10:51:52 +02:00
// PQUEUE_HEAD head = ExAllocatePool2( POOL_FLAG_NON_PAGED, sizeof( QUEUE_HEAD ), QUEUE_POOL_TAG );
2023-08-21 11:45:00 +02:00
//
// if ( !head )
// return NULL;
//
// head->end = NULL;
// head->start = NULL;
// head->entries = 0;
//
// KeInitializeSpinLock( &head->lock );
//
// return head;
//}
2023-08-20 16:12:04 +02:00
2023-10-05 08:27:17 +02:00
VOID
QueuePush(
2023-08-20 16:12:04 +02:00
_In_ PQUEUE_HEAD Head,
_In_ PVOID Data
)
{
KIRQL irql = KeGetCurrentIrql();
2023-10-05 08:27:17 +02:00
KeAcquireSpinLock(&Head->lock, &irql);
2023-08-20 16:12:04 +02:00
2023-10-05 08:27:17 +02:00
PQUEUE_NODE temp = ExAllocatePool2(POOL_FLAG_NON_PAGED, sizeof(QUEUE_NODE), QUEUE_POOL_TAG);
2023-08-20 16:12:04 +02:00
2023-10-05 08:27:17 +02:00
if (!temp)
2023-08-20 16:12:04 +02:00
goto end;
2023-08-20 17:04:53 +02:00
Head->entries += 1;
2023-08-20 16:12:04 +02:00
temp->data = Data;
2023-10-05 08:27:17 +02:00
if (Head->end != NULL)
2023-08-20 16:12:04 +02:00
Head->end->next = temp;
Head->end = temp;
2023-10-05 08:27:17 +02:00
if (Head->start == NULL)
2023-08-20 16:12:04 +02:00
Head->start = temp;
end:
2023-10-05 08:27:17 +02:00
KeReleaseSpinLock(&Head->lock, irql);
2023-08-20 16:12:04 +02:00
}
2023-10-05 08:27:17 +02:00
PVOID
2023-09-27 06:22:14 +02:00
QueuePop(
2023-08-20 16:12:04 +02:00
_In_ PQUEUE_HEAD Head
)
{
KIRQL irql = KeGetCurrentIrql();
2023-10-05 08:27:17 +02:00
KeAcquireSpinLock(&Head->lock, &irql);
2023-08-20 16:12:04 +02:00
PVOID data = NULL;
PQUEUE_NODE temp = Head->start;
2023-10-05 08:27:17 +02:00
if (temp == NULL)
2023-08-20 16:12:04 +02:00
goto end;
2023-08-21 06:45:33 +02:00
Head->entries = Head->entries - 1;
2023-08-20 17:04:53 +02:00
2023-08-20 16:12:04 +02:00
data = temp->data;
Head->start = temp->next;
2023-10-05 08:27:17 +02:00
if (Head->end == temp)
2023-08-20 16:12:04 +02:00
Head->end = NULL;
2023-10-05 08:27:17 +02:00
ExFreePoolWithTag(temp, QUEUE_POOL_TAG);
2023-08-20 16:12:04 +02:00
end:
2023-10-05 08:27:17 +02:00
KeReleaseSpinLock(&Head->lock, irql);
2023-08-20 16:12:04 +02:00
return data;
}
2023-09-02 10:54:04 +02:00
2023-10-05 08:27:17 +02:00
VOID
2023-09-27 06:22:14 +02:00
InsertReportToQueue(
2023-09-02 10:54:04 +02:00
_In_ PVOID Report
)
{
2023-10-05 08:27:17 +02:00
KeAcquireGuardedMutex(&report_queue_config.lock);
QueuePush(&report_queue_config.head, Report);
KeReleaseGuardedMutex(&report_queue_config.lock);
2023-09-02 10:54:04 +02:00
}
2023-10-05 08:27:17 +02:00
VOID
2023-09-27 06:22:14 +02:00
FreeGlobalReportQueueObjects()
2023-09-02 10:54:04 +02:00
{
2023-10-05 08:27:17 +02:00
KeAcquireGuardedMutex(&report_queue_config.lock);
2023-09-02 10:54:04 +02:00
2023-10-05 08:27:17 +02:00
PVOID report = QueuePop(&report_queue_config.head);
2023-09-02 10:54:04 +02:00
2023-10-05 08:27:17 +02:00
while (report != NULL)
2023-09-02 10:54:04 +02:00
{
2023-10-05 08:27:17 +02:00
ExFreePoolWithTag(report, REPORT_POOL_TAG);
report = QueuePop(&report_queue_config.head);
2023-09-02 10:54:04 +02:00
}
end:
2023-10-05 08:27:17 +02:00
KeReleaseGuardedMutex(&report_queue_config.lock);
2023-09-02 10:54:04 +02:00
}
/*
* This function handles sending all the pending reports in the global report
* queue to the usermode application. This function is called periodically by the
* usermode application. The reason I have implemented this is because as this application
* expanded, it became apparent that some of the driver functions will generate multiple
* reports as a result of a single usermode request and hence it makes dealing with
* reports generated from ObRegisterCallbacks for example much easier.
*/
2023-10-05 08:27:17 +02:00
NTSTATUS
2023-09-27 06:22:14 +02:00
HandlePeriodicGlobalReportQueueQuery(
2023-09-02 10:54:04 +02:00
_In_ PIRP Irp
)
{
PVOID report = NULL;
INT count = 0;
GLOBAL_REPORT_QUEUE_HEADER header;
PVOID report_buffer = NULL;
PREPORT_HEADER report_header;
SIZE_T total_size = NULL;
2023-10-05 08:27:17 +02:00
KeAcquireGuardedMutex(&report_queue_config.lock);
report = QueuePop(&report_queue_config.head);
2023-09-02 10:54:04 +02:00
2023-10-05 08:27:17 +02:00
report_buffer = ExAllocatePool2(
POOL_FLAG_NON_PAGED,
sizeof(INVALID_PROCESS_ALLOCATION_REPORT) * MAX_REPORTS_PER_IRP + sizeof(GLOBAL_REPORT_QUEUE_HEADER),
2023-09-23 13:25:48 +02:00
REPORT_QUEUE_TEMP_BUFFER_TAG
);
2023-09-02 10:54:04 +02:00
2023-10-05 08:27:17 +02:00
if (!report_buffer)
2023-09-02 10:54:04 +02:00
{
2023-10-05 08:27:17 +02:00
KeReleaseGuardedMutex(&report_queue_config.lock);
2023-09-02 10:54:04 +02:00
return STATUS_MEMORY_NOT_ALLOCATED;
}
2023-10-05 08:27:17 +02:00
if (report == NULL)
2023-09-02 10:54:04 +02:00
{
2023-10-05 08:27:17 +02:00
DEBUG_LOG("callback report queue is empty, returning");
2023-09-02 10:54:04 +02:00
goto end;
}
2023-10-05 08:27:17 +02:00
while (report != NULL)
2023-09-02 10:54:04 +02:00
{
2023-10-05 08:27:17 +02:00
if (count >= MAX_REPORTS_PER_IRP)
2023-09-02 10:54:04 +02:00
goto end;
2023-10-05 08:27:17 +02:00
report_header = (PREPORT_HEADER)report;
2023-09-02 10:54:04 +02:00
2023-10-05 08:27:17 +02:00
switch (report_header->report_id)
2023-09-02 10:54:04 +02:00
{
case REPORT_ILLEGAL_HANDLE_OPERATION:
RtlCopyMemory(
2023-10-05 08:27:17 +02:00
(UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size,
2023-09-02 10:54:04 +02:00
report,
2023-10-05 08:27:17 +02:00
sizeof(OPEN_HANDLE_FAILURE_REPORT)
2023-09-02 10:54:04 +02:00
);
2023-10-05 08:27:17 +02:00
total_size += sizeof(OPEN_HANDLE_FAILURE_REPORT);
2023-09-02 10:54:04 +02:00
break;
case REPORT_ILLEGAL_ATTACH_PROCESS:
RtlCopyMemory(
2023-10-05 08:27:17 +02:00
(UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size,
2023-09-02 10:54:04 +02:00
report,
2023-10-05 08:27:17 +02:00
sizeof(ATTACH_PROCESS_REPORT)
2023-09-02 10:54:04 +02:00
);
2023-10-05 08:27:17 +02:00
total_size += sizeof(ATTACH_PROCESS_REPORT);
2023-09-02 10:54:04 +02:00
break;
2023-09-18 05:15:26 +02:00
case REPORT_INVALID_PROCESS_ALLOCATION:
RtlCopyMemory(
2023-10-05 08:27:17 +02:00
(UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size,
2023-09-18 05:15:26 +02:00
report,
2023-10-05 08:27:17 +02:00
sizeof(INVALID_PROCESS_ALLOCATION_REPORT)
2023-09-18 05:15:26 +02:00
);
2023-10-05 08:27:17 +02:00
total_size += sizeof(INVALID_PROCESS_ALLOCATION_REPORT);
2023-09-18 05:15:26 +02:00
break;
2023-09-28 15:56:07 +02:00
case REPORT_APC_STACKWALK:
RtlCopyMemory(
2023-10-05 08:27:17 +02:00
(UINT64)report_buffer + sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size,
2023-09-28 15:56:07 +02:00
report,
2023-10-05 08:27:17 +02:00
sizeof(APC_STACKWALK_REPORT)
2023-09-28 15:56:07 +02:00
);
2023-10-05 08:27:17 +02:00
total_size += sizeof(APC_STACKWALK_REPORT);
2023-09-28 15:56:07 +02:00
break;
2023-09-02 10:54:04 +02:00
}
/* QueuePop frees the node, but we still need to free the returned data */
2023-10-05 08:27:17 +02:00
ExFreePoolWithTag(report, REPORT_POOL_TAG);
2023-09-02 10:54:04 +02:00
2023-10-05 08:27:17 +02:00
report = QueuePop(&report_queue_config.head);
2023-09-02 10:54:04 +02:00
count += 1;
}
end:
2023-10-05 08:27:17 +02:00
KeReleaseGuardedMutex(&report_queue_config.lock);
2023-09-03 19:33:27 +02:00
2023-10-05 08:27:17 +02:00
Irp->IoStatus.Information = sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size;
2023-09-02 10:54:04 +02:00
header.count = count;
RtlCopyMemory(
report_buffer,
&header,
2023-10-05 08:27:17 +02:00
sizeof(GLOBAL_REPORT_QUEUE_HEADER));
2023-09-02 10:54:04 +02:00
RtlCopyMemory(
Irp->AssociatedIrp.SystemBuffer,
report_buffer,
2023-10-05 08:27:17 +02:00
sizeof(GLOBAL_REPORT_QUEUE_HEADER) + total_size
2023-09-02 10:54:04 +02:00
);
2023-10-05 08:27:17 +02:00
if (report_buffer)
ExFreePoolWithTag(report_buffer, REPORT_QUEUE_TEMP_BUFFER_TAG);
2023-09-02 10:54:04 +02:00
2023-10-05 08:27:17 +02:00
DEBUG_LOG("Moved all reports into the IRP, sending !");
2023-09-02 10:54:04 +02:00
return STATUS_SUCCESS;
}
2023-09-25 17:41:38 +02:00
2023-10-05 08:27:17 +02:00
VOID
2023-09-27 06:22:14 +02:00
ListInit(
2023-09-25 17:41:38 +02:00
_In_ PLIST_HEAD ListHead
)
{
2023-10-05 08:27:17 +02:00
KeInitializeSpinLock(&ListHead->lock);
2023-09-25 17:41:38 +02:00
ListHead->start = NULL;
}
2023-10-05 08:27:17 +02:00
PLIST_ITEM
2023-09-27 06:22:14 +02:00
ListInsert(
2023-09-25 17:41:38 +02:00
_In_ PLIST_HEAD ListHead,
2023-09-26 12:00:45 +02:00
_In_ PLIST_ITEM NewEntry
2023-09-25 17:41:38 +02:00
)
{
KIRQL irql = KeGetCurrentIrql();
2023-10-05 08:27:17 +02:00
KeAcquireSpinLock(&ListHead->lock, &irql);
2023-09-25 17:41:38 +02:00
2023-09-26 12:00:45 +02:00
PLIST_ITEM old_entry = ListHead->start;
2023-09-25 17:41:38 +02:00
2023-09-26 12:00:45 +02:00
ListHead->start = NewEntry;
NewEntry->next = old_entry;
2023-09-25 17:41:38 +02:00
2023-10-05 08:27:17 +02:00
KeReleaseSpinLock(&ListHead->lock, irql);
2023-09-25 17:41:38 +02:00
}
2023-10-05 08:27:17 +02:00
PVOID
2023-09-27 06:22:14 +02:00
ListRemoveFirst(
2023-09-25 17:41:38 +02:00
_In_ PLIST_HEAD ListHead
)
{
KIRQL irql = KeGetCurrentIrql();
2023-10-05 08:27:17 +02:00
KeAcquireSpinLock(&ListHead->lock, &irql);
2023-09-25 17:41:38 +02:00
2023-10-05 08:27:17 +02:00
if (ListHead->start)
2023-09-25 17:41:38 +02:00
{
PLIST_ITEM entry = ListHead->start;
ListHead->start = ListHead->start->next;
2023-10-05 08:27:17 +02:00
ExFreePoolWithTag(entry, POOL_TAG_APC);
2023-09-25 17:41:38 +02:00
}
2023-10-05 08:27:17 +02:00
KeReleaseSpinLock(&ListHead->lock, irql);
2023-09-25 17:41:38 +02:00
}
2023-10-05 08:27:17 +02:00
PVOID
2023-09-27 06:22:14 +02:00
ListRemoveItem(
2023-09-25 17:41:38 +02:00
_In_ PLIST_HEAD ListHead,
_Inout_ PLIST_ITEM ListItem
)
{
KIRQL irql = KeGetCurrentIrql();
2023-10-05 08:27:17 +02:00
KeAcquireSpinLock(&ListHead->lock, &irql);
2023-09-25 17:41:38 +02:00
PLIST_ITEM entry = ListHead->start;
2023-10-05 08:27:17 +02:00
if (!entry)
2023-09-25 17:41:38 +02:00
goto unlock;
2023-10-05 08:27:17 +02:00
if (entry == ListItem)
2023-09-25 17:41:38 +02:00
{
ListHead->start = entry->next;
2023-10-05 08:27:17 +02:00
ExFreePoolWithTag(ListItem, POOL_TAG_APC);
2023-09-25 17:41:38 +02:00
goto unlock;
}
2023-10-05 08:27:17 +02:00
while (entry->next)
2023-09-25 17:41:38 +02:00
{
2023-10-05 08:27:17 +02:00
if (entry->next == ListItem)
2023-09-25 17:41:38 +02:00
{
2023-09-26 12:00:45 +02:00
entry->next = ListItem->next;
2023-10-05 08:27:17 +02:00
ExFreePoolWithTag(ListItem, POOL_TAG_APC);
2023-09-25 17:41:38 +02:00
goto unlock;
}
entry = entry->next;
}
unlock:
2023-10-05 08:27:17 +02:00
KeReleaseSpinLock(&ListHead->lock, irql);
2023-09-25 17:41:38 +02:00
}