Compartir a través de


Gestión de handles

Una fuente significativa de problemas de seguridad dentro de los controladores es el uso de identificadores pasados entre los componentes del modo de usuario y el modo kernel. Hay varios problemas conocidos sobre el uso de handles en el entorno del kernel, incluidos los siguientes:

  • Una aplicación que pasa el tipo incorrecto de identificador a un controlador de kernel. Es posible que el controlador de kernel se bloquee al intentar usar un objeto de evento en el que se necesita un objeto de archivo.

  • Una aplicación que pasa un identificador a un objeto para el que no tiene el acceso necesario. El controlador de kernel puede realizar una operación que funcione porque la llamada procede del modo kernel, aunque el usuario no tenga los permisos adecuados para hacerlo.

  • Una aplicación que pasa un valor que no es un identificador válido en su espacio de direcciones, pero lo clasifica como identificador del sistema para realizar una operación malintencionada contra el sistema.

  • Aplicación que pasa un valor que no es un identificador adecuado para el objeto de dispositivo (un identificador que este controlador no creó).

Para protegerse contra estos problemas, un controlador del kernel debe tener especial cuidado para garantizar que los identificadores que recibe sean válidos. La política más segura consiste en crear los identificadores necesarios en el contexto del controlador. Estos identificadores, creados por controladores de kernel, deben especificar la opción OBJ_KERNEL_HANDLE, que creará un identificador válido en contexto de proceso arbitrario y uno al que solo se puede acceder desde un llamador en modo kernel.

En el caso de los controladores que utilizan identificadores creados por un programa de aplicación, se debe tener mucho cuidado al usar estos identificadores.

  • El procedimiento recomendado consiste en convertir el identificador en un puntero de objeto mediante una llamada a ObReferenceObjectByHandle, especificando los parámetros AccessMode correctos (normalmente desde Irp-RequestorMode>), DesiredAccess y ObjectType , como IoFileObjectType o ExEventObjectType.

  • Si se debe usar un identificador directamente dentro de una llamada, es mejor usar las variantes Nt de funciones en lugar de las variantes Zw de las funciones. Esto aplicará la comprobación de parámetros y controlará la validación por parte del sistema operativo, ya que el modo anterior será UserMode y, por tanto, no es de confianza. Tenga en cuenta que los parámetros pasados a las funciones Nt que son punteros pueden producir un error de validación si el modo anterior es UserMode. Las rutinas Nt y Zw devuelven un parámetro IoStatusBlock con información de error que debe comprobar si hay errores.

  • Los errores deben quedar atrapados adecuadamente, así como usar __try y __except según sea necesario. Muchas de las rutinas de la biblioteca de tiempo de ejecución del sistema de archivos (FsRtl), administrador de caché (Cc) y administrador de memoria (Mm) generan una excepción cuando se produce un error.

Ningún controlador nunca debe basarse en identificadores o parámetros pasados desde una aplicación en modo de usuario sin tomar las precauciones adecuadas.

Tenga en cuenta que si se usa la variante Nt para abrir un archivo, la variante Nt también debe usarse para cerrar el archivo.