Condividi tramite


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.