¿Qué son vdso y vsyscall?
linux linux-kernel (2)
Hice sudo cat /proc/1/maps -vv
Estoy intentando dar sentido a la salida. Puedo ver muchas bibliotecas compartidas mapeadas al segmento de mapeo de memoria como se esperaba.
7f3c00137000-7f3c00179000 r-xp 00000000 08:01 21233923 /lib/x86_64-linux-gnu/libdbus-1.so.3.5.8
7f3c00179000-7f3c00379000 ---p 00042000 08:01 21233923 /lib/x86_64-linux-gnu/libdbus-1.so.3.5.8
7f3c00379000-7f3c0037a000 r--p 00042000 08:01 21233923 /lib/x86_64-linux-gnu/libdbus-1.so.3.5.8
7f3c0037a000-7f3c0037b000 rw-p 00043000 08:01 21233923 /lib/x86_64-linux-gnu/libdbus-1.so.3.5.8
7f3c0037b000-7f3c00383000 r-xp 00000000 08:01 21237216 /lib/x86_64-linux-gnu/libnih-dbus.so.1.0.0
7f3c00383000-7f3c00583000 ---p 00008000 08:01 21237216 /lib/x86_64-linux-gnu/libnih-dbus.so.1.0.0
7f3c00583000-7f3c00584000 r--p 00008000 08:01 21237216 /lib/x86_64-linux-gnu/libnih-dbus.so.1.0.0
7f3c00584000-7f3c00585000 rw-p 00009000 08:01 21237216 /lib/x86_64-linux-gnu/libnih-dbus.so.1.0.0
7f3c00585000-7f3c0059b000 r-xp 00000000 08:01 21237220 /lib/x86_64-linux-gnu/libnih.so.1.0.0
7f3c0059b000-7f3c0079b000 ---p 00016000 08:01 21237220 /lib/x86_64-linux-gnu/libnih.so.1.0.0
7f3c0079b000-7f3c0079c000 r--p 00016000 08:01 21237220 /lib/x86_64-linux-gnu/libnih.so.1.0.0
Hacia el final hay algo así como
7f3c0165b000-7f3c0177e000 rw-p 00000000 00:00 0 [heap]
7fff97863000-7fff97884000 rw-p 00000000 00:00 0 [stack]
7fff97945000-7fff97946000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
¿Qué significa vdso
y vsyscall
? ¿vsyscall es la porción del kernel de la memoria? Sería genial si alguien puede arrojar algo de luz sobre el tema.
Los segmentos vsyscall y vDSO son dos mecanismos utilizados para acelerar ciertas llamadas al sistema en Linux. Por ejemplo, gettimeofday
generalmente se invoca a través de este mecanismo. El primer mecanismo introducido fue vsyscall , que se agregó como una forma de ejecutar llamadas al sistema específicas que no necesitan ningún nivel real de privilegio para ejecutarse a fin de reducir la sobrecarga de llamadas del sistema. Siguiendo el ejemplo anterior, todo lo que gettimeofday
necesita hacer es leer la hora actual del kernel. Hay aplicaciones que llaman gettimeofday
frecuencia (por ejemplo, para generar marcas de tiempo), hasta el punto de que les importa incluso un poco de sobrecarga. Para abordar esta preocupación, el kernel mapea en el espacio de usuario una página que contiene la hora actual y una implementación rápida gettimeofday
(es decir, solo una función que lee el tiempo guardado en vsyscall ). Al usar esta llamada al sistema virtual, la biblioteca C puede proporcionar un tiempo de entrega rápido que no tiene la sobrecarga introducida por el cambio de contexto entre el espacio del kernel y el espacio de usuario generalmente introducido por el modelo de llamada del sistema clásico INT 0x80
o SYSCALL
.
Sin embargo, este mecanismo vsyscall tiene algunas limitaciones: la memoria asignada es pequeña y permite solo 4 llamadas al sistema, y, más importante y grave, la página vsyscall está asignada estáticamente a la misma dirección en cada proceso, ya que la ubicación de la página vsyscall es clavado en el kernel ABI. Esta asignación estática del vsyscall compromete el beneficio introducido por la asignación al azar del espacio de memoria comúnmente utilizada por Linux. Un atacante, después de comprometer una aplicación explotando un desbordamiento de pila, puede invocar una llamada al sistema desde la página vsyscall con parámetros arbitrarios. Todo lo que necesita es la dirección de la llamada al sistema, que es fácilmente predecible ya que está asignada estáticamente (si intenta ejecutar nuevamente su comando incluso con diferentes aplicaciones, notará que la dirección de vsyscall no cambia). Sería bueno eliminar o al menos aleatorizar la ubicación de la página vsyscall para frustrar este tipo de ataque. Lamentablemente, las aplicaciones dependen de la existencia y la dirección exacta de esa página, por lo que no se puede hacer nada.
Este problema de seguridad se ha solucionado reemplazando todas las instrucciones de llamada del sistema en direcciones fijas por una instrucción de captura especial. Una aplicación que intenta llamar a la página de vsyscall entrará en el núcleo, que luego emulará la llamada al sistema virtual deseada en el espacio del kernel. El resultado es una llamada al sistema kernel que emula una llamada al sistema virtual que se puso allí para evitar la llamada al sistema kernel en primer lugar. El resultado es un vsyscall que tarda más en ejecutarse pero, lo que es más importante, no rompe el ABI existente. En cualquier caso, la ralentización solo se verá si la aplicación está tratando de usar la página vsyscall en lugar de la vDSO .
El vDSO ofrece la misma funcionalidad que el vsyscall, al tiempo que supera sus limitaciones. El vDSO (objetos compartidos virtual dinámicamente vinculados) es un área de memoria asignada en el espacio de usuario que expone algunas funcionalidades del kernel en el espacio de usuario de manera segura. Esto se ha introducido para resolver las amenazas de seguridad causadas por vsyscall
. El vDSO se asigna dinámicamente para resolver problemas de seguridad y puede tener más de 4 llamadas al sistema. Los enlaces vDSO se proporcionan a través de la biblioteca glibc. El enlazador enlazará en la funcionalidad glibc vDSO , siempre que dicha rutina tenga una versión vDSO acompañante, como gettimeofday
. Cuando su programa se ejecuta, si su kernel no tiene soporte para vDSO , se realizará una llamada tradicional.
Créditos y enlaces útiles:
Solo quiero agregar que ahora en kernels nuevos, vDSO
no se usa solo para llamadas de sistema "seguras", sino que se usa para decidir qué mecanismo de syscall es el método preferido para invocar un syscall en el sistema.