Программирование систем защиты

         

Отмена запросов ввода/вывода

Всякий раз, когда запрос ввода/вывода удерживается драйвером в течение продолжительного отрезка времени, драйвер должен быть готов к отмене данного запроса. В случае закрытия потока диспетчер ввода/вывода пытается отменить все запросы ввода/вывода, отправленные этим потоком и еще не завершенные. Пока все такие запросы ввода/вывода не будут завершены устройством, ему не придет запрос IRP_MJ_ CLOSE, и, следовательно, не освободится объект-файл, а впоследствии - и само устройство (драйвер никогда не получит запрос DriverUnload).
Для обеспечения отмены запроса ввода/вывода в пакете IRP, представляющем такой запрос, должен быть указан адрес диспетчерской точки входа драйвера, собственно отменяющей запрос. Для этого служит функция IoSetCancelRoutine().

PDRIVER_CANCEL loSetCancelRoutine(IN PIRP Irp,
PDRIVER_CANCEL CancelRoutine) ;

Где функция CancelRoutine() имеет такой же прототип, как и все диспетчерские функции.

VOID CancelRoutine(IN PDEVICE_OBJECT




DeviceObject,
IN PIRP Irp) ;

Она вызывается на уровне IRQL DISPATCH_LEVEL в случайном контексте потока, однако перед ее вызовом происходит захват специальной системной спин-блокировки. До тех пор, пока системная спин-блокировка не будет освобождена, функция CancelRoutine() работает на уровне IRQL DISPATCH_LEVEL. Уровень IRQL, на который нужно перейти после освобождения блокировки указывается при вызове IoReleaseCancelSpinLock() (см. ниже). Принцип реализации функции следующий:

  • Если указанный пакет IRP не может быть отменен или не принадлежит драйверу, то надо освободить системную спин-блокировку и завершить работу функции.
  • В противном случае:
  1. 1. удалить пакет IRP из любых очередей, в которых он присутствует;
  2. 2. установить функцию отмены IRP в NULL с помощью IoSetCancelRoutine();
  3. 3. освободить системную спин-блокировку;
  4. 4. установить в IRP поле loStatus.Information равном 0, а поле loStatus.Status равном STATUS_CANCELLED;
  5. 5. завершить IRP с помощью loCompleteRequest().

Системная спин-блокировка отмены IRP освобождается с помощью loRelease CancelSpinLock():

VOID IoReleaseCancelSpinLock(IN KIRQL Irgl);

Где: Irql - уровень IRQL, на который система должна вернуться после освобождения спин-блокировки. Это значение хранится в IRP в поле Cancellrql.

Отмена IRP и Системная Очередь

Пример функции отмены IRP драйвера, использующего системную очередь, показан в следующем листинге. Необходимо отметить, что для удаления IRP из системной очереди используется функция KeRemoveEntryDeviceQueue() так, как это показано в листинге.

VOID Cancel(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {
// Обрабатывается ли отменяемый запрос в данный момент?
if (Irp == DeviceOb]ect->Current!rp)
{
// Да. Освободить системную спин-блокировку и указать
// диспетчеру ввода/вывода начать обработку следующего
// пакета. Отмена IRP - в конце функции
loReleaseCancelSpinLock(Irp->CancelIrql);
loStartNextPacket(DeviceOb]ect, TRUE); }
else {
// Нет. Отменяемый IRP находится в очереди. // Удалить его из очереди
KeRemoveEntryDeviceQueue(SDeviceOb]ect->DeviceQueue, &Irp->Tail.Overlay.DeviceQueueEntry);
loReleaseCancelSpinLock(Irp->CancelIrql); }
// Отменить IRP
Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; loCompleteRequest(Irp, IO_NO_INCREMENT); return; }

Отмена IRP и очереди, управляемые драйвером

VOID Cancel(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) { '
PIRP irpToCancel;
PDEVICE_EXT devExt;
KIRQL oldlrql;
// обнулить указатель на функцию отмены loSetCancelRoutine(Irp, NULL); // Освободить системную спин-блокировку // как можно быстрее
loReleaseCancelSpinLock(Irp->CancelIrql); devExt = DeviceObject->DeviceExtension; . // Захватить спин-блокировку доступа к очереди, // удалить IRP и освободить // спин-блокировку KeAcquireSpinLock(&devExt->QueueLock, soldlrql);
RemoveEntryList(&Irp->Tail.Overlay.ListEntry); KeReleaseSpinLock(&devExt->QueueLock, oldlrql) ;
// Отменить IRP
Irp->IoStatus Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; loCompleteRequest(Irp, IO_NO_INCREMENT);

Содержание раздела