पब्लिश होने की तारीख: 19 मार्च, 2025
Blink से FreeType को हटा दिया है.Skrifa को Rust में लिखा गया है. इसे FreeType के विकल्प के तौर पर बनाया गया है, ताकि Chrome में फ़ॉन्ट प्रोसेसिंग को सभी उपयोगकर्ताओं के लिए सुरक्षित बनाया जा सके. Skrifa, Rust की मेमोरी सुरक्षा का फ़ायदा उठाता है. इससे हमें Chrome में फ़ॉन्ट टेक्नोलॉजी को बेहतर बनाने के लिए, तेज़ी से काम करने में मदद मिलती है. FreeType से Skrifa पर स्विच करने से, हमें फ़ॉन्ट कोड में बदलाव करते समय तेज़ी से काम करने और बिना किसी डर के बदलाव करने में मदद मिलती है. अब हमें सुरक्षा से जुड़ी गड़बड़ियों को ठीक करने में बहुत कम समय लगता है. इससे हमें अपडेट को तेज़ी से लागू करने और कोड की क्वालिटी को बेहतर बनाने में मदद मिलती है.
इस पोस्ट में बताया गया है कि Chrome ने FreeType का इस्तेमाल क्यों बंद कर दिया है. साथ ही, इस बदलाव से हुए सुधारों के बारे में कुछ दिलचस्प तकनीकी जानकारी भी दी गई है.
FreeType को क्यों बदला जा रहा है?
वेब की यह खासियत है कि यह उपयोगकर्ताओं को कई तरह के गैर-भरोसेमंद स्रोतों से गैर-भरोसेमंद संसाधन फ़ेच करने की अनुमति देता है. ऐसा इसलिए किया जाता है, ताकि वे आसानी से काम कर सकें और सुरक्षित रहें. आम तौर पर, यह अनुमान सही होता है. हालांकि, उपयोगकर्ताओं से किए गए इस वादे को पूरा करने के लिए, कुछ कीमत चुकानी पड़ती है. उदाहरण के लिए, वेब फ़ॉन्ट (नेटवर्क पर डिलीवर किया गया फ़ॉन्ट) का सुरक्षित तरीके से इस्तेमाल करने के लिए, Chrome सुरक्षा से जुड़े कई तरीके अपनाता है:
- फ़ॉन्ट प्रोसेसिंग को दो के नियम के मुताबिक, सैंडबॉक्स किया गया है: ये भरोसेमंद नहीं हैं और इस्तेमाल किया गया कोड सुरक्षित नहीं है.
- फ़ॉन्ट को प्रोसेस करने से पहले, OpenType Sanitizer से पास किया जाता है.
- फ़ॉन्ट को डीकंप्रेस करने और प्रोसेस करने में शामिल सभी लाइब्रेरी की फ़ज़ टेस्टिंग की जाती है.
Chrome में FreeType शामिल होता है. साथ ही, Android, ChromeOS, और Linux पर फ़ॉन्ट प्रोसेसिंग के लिए, मुख्य लाइब्रेरी के तौर पर इसका इस्तेमाल किया जाता है. इसका मतलब है कि अगर FreeType में कोई गड़बड़ी है, तो कई उपयोगकर्ताओं को इसका सामना करना पड़ सकता है.
Chrome, FreeType लाइब्रेरी का इस्तेमाल करके मेट्रिक का हिसाब लगाता है. साथ ही, फ़ॉन्ट से हिंट वाली आउटलाइन लोड करता है. कुल मिलाकर, Google के लिए FreeType का इस्तेमाल करना बहुत फ़ायदेमंद रहा है. यह एक मुश्किल काम को अच्छी तरह से पूरा करता है. हम इस पर काफ़ी हद तक भरोसा करते हैं और इसमें योगदान देते हैं. हालांकि, इसे असुरक्षित कोड में लिखा गया है. साथ ही, इसे उस समय बनाया गया था, जब नुकसान पहुंचाने वाले इनपुट मिलने की आशंका कम थी. फ़ज़िंग से मिली समस्याओं को ठीक करने के लिए, Google को कम से कम 0.25 फ़ुल टाइम सॉफ़्टवेयर इंजीनियरों की ज़रूरत होती है. इससे भी बुरी बात यह है कि हमें सभी गड़बड़ियां नहीं मिलती हैं या गड़बड़ियां तब मिलती हैं, जब कोड को उपयोगकर्ताओं के लिए उपलब्ध करा दिया जाता है.
इस तरह की समस्याएं सिर्फ़ FreeType में नहीं होती हैं. हमने देखा है कि अन्य असुरक्षित लाइब्रेरी में भी समस्याएं होती हैं. भले ही, हम सबसे अच्छे सॉफ़्टवेयर इंजीनियरों का इस्तेमाल करें, हर बदलाव की कोड समीक्षा करें, और टेस्ट ज़रूरी हों.
समस्याएं क्यों बनी रहती हैं
FreeType की सुरक्षा का आकलन करते समय, हमें तीन मुख्य तरह की समस्याएं मिलीं. हालांकि, इनके अलावा और भी समस्याएं हो सकती हैं:
असुरक्षित भाषा का इस्तेमाल करना
| पैटर्न/समस्या | उदाहरण |
|---|---|
| मैन्युअल तरीके से मेमोरी मैनेज करना |
|
| अनचेक किए गए ऐरे का ऐक्सेस | CVE-2022-27404 |
| पूर्णांक ओवरफ़्लो | CFF ड्राइंग और हिंटिंग के लिए, एम्बेड की गई वर्चुअल मशीनों को लागू करने के दौरान https://issues.oss-fuzz.com/issues?q=FreeType%20Integer-overflow |
| शून्य और गैर-शून्य असाइनमेंट का गलत इस्तेमाल | इसके बाद, https://gitlab.freedesktop.org/freetype/freetype/-/merge_requests/94 पर चर्चा हुई और फ़ज़र से जुड़ी आठ समस्याएं मिलीं |
| अमान्य कास्ट | मैक्रो के इस्तेमाल के बारे में यह लाइन देखें |
प्रोजेक्ट से जुड़ी समस्याएं
| पैटर्न/समस्या | उदाहरण |
|---|---|
| मैक्रो, साइज़ की टाइपिंग की जानकारी साफ़ तौर पर न देने की वजह से धुंधले हो जाते हैं |
|
| नया कोड लिखने पर, उसमें लगातार बग जुड़ते रहते हैं. भले ही, उसे सुरक्षा को ध्यान में रखकर लिखा गया हो. |
|
| टेस्ट की कमी |
|
डिपेंडेंसी से जुड़ी समस्याएं
फ़ज़िंग से, FreeType पर निर्भर रहने वाली लाइब्रेरी में बार-बार समस्याएं पाई गई हैं. जैसे, bzip2, libpng, और zlib. उदाहरण के लिए, freetype_bdf_fuzzer: Use-of-uninitialized-value in inflate की तुलना करें.
फ़ज़िंग काफ़ी नहीं है
फ़ज़िंग, ऑटोमेटेड टेस्टिंग का एक तरीका है. इसमें कई तरह के इनपुट इस्तेमाल किए जाते हैं. इनमें रैंडम तरीके से चुने गए अमान्य इनपुट भी शामिल होते हैं. इसका मकसद, उन समस्याओं का पता लगाना है जो Chrome की स्टेबल रिलीज़ में शामिल हो जाती हैं. हम Google के oss-fuzz प्रोजेक्ट के तहत, FreeType की फ़ज़िंग करते हैं. यह टूल समस्याओं का पता लगाता है. हालांकि, फ़ॉन्ट में गड़बड़ियां ढूंढना मुश्किल होता है. इसकी ये वजहें हैं.
फ़ॉन्ट फ़ाइलें जटिल होती हैं. इनकी तुलना वीडियो फ़ाइलों से की जा सकती है, क्योंकि इनमें कई तरह की जानकारी होती है. फ़ॉन्ट फ़ाइलें, कई टेबल के लिए कंटेनर फ़ॉर्मैट होती हैं. इनमें से हर टेबल, टेक्स्ट और फ़ॉन्ट को एक साथ प्रोसेस करने के लिए अलग-अलग काम करती है. इससे स्क्रीन पर सही जगह पर ग्लिफ़ दिखता है. फ़ॉन्ट की फ़ाइल में, आपको यह जानकारी मिलेगी:
- स्टैटिक मेटाडेटा, जैसे कि फ़ॉन्ट के नाम और वैरिएबल फ़ॉन्ट के लिए पैरामीटर.
- यूनिकोड वर्णों से ग्लिफ़ की मैपिंग.
- ग्लिफ़ के स्क्रीन लेआउट के लिए, नियमों और व्याकरण का एक जटिल सेट.
- विज़ुअल जानकारी: ग्लिफ़ के आकार और इमेज की जानकारी. इससे पता चलता है कि स्क्रीन पर रखे गए ग्लिफ़ कैसे दिखते हैं.
- विज़ुअल टेबल में TrueType हिंटिंग प्रोग्राम शामिल हो सकते हैं. ये छोटे प्रोग्राम होते हैं, जिनका इस्तेमाल ग्लिफ़ के आकार को बदलने के लिए किया जाता है.
- CFF या CFF2 टेबल में मौजूद वर्ण स्ट्रिंग. ये स्ट्रिंग, कर्व बनाने और हिंट देने के ज़रूरी निर्देश होती हैं. इन्हें CFF रेंडरिंग इंजन में लागू किया जाता है.
फ़ॉन्ट फ़ाइलों में जटिलता होती है. यह जटिलता, प्रोग्रामिंग की अपनी भाषा और स्टेट मशीन प्रोसेसिंग के बराबर होती है. इसलिए, इन्हें चलाने के लिए खास वर्चुअल मशीन की ज़रूरत होती है.
फ़ॉर्मैट के जटिल होने की वजह से, फ़ॉन्ट फ़ाइलों में समस्याएं ढूंढने में फ़ज़िंग की कुछ सीमाएं हैं.
इन वजहों से, कोड कवरेज या फ़ज़र की प्रोग्रेस को बेहतर बनाना मुश्किल होता है:
- बिट-फ़्लिपिंग/शिफ़्ट/इंसर्शन/डिलीशन-स्टाइल म्यूटेटर का इस्तेमाल करके, TrueType हिंटिंग प्रोग्राम, CFF char स्ट्रिंग, और OpenType लेआउट को फ़ज़ करने में, राज्यों के सभी कॉम्बिनेशन तक पहुंचने में मुश्किल होती है.
- फ़ज़िंग से कम से कम कुछ हद तक मान्य स्ट्रक्चर जनरेट होने चाहिए. रैंडम म्यूटेशन से ऐसा कभी-कभार ही होता है. इसलिए, अच्छी कवरेज हासिल करना मुश्किल हो जाता है. खास तौर पर, कोड के डीपर लेवल के लिए.
- ClusterFuzz और oss-fuzz में फ़िलहाल किए जा रहे फ़ज़िंग के प्रयासों में, स्ट्रक्चर के हिसाब से म्यूटेशन का इस्तेमाल नहीं किया जा रहा है. व्याकरण या स्ट्रक्चर के बारे में जानकारी रखने वाले म्यूटेटर का इस्तेमाल करने से, ऐसे वैरिएंट बनाने से बचा जा सकता है जिन्हें शुरुआती दौर में अस्वीकार कर दिया जाता है. हालांकि, इससे वैरिएंट बनाने में ज़्यादा समय लगता है और ऐसे वैरिएंट बनने की संभावना बढ़ जाती है जिनमें खोज के कुछ हिस्से शामिल नहीं होते.
फ़ज़िंग की प्रोसेस को आगे बढ़ाने के लिए, यह ज़रूरी है कि एक से ज़्यादा टेबल में मौजूद डेटा सिंक हो:
- फ़ज़र के सामान्य म्यूटेशन पैटर्न से, कुछ हद तक मान्य डेटा नहीं मिलता. इसलिए, कई इटरेशन अस्वीकार कर दिए जाते हैं और प्रोसेस धीमी हो जाती है.
- Glyph मैपिंग, OpenType लेआउट टेबल, और Glyph ड्राइंग एक-दूसरे से जुड़ी होती हैं और एक-दूसरे पर निर्भर करती हैं. ये मिलकर एक कॉम्बिनेटरियल स्पेस बनाती हैं. इस स्पेस के कोनों तक फ़ज़िंग के ज़रिए पहुंचना मुश्किल होता है.
- उदाहरण के लिए, tt_face_get_paint COLRv1 की गंभीर समस्या का पता लगाने में 10 महीने से ज़्यादा समय लगा.
हम पूरी कोशिश करते हैं कि फ़ॉन्ट की सुरक्षा से जुड़ी समस्याएं, उपयोगकर्ताओं तक न पहुंचें. हालांकि, ऐसा कई बार हो चुका है. FreeType को Rust के विकल्प से बदलने पर, कई तरह की कमज़ोरियों से बचा जा सकेगा.
Chrome में लिखना
Skia, Chrome की ओर से इस्तेमाल की जाने वाली ग्राफ़िक्स लाइब्रेरी है. Skia, फ़ॉन्ट से मेटाडेटा और लेटरफ़ॉर्म लोड करने के लिए FreeType पर निर्भर करता है. Skrifa, Rust लाइब्रेरी है. यह Fontations लाइब्रेरी फ़ैमिली का हिस्सा है. यह Skia में इस्तेमाल किए गए FreeType के हिस्सों के लिए सुरक्षित विकल्प उपलब्ध कराती है.
Chrome टीम ने FreeType को Skia में बदलने के लिए, Skrifa पर आधारित एक नया Skia फ़ॉन्ट बैकएंड बनाया. इसके बाद, इस बदलाव को धीरे-धीरे उपयोगकर्ताओं के लिए लॉन्च किया गया:
- हमने Chrome 128 (अगस्त 2024) में, Fontations को चालू किया था. इसका इस्तेमाल, कम इस्तेमाल किए जाने वाले फ़ॉन्ट फ़ॉर्मैट में किया जा सकता है. जैसे, कलर फ़ॉन्ट और CFF2. इसे सुरक्षित तरीके से आज़माने के लिए चालू किया गया था.
- हमने Chrome 133 (फ़रवरी 2025) में, Linux, Android, और ChromeOS पर इस्तेमाल होने वाले सभी वेब फ़ॉन्ट के लिए Fontations की सुविधा चालू की है. साथ ही, Windows और Mac पर फ़ॉलबैक के तौर पर इस्तेमाल होने वाले वेब फ़ॉन्ट के लिए भी यह सुविधा चालू की है. ऐसा उन मामलों में किया गया है जहां सिस्टम किसी फ़ॉन्ट फ़ॉर्मैट के साथ काम नहीं करता है, लेकिन Chrome को उसे दिखाना होता है.
Chrome में इंटिग्रेट करने के लिए, हम Chrome की सुरक्षा टीम की ओर से पेश किए गए कोडबेस में Rust के आसानी से इंटिग्रेट होने पर निर्भर करते हैं.
आने वाले समय में, हम ऑपरेटिंग सिस्टम के फ़ॉन्ट के लिए भी Fontations का इस्तेमाल करेंगे. इसकी शुरुआत Linux और ChromeOS से होगी. इसके बाद, इसे Android पर उपलब्ध कराया जाएगा.
सुरक्षा सबसे ज़रूरी है
हमारा मुख्य मकसद, मेमोरी को तय सीमा से बाहर ऐक्सेस करने की वजह से होने वाली सुरक्षा से जुड़ी कमियों को कम करना है. हमारा लक्ष्य है कि इन कमियों को पूरी तरह से खत्म कर दिया जाए. Rust, यह सुविधा डिफ़ॉल्ट रूप से उपलब्ध कराता है. हालांकि, इसके लिए आपको असुरक्षित कोड ब्लॉक से बचना होगा.
परफ़ॉर्मेंस के लक्ष्यों को पूरा करने के लिए, हमें एक ऐसा ऑपरेशन करना होगा जो फ़िलहाल सुरक्षित नहीं है: किसी भी बाइट को मज़बूत टाइप वाले डेटा स्ट्रक्चर के तौर पर फिर से समझना. इससे हमें फ़ॉन्ट फ़ाइल से डेटा पढ़ने की अनुमति मिलती है. इसके लिए, हमें गैर-ज़रूरी कॉपी नहीं बनानी पड़ती. साथ ही, यह फ़ॉन्ट पार्सर को तेज़ी से बनाने के लिए ज़रूरी है.
हमारा कोड असुरक्षित न हो, इसके लिए हमने इस काम को bytemuck को आउटसोर्स किया है. यह एक रस्ट लाइब्रेरी है, जिसे खास तौर पर इसी काम के लिए डिज़ाइन किया गया है. साथ ही, इसे पूरे इकोसिस्टम में बड़े पैमाने पर टेस्ट किया गया है और इसका इस्तेमाल किया जाता है. बाइटमॉक में रॉ डेटा को फिर से इंटरप्रेट करने पर ध्यान देने से, यह पक्का होता है कि हमारे पास यह सुविधा एक ही जगह पर उपलब्ध है और इसकी ऑडिट की गई है. साथ ही, इससे इस काम के लिए असुरक्षित कोड को दोहराने से बचा जा सकता है. safe transmute project का मकसद, इस सुविधा को सीधे तौर पर Rust कंपाइलर में शामिल करना है. यह सुविधा उपलब्ध होते ही, हम इसे लागू कर देंगे.
सही जवाब देना ज़रूरी है
Skrifa को अलग-अलग कॉम्पोनेंट से बनाया गया है. इसमें ज़्यादातर डेटा स्ट्रक्चर को इस तरह से डिज़ाइन किया गया है कि उनमें बदलाव न किया जा सके. इससे कोड को पढ़ना, बनाए रखना, और मल्टीथ्रेडिंग करना आसान हो जाता है. इससे कोड की यूनिट टेस्टिंग भी आसानी से की जा सकती है. हमने इस मौके का फ़ायदा उठाया है और करीब 700 यूनिट टेस्ट का एक सुइट तैयार किया है. इसमें लो लेवल पार्सिंग रूटीन से लेकर हाई लेवल हिंटिंग वर्चुअल मशीन तक, हमारा पूरा स्टैक शामिल है.
सही होने का मतलब फ़िडेलिटी भी है. FreeType को अच्छी क्वालिटी वाली आउटलाइन जनरेट करने के लिए काफ़ी सराहा जाता है. बदलाव करने के लिए, हमें इस क्वालिटी से मेल खाना होगा. इसके लिए, हमने fauntlet नाम का एक खास टूल बनाया है. यह टूल, अलग-अलग कॉन्फ़िगरेशन के हिसाब से फ़ॉन्ट फ़ाइलों के बैच के लिए, Skrifa और FreeType के आउटपुट की तुलना करता है. इससे हमें यह भरोसा मिलता है कि हम क्वालिटी में गिरावट को रोक सकते हैं.
इसके अलावा, Chromium में इंटिग्रेट करने से पहले, हमने Skia में पिक्सेल की तुलना करने के लिए कई टेस्ट किए. इनमें, FreeType रेंडरिंग की तुलना Skrifa से और Skia रेंडरिंग की तुलना यह पक्का करने के लिए की गई कि पिक्सेल में अंतर कम से कम हो. साथ ही, यह भी पक्का किया गया कि सभी ज़रूरी रेंडरिंग मोड (अलग-अलग एंटीएलियासिंग और हिंटिंग मोड में) में ऐसा हो.
फ़ज़ टेस्टिंग एक अहम टूल है. इससे यह पता लगाया जा सकता है कि कोई सॉफ़्टवेयर, गलत तरीके से बनाए गए और नुकसान पहुंचाने वाले इनपुट पर कैसा व्यवहार करेगा. हम जून 2024 से लगातार अपने नए कोड की फ़ज़िंग कर रहे हैं. इसमें Rust लाइब्रेरी और इंटिग्रेशन कोड, दोनों शामिल हैं. फ़ज़र को (इस लेख के लिखे जाने तक) 39 गड़बड़ियां मिली हैं. हालांकि, यह ध्यान देने वाली बात है कि इनमें से कोई भी गड़बड़ी सुरक्षा के लिहाज़ से गंभीर नहीं है. इनसे अनचाहे विज़ुअल नतीजे मिल सकते हैं या यहां तक कि क्रैश भी हो सकते हैं. हालांकि, इनसे ऐसी कमज़ोरियां नहीं पैदा होंगी जिनका फ़ायदा उठाया जा सके.
Onward!
हमें टेक्स्ट के लिए Rust का इस्तेमाल करने के अपने प्रयासों के नतीजों से बहुत खुशी हुई है. उपयोगकर्ताओं को सुरक्षित कोड उपलब्ध कराना और डेवलपर की कार्यक्षमता को बढ़ाना, हमारे लिए एक बड़ी उपलब्धि है. हम अपने टेक्स्ट स्टैक में Rust का इस्तेमाल करने के लिए, अवसरों की तलाश जारी रखेंगे. अगर आपको ज़्यादा जानना है, तो Oxidize में Google Fonts के कुछ आने वाले प्लान के बारे में बताया गया है.