تاريخ النشر: 19 آذار (مارس) 2025
تم إنشاء مكتبة Skrifa باستخدام لغة برمجة Rust، وهي بديل لواجهة برمجة التطبيقات FreeType لجعل معالجة الخطوط في Chrome آمنة لجميع المستخدمين. يستفيد Skifra من أمان الذاكرة في Rust، ويسمح لنا بإجراء عمليات تكرار أسرع للتحسينات على تكنولوجيا الخطوط في Chrome. يتيح لنا الانتقال من FreeType إلى Skrifa العمل بسرعة وبدون خوف عند إجراء تغييرات على رمز الخط. نقضي الآن وقتًا أقل بكثير في إصلاح أخطاء الأمان، مما يؤدي إلى توفّر التحديثات بشكل أسرع وجودة أفضل للترميز.
تشرح هذه المشاركة سبب توقّف Chrome عن استخدام FreeType، وتقدّم بعض التفاصيل الفنية المثيرة للاهتمام حول التحسينات التي أدّت إلى هذا التغيير.
لماذا يجب استبدال FreeType؟
يتميز الويب بأنّه يسمح للمستخدمين بجلب موارد غير موثوق بها من مجموعة كبيرة من المصادر غير الموثوق بها مع توقّع أن تعمل الأمور ببساطة وأنّه آمن لهم إجراء ذلك. وهذا الافتراض صحيح بشكل عام، ولكن هناك تكلفة مقابل الوفاء بهذا الوعد للمستخدمين. على سبيل المثال، لاستخدام خط ويب بأمان (خط يتم إرساله عبر الشبكة)، يستخدم Chrome عدة إجراءات تهدف إلى معالجة المشاكل المتعلقة بالأمان:
- تتم معالجة الخطوط في بيئة معزولة بموجب قاعدة الاثنين: إنّها غير جديرة بالثقة والرموز البرمجية التي تستخدمها غير آمنة.
- يتم تمرير الخطوط من خلال OpenType Sanitizer قبل معالجتها.
- تخضع جميع المكتبات المشارِكة في فك ضغط الخطوط ومعالجتها لاختبارات الكشف عن الأخطاء.
يتم تثبيت مكتبة FreeType مع Chrome ويتم استخدامها كمكتبة معالجة الخطوط الأساسية على Android وChromeOS وLinux. وهذا يعني أنّ الكثير من المستخدمين معرضون للاختراق في حال توفّر ثغرة أمنية في FreeType.
يستخدم Chrome مكتبة FreeType لاحتساب المقاييس وتحميل المخططات المُشار إليها من الخطوط. بشكل عام، كان استخدام FreeType فوزًا كبيرًا لشركة Google. تؤدي هذه الخدمة مهمة معقدة بشكل جيد، ونحن نعتمد عليها بشكل كبير ونساهم بدورنا في تطويرها. ومع ذلك، تم كتابتها باستخدام رمز برمجي غير آمن، وتعود أصولها إلى وقت عندما كانت مدخلات البرامج الضارة أقل احتمالًا. إنّ مجرد مواكبة سيل الصعوبات التي يتم رصدها من خلال اختبارات التداخل تكلف Google ما لا يقل عن 0.25 مهندس برمجة بدوام كامل. والأسوأ من ذلك، لا نعثر على كل المشاكل أو لا نعثر عليها إلا بعد شحن الرمز إلى المستخدمين.
لا يقتصر نمط المشاكل هذا على مكتبة FreeType، فنحن نلاحظ أنّ المكتبات الأخرى غير الآمنة تواجه مشاكل حتى عندما نستخدم أفضل مهندسي البرامج الذين يمكننا العثور عليهم، ويشمل ذلك مراجعة كل تغيير في الرمز البرمجي وإجراء الاختبارات.
سبب استمرار ظهور المشاكل
عند تقييمنا لأمان FreeType، لاحظنا ثلاث فئات رئيسية من المشاكل التي يمكن أن تحدث (غير شاملة):
استخدام لغة غير آمنة
النمط/المشكلة | مثال |
---|---|
إدارة الذاكرة يدويًا |
|
الوصول إلى الصفيف بدون التحقّق منه | CVE-2022-27404 |
تجاوز سعة الأعداد الصحيحة | أثناء تنفيذ الأجهزة الافتراضية المضمّنة لتحسين TrueType لرسم CFF وتحسينه https://issues.oss-fuzz.com/issues?q=FreeType%20Integer-overflow |
استخدام غير صحيح لميزة "القيمة صفر" مقابل ميزة "القيمة غير صفر" في عملية التوزيع | مناقشة في https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests/94، تم العثور على 8 مشاكل في أداة التدقيق بعد ذلك |
عمليات التحويل غير الصالحة | الاطّلاع على الصف التالي عن استخدام المَعلمات |
المشاكل المتعلّقة بالمشروع
النمط/المشكلة | مثال |
---|---|
وحدات الماكرو تحجب عدم تحديد حجم واضح |
|
تؤدي الرموز البرمجية الجديدة إلى إضافة أخطاء باستمرار، حتى عند كتابتها بشكل دفاعي. |
|
عدم توفّر الاختبارات |
|
مشاكل التبعيات
وقد رصدت تقنية Fuzzing بشكل متكرّر مشاكل في مكتبات FreeType التي يعتمد عليها، مثل bzip2 وlibpng وzlib. على سبيل المثال، قارِن freetype_bdf_fuzzer: Use-of-uninitialized-value in inflate.
لا يكفي استخدام تقنية التزييف.
إنّ اختبار Fuzzing هو اختبار مبرمَج باستخدام مجموعة كبيرة من المدخلات، بما في ذلك المدخلات العمياء غير الصالحة، ويهدف إلى العثور على العديد من أنواع المشاكل التي تظهر في الإصدار الثابت من Chrome. نحن نفحص FreeType بحثًا عن الأخطاء كجزء من مشروع Google المسمى oss-fuzz. يرصد هذا الفحص المشاكل، ولكن ثبت أنّ الخطوط مقاومة إلى حدٍ ما للفحص العشوائي، وذلك للأسباب التالية:
ملفات الخطوط معقدة، ويمكن مقارنتها بملفات الفيديو لأنّها تحتوي على عدة أنواع مختلفة من المعلومات. ملفات الخطوط هي تنسيق حاوية لعدة جدولَين، حيث يخدم كل جدول غرضًا مختلفًا في معالجة النصوص والخطوط معًا لإنتاج رمز مميّز في موضع صحيح على الشاشة. في ملف الخط، ستجد ما يلي:
- البيانات الوصفية الثابتة، مثل أسماء الخطوط ومَعلمات الخطوط المتغيّرة
- عمليات الربط من أحرف Unicode إلى الرموز
- قواعد وقواعد نحوية معقّدة لتنسيق الشاشة للرموز
- المعلومات المرئية: أشكال الرموز الرسومية ومعلومات الصور التي تصف شكل
الرموز الرسومية المعروضة على الشاشة
- يمكن أن تتضمّن الجداول المرئية بدورها برامج التلميح في TrueType، وهي برامج صغيرة يتم تنفيذها لتغيير شكل الرمز.
- سلاسل الأحرف في جداول CFF أو CFF2 التي هي تعليمات رسم منحنيات واقتراحات إلزامية يتم تنفيذها في محرّك عرض CFF
هناك تعقيد في ملفات الخطوط يعادل استخدام لغة برمجة خاصة بها ومعالجة آلة حالة، ما يتطلّب استخدام آلات افتراضية معيّنة لتنفيذها.
بسبب تعقيد التنسيق، تواجه تقنية التزييف عيوبًا في العثور على المشاكل في ملفات الخطوط.
من الصعب تحقيق تغطية جيدة للرمز البرمجي أو مستوى تقدّم جيد لبرنامج التزييف لأسباب التالية:
- إنّ استخدام برامج التلميح في TrueType وسلسلات أحرف CFF وتنسيق OpenType باستخدام مُعدِّلات بسيطة من طراز عكس/تبديل/إدراج/حذف الوحدات لا يمكنه الوصول إلى جميع مجموعات الحالات.
- يجب أن تؤدي عملية التشويش إلى إنشاء هياكل صالحة جزئيًا على الأقل. نادرًا ما تؤدي المعالجة العشوائية للتسلسل إلى ذلك، ما يجعل من الصعب تحقيق تغطية جيدة، خاصةً بالنسبة إلى المستويات الأكثر عمقًا من الرمز.
- لا تستخدم الجهود الحالية لفحص الأخطاء العشوائية في ClusterFuzz وoss-fuzz الطفرات المراعية للبنية بعد. قد يساعد استخدام مُعدِّلات تراعي القواعد النحوية أو البنية في تجنُّب إنتاج صيغ يتم رفضها في وقت مبكر، وذلك على حساب الاستغراق وقتًا أطول في التطوير وتقديم فرص لا تُغطي أجزاءً من مساحة البحث.
يجب أن تكون البيانات في جداول متعددة متزامنة لكي تحقّق ميزة "التشويش" أيّ تقدّم:
- لا تُنتج أنماط الطفرة المعتادة لأدوات البحث عن الأخطاء غير المحدَّدة بيانات صالحة جزئيًا، وبالتالي يتم رفض العديد من التكرارات ويصبح التقدّم بطيئًا.
- إنّ تعيين الأحرف الرسومية وجداول تنسيق OpenType ورسم الأحرف الرسومية مرتبطة ببعضها وتعتمد على بعضها البعض، ما يشكّل مساحة تركيبية يصعب الوصول إلى زواياها باستخدام التداخل.
- على سبيل المثال، استغرق العثور على ثغرة tt_face_get_paint COLRv1 ذات الخطورة العالية أكثر من 10 أشهر.
على الرغم من جهودنا المبذولة، وصلت مشاكل أمان الخطوط بشكل متكرر إلى مستخدمي الخطوط النهائيين. سيؤدي استبدال FreeType ببديل Rust إلى منع هجمات من عدة فئات كاملة من نقاط الضعف.
Skrifa in Chrome
Skia هي مكتبة الرسومات التي يستخدمها Chrome. تعتمد Skia على مكتبة FreeType لتحميل البيانات الوصفية وأشكال الأحرف من الخطوط. Skrifa هي مكتبة مكتوبة بلغة Rust ، وهي جزء من مجموعة مكتبات Fontations ، وتوفر بديلاً آمنًا لأجزاء FreeType التي تستخدمها Skia.
لنقل FreeType إلى Skia، طوَّر فريق Chrome واجهة خلفية جديدة لخطوط Skia استنادًا إلى Skrifa وطرح التغيير تدريجيًا للمستخدمين:
- في Chrome 128 (آب/أغسطس 2024)، فعّلنا علامة ترميز Fontations لاستخدامها في تنسيقات الخطوط الأقل استخدامًا، مثل الخطوط الملونة وملف CFF2، وذلك كتجربة آمنة.
- في الإصدار 133 من Chrome (شباط/فبراير 2025)، فعّلنا ميزة Fontations لجميع استخدامات الخطوط على الويب على Linux وAndroid وChromeOS، ولاستخدام الخطوط على الويب كخط احتياطي على Windows وMac، وذلك في الحالات التي لا يتيح فيها النظام استخدام تنسيق خط معيّن ولكن يحتاج Chrome إلى عرضه.
لدمج Rust في Chrome، نعتمد على عملية الدمج السلسة لـ Rust في codebase التي قدّمها فريق أمان Chrome.
في المستقبل، سنستخدم Fontations لخطوط نظام التشغيل أيضًا، بدءًا من Linux وChromeOS، ثم على Android.
السلامة أولاً وقبل كل شيء
هدفنا الأساسي هو تقليل (أو القضاء على) نقاط الضعف في الأمان التي تحدث بسبب الوصول إلى الذاكرة خارج الحدود المسموح بها. توفّر Rust هذه الميزة تلقائيًا ما دامت تتجنب أي مجموعات رموز غير آمنة.
تتطلّب أهداف الأداء لدينا تنفيذ عملية واحدة غير آمنة حاليًا: إعادة تفسير وحدات البايت العشوائية كبنية بيانات ذات نوع محدّد. يتيح لنا ذلك قراءة البيانات من ملف الخط بدون إجراء عمليات نسخ غير ضرورية، وهو أمر ضروري لإنشاء أداة تحليل سريعة للخطوط.
لتجنّب استخدام الرموز البرمجية غير الآمنة، اخترنا الاستعانة بمصادر خارجية لتنفيذ هذه المهمة، وهي مكتبة bytemuck المصمّمة خصيصًا لهذا الغرض والتي تم اختبارها واستخدامها على نطاق واسع في المنظومة المتكاملة. من خلال تركيز عملية إعادة تفسير البيانات الأولية في أداة bytemuck، نتأكّد من توفّر هذه الوظيفة في مكان واحد ومراجعتها، ونتجنّب تكرار الرمز البرمجي غير الآمن للقيام بهذه المهمة. يهدف مشروع تحويل البيانات بأمان إلى دمج هذه الوظيفة مباشرةً في مُجمِّع Rust، وسنُجري عملية التبديل فور توفّر هذه الوظيفة.
أهمية الدقة
تم إنشاء Skrifa من مكوّنات مستقلة حيث تم تصميم معظم بنى البيانات لتكون غير قابلة للتغيير. ويؤدي ذلك إلى تحسين سهولة القراءة وقابلية الصيانة واستخدام معالجة المهام المتعددة. ويجعل ذلك الرمز البرمجي أكثر ملاءمةً لاختبار الوحدة. لقد استغللنا هذه الفرصة وأنتجنا مجموعة من 700 اختبار وحدة تقريبًا تغطي حِزمنا الكاملة من إجراءات التحليل من المستوى المنخفض إلى مثيلات الأجهزة الافتراضية التي تشير إلى المستوى العالي.
ويشير مصطلح "الدقة" أيضًا إلى الدقّة، ويُعتبَر FreeType مُقدَّرًا بشدة لأجل إنشاء مخطّطات عالية الجودة. يجب أن تتطابق هذه الجودة لتكون بديلاً مناسبًا. وتحقيقًا لذلك، أنشأنا أداة مخصّصة تُسمى fauntlet والتي تقارن بين نتائج Skrifa وFreeType لحِزم من ملفات الخطوط على مستوى مجموعة كبيرة من الإعدادات. ويمنحنا ذلك بعض الطمأنينة بأنّه يمكننا تجنُّب التراجع في الجودة.
بالإضافة إلى ذلك، قبل الدمج في Chromium، أجرينا مجموعة كبيرة من مقارنة البكسل في Skia، من خلال مقارنة معالجة FreeType بمعالجة Skrifa وSkia لضمان أنّ اختلافات البكسل هي الحد الأدنى على الإطلاق، في جميع أوضاع المعالجة المطلوبة (على مستوى أوضاع التمويه والتلميح المختلفة).
اختبار التداخل هو أداة مهمة لتحديد كيفية تفاعل برنامج مع مدخلات ضارة وذات تنسيق غير صحيح. لقد كنا نفحص الرمز البرمجي الجديد باستمرار بحثًا عن أي ثغرات منذ حزيران (يونيو) 2024. ويشمل ذلك مكتبات Rust نفسها ورمز الدمج. على الرغم من أنّ أداة البحث عن الأخطاء قد عثرت (حتى وقت كتابة هذه السطور) على 39 خطأ، من الجدير بالذكر أنّ لم يكن أيّ منها خطيرًا على الأمان. وقد تؤدي إلى نتائج مرئية غير مرغوب فيها أو حتى تعطُّل متحكّم فيه، ولكنّها لن تؤدي إلى ثغرات قابلة للاستغلال.
إلى الأمام.
نحن سعداء جدًا بنتائج جهودنا لاستخدام Rust للنص. إنّ تقديم رموز أكثر أمانًا للمستخدمين وزيادة إنتاجية المطوّرين هو فوز عظيم بالنسبة إلينا. نخطّط لمواصلة البحث عن فرص لاستخدام Rust في أنظمة معالجة النصوص. إذا أردت معرفة المزيد، يمكنك الاطّلاع على مقالة Oxidize التي تلخّص بعض خطط Google Fonts المستقبلية.