Accès aux mémoires tampons utilisateur dans une routine de rappel de post-opération
Une routine de rappel post-opération du pilote minifiltre doit traiter une mémoire tampon dans une opération d’E/S basée sur IRP comme suit :
Vérifiez si une MDL existe pour la mémoire tampon. Le pointeur MDL se trouve dans le paramètre MdlAddress ou OutputMdlAddress dans le FLT_PARAMETERS de l’opération. Les pilotes de minifiltre peuvent appeler FltDecodeParameters pour interroger le pointeur MDL.
Une méthode pour obtenir un MDL valide consiste à rechercher l’indicateur IRP_MN_MDL dans le membre MinorFunction du bloc de paramètres d’E/S, FLT_IO_PARAMETER_BLOCK, dans les données de rappel. L’exemple suivant montre comment case activée pour l’indicateur 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; }
Toutefois, l’indicateur IRP_MN_MDL ne peut être défini que pour les opérations de lecture et d’écriture. Il est préférable d’utiliser FltDecodeParameters pour récupérer un MDL, car la routine recherche un MDL valide pour toute opération. Dans l’exemple suivant, seul le paramètre MDL est retourné s’il est valide.
NTSTATUS status; PMDL *ReadMdl = NULL; PVOID ReadAddress = NULL; status = FltDecodeParameters(CallbackData, &ReadMdl, NULL, NULL, NULL);
S’il existe un MDL pour la mémoire tampon, appelez MmGetSystemAddressForMdlSafe pour obtenir l’adresse système de la mémoire tampon, puis utilisez cette adresse pour accéder à la mémoire tampon. (MmGetSystemAddressForMdlSafe peut être appelé à l’adresse IRQL <= DISPATCH_LEVEL.)
Dans la continuité de l’exemple précédent, le code suivant obtient l’adresse système.
if (*ReadMdl != NULL) { ReadAddress = MmGetSystemAddressForMdlSafe(*ReadMdl, NormalPagePriority); if (ReadAddress == NULL) { CallbackData->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; CallbackData->IoStatus.Information = 0; } }
S’il n’existe pas de MDL pour la mémoire tampon, case activée si l’indicateur de mémoire tampon système est défini pour l’opération à l’aide de la macro FLT_IS_SYSTEM_BUFFER.
Si la macro FLT_IS_SYSTEM_BUFFER retourne TRUE, l’opération utilise des E/S mises en mémoire tampon et la mémoire tampon est accessible en toute sécurité à l’adresse IRQL = DISPATCH_LEVEL.
Si la macro FLT_IS_SYSTEM_BUFFER retourne FALSE, la mémoire tampon ne peut pas être accessible en toute sécurité à l’adresse IRQL = DISPATCH_LEVEL. Si la routine de rappel post-opération peut être appelée à DISPATCH_LEVEL, elle doit appeler FltDoCompletionProcessingWhenSafe pour arrêter l’opération jusqu’à ce qu’elle puisse être traitée à IRQL <= APC_LEVEL. Routine de rappel vers laquelle pointe le paramètre SafePostCallback de FltDoCompletionProcessingWhenSafe doit d’abord appeler FltLockUserBuffer pour verrouiller la mémoire tampon, puis appeler MmGetSystemAddressForMdlSafe pour obtenir l’adresse système de la mémoire tampon.
Une routine de rappel post-opération doit traiter une mémoire tampon dans une opération d’E/S rapide comme suit :
Utilisez l’adresse de mémoire tampon pour accéder à la mémoire tampon (car une opération d’E/S rapide ne peut pas avoir de MDL).
Pour garantir la validité d’une adresse de mémoire tampon d’espace utilisateur, le pilote de minifiltre doit utiliser une routine telle que ProbeForRead ou ProbeForWrite, en plaçant toutes les références de mémoire tampon dans try/, sauf les blocs.
La routine de rappel post-opération pour une opération d’E/S rapide est garantie d’être appelée dans le contexte de thread correct.
La routine de rappel post-opération pour une opération d’E/S rapide est garantie d’être appelée à IRQL <= APC_LEVEL, afin qu’elle puisse appeler en toute sécurité des routines telles que FltLockUserBuffer.
L’exemple de fragment de code suivant recherche la mémoire tampon système ou les indicateurs d’E/S rapides pour une opération de contrôle d’annuaire et reporte le traitement d’achèvement si nécessaire.
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;
}
}
}
Pour les opérations qui peuvent être basées sur des E/S rapides ou des IRP, toutes les références de mémoire tampon doivent être placées dans des blocs try/à l’exception des blocs. Bien que vous n’ayez pas à inclure ces références pour les opérations basées sur IRP qui utilisent des E/S mises en mémoire tampon, les blocs try/except constituent une précaution sûre.