Fecha de publicación: 19 de marzo de 2025
Skrifa está escrito en Rust, y se creó como reemplazo de FreeType para que el procesamiento de fuentes en Chrome sea seguro para todos nuestros usuarios. Skrifa aprovecha la seguridad de la memoria de Rust y nos permite iterar más rápido en las mejoras de la tecnología de fuentes en Chrome. El cambio de FreeType a Skrifa nos permite ser ágiles y audaces cuando realizamos cambios en nuestro código de fuente. Ahora dedicamos mucho menos tiempo a corregir errores de seguridad, lo que genera actualizaciones más rápidas y una mejor calidad del código.
En esta entrada, se explica por qué Chrome dejó de usar FreeType y se incluyen algunos detalles técnicos interesantes de las mejoras que permitió este cambio.
¿Por qué reemplazar FreeType?
La Web es única porque permite a los usuarios recuperar recursos no confiables de una amplia variedad de fuentes no confiables con la expectativa de que todo funcione y que sea seguro hacerlo. Esta suposición suele ser correcta, pero mantener esa promesa a los usuarios tiene un costo. Por ejemplo, para usar una fuente web de forma segura (una fuente que se entrega a través de la red), Chrome emplea varias mitigaciones de seguridad:
- El procesamiento de fuentes se realiza en un entorno de pruebas según la regla de dos: no son confiables y el código de consumo no es seguro.
- Las fuentes pasan por el OpenType Sanitizer antes del procesamiento.
- Todas las bibliotecas involucradas en la descompresión y el procesamiento de fuentes se someten a pruebas de fuzz testing.
Chrome se envía con FreeType y lo usa como la biblioteca principal de procesamiento de fuentes en Android, ChromeOS y Linux. Eso significa que muchos usuarios están expuestos si hay una vulnerabilidad en FreeType.
Chrome usa la biblioteca FreeType para calcular métricas y cargar contornos con sugerencias de fuentes. En general, el uso de FreeType ha sido un gran éxito para Google. Realiza un trabajo complejo y lo hace bien. Dependemos de él en gran medida y contribuimos a él. Sin embargo, está escrito en código no seguro y tiene sus orígenes en una época en la que las entradas maliciosas eran menos probables. Solo mantenerse al día con el flujo de problemas que se encuentran con el fuzzing le cuesta a Google al menos 0.25 ingenieros de software de tiempo completo. Peor aún, no encontramos todo de forma observable ni encontramos cosas solo después de que el código se envió a los usuarios.
Este patrón de problemas no es exclusivo de FreeType. Observamos que otras bibliotecas no seguras admiten problemas incluso cuando usamos los mejores ingenieros de software que podemos encontrar, realizamos una revisión de código de cada cambio y requerimos pruebas.
Por qué los problemas siguen apareciendo
Cuando evaluamos la seguridad de FreeType, observamos que se producen tres clases principales de problemas (no exhaustivas):
Uso de un lenguaje no seguro
| Patrón/problema | Ejemplo |
|---|---|
| Administración manual de la memoria |
|
| Acceso a array sin verificar | CVE-2022-27404 |
| Desbordamientos de números enteros | Durante la ejecución de máquinas virtuales integradas para la sugerencia de TrueType del dibujo y la sugerencia de CFF https://issues.oss-fuzz.com/issues?q=FreeType%20Integer-overflow |
| Uso incorrecto de la asignación de cero frente a la asignación de no cero | Discusión en https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests/94, 8 problemas de fuzzer encontrados después |
| Conversiones no válidas | Consulta la siguiente fila sobre el uso de macros |
Problemas específicos del proyecto
| Patrón/problema | Ejemplo |
|---|---|
| Las macros ocultan la falta de escritura de tamaño explícito |
|
| El código nuevo agrega errores de forma coherente, incluso cuando se escribe de forma defensiva. |
|
| Falta de pruebas |
|
Problemas de dependencia
El fuzzing identificó problemas de forma repetida en las bibliotecas de las que depende FreeType, como bzip2, libpng y zlib. Por ejemplo, compara freetype_bdf_fuzzer: Use-of-uninitialized-value in inflate.
El fuzzing no es suficiente
El fuzzing (pruebas automatizadas con una amplia variedad de entradas, incluidas las no válidas aleatorias) está diseñado para encontrar muchos de los tipos de problemas que llegan a la versión estable de Chrome. Realizamos fuzzing de FreeType como parte del proyecto oss-fuzz de Google. Encuentra problemas, pero las fuentes demostraron ser algo resistentes al fuzzing por los siguientes motivos.
Los archivos de fuentes son complejos, comparables a los archivos de video, ya que contienen varios tipos diferentes de información. Los archivos de fuentes son un formato de contenedor para varias tablas, en el que cada tabla tiene un propósito diferente en el procesamiento de texto y fuentes juntos para producir un glifo posicionado correctamente en la pantalla. En un archivo de fuentes, encontrarás lo siguiente:
- Metadatos estáticos, como nombres de fuentes y parámetros para fuentes variables
- Asignaciones de caracteres Unicode a glifos
- Un conjunto de reglas y una gramática complejos para el diseño de pantalla de los glifos
- Información visual: Formas de glifos e información de imágenes que describen el aspecto de los glifos colocados en la pantalla
- A su vez, las tablas visuales pueden incluir programas de sugerencias de TrueType, que son miniprogramas que se ejecutan para cambiar la forma del glifo.
- Cadenas de caracteres en las tablas CFF o CFF2, que son instrucciones imperativas de dibujo y sugerencias de curvas que se ejecutan en el motor de renderización de CFF
Hay complejidad en los archivos de fuentes equivalente a tener su propio lenguaje de programación y procesamiento de máquinas de estado, lo que requiere máquinas virtuales específicas para ejecutarlos.
Debido a la complejidad del formato, el fuzzing tiene deficiencias para encontrar problemas en los archivos de fuentes.
Es difícil lograr una buena cobertura de código o un buen progreso del fuzzer por los siguientes motivos:
- El fuzzing de programas de sugerencias de TrueType, cadenas de caracteres CFF y diseño de OpenType con mutadores simples de cambio de bits, desplazamiento, inserción o eliminación tiene dificultades para alcanzar todas las combinaciones de estados.
- El fuzzing debe producir al menos estructuras parcialmente válidas. La mutación aleatoria rara vez lo hace, lo que dificulta lograr una buena cobertura, en especial para niveles más profundos de código.
- Los esfuerzos actuales de fuzzing en ClusterFuzz y oss-fuzz aún no usan la mutación que reconoce la estructura. El uso de mutadores que reconocen la gramática o la estructura puede ayudar a evitar la producción de variantes que se rechazan de forma temprana, a costa de tardar más en desarrollarse y de introducir posibilidades que omiten partes del espacio de búsqueda.
Los datos de varias tablas deben estar sincronizados para que el fuzzing avance:
- Los patrones de mutación habituales de los fuzzers no producen datos parcialmente válidos, por lo que se rechazan muchas iteraciones y el progreso se vuelve lento.
- La asignación de glifos, las tablas de diseño de OpenType y el dibujo de glifos están conectados y dependen entre sí, lo que forma un espacio combinatorio cuyos extremos son difíciles de alcanzar con el fuzzing.
- Por ejemplo, la vulnerabilidad tt_face_get_paint COLRv1 de alta gravedad tardó más de 10 meses en encontrarse.
A pesar de nuestros mejores esfuerzos, los problemas de seguridad de las fuentes llegaron a los usuarios finales de forma repetida. Reemplazar FreeType por una alternativa de Rust evitará varias clases completas de vulnerabilidad.
Skrifa en Chrome
Skia es la biblioteca de gráficos que usa Chrome. Skia depende de FreeType para cargar metadatos y formas de letras de fuentes. Skrifa es una biblioteca de Rust, parte de la familia de bibliotecas Fontations, que proporciona un reemplazo seguro para las partes de FreeType que usa Skia.
Para realizar la transición de FreeType a Skia, el equipo de Chrome desarrolló un nuevo backend de fuentes de Skia basado en Skrifa y lanzó el cambio de forma gradual a los usuarios:
- En Chrome 128 (agosto de 2024), habilitamos Fontations para usar en formatos de fuentes menos de uso frecuente, como fuentes de color y CFF2, como una prueba segura.
- En Chrome 133 (febrero de 2025), habilitamos Fontations para todo el uso de fuentes web en Linux, Android y ChromeOS, y para el uso de fuentes web como resguardo en Windows y Mac, en los casos en que el sistema no admite un formato de fuente, pero Chrome necesita mostrarlo.
Para la integración en Chrome, dependemos de la integración fluida de Rust en la base de código que introdujo el equipo de seguridad de Chrome.
En el futuro, también cambiaremos a Fontations para las fuentes del sistema operativo, comenzando con Linux y ChromeOS, y luego en Android.
La seguridad es lo más importante
Nuestro objetivo principal es reducir (o, idealmente, eliminar) las vulnerabilidades de seguridad que se producen por el acceso fuera de límites a la memoria. Rust proporciona esto de inmediato, siempre que evites los bloques de código no seguros.
Nuestros objetivos de rendimiento requieren que realicemos una operación que actualmente no es segura: la reinterpretación de bytes arbitrarios como una estructura de datos con tipo seguro. Esto nos permite leer los datos de un archivo de fuentes sin realizar copias innecesarias y es esencial para producir un analizador de fuentes rápido.
Para evitar nuestro propio código no seguro, decidimos externalizar esta responsabilidad a bytemuck, que es una biblioteca de Rust diseñada específicamente para este propósito y que se prueba y usa ampliamente en todo el ecosistema. Concentrar la reinterpretación de datos sin procesar en bytemuck garantiza que tengamos esta funcionalidad en un solo lugar y que se audite, y evita repetir código no seguro para el propósito. El proyecto de transmutación segura tiene como objetivo incorporar esta funcionalidad directamente en el compilador de Rust, y haremos el cambio en cuanto esté disponible.
La precisión es importante
Skrifa se basa en componentes independientes en los que la mayoría de las estructuras de datos están diseñadas para ser inmutables. Esto mejora la legibilidad, el mantenimiento y la multihilo. También hace que el código sea más adecuado para las pruebas de unidades. Aprovechamos esta oportunidad y produjimos un conjunto de aproximadamente 700 pruebas unitarias que abarcan nuestra pila completa, desde rutinas de análisis de bajo nivel hasta máquinas virtuales de sugerencias de alto nivel.
La precisión también implica fidelidad, y FreeType es muy apreciado por su generación de contornos de alta calidad. Debemos igualar esta calidad para ser un reemplazo adecuado. Con ese fin, creamos una herramienta personalizada llamada fauntlet que compara el resultado de Skrifa y FreeType para lotes de archivos de fuentes en una amplia variedad de configuraciones. Esto nos brinda cierta seguridad de que podemos evitar regresiones en la calidad.
Además, antes de la integración en Chromium, ejecutamos un amplio conjunto de píxeles comparaciones en Skia, comparando la renderización de FreeType con la de Skrifa y la de Skia para garantizar que las diferencias de píxeles sean absolutamente mínimas, en todos los modos de renderización requeridos (en diferentes modos de suavizado y sugerencias).
Las pruebas de fuzzing son una herramienta importante para determinar cómo reaccionará un software a entradas mal formadas y maliciosas Realizamos fuzzing de nuestro código nuevo de forma continua desde junio de 2024. Esto abarca las bibliotecas de Rust en sí y el código de integración. Si bien el fuzzer encontró (al momento de escribir este artículo) 39 errores, vale la pena destacar que ninguno de ellos fue crítico para la seguridad. Pueden causar resultados visuales no deseados o incluso fallas controladas, pero no generarán vulnerabilidades explotables.
A continuación,
Estamos muy satisfechos con los resultados de nuestros esfuerzos por usar Rust para texto. Entregar código más seguro a los usuarios y aumentar la productividad de los desarrolladores es un gran éxito para nosotros. Planeamos seguir buscando oportunidades para usar Rust en nuestras pilas de texto. Si quieres obtener más información, Oxidize describe algunos de los planes futuros de Google Fonts.