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 syscall alcanzable 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 execve si el programa normalmente lo hace).
  • Para binarios estáticos, los atacantes no pueden hacer ROP hacia syscalls que el programa nunca usó (por ejemplo, execve si 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 syscall en 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 MAX permite 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 npins a -1, que se recorta a un valor positivo pequeño antes de la asignación.
  • 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.