OpenBSD – fijar todos los syscalls del sistema
La nueva función de “fijación” de syscalls de OpenBSD —que restringe desde dónde y cuáles llamadas al sistema puede invocar un binario— está generando debate sobre cuánta protección real ofrece frente a técnicas de explotación modernas como ROP, y si solo refuerza vías de ataque ya poco comunes. Los comentaristas comparan el historial de mitigaciones proactivas, a veces especulativas, de OpenBSD con preocupaciones sobre la complejidad añadida, los modelos de amenazas poco claros y el hallazgo de un desbordamiento de búfer en esta misma implementación. El hilo también aborda cuestiones más amplias de ingeniería de seguridad, incluida la dependencia de C frente a la adopción de Rust o de comprobaciones más fuertes del compilador, y cómo medir el valor de mitigaciones que pueden prevenir, y no solo corregir, vulnerabilidades.
Alcance del nuevo anclaje de syscalls
- El kernel ahora restringe los syscalls de forma más estricta:
- Antes: los syscalls solo se permitían desde la región de texto de libc de los procesos.
- Ahora: se fijan a stubs de syscall específicos de libc.
- Para binarios estáticos: solo se permiten los syscalls que realmente se referencian en el binario; los demás quedan efectivamente deshabilitados.
- El .text del programa ya no puede ejecutar syscalls directamente; deben pasar por libc (o por ld.so durante el arranque).
- Los runtimes de lenguaje normalmente llaman a libc, así que siguen siendo utilizables; los runtimes “raros” o JITs que sintetizan syscalls en bruto en tiempo de ejecución pueden quedar bloqueados.
Impacto en seguridad y técnicas de explotación
- El anclaje reduce parte de la libertad de ROP/JOP:
- Ya no puedes convertir cualquier instrucción
syscallalcanzable en un syscall arbitrario; solo se permite el número de syscall registrado. - Aun así, puedes abusar de los argumentos del syscall permitido (por ejemplo, seguir llamando a
execvesi el programa normalmente lo hace).
- Ya no puedes convertir cualquier instrucción
- Para binarios estáticos, los atacantes no pueden hacer ROP hacia syscalls que el programa nunca usó (por ejemplo,
execvesi no está presente), lo que se ve como una contención útil. - Los JITs todavía pueden saltar a thunks de syscall permitidos; normalmente JavaScript en el navegador no hace syscalls directamente de todos modos.
- Otro efecto de mitigación: restringir los syscalls a libc complica la evasión de ASLR cuando un atacante solo conoce el layout del binario principal y busca patrones
syscallen el texto.
Debate sobre eficacia y modelado de amenazas
- Puntos de vista favorables:
- Si la mitigación es barata y no añade superficie de ataque, vale la pena incluirla.
- OpenBSD históricamente ha desplegado mitigaciones antes de que las clases de ataques fueran públicas (por ejemplo, desactivar hyperthreading antes de Spectre/Meltdown; aleatoriedad “innecesaria” que luego bloqueó ataques a la caché DNS).
- Los bajos recuentos de CVE y las mitigaciones que anticipan vulnerabilidades se citan como evidencia de buena intuición.
- Puntos de vista escépticos:
- Se critican las mitigaciones sin una relación explícita con exploits/CVEs del mundo real y cadenas de explotación probadas, por ser “amorfas” y potencialmente “teatro de seguridad”.
- Cada mitigación añade complejidad y coste de mantenimiento a largo plazo; sin un modelo de amenazas claro, esto puede degradar la seguridad en general.
- Algunos argumentan que, si una mitigación no frena claramente técnicas actuales en uso real, es sobre todo un ejercicio académico.
- Otros responden que centrarse estrechamente en “CVEs corregidos” recompensa errores pasados y subestima los fallos evitados.
Error de implementación descubierto
- Se encuentra un bug trivial pero real en el nuevo código:
- La mezcla de signed/unsigned en una macro
MAXpermite a un atacante empujar un conteo interno (npins) a negativo, lo que lleva a una subasignación y escrituras fuera de límites en el heap indexadas por números de syscall controlados por el atacante. - Un esquema de exploit de ejemplo usa entradas de una tabla de “syscalls fijados” manipuladas para primero envenenar la memoria y luego forzar
npinsa -1, que se recorta a un valor positivo pequeño antes de la asignación.
- La mezcla de signed/unsigned en una macro
- Discusión sobre herramientas:
- Algunos señalan que comprobaciones de enteros y tipado al estilo Rust podrían haber evitado esta clase de bug.
- Otros apuntan que los compiladores de C ya tienen flags (por ejemplo, avisos de comparación con signo, sanitizers, trampas de overflow) que podrían haberlo detectado, pero no están habilitados de forma universal.
C vs. Rust y las limitaciones de OpenBSD
- Se elogia Rust por su semántica más segura para enteros y su comprobación de tipos, pero:
- OpenBSD tiene ~decenas de millones de líneas de C, muchas plataformas y muy poca mano de obra.
- Reescribir o integrar profundamente Rust en el código central del sistema operativo se ve como de alto riesgo y muy intensivo en recursos.
- Algunos sostienen que los nuevos sistemas operativos orientados a seguridad deberían empezar con Rust; otros enfatizan que Rust no es una bala de plata y que el código C maduro, junto con herramientas cuidadosas, puede seguir siendo viable.
Meta: postura de seguridad de OpenBSD y ecosistema
- Algunos participantes dicen que la base de usuarios de OpenBSD es demasiado pequeña como para que exista una “meta” de explotación rica y conocida empíricamente, así que mucho de esto se extrapola desde otras plataformas.
- Hay tensión entre:
- Quienes ven el eslogan y la reputación de OpenBSD como exagerados o engañosos.
- Quienes consideran que el trabajo sostenido de endurecimiento y la relativa escasez de agujeros graves bastan como justificación, y se muestran desconcertados por intentos agresivos de disuadir a otros de usarlo.