2009-10-12 03:35:35 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS Kernel
|
|
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
|
|
* FILE: ntoskrnl/fsrtl/stackovf.c
|
|
|
|
* PURPOSE: Provides Stack Overflow support for File System Drivers
|
2013-05-01 20:53:15 +00:00
|
|
|
* PROGRAMMERS: Pierre Schweitzer (pierre@reactos.org)
|
2009-10-12 03:35:35 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
|
|
|
|
#include <ntoskrnl.h>
|
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
2013-05-01 20:53:15 +00:00
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
|
|
|
/* We have one queue for paging files, one queue for normal files
|
|
|
|
* Queue 0 is for non-paging files
|
|
|
|
* Queue 1 is for paging files
|
|
|
|
* Don't add new/change current queues unless you know what you do
|
|
|
|
* Most of the code relies on the fact that we have two queues in that order
|
|
|
|
*/
|
|
|
|
#define FSRTLP_MAX_QUEUES 2
|
|
|
|
|
|
|
|
typedef struct _STACK_OVERFLOW_WORK_ITEM
|
|
|
|
{
|
|
|
|
|
|
|
|
WORK_QUEUE_ITEM WorkItem;
|
|
|
|
PFSRTL_STACK_OVERFLOW_ROUTINE Routine;
|
|
|
|
PVOID Context;
|
|
|
|
PKEVENT Event;
|
|
|
|
} STACK_OVERFLOW_WORK_ITEM, *PSTACK_OVERFLOW_WORK_ITEM;
|
|
|
|
|
|
|
|
KEVENT StackOverflowFallbackSerialEvent;
|
|
|
|
STACK_OVERFLOW_WORK_ITEM StackOverflowFallback;
|
|
|
|
KQUEUE FsRtlWorkerQueues[FSRTLP_MAX_QUEUES];
|
|
|
|
|
2013-05-01 10:54:02 +00:00
|
|
|
/* PRIVATE FUNCTIONS *********************************************************/
|
|
|
|
|
2013-05-01 20:53:15 +00:00
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
FsRtlStackOverflowRead(IN PVOID Context)
|
|
|
|
{
|
|
|
|
PSTACK_OVERFLOW_WORK_ITEM WorkItem;
|
|
|
|
|
|
|
|
WorkItem = (PSTACK_OVERFLOW_WORK_ITEM)Context;
|
|
|
|
|
|
|
|
/* Put us as top IRP for current thread */
|
|
|
|
IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP);
|
|
|
|
/* And call FsRtlSORoutine */
|
|
|
|
WorkItem->Routine(WorkItem->Context, WorkItem->Event);
|
|
|
|
|
|
|
|
/* If we were using fallback workitem, don't free it, just reset event */
|
|
|
|
if (WorkItem == &StackOverflowFallback)
|
|
|
|
{
|
|
|
|
KeSetEvent(&StackOverflowFallbackSerialEvent, 0, FALSE);
|
|
|
|
}
|
|
|
|
/* Otherwise, free the work item */
|
|
|
|
else
|
|
|
|
{
|
2019-11-01 18:05:20 +00:00
|
|
|
ExFreePoolWithTag(WorkItem, 'srSF');
|
2013-05-01 20:53:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset top level */
|
|
|
|
IoSetTopLevelIrp(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2013-05-01 10:54:02 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
FsRtlpPostStackOverflow(IN PVOID Context,
|
|
|
|
IN PKEVENT Event,
|
|
|
|
IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine,
|
|
|
|
IN BOOLEAN IsPaging)
|
|
|
|
{
|
2013-05-01 20:53:15 +00:00
|
|
|
PSTACK_OVERFLOW_WORK_ITEM WorkItem;
|
|
|
|
|
|
|
|
/* Try to allocate a work item */
|
2019-11-01 18:05:20 +00:00
|
|
|
WorkItem = ExAllocatePoolWithTag(NonPagedPool, sizeof(STACK_OVERFLOW_WORK_ITEM), 'srSF');
|
2013-05-01 20:53:15 +00:00
|
|
|
if (WorkItem == NULL)
|
|
|
|
{
|
|
|
|
/* If we failed, and we are not a paging file, just raise an error */
|
|
|
|
if (!IsPaging)
|
|
|
|
{
|
|
|
|
RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Otherwise, wait for fallback workitem to be available and use it */
|
|
|
|
KeWaitForSingleObject(&StackOverflowFallbackSerialEvent, Executive, KernelMode, FALSE, NULL);
|
|
|
|
WorkItem = &StackOverflowFallback;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize work item */
|
|
|
|
WorkItem->Context = Context;
|
|
|
|
WorkItem->Event = Event;
|
|
|
|
WorkItem->Routine = StackOverflowRoutine;
|
|
|
|
ExInitializeWorkItem(&WorkItem->WorkItem, FsRtlStackOverflowRead, WorkItem);
|
|
|
|
|
|
|
|
/* And queue it in the appropriate queue (paging or not?) */
|
|
|
|
KeInsertQueue(&FsRtlWorkerQueues[IsPaging], &WorkItem->WorkItem.List);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
FsRtlWorkerThread(IN PVOID StartContext)
|
|
|
|
{
|
|
|
|
KIRQL Irql;
|
|
|
|
PLIST_ENTRY Entry;
|
|
|
|
PWORK_QUEUE_ITEM WorkItem;
|
2017-11-13 14:06:29 +00:00
|
|
|
ULONG_PTR QueueId = (ULONG_PTR)StartContext;
|
2013-05-01 20:53:15 +00:00
|
|
|
|
|
|
|
/* Set our priority according to the queue we're dealing with */
|
|
|
|
KeSetPriorityThread(&PsGetCurrentThread()->Tcb, LOW_REALTIME_PRIORITY + QueueId);
|
|
|
|
|
|
|
|
/* Loop for events */
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
/* Look for next event */
|
|
|
|
Entry = KeRemoveQueue(&FsRtlWorkerQueues[QueueId], KernelMode, NULL);
|
|
|
|
WorkItem = CONTAINING_RECORD(Entry, WORK_QUEUE_ITEM, List);
|
|
|
|
|
|
|
|
/* Call its routine (here: FsRtlStackOverflowRead) */
|
|
|
|
WorkItem->WorkerRoutine(WorkItem->Parameter);
|
|
|
|
|
|
|
|
/* Check we're still at passive level or bugcheck */
|
|
|
|
Irql = KeGetCurrentIrql();
|
|
|
|
if (Irql != PASSIVE_LEVEL)
|
|
|
|
{
|
|
|
|
KeBugCheckEx(IRQL_NOT_LESS_OR_EQUAL, (ULONG_PTR)WorkItem->WorkerRoutine,
|
|
|
|
(ULONG_PTR)Irql, (ULONG_PTR)WorkItem->WorkerRoutine,
|
|
|
|
(ULONG_PTR)WorkItem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2018-12-30 11:19:11 +00:00
|
|
|
INIT_FUNCTION
|
2013-05-01 20:53:15 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
2013-05-02 08:04:12 +00:00
|
|
|
FsRtlInitializeWorkerThread(VOID)
|
2013-05-01 20:53:15 +00:00
|
|
|
{
|
2017-11-13 14:06:29 +00:00
|
|
|
ULONG_PTR i;
|
2013-05-01 20:53:15 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
HANDLE ThreadHandle;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
|
|
|
|
/* Initialize each queue we have */
|
|
|
|
for (i = 0; i < FSRTLP_MAX_QUEUES; ++i)
|
|
|
|
{
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
NULL,
|
|
|
|
0,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
/* Initialize the queue and its associated thread and pass it the queue ID */
|
|
|
|
KeInitializeQueue(&FsRtlWorkerQueues[i], 0);
|
|
|
|
Status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, &ObjectAttributes,
|
|
|
|
0, 0, FsRtlWorkerThread, (PVOID)i);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Don't leak handle */
|
|
|
|
ZwClose(ThreadHandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Also initialize our fallback event, set it to ensure it's already usable */
|
|
|
|
KeInitializeEvent(&StackOverflowFallbackSerialEvent, SynchronizationEvent, TRUE);
|
|
|
|
|
|
|
|
return Status;
|
2013-05-01 10:54:02 +00:00
|
|
|
}
|
|
|
|
|
2009-10-12 03:35:35 +00:00
|
|
|
/* PUBLIC FUNCTIONS **********************************************************/
|
|
|
|
|
|
|
|
/*++
|
|
|
|
* @name FsRtlPostPagingFileStackOverflow
|
2013-05-01 20:53:15 +00:00
|
|
|
* @implemented NT 5.2
|
2009-10-12 03:35:35 +00:00
|
|
|
*
|
|
|
|
* The FsRtlPostPagingFileStackOverflow routine
|
|
|
|
*
|
|
|
|
* @param Context
|
|
|
|
*
|
|
|
|
* @param Event
|
|
|
|
*
|
|
|
|
* @param StackOverflowRoutine
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*
|
|
|
|
* @remarks None.
|
|
|
|
*
|
|
|
|
*--*/
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
FsRtlPostPagingFileStackOverflow(IN PVOID Context,
|
|
|
|
IN PKEVENT Event,
|
|
|
|
IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine)
|
|
|
|
{
|
2013-05-01 10:54:02 +00:00
|
|
|
FsRtlpPostStackOverflow(Context, Event, StackOverflowRoutine, TRUE);
|
2009-10-12 03:35:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
* @name FsRtlPostStackOverflow
|
2013-05-01 20:53:15 +00:00
|
|
|
* @implemented NT 5.2
|
2009-10-12 03:35:35 +00:00
|
|
|
*
|
|
|
|
* The FsRtlPostStackOverflow routine
|
|
|
|
*
|
|
|
|
* @param Context
|
|
|
|
*
|
|
|
|
* @param Event
|
|
|
|
*
|
|
|
|
* @param StackOverflowRoutine
|
|
|
|
*
|
|
|
|
* @return
|
|
|
|
*
|
|
|
|
* @remarks None.
|
|
|
|
*
|
|
|
|
*--*/
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
FsRtlPostStackOverflow(IN PVOID Context,
|
|
|
|
IN PKEVENT Event,
|
|
|
|
IN PFSRTL_STACK_OVERFLOW_ROUTINE StackOverflowRoutine)
|
|
|
|
{
|
2013-05-01 10:54:02 +00:00
|
|
|
FsRtlpPostStackOverflow(Context, Event, StackOverflowRoutine, FALSE);
|
2009-10-12 03:35:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|