Teoretycznie menadżer I/O mógłby wiedzieć z jakiej metody korzystasz gdybyś ustawił odopwiednią flagę w obiekcie urządzenia (w twoim przypadku nie ustawiał nic, bo chyba standardowo jest tak, że jeśli nie ustawisz flagi DO_BUFFERED_IO lub DO_DIRECT_IO to teoretycznie korzystasz z DO_NEITHER_IO (nie ma zdefiniowanej takiej flagi)). Niestety funkcja IopXxxControlFile nie korzysta z tej cennej informacji. Z drugiej jednak strony nie jest powiedziane, że twój driver będzie korzystał tylko z jednaj metody. Zazwyczaj jest tak, że do przesyłania dużych bloków używasz NEITHER lub DIRECT a do mniejszych BUFFERED. Tu jest fragment funkcji IopXxxControlFile, która nie sprawdza w żaden sposób czy zwrócony adres puli jest prawidłowy, czy nie, zamiast tego kod opakowany jest w __try/__except i generuje wyjątek gdy funkcja usiłuje skopiować coś pod NULL'a. Zatem durny użytkownik może generować żądania I/O przekazując kosmiczne rozmiary buforów a menadżer I/O i tak je zaakceptuje usiłując przydzielić zasób z góry nie możliwy do przydzielenia.
case METHOD_BUFFERED:
//
// For this case, allocate a buffer that is large enough to contain
// both the input and the output buffers. Copy the input buffer to
// the allocated buffer and set the appropriate IRP fields.
//
irpSp->Parameters.DeviceIoControl.Type3InputBuffer = (PVOID) NULL;
try {
if (InputBufferLength || OutputBufferLength) {
irp->AssociatedIrp.SystemBuffer =
ExAllocatePoolWithQuota( poolType,
(InputBufferLength > OutputBufferLength) ? InputBufferLength : OutputBufferLength );
if (ARGUMENT_PRESENT( InputBuffer )) {
RtlCopyMemory( irp->AssociatedIrp.SystemBuffer,
InputBuffer,
InputBufferLength );
}
irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
irp->UserBuffer = OutputBuffer;
if (ARGUMENT_PRESENT( OutputBuffer )) {
irp->Flags |= IRP_INPUT_OPERATION;
}
} else {
irp->Flags = 0;
irp->UserBuffer = (PVOID) NULL;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
//
// An exception was incurred while either allocating the
// the system buffer or moving the caller's data. Determine
// what actually happened, cleanup accordingly, and return
// an appropriate error status code.
//
IopExceptionCleanup( fileObject,
irp,
eventObject,
(PKEVENT) NULL );
return GetExceptionCode();
}
break;
lord_zero