1 puntos por GN⁺ 2025-12-14 | 1 comentarios | Compartir por WhatsApp
  • La seguridad de memoria y el sandboxing son conceptos de seguridad independientes entre sí, y se necesita contar con ambos para formar una defensa sólida
  • Fil-C es una implementación con seguridad de memoria para C/C++, que garantiza seguridad hasta el nivel de llamadas al sistema de Linux y puede usarse incluso en componentes del sistema como OpenSSH
  • Durante el proceso de portar el sandbox basado en seccomp-BPF de OpenSSH a Fil-C, los desafíos clave fueron la limitación en la creación de hilos y el ajuste de los filtros de seccomp
  • Para la gestión de hilos en segundo plano del runtime de Fil-C, se agregó la API zlock_runtime_threads(), que controla el comportamiento de los hilos dentro del sandbox
  • Fil-C implementa la aplicación sincronizada de las llamadas a prctl en todos los hilos del runtime, para que no_new_privs y los filtros seccomp se apliquen de forma consistente a todo el proceso

Relación entre seguridad de memoria y sandboxing

  • La seguridad de memoria y el sandboxing son capas de seguridad distintas, y una sola no proporciona protección completa
    • Ejemplo de algo seguro en memoria pero sin sandbox: un programa en Java que puede sobrescribir archivos a través de la entrada del usuario
    • Ejemplo de algo con sandbox pero sin seguridad de memoria: un programa escrito en ensamblador con privilegios restringidos
  • Los sandboxes reales tienen puntos débiles estructurales, como permitir la comunicación con un proceso broker
  • Por eso, combinar seguridad de memoria y sandboxing es la mejor estrategia de defensa

Integración de Fil-C con el sandbox de OpenSSH

  • Fil-C es una implementación con seguridad de memoria para C/C++ que mantiene esa seguridad al nivel de llamadas al sistema de Linux
    • El runtime de Fil-C puede funcionar incluso en componentes de sistema de bajo nivel como init y udevd
    • OpenSSH funciona correctamente sobre Fil-C y aprovecha el sandbox seccomp-BPF
  • En Linux, OpenSSH construye su sandbox con las siguientes herramientas
    • chroot para restringir el acceso al sistema de archivos
    • ejecución con el usuario/grupo sshd
    • setrlimit para limitar la apertura de archivos y la creación de procesos
    • filtros seccomp-BPF para permitir solo las llamadas al sistema autorizadas
  • Fil-C admite por defecto chroot y el cambio de usuario, pero setrlimit y seccomp-BPF pueden entrar en conflicto con el comportamiento del runtime, por lo que se requirieron ajustes adicionales

Control de hilos en el runtime de Fil-C

  • El runtime de Fil-C usa hilos en segundo plano para el recolector de basura y los detiene o reinicia automáticamente cuando es necesario
  • El sandbox de setrlimit de OpenSSH busca prohibir la creación de nuevos procesos, por lo que la creación de hilos por parte del runtime puede violar esa restricción
  • Para resolverlo, se agregó la API zlock_runtime_threads() en <stdfil.h>
    • El runtime crea de inmediato los hilos que necesita y luego desactiva su finalización automática
    • Se ejecuta en la función ssh_sandbox_child de OpenSSH antes de llamar a setrlimit o seccomp-BPF

Ajustes al filtro seccomp de OpenSSH

  • Después de aplicar zlock_runtime_threads(), la mayor parte de las funciones del sandbox siguieron operando igual
  • En el filtro seccomp se hicieron los siguientes cambios
    • En caso de violación, se configuró SECCOMP_RET_KILL_PROCESS para terminar también los hilos en segundo plano de Fil-C
    • Se agregó MAP_NORESERVE a la lista permitida para soportar el uso del asignador de memoria de Fil-C
    • Se permitió la llamada a sched_yield, que se usa en la implementación de locks de Fil-C
  • Las llamadas futex de Fil-C para sincronización ya estaban permitidas, así que no hicieron falta más cambios

Implementación de prctl en Fil-C

  • OpenSSH usa dos llamadas a prctl al instalar el filtro seccomp
    • PR_SET_NO_NEW_PRIVS para bloquear la obtención de privilegios adicionales
    • PR_SET_SECCOMP, SECCOMP_MODE_FILTER para activar el filtro
  • El problema es que prctl solo se aplica al hilo que lo invoca, lo que deja el riesgo de que otros hilos del runtime de Fil-C queden sin filtro
  • Para evitarlo, Fil-C usa la API filc_runtime_threads_handshake() para aplicar la configuración de forma sincronizada a todos los hilos del runtime
    • Garantiza que cada hilo ejecute la misma llamada a prctl
    • Si existen varios hilos de usuario, genera un error de seguridad de Fil-C para reforzar la protección

Conclusión

  • Combinar seguridad de memoria y sandboxing es la combinación de seguridad más sólida
  • Fil-C integra por completo el sandbox basado en seccomp de OpenSSH sin reducir el nivel de protección y manteniendo la seguridad de memoria
  • En entornos Linux, usar Fil-C permite asegurar al mismo tiempo la seguridad a nivel de sistema y la seguridad a nivel de lenguaje

1 comentarios

 
GN⁺ 2025-12-14
Comentarios en Hacker News
  • Se preguntan por qué no hay ninguna mención de landlock

  • Existe un enfoque de compilación híbrido que va de C → WASM → C
    Esto permite controlar por completo la interacción con el SO y, al mismo tiempo, sandboxear el acceso a memoria como en WASM, aunque técnicamente siga siendo código C
    Se puede ver material relacionado en RLBox

    • Los sandboxes de WASM no garantizan la corrección (soundness) del programa
      Pueden corromper la memoria, pero el alcance queda limitado al interior del sandbox
      Sistemas como SECCOMP son burocráticos porque obligan a definir con mucho detalle todas las políticas de interacción
      En cambio, Fil-C adopta un enfoque donde el propio lenguaje y el runtime buscan garantizar el comportamiento correcto del programa
      Los binarios de Fil-C son ejecutables normales, así que también pueden usarse junto con sandboxes como SECCOMP
      A Linux le tomó 20 años crear la interfaz prctl, así que probablemente habrá que esperar 10 años para ver algo parecido en WASI
    • RLBox es una tecnología de sandboxing, no una tecnología de seguridad de memoria
      Incluso dentro del sandbox se pueden generar flujos de ejecución extraños
  • El autor de Fil-C suele hacer inventos técnicamente interesantes, pero preocupa si la implementación ha sido suficientemente validada
    Dijo que se pueden compilar programas setuid con Fil-C, pero la parte modificada de ld.so podría ser riesgosa
    Las apps setuid tienen que escribirse de forma muy defensiva respecto a variables de entorno, descriptores de archivo, rlimit, señales y más
    Esas partes todavía parecen incompletas, así que usarlo en infraestructura real implica riesgo
    Aun así, probar una base de código con Fil-C podría descubrir bugs interesantes

    • De hecho están probando si hay formas de romper Fil-C
    • Si de verdad preocupa, habría que experimentar directamente y compartir los resultados
    • El objetivo es hacer el runtime transparente para permitir su auditoría
      La modificación de ld.so es pequeña y básicamente sirve para enseñarle el layout de libc
      El bug de getenv relacionado con setuid ya se corrigió usando secure_getenv
      En lo señalado hay algo de verdad y algo de FUD
    • Decepciona la forma en que el autor de Fil-C responde a las críticas de manera poco colaborativa
      En situaciones de data races, en Fil-C podrían desalinearse los punteros y las capabilities
      Eso podría causar una violación de seguridad de memoria
      El autor lo niega, pero compararlo con Java no es apropiado
      La tecnología es excelente, pero la actitud del autor reduce la confianza
  • WASM es a la vez sandbox y entorno de ejecución, y según cómo se use puede ofrecer cierto grado de seguridad de memoria
    Si se compila C a WASM, los bugs siguen existiendo, pero su alcance queda limitado
    Por eso tiene sentido clasificar a WASM como tecnología de sandboxing, aunque como entorno de ejecución ofrece más posibilidades

    • WASM al final sí es una tecnología de sandboxing
      Un bug en el módulo B puede permitir leer datos del módulo A
      O sea, WASM no es más que un reemplazo de los sandboxes de procesos livianos
    • Decir “depende de cómo se use” ya es una prueba de que WASM no es completamente seguro
      Porque también podría decirse que C “es seguro dependiendo de cómo se use”
    • WASM no entiende el modelo de memoria de C, así que no puede implementar protecciones como las de Fil-C
      WASM evita escapar del runtime, pero no impide escapar de la memoria del programa interno
  • Piden una comparación entre Fil-C y Rust

    • Ambas tecnologías son excelentes, pero su enfoque es distinto
      Fil-C sirve para reforzar programas C existentes priorizando compatibilidad y seguridad
      Rust es mejor para crear codebases nuevas con seguridad estática y rendimiento
      Fil-C tiene una pequeña pérdida de rendimiento, pero es útil para código C existente (ffmpeg, nginx, sudo, etc.)
      Rust destaca por el multithreading y su sistema de tipos
    • Fil-C introduce GC, por lo que puede haber degradación de rendimiento
      Su objetivo no es mejorar el diseño del lenguaje, sino asegurar la seguridad de memoria
      Sus competidores se parecen más a D, Nim y Go que a Rust
    • Fil-C usa verificaciones en runtime para detectar accesos inseguros a memoria y detener el programa
      Rust los previene en tiempo de compilación
      Ambos enfoques son ortogonales, y a Rust también se le podrían añadir verificaciones en runtime al estilo Fil-C
  • Los MicroVM se están volviendo cada vez más populares
    Hay curiosidad por cómo Fil-C podría aprovechar eso

    • Haría falta algo de porting, pero parte de las funciones de un microVM podría subirse al userland seguro en memoria de Fil-C
  • Ojalá este proyecto reciba más atención
    Sería bueno que herramientas clave como sudo o polkit se distribuyeran con seguridad de memoria

  • También quisieran ver más uso de sandboxing incluso en lenguajes con seguridad de memoria
    Da pena que ni en Rust ni en Go se usen mucho los sandboxes a nivel de SO

    • Seccomp tiene mala portabilidad y composabilidad
      Es difícil configurarlo a nivel de librería y depende bastante de la versión del kernel o de la implementación de libc
      Además, tiene límites porque no puede filtrar entradas detrás de punteros, como rutas de archivo
      Por eso normalmente hay que configurarlo de forma manual a nivel de aplicación
    • Rust casi no tiene runtime, así que es adecuado para sandboxing
      En cambio, Go tiene un runtime grande y por eso es más difícil volverlo seguro como Fil-C
  • Preguntan en qué se diferencia Fil-C del Address Sanitizer (ASan) de clang
    Si solo produce un pánico en runtime, dicen, cuesta llamarlo “seguridad de memoria”

    • ASan detecta bien los bugs, pero no garantiza una seguridad de memoria completa
      Algunos bugs no los detecta
      Funciona dejando “red zones” alrededor de la memoria, así que a veces los detecta por suerte
    • Si un error de memoria se detiene con un pánico antes de causar efectos, eso también puede considerarse seguridad de memoria
      Seguridad de memoria no significa “no se cae”, sino “un acceso inválido no logra producir efectos”
  • Preguntan por qué no usar una VM completa como sandbox

    • Las VM son excelentes sandboxes, pero apps como Chrome u OpenSSH necesitan separación de privilegios
      Un proceso analiza la entrada sin privilegios, y otro funciona con privilegios altos
      Ambos procesos se comunican por IPC
      Usar una VM mejora la seguridad, pero añade mucho overhead y complica cosas como el acceso a GPU o archivos
      Por eso, en general, el sandboxing a nivel de SO suele ser más limpio
    • Las VM resuelven la mayoría de los problemas, pero la aceleración gráfica de escritorio sigue siendo difícil
      Hay que asignar la GPU de forma dedicada, y Qubes también se conecta solo por reenvío X11, así que no tiene aceleración