Compartir a través de


Error al comprobar el tamaño de los búferes

Al controlar las E/S por segundo y las E/S almacenadas en búfer, un controlador siempre debe comprobar los tamaños de los búferes de entrada y salida para asegurarse de que los búferes pueden contener todos los datos solicitados. Si la solicitud especifica FILE_ANY_ACCESS, como hacen la mayoría de los IOCTLs y FSCTLs del controlador, cualquier autor de llamada que tenga un identificador para el dispositivo tiene acceso a las solicitudes IOCTL o FSCTL almacenadas en búfer para ese dispositivo, y podría leer o escribir datos más allá del final del búfer.

Tamaño del búfer de entrada

Por ejemplo, supongamos que el código siguiente aparece en una rutina a la que se llama desde una rutina dispatch y que el controlador no ha validado los tamaños de búfer pasados en el IRP:

   switch (ControlCode)
      ...
      ...
      case IOCTL_NEW_ADDRESS:{
         tNEW_ADDRESS *pNewAddress = 
            pIrp->AssociatedIrp.SystemBuffer;

         pDeviceContext->Addr = RtlUlongByteSwap (pNewAddress->Address);

En el ejemplo no se comprueban los tamaños del búfer antes de la instrucción de asignación (resaltada). Como resultado, la referencia pNewAddress-Address> en la siguiente línea puede producir un error si el búfer de entrada no es lo suficientemente grande como para contener una estructura de tNEW_ADDRESS.

El código siguiente comprueba los tamaños del búfer, lo que evita el posible problema:

   case IOCTL_NEW_ADDRESS: {
      tNEW_ADDRESS *pNewAddress =
         pIrp->AssociatedIrp.SystemBuffer;

      if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength >=
             sizeof(tNEW_ADDRESS)) {
         pDeviceContext->Addr = RtlUlongByteSwap (pNewAddress->Address);

El código para controlar otras E/S almacenadas en búfer, como las solicitudes WMI que usan búferes de tamaño variable, pueden tener errores similares.

Tamaño del búfer de salida

Los problemas del búfer de salida son similares a los problemas del búfer de entrada. Pueden dañar fácilmente el grupo y los autores de llamadas en modo de usuario pueden no tener en cuenta que se ha producido cualquier error.

En el ejemplo siguiente, el controlador no puede comprobar el tamaño de SystemBuffer:

   case IOCTL_GET_INFO: {

       Info = Irp->AssociatedIrp.SystemBuffer;

       Info->NumIF = NumIF;
       ...
       ...
       Irp->IoStatus.Information =
             NumIF*sizeof(GET_INFO_ITEM)+sizeof(ULONG);
       Irp->IoStatus.Status = ntStatus;
   }

Suponiendo que el campo NumIF del búfer del sistema especifica el número de elementos de entrada, este ejemplo puede establecer IoStatus.Information en un valor mayor que el búfer de salida y, por tanto, devolver demasiada información al código en modo de usuario. Si una aplicación está codificada incorrectamente y llama a con un búfer de salida demasiado pequeño, el código anterior podría dañar el grupo escribiendo más allá del final del búfer del sistema.

Recuerde que el administrador de E/S supone que el valor del campo Información es válido. Si un llamador pasa una dirección en modo kernel válida para el búfer de salida y un tamaño de cero bytes, pueden producirse problemas graves si el controlador no comprueba el tamaño del búfer de salida y, por tanto, encuentra el error.