Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
El problema de E/S directa más común es no controlar correctamente los búferes de longitud cero. Dado que el administrador de E/S no crea MDL para transferencias de longitud cero, un búfer de longitud cero da como resultado un valor NULL en Irp-MdlAddress>.
Para asignar el espacio de direcciones, los controladores deben usar MmGetSystemAddressForMdlSafe, que devuelve NULL si se produce un error en la asignación, tal como ocurrirá si un controlador pasa un NULLMdlAddress. Los controladores siempre deben comprobar si hay un valor NULL antes de intentar usar la dirección devuelta.
La E/S directa implica la asignación doble del espacio de direcciones del usuario a un búfer de direcciones del sistema, de modo que dos direcciones virtuales diferentes tengan la misma dirección física. La asignación doble tiene las siguientes consecuencias, que a veces pueden causar problemas para los conductores:
El desplazamiento en la página virtual de la dirección del usuario se convierte en el desplazamiento en la página del sistema.
El acceso más allá del final de estos búferes del sistema puede pasar desapercibido durante largos períodos de tiempo, dependiendo de la granularidad de página de la asignación de memoria. A menos que un llamante asigne su búfer cerca del final de una página, los datos escritos más allá del final del búfer seguirán apareciendo en él, y el llamante no será consciente de que se ha producido un error. Si el final del búfer coincide con el final de una página, las direcciones virtuales del sistema más allá de este límite podrían apuntar a cualquier cosa o podrían no ser válidas. Estos problemas pueden ser extremadamente difíciles de encontrar.
Si el proceso de llamada tiene otro subproceso que modifica la asignación del usuario de la memoria, el contenido del búfer del sistema cambiará cuando cambie la asignación de memoria del usuario.
En esta situación, el uso del búfer del sistema para almacenar datos temporales puede causar problemas. Dos capturas de la misma ubicación de memoria pueden producir valores diferentes.
El siguiente fragmento de código recibe una cadena en una solicitud de E/S directa y, a continuación, intenta convertir esa cadena en caracteres en mayúsculas:
PWCHAR PortName = NULL; PortName = (PWCHAR)MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority); // // Null-terminate the PortName so that RtlInitUnicodeString will not // be invalid. // PortName[Size / sizeof(WCHAR) - 1] = UNICODE_NULL; RtlInitUnicodeString(&AdapterName, PortName);Dado que es posible que el búfer no se haya formado correctamente, el código intenta forzar un valor NULL Unicode como último carácter de búfer. Sin embargo, si la memoria física subyacente se asigna de forma doble tanto a una dirección de usuario como a una dirección de modo kernel, otro subproceso del proceso puede sobrescribir el búfer en cuanto se complete esta operación de escritura.
Por el contrario, si el valor NULL no está presente, la llamada a RtlInitUnicodeString puede superar el intervalo del búfer y, posiblemente, provocar una comprobación de errores si se encuentra fuera de la asignación del sistema.
Si un controlador crea y mapea su propia MDL, debe asegurarse de que accede a la MDL solo con el método para el que ha sondado. Es decir, cuando el controlador llama a MmProbeAndLockPages, especifica un método de acceso (IoReadAccess, IoWriteAccess o IoModifyAccess). Si el controlador especifica IoReadAccess, no debe intentar escribir en el búfer del sistema disponible por MmGetSystemAddressForMdl o MmGetSystemAddressForMdlSafe.