AddressSanitizer (ASan), तेज़ कंपाइलर पर आधारित एक टूल है. इसका इस्तेमाल, नेटिव कोड में मौजूद मेमोरी बग का पता लगाने के लिए किया जाता है.
ASan इनका पता लगाता है:
- स्टैक और हीप बफ़र ओवरफ़्लो/अंडरफ़्लो
- मुफ़्त के बाद हीप का इस्तेमाल
- स्कोप के बाहर स्टैक का इस्तेमाल करना
- डबल फ़्री/वाइल्ड फ़्री
ASan, 32-बिट और 64-बिट ARM, साथ ही, x86 और x86-64, दोनों पर काम करता है. ASan के सीपीयू पर होने वाला ओवरहेड करीब दो गुना होता है. कोड साइज़ का ओवरहेड 50% से दो गुना के बीच होता है. साथ ही, ज़्यादा मेमोरी का ओवरहेड होता है. यह आपके ऐलोकेशन पैटर्न पर निर्भर करता है, लेकिन यह दो गुना होता है.
AArch64 पर Android 10 और AOSP की मुख्य शाखा, हार्डवेयर की मदद से काम करने वाले AddressSanitizer (HWASan) के साथ काम करती है. यह एक ऐसा टूल है जो रैम का कम इस्तेमाल करता है और ज़्यादा बग का पता लगाता है. HWASan, वापस आने के बाद, स्टैक इस्तेमाल का पता लगाता है. इसके अलावा, ASan ने जिन गड़बड़ियों का पता लगाया है उनका पता भी लगा देता है.
HWASan में सीपीयू और कोड साइज़ का ओवरहेड एक जैसा है, लेकिन रैम का ओवरहेड बहुत कम (15%) है. HWASan पूरी तरह से तय नहीं होता है. टैग की सिर्फ़ 256 वैल्यू हो सकती हैं. इसलिए, किसी भी गड़बड़ी को न ढूंढ पाने की संभावना 0.4% होती है. HWASan में, ASan के सीमित साइज़ वाले रेड ज़ोन नहीं होते. ये ज़ोन, ओवरफ़्लो का पता लगाने के लिए होते हैं. साथ ही, इसमें सीमित क्षमता वाले क्वॉरंटीन भी नहीं होते. ये क्वॉरंटीन, इस्तेमाल के बाद मेमोरी को डिलीकेट करने का पता लगाने के लिए होते हैं. इसलिए, HWASan के लिए यह मायने नहीं रखता कि ओवरफ़्लो कितना बड़ा है या मेमोरी को कब डिलीकेट किया गया था. इससे HWASan, ASan से बेहतर बनता है. HWASan के डिज़ाइन या Android पर HWASan के इस्तेमाल के बारे में ज़्यादा पढ़ा जा सकता है.
ASan, हेप ओवरफ़्लो के साथ-साथ स्टैक/ग्लोबल ओवरफ़्लो का पता लगाता है. साथ ही, यह कम से कम मेमोरी ओवरहेड के साथ तेज़ी से काम करता है.
इस दस्तावेज़ में, ASan की मदद से Android के कुछ हिस्सों या पूरे Android को बनाने और चलाने का तरीका बताया गया है. अगर आपको ASan की मदद से, SDK टूल/NDK ऐप्लिकेशन बनाना है, तो Address Sanitizer देखें.
ASan की मदद से, अलग-अलग एक्सीक्यूटेबल को साफ़ करना
रन किए जा सकने वाले प्रोग्राम के लिए, बिल्ड नियम में LOCAL_SANITIZE:=address
या sanitize: { address: true }
जोड़ें. मौजूदा उदाहरणों के लिए या उपलब्ध अन्य सैनिटाइज़र ढूंढने के लिए, कोड खोजा जा सकता है.
गड़बड़ी का पता चलने पर, ASan स्टैंडर्ड आउटपुट और logcat
, दोनों में एक लंबी रिपोर्ट प्रिंट करता है. इसके बाद, प्रोसेस क्रैश हो जाती है.
ASan की मदद से, शेयर की गई लाइब्रेरी को सुरक्षित करना
ASan के काम करने के तरीके की वजह से, ASan की मदद से बनाई गई लाइब्रेरी का इस्तेमाल, सिर्फ़ ASan की मदद से बनाई गई किसी प्रोग्राम को चलाने के लिए किया जा सकता है.
शेयर की गई ऐसी लाइब्रेरी को सैनिटाइज़ करने के लिए जिसका इस्तेमाल कई एक्सीक्यूटेबल में किया जाता है, आपको लाइब्रेरी की दो कॉपी की ज़रूरत होती है. हालांकि, इनमें से सभी एक्सीक्यूटेबल को ASan के साथ नहीं बनाया जाता. ऐसा करने का सुझाया गया तरीका यह है कि जिस मॉड्यूल की शिकायत की गई है उसके लिए Android.mk
में यह तरीका जोड़ें:
LOCAL_SANITIZE:=address LOCAL_MODULE_RELATIVE_PATH := asan
इससे लाइब्रेरी, /system/lib
के बजाय /system/lib/asan
में दिखती है. इसके बाद, अपनी एक्ज़ीक्यूटेबल फ़ाइल को इसके साथ चलाएं:
LD_LIBRARY_PATH=/system/lib/asan
सिस्टम डेमन के लिए, /init.rc
या /init.$device$.rc
के सही सेक्शन में ये जोड़ें.
setenv LD_LIBRARY_PATH /system/lib/asan
पुष्टि करें कि प्रोसेस, /proc/$PID/maps
को पढ़कर /system/lib/asan
की लाइब्रेरी का इस्तेमाल कर रही है. अगर ऐसा नहीं है, तो आपको SELinux को बंद करना पड़ सकता है:
adb root
adb shell setenforce 0
# restart the process with adb shell kill $PID # if it is a system service, or may be adb shell stop; adb shell start.
बेहतर स्टैक ट्रेस
ASan, प्रोग्राम में हर मेमोरी ऐलोकेशन और डिऐलोकेशन इवेंट के लिए, स्टैक ट्रैस रिकॉर्ड करने के लिए, फ़्रेम-पॉइंटर पर आधारित तेज़ अनवाइंडर का इस्तेमाल करता है. Android का ज़्यादातर हिस्सा, फ़्रेम पॉइंटर के बिना बनाया गया है. इस वजह से, आपको अक्सर एक या दो काम के फ़्रेम ही मिलते हैं. इसे ठीक करने के लिए, लाइब्रेरी को ASan (सुझाया गया!) या इनमें से किसी एक के साथ फिर से बनाएं:
LOCAL_CFLAGS:=-fno-omit-frame-pointer LOCAL_ARM_MODE:=arm
इसके अलावा, प्रोसेस के एनवायरमेंट में ASAN_OPTIONS=fast_unwind_on_malloc=0
सेट करें. बाद वाले कोड के लोड के हिसाब से, सीपीयू पर काफ़ी ज़्यादा डेटा खर्च हो सकता है.
प्रतीक
शुरुआत में, ASan रिपोर्ट में बाइनरी और शेयर की गई लाइब्रेरी में ऑफ़सेट के रेफ़रंस होते हैं. सोर्स फ़ाइल और लाइन की जानकारी पाने के दो तरीके हैं:
- पक्का करें कि
llvm-symbolizer
बाइनरी,/system/bin
में मौजूद हो.llvm-symbolizer
कोthird_party/llvm/tools/llvm-symbolizer
में मौजूद सोर्स से बनाया गया है. external/compiler-rt/lib/asan/scripts/symbolize.py
स्क्रिप्ट से रिपोर्ट को फ़िल्टर करें.
होस्ट पर सिंबल वाली लाइब्रेरी उपलब्ध होने की वजह से, दूसरे तरीके से ज़्यादा डेटा (यानी file:line
जगहें) मिल सकता है.
ऐप्लिकेशन में ASan
ASan, Java कोड को नहीं देख सकता. हालांकि, यह JNI
लाइब्रेरी में बग का पता लगा सकता है. इसके लिए, आपको ASan की मदद से, एक्सीक्यूटेबल बनाना होगा, जो इस मामले में /system/bin/app_process(32|64)
है. इससे, डिवाइस पर मौजूद सभी ऐप्लिकेशन में एक साथ ASan चालू हो जाता है. यह डिवाइस पर ज़्यादा लोड डालता है. हालांकि, 2 जीबी रैम वाला डिवाइस इसे हैंडल कर सकता है.
frameworks/base/cmds/app_process
में app_process
के बिल्ड नियम में LOCAL_SANITIZE:=address
जोड़ें. फ़िलहाल, उसी फ़ाइल में app_process__asan
टारगेट को अनदेखा करें (अगर इसे पढ़ते समय यह अब भी वहां मौजूद है).
class main
वाली इंडेंट की गई लाइनों के ब्लॉक में, ये लाइनें जोड़ने के लिए, सही system/core/rootdir/init.zygote(32|64).rc
फ़ाइल के service zygote
सेक्शन में बदलाव करें. इन लाइनों को भी उतनी ही इंडेंट करें जितनी इंडेंट की गई class main
वाली लाइनों को किया गया है:
setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib setenv ASAN_OPTIONS allow_user_segv_handler=true
बिल्ड, adb सिंक, फ़ास्टबूट फ़्लैश बूट, और रीबूट.
wrap प्रॉपर्टी का इस्तेमाल करना
पिछले सेक्शन में बताए गए तरीके से, सिस्टम के हर ऐप्लिकेशन में ASan को शामिल किया जाता है. असल में, Zygote प्रोसेस के हर डिससेंडेंट में इसे शामिल किया जाता है. ASan की मदद से, सिर्फ़ एक या कई ऐप्लिकेशन चलाए जा सकते हैं. इसके लिए, ऐप्लिकेशन के स्टार्टअप में थोड़ी देरी हो सकती है.
ऐसा करने के लिए, अपने ऐप्लिकेशन को wrap.
प्रॉपर्टी से शुरू करें.
नीचे दिया गया उदाहरण ASan के तहत Gmail ऐप्लिकेशन चलाता है:
adb root
adb shell setenforce 0 # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"
इस संदर्भ में, asanwrapper
/system/bin/app_process
को /system/bin/asan/app_process
में फिर से लिखता है, जिसे ASan के साथ बनाया गया है. यह डाइनैमिक लाइब्रेरी के खोज पाथ की शुरुआत में भी /system/lib/asan
जोड़ता है. इस तरह, asanwrapper
के साथ चलाते समय /system/lib
में मौजूद सामान्य लाइब्रेरी की जगह /system/lib/asan
की ASan-instrumented लाइब्रेरी को प्राथमिकता दी जाती है.
अगर कोई गड़बड़ी मिलती है, तो ऐप्लिकेशन क्रैश हो जाता है और रिपोर्ट को लॉग में प्रिंट कर दिया जाता है.
SANITIZE_TARGET
Android 7.0 और इसके बाद के वर्शन में, पूरे Android प्लैटफ़ॉर्म को एक साथ ASan के साथ बनाने की सुविधा शामिल है. (अगर Android 9 से ज़्यादा वर्शन की रिलीज़ बनाई जा रही है, तो HWASan एक बेहतर विकल्प है.)
उसी बिल्ड ट्री में ये कमांड चलाएं.
make -j42
SANITIZE_TARGET=address make -j42
इस मोड में, userdata.img
में अतिरिक्त लाइब्रेरी होती हैं और इन्हें डिवाइस पर भी फ़्लैश करना ज़रूरी होता है. इस कमांड लाइन का इस्तेमाल करें:
fastboot flash userdata && fastboot flashall
इससे शेयर की गई लाइब्रेरी के दो सेट बनते हैं: /system/lib
में सामान्य (make का पहला अनुरोध) और /data/asan/lib
में ASan-इंस्ट्रूमेंट किया गया (make का दूसरा अनुरोध). दूसरे बिल्ड के एक्सीक्यूटेबल, पहले बिल्ड के एक्सीक्यूटेबल को ओवरराइट कर देते हैं. ASan से इंस्ट्रूमेंट किए गए, रन किए जा सकने वाले प्रोग्राम को लाइब्रेरी का एक अलग खोज पाथ मिलता है. इसमें PT_INTERP
में /system/bin/linker_asan
का इस्तेमाल करके, /system/lib
से पहले /data/asan/lib
शामिल होता है.
$SANITIZE_TARGET
वैल्यू बदलने पर, बिल्ड सिस्टम इंटरमीडिएट ऑब्जेक्ट डायरेक्ट्री को मिटा देता है. ऐसा करने से, सभी टारगेट फिर से बनाए जाते हैं, जबकि /system/lib
में इंस्टॉल की गई बाइनरी सुरक्षित रहती हैं.
कुछ टारगेट, ASan की मदद से नहीं बनाए जा सकते:
- स्टैटिक रूप से लिंक किए गए एक्ज़ीक्यूटेबल
LOCAL_CLANG:=false
टारगेटLOCAL_SANITIZE:=false
कोSANITIZE_TARGET=address
के लिए ASan नहीं किया गया है
इस तरह के एक्सीक्यूटेबल, SANITIZE_TARGET
बिल्ड में शामिल नहीं किए जाते. साथ ही, पहले make अनुरोध का वर्शन /system/bin
में ही छोड़ दिया जाता है.
इस तरह की लाइब्रेरी ASan के बिना बनाई गई हैं. इनमें उन स्टैटिक लाइब्रेरी का कुछ ASan कोड शामिल हो सकता है जिन पर ये निर्भर हैं.