Driver: Clear IRP's cancel routine before completion

This commit is contained in:
Nodir Temirkhodjaev 2023-04-28 08:09:31 +03:00
parent 4909074510
commit ada5f6857d
6 changed files with 58 additions and 32 deletions

View File

@ -2,7 +2,9 @@
#include "fortbuf.h"
#include "fortdev.h"
#include "forttrace.h"
#include "fortutl.h"
#define FORT_BUFFER_POOL_TAG 'BwfF'
@ -282,7 +284,7 @@ FORT_API NTSTATUS fort_buffer_xmove(
return status;
}
FORT_API NTSTATUS fort_buffer_cancel_pending(PFORT_BUFFER buf, PIRP irp, ULONG_PTR *info)
inline static NTSTATUS fort_buffer_cancel_pending(PFORT_BUFFER buf, PIRP irp, ULONG_PTR *info)
{
NTSTATUS status = STATUS_CANCELLED;
@ -308,6 +310,32 @@ FORT_API NTSTATUS fort_buffer_cancel_pending(PFORT_BUFFER buf, PIRP irp, ULONG_P
return status;
}
static void fort_device_cancel_pending(PDEVICE_OBJECT device, PIRP irp)
{
UNUSED(device);
ULONG_PTR info;
const NTSTATUS status = fort_buffer_cancel_pending(&fort_device()->buffer, irp, &info);
IoSetCancelRoutine(irp, NULL);
IoReleaseCancelSpinLock(irp->CancelIrql); /* before IoCompleteRequest()! */
fort_request_complete_info(irp, status, info);
}
FORT_API void fort_buffer_irp_mark_pending(PIRP irp)
{
IoMarkIrpPending(irp);
fort_irp_set_cancel_routine(irp, &fort_device_cancel_pending);
}
FORT_API void fort_buffer_irp_clear_pending(PIRP irp)
{
fort_irp_set_cancel_routine(irp, NULL);
}
FORT_API void fort_buffer_dpc_begin(PFORT_BUFFER buf, PKLOCK_QUEUE_HANDLE lock_queue)
{
KeAcquireInStackQueuedSpinLockAtDpcLevel(&buf->lock, lock_queue);

View File

@ -54,7 +54,9 @@ FORT_API NTSTATUS fort_buffer_proc_new_write(PFORT_BUFFER buf, UINT32 pid, UINT3
FORT_API NTSTATUS fort_buffer_xmove(
PFORT_BUFFER buf, PIRP irp, PVOID out, ULONG out_len, ULONG_PTR *info);
FORT_API NTSTATUS fort_buffer_cancel_pending(PFORT_BUFFER buf, PIRP irp, ULONG_PTR *info);
FORT_API void fort_buffer_irp_mark_pending(PIRP irp);
FORT_API void fort_buffer_irp_clear_pending(PIRP irp);
FORT_API void fort_buffer_dpc_begin(PFORT_BUFFER buf, PKLOCK_QUEUE_HANDLE lock_queue);

View File

@ -350,6 +350,7 @@ inline static void fort_callout_ale_by_conf(PCFORT_CALLOUT_ARG ca, PCFORT_CALLOU
fort_conf_ref_put(device_conf, conf_ref);
if (cx->irp != NULL) {
fort_buffer_irp_clear_pending(cx->irp);
fort_request_complete_info(cx->irp, STATUS_SUCCESS, cx->info);
}
}
@ -985,6 +986,7 @@ FORT_API void NTAPI fort_callout_timer(void)
fort_buffer_dpc_end(&buf_lock_queue);
if (irp != NULL) {
fort_buffer_irp_clear_pending(irp);
fort_request_complete_info(irp, STATUS_SUCCESS, info);
}
}

View File

@ -9,6 +9,7 @@
#include "fortps.h"
#include "fortscb.h"
#include "forttrace.h"
#include "fortutl.h"
static PFORT_DEVICE g_device = NULL;
@ -107,32 +108,6 @@ FORT_API NTSTATUS fort_device_cleanup(PDEVICE_OBJECT device, PIRP irp)
return STATUS_SUCCESS;
}
static void fort_device_cancel_pending(PDEVICE_OBJECT device, PIRP irp)
{
UNUSED(device);
ULONG_PTR info;
const NTSTATUS status = fort_buffer_cancel_pending(&fort_device()->buffer, irp, &info);
IoSetCancelRoutine(irp, NULL);
IoReleaseCancelSpinLock(irp->CancelIrql); /* before IoCompleteRequest()! */
fort_request_complete_info(irp, status, info);
}
static void fort_device_mark_pending(PIRP irp)
{
IoMarkIrpPending(irp);
KIRQL cirq;
IoAcquireCancelSpinLock(&cirq);
{
IoSetCancelRoutine(irp, &fort_device_cancel_pending);
}
IoReleaseCancelSpinLock(cirq);
}
static NTSTATUS fort_device_control_validate(const PFORT_CONF_VERSION conf_ver, ULONG len)
{
if (len == sizeof(FORT_CONF_VERSION)) {
@ -199,7 +174,13 @@ static NTSTATUS fort_device_control_getlog(PVOID out, ULONG out_len, PIRP irp, U
if (out_len < FORT_BUFFER_SIZE)
return STATUS_BUFFER_TOO_SMALL;
return fort_buffer_xmove(&fort_device()->buffer, irp, out, out_len, info);
const NTSTATUS status = fort_buffer_xmove(&fort_device()->buffer, irp, out, out_len, info);
if (status == STATUS_PENDING) {
fort_buffer_irp_mark_pending(irp);
}
return status;
}
inline static NTSTATUS fort_device_control_app_conf(
@ -320,9 +301,7 @@ FORT_API NTSTATUS fort_device_control(PDEVICE_OBJECT device, PIRP irp)
TRACE(FORT_DEVICE_DEVICE_CONTROL_ERROR, status, 0, 0);
}
if (status == STATUS_PENDING) {
fort_device_mark_pending(irp);
} else {
if (status != STATUS_PENDING) {
fort_request_complete_info(irp, status, info);
}

View File

@ -409,6 +409,19 @@ FORT_API UINT32 fort_bits_duplicate16(UINT16 num)
return fort_bits_duplicate8(num & 0xFF) | (fort_bits_duplicate8(num >> 8) << 16);
}
FORT_API void fort_irp_set_cancel_routine(PIRP irp, PDRIVER_CANCEL routine)
{
if (irp == NULL)
return;
KIRQL cirq;
IoAcquireCancelSpinLock(&cirq);
{
IoSetCancelRoutine(irp, routine);
}
IoReleaseCancelSpinLock(cirq);
}
static void NTAPI fort_expand_stack_call(PVOID context)
{
PFORT_EXPAND_STACK_ARG arg = context;

View File

@ -32,6 +32,8 @@ FORT_API BOOL fort_addr_is_local_broadcast(const UINT32 *ip, BOOL isIPv6);
FORT_API UINT32 fort_bits_duplicate16(UINT16 num);
FORT_API void fort_irp_set_cancel_routine(PIRP irp, PDRIVER_CANCEL routine);
FORT_API NTSTATUS fort_expand_stack(FORT_EXPAND_STACK_FUNC func, PVOID param);
#ifdef __cplusplus