BookinglyTech News
Software

Un bug en el kernel de iOS hace que los sockets UNIX cambien de inodo tras el primer arranque

Un investigador encontró que fstat() devuelve inodos inconsistentes en los UNIX domain sockets de iOS debido a un incremento post-fijo en una variable global.

2 min de lecturaLobsters0 vistas

Durante una charla en DEFCON 34, la demo de un exploit de elevación de privilegios se cayó en el escenario. Tras resolver el problema inicial de la presentación, el autor investigó el fallo y descubrió un comportamiento extraño en el kernel de iOS: los sockets de dominio UNIX no mantenían un identificador de nodo (inodo) estable.

El proyecto consiste en una máquina virtual dentro de una app de iOS que ejecuta un servidor SSH. Dado que iOS no permite crear procesos hijos, la VM emula la semántica de multiproceso usando hilos. Para gestionar las terminales (TTY), el código crea pares de sockets de dominio UNIX conectados entre sí y gestiona la señalización en espacio de usuario. El fallo ocurría siempre tras el primer arranque del dispositivo, nunca en sesiones posteriores, descartando causas como ASLR o condiciones de carrera no deterministas.

Al depurar, el autor notó que una llamada a fstat() sobre un extremo del socket devolvía un inodo, y una segunda llamada sobre el mismo descriptor devolvía un inodo diferente. La corrupción de memoria parecía improbable, así que revisó el código del kernel.

El bug reside en la función uipc_sense() de /bsd/kern/uipc_usrreq.c. Esta función rellena el campo st_ino de la estructura stat. El código asigna un inodo al socket de forma perezosa la primera vez que se llama a stat, usando la variable global unp_ino.

El error es sutil: el código utiliza unp_ino++ en lugar de ++unp_ino. Como la variable global se inicializa a cero, la primera llamada del sistema entero devuelve 0 como inodo. Sin embargo, la lógica interna asume que un valor de 0 significa "inodo no inicializado". Por tanto, la segunda llamada a stat sobre el mismo socket detecta el 0, asume que es el primer uso y asigna un nuevo inodo incrementando el contador global. Esto hace que el inodo cambie bajo los pies de las aplicaciones que dependen de su consistencia, causando el pánico en la VM.

Es un fallo clásico de of-by-one en lógica de inicialización más que una vulnerabilidad de seguridad tradicional, pero expone una fragilidad en la implementación de los sockets UNIX en el kernel de Apple. Para cualquier desarrollador que trabaje con IPC en iOS, es una lección sobre las limitaciones del sistema y la importancia de no asumir que los identificadores del kernel son inmutables si el comportamiento es anómalo.