साल 2016 तक, Android पर मौजूद सभी कमज़ोरियों में से करीब 86%, मेमोरी की सुरक्षा से जुड़ी थीं. ज़्यादातर जोखिम की आशंकाओं का फ़ायदा उठाकर, हमलावर किसी ऐप्लिकेशन के सामान्य कंट्रोल फ़्लो में बदलाव करते हैं. ऐसा इसलिए किया जाता है, ताकि वे ऐप्लिकेशन के सभी विशेषाधिकारों का इस्तेमाल करके, नुकसान पहुंचाने वाली गतिविधियां कर सकें. कंट्रोल फ़्लो इंटिग्रिटी (CFI) एक सुरक्षा तंत्र है. यह किसी कंपाइल किए गए बाइनरी के मूल कंट्रोल फ़्लो ग्राफ़ में बदलाव करने की अनुमति नहीं देता. इससे इस तरह के हमले करना काफ़ी मुश्किल हो जाता है.
Android 8.1 में, हमने मीडिया स्टैक में LLVM के CFI को लागू किया है. Android 9 में, हमने ज़्यादा कॉम्पोनेंट और कर्नेल में सीएफ़आई को चालू किया है. सिस्टम सीएफ़आई डिफ़ॉल्ट रूप से चालू होता है. हालांकि, आपको कर्नेल सीएफ़आई चालू करना होगा.
LLVM के CFI को लिंक-टाइम ऑप्टिमाइज़ेशन (LTO) के साथ कॉम्पाइल करने की ज़रूरत होती है. LTO, ऑब्जेक्ट फ़ाइलों के LLVM बिटकोड को लिंक करने के समय तक सुरक्षित रखता है. इससे कंपाइलर को यह तय करने में मदद मिलती है कि कौनसे ऑप्टिमाइज़ेशन किए जा सकते हैं. LTO को चालू करने से, फ़ाइनल बाइनरी का साइज़ कम हो जाता है और परफ़ॉर्मेंस बेहतर होती है. हालांकि, इससे कंपाइल करने में लगने वाला समय बढ़ जाता है. Android पर टेस्ट करने पर, LTO और CFI के कॉम्बिनेशन से कोड के साइज़ और परफ़ॉर्मेंस पर बहुत कम असर पड़ता है. कुछ मामलों में, दोनों में सुधार होता है.
सीएफ़आई और फ़ॉरवर्ड-कंट्रोल की अन्य जांच को मैनेज करने के तरीके के बारे में ज़्यादा तकनीकी जानकारी के लिए, LLVM डिज़ाइन दस्तावेज़ देखें.
उदाहरण और सोर्स
सीएफ़आई, कंपाइलर की ओर से उपलब्ध कराया जाता है. यह कंपाइल करने के दौरान, बाइनरी में इंस्ट्रूमेंटेशन जोड़ता है. हम Clang टूलचेन और AOSP में Android बिल्ड सिस्टम में सीएफ़आई का इस्तेमाल करते हैं.
/platform/build/target/product/cfi-common.mk
में मौजूद कॉम्पोनेंट के सेट के लिए, Arm64 डिवाइसों पर सीएफ़आई डिफ़ॉल्ट रूप से चालू होता है.
यह सुविधा, मीडिया कॉम्पोनेंट की मेकफ़ाइल/ब्लूप्रिंट फ़ाइलों के सेट में भी सीधे तौर पर चालू होती है. जैसे, /platform/frameworks/av/media/libmedia/Android.bp
और /platform/frameworks/av/cmds/stagefright/Android.mk
.
सिस्टम सीएफ़आई लागू करना
Clang और Android बिल्ड सिस्टम का इस्तेमाल करने पर, सीएफ़आई डिफ़ॉल्ट रूप से चालू होता है. सीएफ़आई की मदद से, Android उपयोगकर्ताओं को सुरक्षित रखा जा सकता है. इसलिए, आपको इसे बंद नहीं करना चाहिए.
हमारा सुझाव है कि आप अन्य कॉम्पोनेंट के लिए भी सीएफ़आई चालू करें. इसके लिए, खास तौर पर, ऐक्सेस लेवल वाला नेटिव कोड या ऐसा नेटिव कोड इस्तेमाल किया जाता है जो उपयोगकर्ता के अविश्वसनीय इनपुट को प्रोसेस करता है. अगर clang और Android बिल्ड सिस्टम का इस्तेमाल किया जा रहा है, तो अपनी मेकफ़ाइलों या ब्लूप्रिंट फ़ाइलों में कुछ लाइनें जोड़कर, नए कॉम्पोनेंट में सीएफ़आई को चालू किया जा सकता है.
मेकफ़ाइल में सीएफ़आई का इस्तेमाल करना
/platform/frameworks/av/cmds/stagefright/Android.mk
जैसी किसी मेक फ़ाइल में सीएफ़आई चालू करने के लिए,
यह जोड़ें:
LOCAL_SANITIZE := cfi # Optional features LOCAL_SANITIZE_DIAG := cfi LOCAL_SANITIZE_BLACKLIST := cfi_blacklist.txt
LOCAL_SANITIZE
, बिल्ड के दौरान CFI को सैनिटाइज़र के तौर पर तय करता है.LOCAL_SANITIZE_DIAG
, सीएफ़आई के लिए गड़बड़ी की जानकारी देने वाला मोड चालू करता है. गड़बड़ी का पता लगाने वाला मोड, क्रैश होने के दौरान, logcat में डीबग से जुड़ी अतिरिक्त जानकारी प्रिंट करता है. यह जानकारी, बाइल्ड बनाने और उनकी जांच करते समय काम की होती है. हालांकि, प्रोडक्शन बिल्ड से डाइग्नोस्टिक्स मोड को हटाना न भूलें.LOCAL_SANITIZE_BLACKLIST
की मदद से, कॉम्पोनेंट अलग-अलग फ़ंक्शन या सोर्स फ़ाइलों के लिए, CFI इंस्ट्रूमेंटेशन को चुनिंदा तौर पर बंद कर सकते हैं. उपयोगकर्ताओं को होने वाली किसी भी समस्या को ठीक करने के लिए, आखिरी उपाय के तौर पर ब्लैकलिस्ट का इस्तेमाल किया जा सकता है. ज़्यादा जानकारी के लिए, सीएफ़आई बंद करना लेख पढ़ें.
ब्लूप्रिंट फ़ाइलों में सीएफ़आई का इस्तेमाल करना
/platform/frameworks/av/media/libmedia/Android.bp
जैसी ब्लूप्रिंट फ़ाइल में सीएफ़आई चालू करने के लिए, ये जोड़ें:
sanitize: { cfi: true, diag: { cfi: true, }, blacklist: "cfi_blacklist.txt", },
समस्या का हल
अगर नए कॉम्पोनेंट में सीएफ़आई चालू किया जा रहा है, तो आपको फ़ंक्शन टाइप मैच न होने की गड़बड़ियां और असेंबली कोड टाइप मैच न होने की गड़बड़ियां हो सकती हैं.
फ़ंक्शन टाइप मैच न होने की गड़बड़ियां इसलिए होती हैं, क्योंकि सीएफ़आई, इनडायरेक्ट कॉल को सिर्फ़ उन फ़ंक्शन पर जंप करने की अनुमति देता है जिनका डाइनैमिक टाइप, कॉल में इस्तेमाल किए गए स्टैटिक टाइप जैसा होता है. सीएफ़आई, वर्चुअल और नॉन-वर्चुअल मेंबर फ़ंक्शन कॉल को सिर्फ़ उन ऑब्जेक्ट पर जंप करने की अनुमति देता है जो कॉल करने के लिए इस्तेमाल किए गए ऑब्जेक्ट के स्टैटिक टाइप के डेरिव्ड क्लास होते हैं. इसका मतलब है कि अगर आपके पास ऐसा कोड है जो इनमें से किसी भी अनुमान का उल्लंघन करता है, तो CFI जो इंस्ट्रूमेंटेशन जोड़ता है वह बंद हो जाएगा. उदाहरण के लिए, स्टैक ट्रेस में SIGABRT दिखता है और logcat में कंट्रोल फ़्लो इंटिग्रिटी के बारे में एक लाइन होती है, जिसमें मैच न होने की जानकारी मिलती है.
इसे ठीक करने के लिए, पक्का करें कि जिस फ़ंक्शन को कॉल किया गया है उसका टाइप, स्टैटिक तौर पर तय किए गए टाइप से मेल खाता हो. यहां सीएल के दो उदाहरण दिए गए हैं:
- ब्लूटूथ: /c/platform/system/bt/+/532377
- एनएफ़सी: /c/platform/system/nfc/+/527858
एक और संभावित समस्या यह है कि ऐसे कोड में सीएफ़आई चालू करने की कोशिश की जा रही है जिसमें असेंबली के लिए इनडायरेक्ट कॉल शामिल हैं. असेंबली कोड टाइप नहीं किया जाता है, इसलिए टाइप मैच नहीं होता.
इसे ठीक करने के लिए, हर असेंबली कॉल के लिए नेटिव कोड के रैपर बनाएं. साथ ही, रैपर को वही फ़ंक्शन हस्ताक्षर दें जो कॉलिंग पॉइंटर के लिए है. इसके बाद, रैपर सीधे तौर पर असेंबली कोड को कॉल कर सकता है. सीधे ब्रैंच को सीएफ़आई से इंस्ट्रूमेंट नहीं किया जाता है. साथ ही, उन्हें रनटाइम पर फिर से पॉइंट नहीं किया जा सकता. इसलिए, इनसे सुरक्षा से जुड़ा कोई जोखिम नहीं होता. इससे समस्या ठीक हो जाएगी.
अगर असेंबली फ़ंक्शन बहुत ज़्यादा हैं और उन सभी को ठीक नहीं किया जा सकता, तो उन सभी फ़ंक्शन को भी ब्लैकलिस्ट किया जा सकता है जिनमें असेंबली के लिए इनडायरेक्ट कॉल हैं. इसका सुझाव नहीं दिया जाता, क्योंकि इससे इन फ़ंक्शन पर सीएफ़आई जांच बंद हो जाती है. इससे, हमले का दायरा बढ़ जाता है.
सीएफ़आई बंद करना
हमें परफ़ॉर्मेंस में कोई समस्या नहीं मिली. इसलिए, आपको सीएफ़आई को बंद करने की ज़रूरत नहीं है. हालांकि, अगर उपयोगकर्ता पर असर पड़ता है, तो कंपाइल करने के समय सैनिटाइज़र की ब्लैकलिस्ट फ़ाइल देकर, अलग-अलग फ़ंक्शन या सोर्स फ़ाइलों के लिए CFI को चुनिंदा तौर पर बंद किया जा सकता है. ब्लैकलिस्ट, कंपाइलर को बताती है कि वह तय की गई जगहों पर CFI इंस्ट्रूमेंटेशन को बंद करे.
Android बिल्ड सिस्टम, हर कॉम्पोनेंट के लिए ब्लैकलिस्ट की सुविधा देता है. इससे आपको ऐसी सोर्स फ़ाइलें या अलग-अलग फ़ंक्शन चुनने की अनुमति मिलती है जिन्हें सीएफ़आई इंस्ट्रूमेंटेशन नहीं मिलेगा. यह सुविधा, Make और Soong, दोनों के लिए उपलब्ध है. ब्लैकलिस्ट फ़ाइल के फ़ॉर्मैट के बारे में ज़्यादा जानकारी के लिए, अपस्ट्रीम Clang दस्तावेज़ देखें.
पुष्टि करें
फ़िलहाल, सीएफ़आई के लिए कोई सीटीएस टेस्ट उपलब्ध नहीं है. इसके बजाय, पक्का करें कि सीटीएस टेस्ट, सीएफ़आई चालू होने पर और बिना चालू होने पर, दोनों ही स्थितियों में पास हों. इससे यह पुष्टि की जा सकेगी कि सीएफ़आई का डिवाइस पर कोई असर नहीं पड़ रहा है.