Accesso ai buffer utente in una routine di callback postperation
Una routine di callback del driver minifilter deve trattare un buffer in un'operazione di I/O basata su IRP come indicato di seguito:
Verificare se esiste un MDL per il buffer. Il puntatore MDL è disponibile nel parametro MdlAddress o OutputMdlAddress nella FLT_PARAMETERS per l'operazione. I driver minifilter possono chiamare FltDecodeParameters per eseguire query per il puntatore MDL.
Un metodo per ottenere un MDL valido consiste nel cercare il flag di IRP_MN_MDL nel membro MinorFunction del blocco di parametri I/O, FLT_IO_PARAMETER_BLOCK, nei dati di callback. Nell'esempio seguente viene illustrato come verificare la presenza del flag di IRP_MN_MDL.
NTSTATUS status; PMDL *ReadMdl = NULL; PVOID ReadAddress = NULL; if (FlagOn(CallbackData->Iopb->MinorFunction, IRP_MN_MDL)) { ReadMdl = &CallbackData->Iopb->Parameters.Read.MdlAddress; }
Tuttavia, il flag di IRP_MN_MDL può essere impostato solo per le operazioni di lettura e scrittura. È consigliabile usare FltDecodeParameters per recuperare un MDL, perché la routine verifica una MDL valida per qualsiasi operazione. Nell'esempio seguente viene restituito solo il parametro MDL se valido.
NTSTATUS status; PMDL *ReadMdl = NULL; PVOID ReadAddress = NULL; status = FltDecodeParameters(CallbackData, &ReadMdl, NULL, NULL, NULL);
Se esiste un MDL per il buffer, chiamare MmGetSystemAddressForMdlSafe per ottenere l'indirizzo di sistema per il buffer e quindi usare questo indirizzo per accedere al buffer. (MmGetSystemAddressForMdlSafe può essere chiamato in IRQL <= DISPATCH_LEVEL.)
Continuando dall'esempio precedente, il codice seguente ottiene l'indirizzo di sistema.
if (*ReadMdl != NULL) { ReadAddress = MmGetSystemAddressForMdlSafe(*ReadMdl, NormalPagePriority); if (ReadAddress == NULL) { CallbackData->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; CallbackData->IoStatus.Information = 0; } }
Se non è presente MDL per il buffer, verificare se il flag del buffer di sistema è impostato per l'operazione usando la macro FLT_IS_SYSTEM_BUFFER .
Se la macro FLT_IS_SYSTEM_BUFFER restituisce TRUE, l'operazione usa l'I/O con buffer e il buffer può essere accessibile in modo sicuro in IRQL = DISPATCH_LEVEL.
Se la macro FLT_IS_SYSTEM_BUFFER restituisce FALSE, il buffer non può essere accessibile in modo sicuro in IRQL = DISPATCH_LEVEL. Se la routine di callback postperazione può essere chiamata in DISPATCH_LEVEL, deve chiamare FltDoCompletionProcessingWhenSafe per pennare l'operazione fino a quando non può essere elaborata in IRQL <= APC_LEVEL. La routine di callback a cui punta il parametro SafePostCallback di FltDoCompletionProcessingWhenSafe deve prima chiamare FltLockUserBuffer per bloccare il buffer e quindi chiamare MmGetSystemAddressForMdlSafe per ottenere l'indirizzo di sistema per il buffer.
Una routine di callback di postperazione deve trattare un buffer in un'operazione di I/O veloce come segue:
Usare l'indirizzo del buffer per accedere al buffer perché un'operazione di I/O rapida non può avere un MDL.
Per assicurarsi che un indirizzo del buffer dello spazio utente sia valido, il driver minifilter deve usare una routine, ad esempio ProbeForRead o ProbeForWrite, racchiudendo tutti i riferimenti al buffer in prova/ad eccezione dei blocchi.
La routine di callback di postperazione per un'operazione di I/O veloce è garantita la chiamata nel contesto del thread corretto.
La routine di callback di postperazione per un'operazione di I/O veloce è garantita la chiamata a IRQL <= APC_LEVEL, in modo da poter chiamare in modo sicuro routine come FltLockUserBuffer.
Il frammento di codice di esempio seguente controlla il buffer di sistema o i flag di I/O veloci per un'operazione di controllo della directory e deferare l'elaborazione del completamento, se necessario.
if (*DirectoryControlMdl == NULL)
{
if (FLT_IS_SYSTEM_BUFFER(CallbackData) || FLT_IS_FASTIO_OPERATION(CallbackData))
{
dirBuffer = CallbackData->Iopb->Parameters.DirectoryControl.QueryDirectory.DirectoryBuffer;
}
else
{
// Defer processing until safe.
if (!FltDoCompletionProcessingWhenSafe(CallbackData, FltObjects, CompletionContext, Flags, ProcessPostDirCtrlWhenSafe, &retValue))
{
CallbackData->IoStatus.Status = STATUS_UNSUCCESSFUL;
CallbackData->IoStatus.Information = 0;
}
}
}
Per le operazioni che possono essere veloci I/O o basate su IRP, tutti i riferimenti al buffer devono essere racchiusi tra iblocchidi prova/. Anche se non è necessario racchiudere questi riferimenti per le operazioni basate su IRP che usano I/O con buffer, il tentativo/tranne i blocchi è una precauzione sicura.