Veröffentlicht: 19. März 2025
Skrifa ist in Rust geschrieben und wurde als Ersatz für FreeType entwickelt, um die Schriftverarbeitung in Chrome für alle Nutzer sicherer zu machen. Skifra nutzt die Speichersicherheit von Rust und ermöglicht es uns, schneller Verbesserungen an der Schrifttechnologie in Chrome vorzunehmen. Durch den Wechsel von FreeType zu Skrifa können wir sowohl agil als auch unbesorgt Änderungen an unserem Schriftcode vornehmen. Wir benötigen jetzt viel weniger Zeit, um Sicherheitsfehler zu beheben. Das führt zu schnelleren Updates und einer besseren Codequalität.
In diesem Beitrag erfahren Sie, warum wir in Chrome von FreeType zu HarfBuzz gewechselt sind, und es werden einige interessante technische Details zu den Verbesserungen erläutert, die durch diesen Wechsel möglich wurden.
Warum wird FreeType ersetzt?
Das Web ist insofern einzigartig, als dass Nutzer nicht vertrauenswürdige Ressourcen aus einer Vielzahl von nicht vertrauenswürdigen Quellen abrufen können, in der Erwartung, dass alles funktioniert und dass sie dabei sicher sind. Diese Annahme ist im Allgemeinen richtig, aber die Erfüllung dieses Versprechens an die Nutzer hat ihren Preis. Um beispielsweise eine Webschriftart (eine Schriftart, die über das Netzwerk bereitgestellt wird) sicher zu verwenden, setzt Chrome mehrere Sicherheitsmaßnahmen ein:
- Die Schriftverarbeitung wird gemäß der Zwei-Faktor-Regel in einer Sandbox ausgeführt: Sie ist nicht vertrauenswürdig und der Code, der sie nutzt, ist unsicher.
- Schriftarten werden vor der Verarbeitung durch den OpenType-Sanitizer geleitet.
- Alle Bibliotheken, die beim Entpacken und Verarbeiten von Schriftarten verwendet werden, werden Fuzz-Tests unterzogen.
FreeType ist in Chrome enthalten und wird als primäre Bibliothek zur Schriftverarbeitung unter Android, ChromeOS und Linux verwendet. Das bedeutet, dass viele Nutzer gefährdet sind, wenn es eine Sicherheitslücke in FreeType gibt.
Die FreeType-Bibliothek wird von Chrome verwendet, um Messwerte zu berechnen und angedeutete Konturen aus Schriftarten zu laden. Insgesamt war die Verwendung von FreeType ein großer Gewinn für Google. Es erledigt eine komplexe Aufgabe und das gut. Wir stützen uns stark darauf und tragen dazu bei. Sie ist jedoch in unsicherem Code geschrieben und stammt aus einer Zeit, in der schädliche Eingaben weniger wahrscheinlich waren. Allein die Bearbeitung der durch Fuzzing gefundenen Probleme kostet Google mindestens 0,25 Vollzeit-Softwareentwickler. Schlimmer noch: Offenbar finden wir nicht alles oder erst, nachdem der Code an die Nutzer gesendet wurde.
Dieses Muster von Problemen ist nicht auf FreeType beschränkt. Wir stellen fest, dass auch andere unsichere Bibliotheken Probleme aufweisen, selbst wenn wir die besten Softwareentwickler finden, jede Änderung codeüberprüfen und Tests verlangen.
Warum Probleme immer wieder auftreten
Bei der Bewertung der Sicherheit von FreeType haben wir drei Hauptarten von Problemen festgestellt (nicht erschöpfend):
Verwendung einer unsicheren Sprache
Muster/Problem | Beispiel |
---|---|
Manuelle Speicherverwaltung |
|
Unkontrollierter Arrayzugriff | CVE-2022-27404 |
Ganzzahlüberlauf | Bei der Ausführung eingebetteter virtueller Maschinen für TrueType-Hinting von CFF-Zeichnen und -Hinting https://issues.oss-fuzz.com/issues?q=FreeType%20Integer-overflow |
Falsche Verwendung von Zuweisungen mit und ohne Nullen | Diskussion unter https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests/94, danach wurden 8 Fuzzer-Probleme gefunden |
Ungültige Umwandlungen | Siehe folgende Zeile zur Makronutzung |
Projektspezifische Probleme
Muster/Problem | Beispiel |
---|---|
Makros verschleiern fehlende explizite Größenangaben |
|
Neuer Code führt immer wieder zu Fehlern, auch wenn er fehlertolerant geschrieben wurde. |
|
Fehlende Tests |
|
Abhängigkeitsprobleme
Durch Fuzzing wurden wiederholt Probleme in Bibliotheken gefunden, von denen FreeType abhängt, z. B. bzip2, libpng und zlib. Vergleichen Sie dazu beispielsweise freetype_bdf_fuzzer: Verwendung eines nicht initialisierten Werts in inflate.
Fuzzing reicht nicht aus
Mit Fuzzing, also automatisierten Tests mit einer Vielzahl von Eingaben, einschließlich zufälliger ungültiger Eingaben, sollen viele der Probleme gefunden werden, die in die stabile Version von Chrome gelangen. Wir führen Fuzzing für FreeType im Rahmen des Google-Projekts oss-fuzz durch. Es werden zwar Probleme gefunden, aber Fonts sind aus den folgenden Gründen etwas widerstandsfähig gegen Fuzzing:
Schriftdateien sind komplex und vergleichbar mit Videodateien, da sie mehrere verschiedene Arten von Informationen enthalten. Schriftdateien sind ein Containerformat für mehrere Tabellen, wobei jede Tabelle einen anderen Zweck bei der Verarbeitung von Text und Schriftarten hat, um ein korrekt positioniertes Schriftzeichen auf dem Bildschirm zu erzeugen. In einer Schriftdatei finden Sie Folgendes:
- Statische Metadaten wie Schriftnamen und Parameter für variable Schriftarten.
- Zuordnungen von Unicode-Zeichen zu Glyphen.
- Eine komplexe Regelsammlung und Grammatik für das Bildschirmlayout von Glyphen.
- Visuelle Informationen: Glyphformen und Bildinformationen, die beschreiben, wie die auf dem Bildschirm platzierten Glyphen aussehen.
- Die visuellen Tabellen können wiederum TrueType-Hinting-Programme enthalten, d. h. Miniprogramme, die ausgeführt werden, um die Schriftzeichenform zu ändern.
- Zeichenfolgen in den CFF- oder CFF2-Tabellen, die Anweisungen zur Kurvenzeichnung und zum Hinting sind, die in der CFF-Rendering-Engine ausgeführt werden.
Schriftdateien sind so komplex, dass sie eine eigene Programmiersprache und eine eigene Zustandsmaschinenverarbeitung erfordern. Daher sind spezielle virtuelle Maschinen erforderlich, um sie auszuführen.
Aufgrund der Komplexität des Formats ist Fuzzing nicht in der Lage, Probleme in Schriftdateien zu finden.
Eine gute Codeabdeckung oder ein guter Fortschritt des Fuzzers ist aus den folgenden Gründen schwierig zu erreichen:
- Beim Fuzzing von TrueType-Hinting-Programmen, CFF-Zeichenstrings und OpenType-Layouts mithilfe einfacher Mutatatoren vom Typ Bit-Flip/Verschiebung/Einfügen/Löschen ist es schwierig, alle Kombinationen von Zuständen zu erreichen.
- Beim Fuzzing müssen mindestens teilweise gültige Strukturen erzeugt werden. Bei der Zufallsmutation ist das selten der Fall, was eine gute Abdeckung erschwert, insbesondere bei tieferen Codeebenen.
- Bei den aktuellen Fuzzing-Bemühungen in ClusterFuzz und oss-fuzz wird noch keine struktursensitive Mutation verwendet. Die Verwendung von grammatik- oder struktursensitiven Modifikatoren kann dazu beitragen, die Produktion von Varianten zu vermeiden, die früh abgelehnt werden. Dies geht jedoch zu Lasten der Entwicklungszeit und es besteht die Gefahr, dass Teile des Suchraums nicht abgedeckt werden.
Die Daten in mehreren Tabellen müssen synchronisiert sein, damit der Fuzzing-Prozess fortgesetzt werden kann:
- Die üblichen Mutationsmuster von Fuzzern erzeugen keine teilweise gültigen Daten, sodass viele Iterationen abgelehnt werden und der Fortschritt langsam wird.
- Die Glyphenzuordnung, die OpenType-Layouttabellen und die Glyphenzeichnung sind miteinander verbunden und voneinander abhängig. Sie bilden einen kombinatorischen Raum, dessen Ecken mit Fuzzing nur schwer zu erreichen sind.
- So dauerte es beispielsweise mehr als 10 Monate, bis die Sicherheitslücke tt_face_get_paintCOLRv1 mit dem hohen Schweregrad gefunden wurde.
Trotz unserer Bemühungen haben Sicherheitsprobleme mit Schriftarten wiederholt Endnutzer erreicht. Durch das Ersetzen von FreeType durch eine Rust-Alternative werden mehrere ganze Sicherheitslückenklassen verhindert.
Skrifa in Chrome
Skia ist die von Chrome verwendete Grafikbibliothek. Skia verwendet FreeType, um Metadaten und Buchstabenformen aus Schriftarten zu laden. Skrifa ist eine Rust-Bibliothek, die zur Fontations-Bibliotheksfamilie gehört und einen sicheren Ersatz für die von Skia verwendeten FreeType-Teile bietet.
Für die Umstellung von FreeType auf Skia hat das Chrome-Team ein neues Skia-Schrift-Backend entwickelt, das auf Skrifa basiert. Die Änderung wurde dann schrittweise für Nutzer eingeführt:
- In Chrome 128 (August 2024) haben wir Fontations für die Verwendung in weniger gängigen Schriftformaten wie Farbschriften und CFF2 als sicheren Test aktiviert.
- In Chrome 133 (Februar 2025) haben wir Fontations für die Verwendung aller Webschriften unter Linux, Android und ChromeOS sowie für die Verwendung von Webschriften als Fallback unter Windows und Mac aktiviert. Das ist der Fall, wenn das System ein Schriftformat nicht unterstützt, es aber in Chrome angezeigt werden muss.
Für die Einbindung in Chrome stützen wir uns auf die reibungslose Einbindung von Rust in die Codebasis, die vom Chrome-Sicherheitsteam eingeführt wurde.
Künftig werden wir auch für Betriebssystemschriften auf Fontations umstellen, zuerst für Linux und ChromeOS, dann für Android.
Sicherheit geht vor
Unser Hauptziel besteht darin, Sicherheitslücken zu reduzieren (oder idealerweise zu beseitigen), die durch einen nicht zulässigen Zugriff auf den Arbeitsspeicher verursacht werden. Rust bietet dies standardmäßig, solange Sie unsichere Codeblöcke vermeiden.
Aufgrund unserer Leistungsziele müssen wir einen Vorgang ausführen, der derzeit nicht sicher ist: die Neuinterpretation beliebiger Bytes als stark typisierte Datenstruktur. So können wir die Daten aus einer Schriftdatei lesen, ohne unnötige Kopien auszuführen. Dies ist für die Erstellung eines schnellen Schriftparsers unerlässlich.
Um unsicheren Code zu vermeiden, haben wir diese Aufgabe an bytemuck ausgelagert. Das ist eine speziell für diesen Zweck entwickelte Rust-Bibliothek, die weithin getestet und im gesamten Ökosystem verwendet wird. Durch die Konzentration der Neuinterpretation von Rohdaten in Bytemuck können wir diese Funktion an einem Ort prüfen und vermeiden, unsicheren Code zu diesem Zweck zu wiederholen. Das safe transmute-Projekt zielt darauf ab, diese Funktion direkt in den Rust-Compiler einzubinden. Wir werden die Umstellung vornehmen, sobald sie verfügbar ist.
Richtigkeit ist wichtig
Skrifa besteht aus unabhängigen Komponenten, wobei die meisten Datenstrukturen unveränderlich sind. Dies verbessert die Lesbarkeit, Wartbarkeit und Multithreading. Außerdem eignet sich der Code besser für Unit-Tests. Wir haben diese Gelegenheit genutzt und eine Suite mit etwa 700 Einheitstests erstellt, die unseren gesamten Stack abdecken, von Low-Level-Parsing-Routinen bis hin zu High-Level-Hinweisen für virtuelle Maschinen.
Korrektheit bedeutet auch Treue und FreeType wird für die Erzeugung hochwertiger Konturen hoch geschätzt. Wir müssen diese Qualität erreichen, um ein geeigneter Ersatz zu sein. Dazu haben wir ein spezielles Tool namens fauntlet entwickelt, das die Ausgabe von Skrifa und FreeType für Batches von Schriftdateien in einer Vielzahl von Konfigurationen vergleicht. So können wir Qualitätsrückschritte vermeiden.
Vor der Einbindung in Chromium haben wir außerdem eine Vielzahl von Pixelvergleichen in Skia durchgeführt, bei denen wir das FreeType-Rendering mit dem Skrifa- und Skia-Rendering verglichen haben, um sicherzustellen, dass die Pixelunterschiede in allen erforderlichen Rendering-Modi (über verschiedene Anti-Aliasing- und Hinting-Modi hinweg) absolut minimal sind.
Fuzz-Tests sind ein wichtiges Tool, um zu ermitteln, wie eine Software auf fehlerhafte und schädliche Eingaben reagiert. Seit Juni 2024 führen wir kontinuierlich Fuzzing-Tests für unseren neuen Code durch. Dies gilt für die Rust-Bibliotheken selbst und den Integrationscode. Der Fuzzer hat zwar (zum Zeitpunkt der Erstellung dieses Artikels) 39 Fehler gefunden, aber keiner davon war sicherheitskritisch. Sie können zu unerwünschten visuellen Ergebnissen oder sogar zu kontrollierten Abstürzen führen, aber nicht zu ausnutzbaren Sicherheitslücken.
Nur Mut!
Wir sind sehr zufrieden mit den Ergebnissen unserer Bemühungen, Rust für Text zu verwenden. Wir sind sehr zufrieden, dass wir Nutzern jetzt noch sichereren Code anbieten und die Produktivität der Entwickler steigern können. Wir werden weiterhin nach Möglichkeiten suchen, Rust in unseren Text-Stacks zu verwenden. Weitere Informationen finden Sie in Oxidize, wo einige der zukünftigen Pläne für Google Fonts beschrieben werden.