वेब फ़ॉन्ट के लिए मेमोरी की सुरक्षा

Rod Sheeter
Rod Sheeter
Chad Brokaw
Chad Brokaw

पब्लिश किया गया: 19 मार्च, 2025

Skrifa को Rust में लिखा गया है. इसे FreeType की जगह पर इसलिए बनाया गया है, ताकि Chrome में फ़ॉन्ट प्रोसेसिंग को सभी उपयोगकर्ताओं के लिए सुरक्षित बनाया जा सके. Skifra, Rust की मेमोरी सेफ़्टी का फ़ायदा लेता है. साथ ही, इससे हमें Chrome में फ़ॉन्ट टेक्नोलॉजी के सुधारों को तेज़ी से लागू करने में मदद मिलती है. FreeType से Skrifa पर स्विच करने से, हमें फ़ॉन्ट कोड में बदलाव करते समय, तेज़ी से और बिना किसी डर के काम करने में मदद मिलती है. अब हम सुरक्षा से जुड़ी गड़बड़ियों को ठीक करने में काफ़ी कम समय लगाते हैं. इससे, अपडेट तेज़ी से किए जा सकते हैं और कोड की क्वालिटी भी बेहतर होती है.

इस पोस्ट में बताया गया है कि Chrome ने FreeType का इस्तेमाल क्यों बंद किया है. साथ ही, इस बदलाव से होने वाले सुधारों के बारे में कुछ दिलचस्प तकनीकी जानकारी भी दी गई है.

FreeType को क्यों बदलना चाहिए?

वेब एक ऐसा प्लैटफ़ॉर्म है जिस पर उपयोगकर्ता, कई तरह के गैर-भरोसेमंद सोर्स से गैर-भरोसेमंद रिसॉर्स फ़ेच कर सकते हैं. ऐसा करने पर, वे उम्मीद करते हैं कि सब कुछ ठीक से काम करेगा और वे सुरक्षित रहेंगे. आम तौर पर, यह उम्मीद सही होती है. हालांकि, उपयोगकर्ताओं को यह भरोसा दिलाने की कीमत चुकाई जाती है. उदाहरण के लिए, किसी वेब फ़ॉन्ट (नेटवर्क से डिलीवर किया जाने वाला फ़ॉन्ट) का सुरक्षित तरीके से इस्तेमाल करने के लिए, Chrome कई सुरक्षा उपाय अपनाता है:

  • दो के नियम के मुताबिक, फ़ॉन्ट प्रोसेसिंग को सैंडबॉक्स में रखा जाता है: ये भरोसेमंद नहीं होते और इन्हें इस्तेमाल करने वाला कोड असुरक्षित होता है.
  • फ़ॉन्ट को प्रोसेस करने से पहले, OpenType Sanitizer की मदद से फ़ॉन्ट की जांच की जाती है.
  • फ़ॉन्ट को डिकंप्रेस और प्रोसेस करने वाली सभी लाइब्रेरी की फ़ज़ जांच की जाती है.

Chrome में FreeType पहले से मौजूद होता है. साथ ही, Android, ChromeOS, और Linux पर फ़ॉन्ट प्रोसेस करने वाली मुख्य लाइब्रेरी के तौर पर इसका इस्तेमाल किया जाता है. इसका मतलब है कि अगर FreeType में कोई समस्या है, तो कई उपयोगकर्ताओं को खतरा हो सकता है.

Chrome, मेट्रिक का हिसाब लगाने और फ़ॉन्ट से हिंट वाली आउटलाइन लोड करने के लिए, FreeType लाइब्रेरी का इस्तेमाल करता है. कुल मिलाकर, FreeType का इस्तेमाल Google के लिए एक बड़ी जीत साबित हुआ है. यह एक मुश्किल काम करता है और इसे अच्छी तरह से करता है. हम इस पर काफ़ी भरोसा करते हैं और इसमें योगदान देते हैं. हालांकि, यह असुरक्षित कोड में लिखा गया है और इसकी शुरुआत उस समय हुई थी, जब नुकसान पहुंचाने वाले इनपुट की संभावना कम थी. फ़ज़िंग की मदद से मिलने वाली समस्याओं को ठीक करने के लिए, Google को कम से कम 0.25 फ़ुल टाइम सॉफ़्टवेयर इंजीनियर की ज़रूरत पड़ती है. इससे भी बुरा यह है कि हमें कुछ चीज़ें नहीं मिलती हैं या हमें वे चीज़ें सिर्फ़ तब मिलती हैं, जब कोड को उपयोगकर्ताओं को भेज दिया जाता है.

समस्याओं का यह पैटर्न सिर्फ़ FreeType के लिए नहीं है. हमने देखा है कि असुरक्षित दूसरी लाइब्रेरी में भी समस्याएं आती हैं. भले ही, हम सबसे अच्छे सॉफ़्टवेयर इंजीनियर का इस्तेमाल करें, हर बदलाव की कोड समीक्षा करें, और टेस्ट की ज़रूरत हो.

समस्याएं क्यों बार-बार आती रहती हैं

FreeType की सुरक्षा का आकलन करने पर, हमें पता चला है कि इसकी वजह से तीन तरह की समस्याएं हो सकती हैं. हालांकि, इनके अलावा और भी समस्याएं हो सकती हैं:

असुरक्षित भाषा का इस्तेमाल करना

पैटर्न/समस्या उदाहरण
मेमोरी को मैन्युअल तरीके से मैनेज करना
  • CVE-2014-9661, मुफ़्त में आज़माने के बाद इस्तेमाल करने की सुविधा, जिसकी पहचान Project Zero, Project Zero ट्रैकर ने की है
बिना जांच के ऐरे को ऐक्सेस करना CVE-2022-27404
इंटिजर ओवरफ़्लो CFF ड्रॉइंग और हिंट करने के लिए, एम्बेड की गई वर्चुअल मशीनों को चलाने के दौरान
https://issues.oss-fuzz.com/issues?q=FreeType%20Integer-overflow
शून्य और शून्य न होने वाले एलोकेशन का गलत इस्तेमाल https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests/94 में चर्चा, इसके बाद फ़ज़र से जुड़ी आठ समस्याएं मिलीं
अमान्य कास्ट मैक्रो के इस्तेमाल से जुड़ी यह लाइन देखें

प्रोजेक्ट से जुड़ी समस्याएं

पैटर्न/समस्या उदाहरण
मैक्रो की वजह से, साइज़ की जानकारी साफ़ तौर पर नहीं दिखती
  • FT_READ_* और FT_PEEK_* जैसे मैक्रो से यह पता नहीं चलता कि इंटिजर टाइप का इस्तेमाल किया जा रहा है या नहीं. साथ ही, यह भी नहीं पता चलता कि साफ़ तौर पर साइज़ (int16_t वगैरह) वाले C99 टाइप का इस्तेमाल नहीं किया जा रहा है
नए कोड में लगातार गड़बड़ियां जुड़ती रहती हैं. भले ही, उसे सुरक्षा के लिहाज़ से लिखा गया हो.
  • COLRv1 और OT-SVG, दोनों में समस्याएं आ सकती हैं
  • फ़ज़िंग से कुछ गड़बड़ियां मिलती हैं, लेकिन ज़रूरी नहीं कि सभी गड़बड़ियां मिलें, #32421, #52404
टेस्ट की कमी
  • टेस्ट फ़ॉन्ट बनाने में समय लगता है और यह मुश्किल भी होता है
  • उदाहरण के लिए, CVE-2020-15999 के लिए ठीक करने की सुविधा में कोई जांच नहीं जोड़ी गई है

डिपेंडेंसी से जुड़ी समस्याएं

फ़ज़िंग की मदद से, उन लाइब्रेरी में बार-बार समस्याओं का पता चला है जिन पर FreeType निर्भर है. जैसे, bzip2, libpng, और zlib. उदाहरण के लिए, freetype_bdf_fuzzer: inflate में, शुरू में वैल्यू सेट न करने की वजह से होने वाली गड़बड़ी की तुलना करें.

फ़ज़िंग काफ़ी नहीं है

फ़ज़िंग, कई तरह के इनपुट के साथ ऑटोमेटेड टेस्टिंग है. इसमें अमान्य इनपुट भी शामिल होते हैं. इसका मकसद, Chrome के स्थिर वर्शन में आने वाली कई तरह की समस्याओं का पता लगाना है. हम Google के oss-fuzz प्रोजेक्ट के तहत, FreeType को फ़ज़ करते हैं. यह समस्याओं का पता लगाता है, लेकिन फ़ॉन्ट, फ़ज़िंग के लिए कुछ हद तक प्रतिरोधी होते हैं. इसकी ये वजहें हैं.

फ़ॉन्ट फ़ाइलें वीडियो फ़ाइलों की तरह ही जटिल होती हैं. इसकी वजह यह है कि इनमें कई तरह की जानकारी होती है. फ़ॉन्ट फ़ाइलें, कई टेबल के लिए एक कंटेनर फ़ॉर्मैट होती हैं. इसमें हर टेबल, टेक्स्ट और फ़ॉन्ट को प्रोसेस करने में अलग-अलग काम करती है, ताकि स्क्रीन पर सही जगह पर ग्लिफ़ बनाया जा सके. फ़ॉन्ट फ़ाइल में, आपको ये चीज़ें मिलेंगी:

  • स्टैटिक मेटाडेटा, जैसे कि वैरिएबल फ़ॉन्ट के लिए फ़ॉन्ट के नाम और पैरामीटर.
  • यूनिकोड वर्णों से ग्लिफ़ में मैपिंग.
  • ग्लिफ़ के स्क्रीन लेआउट के लिए, नियमों का एक जटिल सेट और व्याकरण.
  • विज़ुअल जानकारी: स्क्रीन पर मौजूद ग्लिफ़ के आकार और इमेज की जानकारी.
    • विज़ुअल टेबल में TrueType हिंटिंग प्रोग्राम शामिल हो सकते हैं. ये ऐसे छोटे प्रोग्राम होते हैं जिन्हें ग्लिफ़ के आकार को बदलने के लिए चलाया जाता है.
    • CFF या CFF2 टेबल में मौजूद वर्ण स्ट्रिंग, जो CFF रेंडरिंग इंजन में लागू किए गए कर्व ड्रॉइंग और हिंट करने के निर्देश हैं.

फ़ॉन्ट फ़ाइलों में अपनी प्रोग्रामिंग भाषा और स्टेट मशीन प्रोसेसिंग होती है. इन फ़ाइलों को चलाने के लिए, खास वर्चुअल मशीनों की ज़रूरत होती है.

फ़ॉर्मैट की जटिलता की वजह से, फ़ॉन्ट फ़ाइलों में समस्याओं का पता लगाने में फ़ज़िंग की सुविधा काम नहीं करती.

अच्छी कोड कवरेज या फ़ज़र की प्रोग्रेस हासिल करना, इन वजहों से मुश्किल होता है:

  • बिट-फ़्लिपिंग/शिफ़्ट/इंसर्शन/मिटेशन वाले म्यूटेटर का इस्तेमाल करके, TrueType हिंटिंग प्रोग्राम, CFF चैरेक्टर स्ट्रिंग, और OpenType लेआउट को फ़ज़ करने पर, राज्यों के सभी कॉम्बिनेशन तक पहुंचने में मुश्किल होती है.
  • फ़ज़िंग से कम से कम कुछ हद तक मान्य स्ट्रक्चर होने चाहिए. रैंडम मल्टीटेशन से ऐसा कभी-कभार ही होता है. इससे कोड के गहरे लेवल के लिए, अच्छी कवरेज हासिल करना मुश्किल हो जाता है.
  • ClusterFuzz और oss-fuzz में फ़ज़िंग के मौजूदा तरीके, अब तक स्ट्रक्चर के हिसाब से म्यूटेशन का इस्तेमाल नहीं कर रहे हैं. व्याकरण या स्ट्रक्चर के बारे में जानकारी रखने वाले म्यूटेटर का इस्तेमाल करने से, ऐसे वैरिएंट बनाने से बचा जा सकता है जिन्हें शुरुआत में ही अस्वीकार कर दिया जाता है. हालांकि, इसके लिए, म्यूटेटर बनाने में ज़्यादा समय लगता है. साथ ही, ऐसे वैरिएंट भी बन सकते हैं जो खोज के लिए उपलब्ध जगह के कुछ हिस्सों को शामिल नहीं करते.

फ़ज़िंग की प्रोसेस को आगे बढ़ाने के लिए, एक से ज़्यादा टेबल में मौजूद डेटा सिंक होना चाहिए:

  • फ़ज़र के सामान्य म्यूटेशन पैटर्न से, कुछ हद तक मान्य डेटा नहीं मिलता. इसलिए, कई बार दोहराए जाने वाले टेस्ट अस्वीकार हो जाते हैं और प्रोग्रेस धीमी हो जाती है.
  • ग्लिफ़ मैपिंग, OpenType लेआउट टेबल, और ग्लिफ़ ड्रॉइंग एक-दूसरे से जुड़ी होती हैं और एक-दूसरे पर निर्भर करती हैं. इनसे एक ऐसा कॉम्बिनेटरी स्पेस बनता है जिसके कोने तक फ़ज़िंग की मदद से पहुंचना मुश्किल होता है.
  • उदाहरण के लिए, tt_face_get_paint COLRv1 की गंभीर समस्या का पता लगाने में 10 महीने से ज़्यादा समय लगा.

हमारी पूरी कोशिशों के बावजूद, फ़ॉन्ट की सुरक्षा से जुड़ी समस्याएं बार-बार असली उपयोगकर्ताओं तक पहुंच रही हैं. FreeType को Rust के किसी विकल्प से बदलने पर, कई तरह की कमज़ोरियों से बचा जा सकेगा.

Chrome में Skrifa का इस्तेमाल करना

Skia, Chrome की ग्राफ़िक लाइब्रेरी है. Skia, फ़ॉन्ट से मेटाडेटा और लेटरफ़ॉर्म लोड करने के लिए, FreeType पर निर्भर करता है. Skrifa एक Rust लाइब्रेरी है. यह लाइब्रेरी, Fontations लाइब्रेरी फ़ैमिली का हिस्सा है. यह Skia के इस्तेमाल किए जाने वाले FreeType के हिस्सों को सुरक्षित तरीके से बदलती है.

FreeType को Skia पर ट्रांज़िशन करने के लिए, Chrome की टीम ने Skrifa के आधार पर, एक नया Skia फ़ॉन्ट बैकएंड बनाया. साथ ही, इस बदलाव को धीरे-धीरे उपयोगकर्ताओं के लिए लॉन्च किया:

Chrome में इंटिग्रेशन के लिए, हम Chrome की सुरक्षा टीम के बनाए गए कोडबेस में Rust को आसानी से इंटिग्रेट करने पर भरोसा करते हैं.

आने वाले समय में, हम ऑपरेटिंग सिस्टम के फ़ॉन्ट के लिए भी Fontations का इस्तेमाल करेंगे. सबसे पहले, हम Linux और ChromeOS के लिए ऐसा करेंगे. इसके बाद, Android के लिए भी ऐसा करेंगे.

सुरक्षा सबसे अहम है

हमारा मुख्य मकसद, मेमोरी के ऐक्सेस की सीमा से बाहर होने की वजह से, सुरक्षा से जुड़ी जोखिम को कम करना (या पूरी तरह खत्म करना!) है. Rust में यह सुविधा पहले से मौजूद होती है. हालांकि, इसके लिए असुरक्षित कोड ब्लॉक का इस्तेमाल नहीं किया जाना चाहिए.

परफ़ॉर्मेंस के लक्ष्यों को पूरा करने के लिए, हमें एक ऐसा काम करना होगा जो फ़िलहाल सुरक्षित नहीं है: किसी भी तरह के बाइट को स्ट्रोंगली टाइप किए गए डेटा स्ट्रक्चर के तौर पर फिर से समझना. इससे, ग़ैर-ज़रूरी कॉपी बनाए बिना, फ़ॉन्ट फ़ाइल से डेटा पढ़ा जा सकता है. साथ ही, तेज़ फ़ॉन्ट पार्सर बनाने के लिए यह ज़रूरी है.

अपने को असुरक्षित कोड से बचाने के लिए, हमने इस ज़िम्मेदारी को bytemuck को आउटसोर्स करने का विकल्प चुना है. यह Rust लाइब्रेरी है, जिसे खास तौर पर इस काम के लिए डिज़ाइन किया गया है. इसे पूरे पारिस्थितिक तंत्र में बड़े पैमाने पर टेस्ट किया जाता है और इसका इस्तेमाल किया जाता है. रॉ डेटा को फिर से समझने की प्रोसेस को bytemuck में करने से, यह पक्का होता है कि हमारे पास यह सुविधा एक ही जगह पर हो और उसकी ऑडिटिंग की गई हो. साथ ही, इस काम के लिए असुरक्षित कोड का दोबारा इस्तेमाल करने से भी बचा जा सकता है. safe transmute प्रोजेक्ट का मकसद, इस सुविधा को सीधे Rust कंपाइलर में शामिल करना है. यह सुविधा उपलब्ध होने के बाद, हम इसे तुरंत इस्तेमाल करना शुरू कर देंगे.

सही जवाब देना ज़रूरी है

Skrifa को अलग-अलग कॉम्पोनेंट के साथ बनाया गया है. इसमें ज़्यादातर डेटा स्ट्रक्चर को बदले बिना इस्तेमाल करने के लिए डिज़ाइन किया गया है. इससे कोड को पढ़ने, उसे मैनेज करने, और कई प्रोसेस को एक साथ चलाने में मदद मिलती है. इससे कोड को यूनिट टेस्टिंग के लिए ज़्यादा आसानी से इस्तेमाल किया जा सकता है. हमने इस अवसर का फ़ायदा उठाया है और करीब 700 यूनिट टेस्ट का एक सुइट बनाया है. यह सुइट, हमारे पूरे स्टैक को कवर करता है. इसमें, कम लेवल के पार्सिंग रूटीन से लेकर, हाई लेवल की हिंट देने वाली वर्चुअल मशीनें शामिल हैं.

सही होने का मतलब फ़िडेलिटी से भी है. FreeType को अच्छी क्वालिटी वाली आउटलाइन जनरेट करने के लिए काफ़ी सम्मान मिलता है. सही विकल्प के तौर पर, हमें इस क्वालिटी से मेल खाने वाला विकल्प देना होगा. इसके लिए, हमने fauntlet नाम का एक टूल बनाया है. यह टूल, अलग-अलग कॉन्फ़िगरेशन में फ़ॉन्ट फ़ाइलों के बैच के लिए, Skrifa और FreeType के आउटपुट की तुलना करता है. इससे हमें यह भरोसा मिलता है कि हम क्वालिटी में गिरावट से बच सकते हैं.

इसके अलावा, Chromium में इंटिग्रेशन से पहले, हमने Skia में पिक्सल की तुलना करने के लिए कई तरह के टेस्ट किए. इनमें, FreeType रेंडरिंग की तुलना Skrifa और Skia रेंडरिंग से की गई. इससे यह पक्का किया जा सका कि ज़रूरी सभी रेंडरिंग मोड (अलग-अलग ऐंटीऐलिऐसिंग और हिंट मोड में) में, पिक्सल के बीच का फ़र्क़ कम से कम हो.

फ़ज़ टेस्टिंग एक अहम टूल है. इससे यह पता चलता है कि कोई सॉफ़्टवेयर, गलत और नुकसान पहुंचाने वाले इनपुट पर कैसे प्रतिक्रिया देगा. हम जून 2024 से अपने नए कोड को लगातार फ़ज़ कर रहे हैं. इसमें, Rust लाइब्रेरी और इंटिग्रेशन कोड शामिल हैं. फ़ज़र को (यह लेख लिखे जाने तक) 39 गड़बड़ियां मिली हैं. हालांकि, यह ध्यान देने वाली बात है कि इनमें से कोई भी गड़बड़ी, सुरक्षा के लिहाज़ से गंभीर नहीं है. इनकी वजह से, अनचाहे विज़ुअल नतीजे या कंट्रोल किए गए क्रैश हो सकते हैं. हालांकि, इनसे ऐसी कमजोरियां नहीं पैदा होंगी जिनका गलत इस्तेमाल किया जा सके.

आगे बढ़ें!

टेक्स्ट के लिए Rust का इस्तेमाल करने की हमारी कोशिशों के नतीजों से हमें बेहद खुशी हो रही है. उपयोगकर्ताओं को सुरक्षित कोड उपलब्ध कराना और डेवलपर की उत्पादकता बढ़ाना, हमारे लिए एक बड़ी उपलब्धि है. हम अपने टेक्स्ट स्टैक में Rust का इस्तेमाल करने के अवसरों को खोजते रहेंगे. अगर आपको ज़्यादा जानकारी चाहिए, तो Oxidize पर जाएं. यहां आपको Google Fonts के आने वाले समय के कुछ प्लान के बारे में जानकारी मिलेगी.