En la conferencia SPLASH'24, Filip Pizlo presentó el compilador abierto C/C++ Fil-C, que proporciona protección contra problemas causados por errores al trabajar con la memoria. El proyecto tiene como objetivo garantizar la compatibilidad total con el código existente en los lenguajes C y C++; para garantizar un funcionamiento seguro con la memoria, basta con reconstruir el código existente. El compilador se construye utilizando componentes del proyecto LLVM y se distribuye bajo la licencia Apache 2.0. El tiempo de ejecución se suministra bajo la licencia BSD. A diferencia del proyecto TrapC recientemente anunciado, que aún se encuentra en su fase de diseño, el compilador Fil-C ya está listo para construir el código existente.
El proyecto también proporciona versiones seguras para la memoria de las bibliotecas estándar C (libc) y C++ (libc++), basadas en las bibliotecas Musl y LLVM libc++. Entre otras cosas, los programas creados pueden utilizar funciones como subprocesos múltiples, procesamiento de señales, mapeo de memoria (mmap), longjmp/setjmp y manejo de excepciones en C++. Con Fil-C, bzip2, zip, pcre y ncurses se pueden crear proyectos sin realizar ningún cambio. Con modificaciones menores, se admite la compilación de OpenSSH, OpenSSL, CPython, SQLite, Lua, Curl, Lynx, jpeg6b, zsh, xzutils y simdutf.
La protección contra problemas de memoria se proporciona mediante el uso de punteros MonoCaps de 128 bits con metadatos para la verificación de tipos y el seguimiento de los límites del búfer, así como el uso del recolector de basura FUGC, que controla todas las operaciones de asignación y desasignación de memoria. En caso de errores al trabajar con la memoria, la aplicación falla inmediatamente, lo que no permite explotar posibles vulnerabilidades.
Se afirma que la combinación de MonoCaps y FUGC le permite detectar y bloquear todos los errores asociados con ir más allá de los límites del búfer en la pila y el montón, acceder a la memoria ya liberada, condiciones de carrera al trabajar con punteros, así como el manejo incorrecto de tipos ( Type Confusion) en la intersección de contexto de tipos punteros y no punteros, problemas con enlaces dinámicos y uso incorrecto de va_lists. Además, Fil-C verifica por separado los límites y tipos de los búferes pasados a las llamadas al sistema.
Ценой возможности использования Fil-C для защиты существующих проектов, без необходимости переписывания их кода или задействования особых языковых конструкций, является снижение производительности. На текущем этапе развития, собираемые в Fil-C программы медленнее примерно в 1.5-5 раз, по сравнению со сборкой обычными компиляторами. В планах заявлена работа по проведению оптимизации. Предполагается, что после завершения этой работы в большинстве случаев код будет выполняться медленнее в 1.2 раза, а в наихудших сценариях замедление не превысит полтора раза. Компилятор пока поддерживает только платформу Linux на системах X86_64. Предыдущие версии поддерживали macOS и FreeBSD, но затем было решено не распылять усилия и вначале подготовить качественный порт libc для одной платформы.
Otra limitación de Fil-C es la negativa fundamental a mantener la compatibilidad a nivel ABI para el código C/C++, lo que no permite vincular el código compilado en Fil-C con bibliotecas y archivos objeto compilados por otros compiladores. El método de llamada de funciones y la forma de enlace dinámico en Fil-C difiere de los compiladores y enlazadores existentes. Esta decisión se explica por el hecho de que al vincular con código desprotegido, la esencia de la protección ofrecida en Fil-C se pierde y surge la ilusión de una aplicación protegida; con la compatibilidad ABI, los desarrolladores se sentirían tentados a recopilar solo archivos individuales en Fil. -C, sin molestarse en portar todo el proyecto.
El mecanismo MonoCap de Fil-C se basa en el uso de punteros de 16 bytes que, además de una dirección de memoria, indican una referencia a un objeto que incluye información sobre capacidades, como los límites superior e inferior del búfer asociado con el puntero, así como una matriz, que define los tipos de datos almacenados en cada bloque de memoria (1 byte con información de tipo (unset, int, ptr, free) para cada bloque de memoria de 16 bytes). Cada vez que un puntero accede a una memoria, se verifican los límites y el tipo (por ejemplo, los datos con tipo "int" no se pueden escribir en la memoria con tipo "ptr" y viceversa).
Todas las operaciones de asignación y desasignación de memoria son procesadas por el increíble recolector de basura de Fil (FUGC), que, cuando se libera la memoria, establece todos los registros de tipo asociados con el búfer liberado en el valor "libre" y luego redirige todos los punteros a los objetos liberados a un objeto separado que indica que la memoria ya ha sido liberada. Cualquier acceso posterior a un bloque de datos de tipo "libre" o a un puntero asociado con un objeto liberado da como resultado la generación de una excepción, que permite la protección contra vulnerabilidades de uso después de la liberación. El recolector de basura se ejecuta en paralelo y no detiene la ejecución de otros subprocesos.
El uso de una combinación de MonoCaps y FUGC le permite conservar la capacidad de trabajar con punteros como de costumbre y dejar la semántica de malloc y llamadas gratuitas sin cambios, al tiempo que brinda protección garantizada. El código del programa puede contener varios errores lógicos, como conversiones de tipos incorrectas, aritmética de punteros incorrecta, condiciones de carrera y llamadas inoportunas a free(), pero independientemente de todo esto, Fil-C recordará los límites y el tipo de datos originales y abortará la ejecución. , si se intenta acceder a un puntero a un área fuera de los límites recordados, acceder a un bloque de memoria liberado o leer datos de tipo "int" como un puntero o viceversa.
El autor de Fil-C, Philip Pizlo, es director de proyectos de lenguajes de programación en Epic Games. Philip cuenta con una amplia experiencia trabajando con máquinas virtuales, lenguajes de programación, compiladores y recolectores de basura. Por ejemplo, en IBM, desarrolló el lenguaje de programación X10; en Microsoft, trabajó en los recolectores de basura Stopless, Clover y Chicken; en Apple, trabajó en el compilador JIT y las optimizaciones para el motor de navegador WebKit; y en Epic Games, lidera el equipo de desarrollo del lenguaje de programación Verse y su máquina virtual asociada. Philip también es un desarrollador clave. máquinas virtuales Jikes RVM, Ovm y Fiji VM.

Fuente: opennet.ru
