Web yazı tipleri için bellek güvenliği

Dominik Röttsches
Dominik Röttsches
Rod Sheeter
Rod Sheeter
Chad Brokaw
Chad Brokaw

Yayınlanma tarihi: 19 Mart 2025

FreeType'ı Blink'ten kaldırdık.

Skrifa, Rust ile yazılmış ve Chrome'da yazı tipi işlemeyi tüm kullanıcılarımız için güvenli hale getirmek amacıyla FreeType'ın yerine geçecek şekilde oluşturulmuştur. Skrifa, Rust'ın bellek güvenliğinden yararlanır ve Chrome'daki yazı tipi teknolojisi iyileştirmeleri üzerinde daha hızlı yineleme yapmamıza olanak tanır. FreeType'tan Skrifa'ya geçiş, yazı tipi kodumuzda değişiklik yaparken hem hızlı hem de cesur olmamızı sağlıyor. Artık güvenlik hatalarını düzeltmek için çok daha az zaman harcıyoruz. Bu sayede güncellemeler daha hızlı yapılıyor ve kod kalitesi artıyor.

Bu gönderide, Chrome'un FreeType'tan neden vazgeçtiği ve bu değişikliğin sağladığı iyileştirmelerle ilgili bazı ilginç teknik ayrıntılar paylaşılıyor.

FreeType neden değiştiriliyor?

Web, kullanıcıların çok çeşitli güvenilmeyen kaynaklardan güvenilmeyen kaynakları almasına olanak tanıması ve bu kaynakların çalışacağı ve güvenli olacağı beklentisiyle benzersizdir. Bu varsayım genellikle doğrudur ancak kullanıcılara bu sözü tutmanın bir maliyeti vardır. Örneğin, bir web yazı tipini (ağ üzerinden sunulan bir yazı tipi) güvenli bir şekilde kullanmak için Chrome çeşitli güvenlik önlemleri uygular:

  • Yazı tipi işleme, iki kuralı uyarınca korumalı alanda yapılır: Yazı tipleri güvenilmezdir ve kullanılan kod güvenli değildir.
  • Yazı tipleri, işlenmeden önce OpenType Sanitizer'dan geçirilir.
  • Yazı tiplerinin sıkıştırılmasını açma ve işleme işlemlerinde kullanılan tüm kitaplıklar fuzz testine tabi tutulur.

Chrome, FreeType ile birlikte gelir ve Android, ChromeOS ve Linux'ta birincil yazı tipi işleme kitaplığı olarak FreeType'ı kullanır. Bu nedenle, FreeType'ta bir güvenlik açığı varsa çok sayıda kullanıcı bu durumdan etkilenir.

FreeType kitaplığı, Chrome tarafından metrikleri hesaplamak ve yazı tiplerinden ipuçlu ana hatları yüklemek için kullanılır. Genel olarak, FreeType'ın kullanılması Google için büyük bir başarı olmuştur. Bu araç, karmaşık bir işi iyi bir şekilde yapıyor. Biz de bu aracı yoğun bir şekilde kullanıyor ve katkıda bulunuyoruz. Ancak güvenli olmayan bir kodla yazılmıştır ve kötü amaçlı girişlerin daha az olası olduğu bir zamanda ortaya çıkmıştır. Yalnızca bulanıklaştırma ile bulunan sorunları takip etmek Google'a en az 0,25 tam zamanlı yazılım mühendisi maliyetine neden oluyor. Daha da kötüsü, her şeyi bulamadığımız veya yalnızca kod kullanıcılara gönderildikten sonra bulduğumuz açıkça görülüyor.

Bu sorunlar yalnızca FreeType'a özgü değildir. En iyi yazılım mühendislerini kullansak, her değişikliği kod incelemesinden geçirsek ve testler zorunlu tutsak bile diğer güvenli olmayan kitaplıkların sorunlara yol açtığını görüyoruz.

Sorunların neden gizlice girmeye devam ettiği

FreeType'ın güvenliğini değerlendirirken üç ana sorun sınıfının oluştuğunu gözlemledik (kapsamlı değildir):

Güvenli olmayan bir dilin kullanılması

Desen/Sorun Örnek
Manuel bellek yönetimi
İşaretlenmemiş dizi erişimi CVE-2022-27404
Tam sayı taşmaları CFF çizimi ve ipucu için TrueType ipucu oluşturma amacıyla yerleştirilmiş sanal makineler yürütülürken
https://issues.oss-fuzz.com/issues?q=FreeType%20Integer-overflow
Sıfırlama ve sıfırlamama tahsisinin yanlış kullanımı https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests/94 adresindeki tartışmada, 8 fuzzer sorunu bulundu
Geçersiz yayınlar Makro kullanımıyla ilgili aşağıdaki satıra bakın.

Projeye özgü sorunlar

Desen/Sorun Örnek
Makrolar, açık boyut türü eksikliğini gizliyor
  • FT_READ_* ve FT_PEEK_* gibi makrolar, hangi tam sayı türlerinin kullanıldığını gizleyerek açık boyutlara sahip C99 türlerinin (int16_t vb.) kullanılmadığını saklar.
Yeni kod, savunma amaçlı yazıldığında bile sürekli olarak hatalara neden oluyor.
  • COLRv1 ve OT-SVG, her iki üretilmiş sorunu da destekler.
  • Fuzzing, #32421, #52404 numaralı sorunların bir kısmını bulur ancak hepsini bulmayabilir.
Test eksikliği
  • Test yazı tipleri oluşturmak zaman alıcı ve zordur.

Bağımlılık sorunları

Fuzzing, FreeType'ın bağlı olduğu kitaplıklarda (ör. bzip2, libpng ve zlib) tekrar tekrar sorunlar tespit etti. Örneğin, freetype_bdf_fuzzer: Use-of-uninitialized-value in inflate ile karşılaştırın.

Fuzzing yeterli değildir

Fuzzing (rastgele geçersiz girişler de dahil olmak üzere çok çeşitli girişlerle yapılan otomatik test), Chrome'un kararlı sürümüne giren birçok sorunu bulmayı amaçlar. FreeType, Google'ın oss-fuzz projesi kapsamında bulanıklaştırma işlemine tabi tutulur. Bu araç sorunları tespit etse de yazı tiplerinin aşağıdaki nedenlerden dolayı bulanıklaştırmaya karşı biraz dirençli olduğu kanıtlanmıştır.

Yazı tipi dosyaları, birden fazla farklı bilgi türü içerdiğinden video dosyalarına benzer şekilde karmaşıktır. Yazı tipi dosyaları, birden fazla tablonun bulunduğu bir kapsayıcı biçimidir. Her tablo, metin ve yazı tiplerini birlikte işleyerek ekranda doğru konumlandırılmış bir glif oluşturmak için farklı bir amaca hizmet eder. Yazı tipi dosyasında şunlar bulunur:

  • Yazı tipi adları ve değişken yazı tipleri için parametreler gibi statik meta veriler.
  • Unicode karakterlerden gliflere yapılan eşlemeler.
  • Gliflerin ekran düzeni için karmaşık bir kural grubu ve dil bilgisi.
  • Görsel bilgiler: Glif şekilleri ve ekranda yer alan gliflerin nasıl göründüğünü açıklayan resim bilgileri.
    • Görsel tablolar da glif şeklini değiştirmek için yürütülen mini programlar olan TrueType ipucu programlarını içerebilir.
    • CFF veya CFF2 tablolarındaki, CFF oluşturma motorunda yürütülen zorunlu eğri çizme ve ipucu talimatları olan karakter dizeleri.

Yazı tipi dosyaları, kendi programlama diline ve durum makinesi işlemine sahip olmaya eşdeğer bir karmaşıklığa sahiptir. Bu nedenle, yürütülmeleri için belirli sanal makineler gerekir.

Biçimin karmaşıklığı nedeniyle, bulanıklaştırma yöntemiyle yazı tipi dosyalarındaki sorunları bulmakta eksiklikler vardır.

Aşağıdaki nedenlerden dolayı iyi bir kod kapsamı veya fuzzer ilerlemesi elde etmek zordur:

  • Basit bit çevirme/kaydırma/ekleme/silme tarzı mutasyonlar kullanılarak TrueType ipucu programlarının, CFF karakter dizelerinin ve OpenType düzeninin bulanıklaştırılması, tüm durum kombinasyonlarına ulaşmakta zorlanır.
  • Fuzzing, en azından kısmen geçerli yapılar oluşturmalıdır. Rastgele mutasyon bunu nadiren yapar ve özellikle daha derin kod seviyelerinde iyi bir kapsam elde etmeyi zorlaştırır.
  • ClusterFuzz ve oss-fuzz'daki mevcut bulanıklaştırma çalışmaları henüz yapıya duyarlı mutasyon kullanmamaktadır. Dilbilgisi veya yapı odaklı mutasyonlar kullanmak, geliştirme süresini uzatma ve arama alanının bazı bölümlerini kaçırma riskiyle birlikte, erken aşamada reddedilen varyantların oluşturulmasını önlemeye yardımcı olabilir.

Fuzzing işleminin ilerlemesi için birden fazla tablodaki verilerin senkronize edilmesi gerekir:

  • Fuzzers'ın mutasyon kalıpları genellikle kısmen geçerli veriler üretmez. Bu nedenle birçok yineleme reddedilir ve ilerleme yavaşlar.
  • Glif eşleme, OpenType düzen tabloları ve glif çizimi birbirine bağlıdır ve birbirine bağımlıdır. Bu nedenle, köşelerine bulanıklaştırma ile ulaşılması zor olan bir kombinasyon alanı oluştururlar.
  • Örneğin, yüksek önem derecesine sahip tt_face_get_paint COLRv1 güvenlik açığının bulunması 10 aydan uzun sürdü.

Eldeki tüm imkanlara rağmen, yazı tipi güvenliğiyle ilgili sorunlar tekrar tekrar son kullanıcılara ulaştı. FreeType'ı Rust alternatifiyle değiştirmek, birden fazla güvenlik açığı sınıfını önleyecektir.

Skrifa in Chrome

Skia, Chrome'un kullandığı grafik kitaplığıdır. Skia, yazı tiplerinden meta verileri ve harf biçimlerini yüklemek için FreeType'ı kullanır. Skrifa, Fontations kitaplık ailesinin bir parçası olan bir Rust kitaplığıdır. Skia tarafından kullanılan FreeType bölümleri için güvenli bir alternatif sunar.

Chrome ekibi, FreeType'ı Skia'ya geçirmek için Skrifa'ya dayalı yeni bir Skia yazı tipi arka ucu geliştirdi ve değişikliği kullanıcılara kademeli olarak sundu:

  • Chrome 128'de (Ağustos 2024) Fontations'ı güvenli bir deneme sürümü olarak daha az kullanılan yazı tipi biçimlerinde (ör. renkli yazı tipleri ve CFF2) kullanıma sunduk.
  • Chrome 133'te (Şubat 2025) Fontations'ı etkinleştirdik. Bu özellik, Linux, Android ve ChromeOS'te tüm web yazı tiplerinin kullanımının yanı sıra Windows ve Mac'te yedek olarak web yazı tiplerinin kullanımını destekler. Bu, sistemin bir yazı tipi biçimini desteklemediği ancak Chrome'un bu biçimi göstermesi gerektiği durumlarda geçerlidir.

Chrome'a entegrasyon için Chrome güvenlik ekibi tarafından kullanıma sunulan kod tabanına Rust'ın sorunsuz bir şekilde entegre edilmesini sağlıyoruz.

Gelecekte, işletim sistemi yazı tipleri için de Fontations'a geçeceğiz. Bu geçiş, önce Linux ve ChromeOS'te, ardından Android'de başlayacak.

Öncelikle güvenlik

Asıl amacımız, bellek sınırları dışında erişimden kaynaklanan güvenlik açıklarını azaltmak (ideal olarak ortadan kaldırmak) Rust, unsafe kod bloklarından kaçındığınız sürece bu özelliği kullanıma hazır olarak sunar.

Performans hedeflerimiz, şu anda güvenli olmayan bir işlemi gerçekleştirmemizi gerektiriyor: rastgele baytların kesin olarak türlenmiş bir veri yapısı olarak yeniden yorumlanması. Bu sayede, gereksiz kopyalar oluşturmadan bir yazı tipi dosyasındaki verileri okuyabiliriz. Bu, hızlı bir yazı tipi ayrıştırıcı oluşturmak için gereklidir.

Güvenli olmayan kod yazmaktan kaçınmak için bu sorumluluğu, özellikle bu amaç için tasarlanmış ve ekosistemde yaygın olarak test edilip kullanılan bir Rust kitaplığı olan bytemuck'a devretmeyi tercih ettik. Ham verilerin yeniden yorumlanmasını bytemuck'ta yoğunlaştırmak, bu işlevin tek bir yerde ve denetlenmiş olarak bulunmasını sağlar ve bu amaçla güvenli olmayan kodların tekrar edilmesini önler. safe transmute project, bu işlevi doğrudan Rust derleyicisine dahil etmeyi amaçlıyor ve kullanıma sunulur sunulmaz geçiş yapacağız.

Doğruluk önemlidir

Skrifa, çoğu veri yapısının değişmez olacak şekilde tasarlandığı bağımsız bileşenlerden oluşur. Bu, okunabilirliği, sürdürülebilirliği ve çoklu iş parçacığını iyileştirir. Ayrıca, kodun birim testi için daha uygun olmasını sağlar. Bu fırsattan yararlanarak, düşük seviyeli ayrıştırma rutinlerinden yüksek seviyeli ipucu sanal makinelerine kadar tüm yığınımızı kapsayan yaklaşık 700 birim testinden oluşan bir paket oluşturduk.

Doğruluk, aslına uygunluğu da ifade eder ve FreeType, yüksek kaliteli ana hatlar oluşturmasıyla bilinir. Uygun bir alternatif olabilmek için bu kaliteyi karşılamamız gerekir. Bu amaçla, çok çeşitli yapılandırmalarda yazı tipi dosyaları grupları için Skrifa ve FreeType'ın çıkışını karşılaştıran fauntlet adlı özel bir araç geliştirdik. Bu sayede, kalite düşüşlerini önleyebileceğimizden emin olabiliriz.

Ayrıca, Chromium'a entegrasyondan önce Skia'da çok çeşitli piksel karşılaştırmaları yaptık. Bu karşılaştırmalarda, piksel farklılıklarının tüm gerekli oluşturma modlarında (farklı kenarları yumuşatma ve ipucu modlarında) kesinlikle minimum düzeyde olduğundan emin olmak için FreeType oluşturma ile Skrifa oluşturma ve Skia oluşturma ile Skrifa oluşturma karşılaştırıldı.

Fuzz testi, bir yazılımın hatalı ve kötü amaçlı girişlere nasıl tepki vereceğini belirlemek için kullanılan önemli bir araçtır. Haziran 2024'ten beri yeni kodumuzda sürekli olarak bulanıklaştırma işlemi yapıyoruz. Bu, Rust kitaplıklarının kendisini ve entegrasyon kodunu kapsar. Fuzzer, bu yazı yazıldığı sırada 39 hata bulmuş olsa da bunların hiçbirinin güvenlik açısından kritik olmadığı belirtilmelidir. İstenmeyen görsel sonuçlara veya hatta kontrollü kilitlenmelere neden olabilirler ancak istismar edilebilir güvenlik açıklarına yol açmazlar.

Devam!

Metin için Rust kullanma çalışmalarımızın sonuçlarından çok memnunuz. Kullanıcılara daha güvenli kod sunmak ve geliştiricilerin üretkenliğini artırmak bizim için büyük bir başarıdır. Metin yığınlarımızda Rust'ı kullanma fırsatlarını aramaya devam etmeyi planlıyoruz. Daha fazla bilgi edinmek isterseniz Oxidize, Google Fonts'un gelecekteki planlarından bazılarını özetliyor.