La computación distribuida trata sobre el tiempo y el estado. Es decir, para que más de un componente se comunique, debe compartir el estado, y todo esto requiere tiempo.
La mayoría de programadores antropomorfizan su trabajo. Piensan en un único puesto de control que lleva a cabo todo el programa de igual forma que harían ellos si tuviesen que realizar la tarea ellos mismos. Sin embargo, los equipos modernos cambian entre tareas con gran rapidez y, en una CPU múltiple con varios núcleos, o en los sistemas distribuidos, dos eventos pueden llevarse a cabo a la vez exactamente. Estos defectos hacen que sea urgente que se unan posturas entre el modelo de los programadores sobre cómo un programa se ejecuta y lo que sucede en la realidad. Dichos defectos están relacionados con interacciones inesperadas entre los puestos, los procesos, el tiempo y la información. Estas interacciones se producen a través del estado compartido: semáforos, variables, el sistema de archivos y, básicamente, cualquier cosa que pueda guardar información.
Race Condition: File System Access
1. El programa comprueba una propiedad en un archivo, referenciando el archivo por su nombre.
2. A continuación el programa realiza una operación de sistema del archivo utilizando el mismo nombre de archivo y asume que la propiedad que ya se comprobó anteriormente no ha cambiado.
Ejemplo: El siguiente programa llama la rutina de
CBL_CHECK_FILE_EXIST
para comprobar si el archivo existe antes de crear uno y lleva a cabo las operaciones necesarias.
CALL "CBL_CHECK_FILE_EXIST" USING
filename
file-details
RETURNING status-code
END-CALL
IF status-code NOT = 0
MOVE 3 to access-mode
MOVE 0 to deny-mode
MOVE 0 to device
CALL "CBL_CREATE_FILE" USING
filename
access-mode
deny-mode
device
file-handle
RETURNING status-code
END-CALL
END-IF
La llamada a
CBL_CHECK_FILE_EXIST
se comporta tal y como se esperaba y devuelve un valor distinto de cero, que indica que el archivo no existe. Sin embargo, dado que tanto CBL_CHECK_FILE_EXIST
como CBL_CREATE_FILE
operan sobre los nombres de los archivos y no sobre los identificadores, no hay garantía de que la variable filename
todavía se refiera al mismo archivo en el disco cuando se pase a CBL_CREATE_FILE
que era cuando se pasó a CBL_CHECK_FILE_EXIST
. Si un atacante crea un filename
después de la llamada a CBL_CHECK_FILE_EXIST
, la llamada a CBL_CREATE_FILE
fallará, lo que llevará al programa a creer que el archivo está vacío, cuando de hecho este contiene datos controlados por el atacante.La ventana de vulnerabilidad para un ataque de esta naturaleza se da en el período de tiempo entre cuando una propiedad de archivo se comprueba y cuando el archivo se usa. Incluso si el uso se produce inmediatamente después de la comprobación, los sistemas de operación modernos no garantizan la cantidad de código que se ejecuta antes de que el proceso abandona la CPU. Los atacantes disponen de una amplia variedad de técnicas para expandir la longitud de la ventana de oportunidad para que sea más fácil de explotar. Sin embargo, incluso con una ventana pequeña, un intento de ataque puede repetirse una y otra vez hasta que tiene éxito.
Además, este tipo de vulnerabilidad se puede aplicar a un programa con privilegios de
root
que realiza ciertas operaciones de archivo en nombre de usuarios no privilegiados, y usa comprobaciones de acceso para asegurar que este no usa sus privilegios origen para realizar operaciones que no deberían estar disponibles para el usuario actual. Engañando al programa para que realice una operación que no sería permisible de otro modo, el atacante puede ganar ciertos privilegios superiores.