पता सेनिटाइज़र

एड्रेससैनिटाइज़र (ASan) नेटिव कोड में मेमोरी बग का पता लगाने के लिए एक तेज़ कंपाइलर-आधारित टूल है।

एएसएएन ने पता लगाया:

  • स्टैक और हीप बफ़र ओवरफ़्लो/अंडरफ़्लो
  • मुफ़्त के बाद ढेर का उपयोग करें
  • दायरे के बाहर स्टैक का उपयोग
  • डबल फ्री/वाइल्ड फ्री

एएसएएन 32-बिट और 64-बिट एआरएम, प्लस x86 और x86-64 दोनों पर चलता है। ASan का CPU ओवरहेड लगभग 2x है, कोड आकार ओवरहेड 50% और 2x के बीच है, और एक बड़ी मेमोरी ओवरहेड (आपके आवंटन पैटर्न पर निर्भर है, लेकिन 2x के क्रम पर)।

एंड्रॉइड 10 और AArch64 पर AOSP मुख्य शाखा हार्डवेयर-त्वरित ASan (HWASan) का समर्थन करती है, जो कम रैम ओवरहेड और पता लगाए गए बग की एक बड़ी श्रृंखला के साथ एक समान उपकरण है। HWASan, ASan द्वारा खोजे गए बग के अलावा, वापसी के बाद स्टैक उपयोग का पता लगाता है।

HWASan में समान CPU और कोड आकार ओवरहेड है, लेकिन बहुत छोटा RAM ओवरहेड (15%) है। HWASan गैर नियतिवादी है। केवल 256 संभावित टैग मान हैं, इसलिए किसी भी बग के गायब होने की संभावना 0.4% है। HWASan के पास ओवरफ्लो का पता लगाने के लिए ASan के सीमित आकार के लाल क्षेत्र और उपयोग के बाद-मुक्त उपयोग का पता लगाने के लिए सीमित क्षमता वाला संगरोध नहीं है, इसलिए HWASan के लिए यह मायने नहीं रखता कि ओवरफ्लो कितना बड़ा है या मेमोरी को कितने समय पहले हटा दिया गया था। यह HWASan को ASan से बेहतर बनाता है। आप HWASan के डिज़ाइन के बारे में या Android पर HWASan के उपयोग के बारे में अधिक पढ़ सकते हैं।

एएसएन हीप ओवरफ्लो के अलावा स्टैक/ग्लोबल ओवरफ्लो का पता लगाता है, और न्यूनतम मेमोरी ओवरहेड के साथ तेज़ है।

यह दस्तावेज़ वर्णन करता है कि एएसएएन के साथ एंड्रॉइड के सभी हिस्सों को कैसे बनाया और चलाया जाए। यदि आप ASan के साथ SDK/NDK ऐप बना रहे हैं, तो इसके बजाय एड्रेस सैनिटाइज़र देखें।

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/asan के बजाय /system/lib /san में रखता है। फिर, अपना निष्पादन योग्य इसके साथ चलाएँ:

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 (अनुशंसित!) के साथ लाइब्रेरी का पुनर्निर्माण करें, या इसके साथ:

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 जावा कोड को नहीं देख सकता है, लेकिन यह JNI लाइब्रेरीज़ में बग का पता लगा सकता है। उसके लिए, आपको ASan के साथ निष्पादन योग्य बनाने की आवश्यकता है, जो इस मामले में /system/bin/app_process( 32|64 ) है। यह एक ही समय में डिवाइस पर सभी ऐप्स में एएसएएन को सक्षम बनाता है, जो एक भारी भार है, लेकिन 2 जीबी रैम वाला डिवाइस इसे संभालने में सक्षम होना चाहिए।

frameworks/base/cmds/app_process में app_process बिल्ड नियम में LOCAL_SANITIZE:=address जोड़ें। अभी के लिए उसी फ़ाइल में app_process__asan लक्ष्य को अनदेखा करें (यदि यह आपके इसे पढ़ने के समय भी मौजूद है)।

उपयुक्त 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

बिल्ड, एडीबी सिंक, फास्टबूट फ्लैश बूट और रीबूट।

रैप प्रॉपर्टी का उपयोग करना

पिछले अनुभाग में दृष्टिकोण ASan को सिस्टम के प्रत्येक ऐप में डालता है (वास्तव में, ज़ीगोट प्रक्रिया के प्रत्येक वंशज में)। ASan के साथ केवल एक (या कई) ऐप्स चलाना संभव है, धीमे ऐप स्टार्टअप के लिए कुछ मेमोरी ओवरहेड का व्यापार करना।

यह आपके ऐप को wrap. संपत्ति। निम्नलिखित उदाहरण ASan के अंतर्गत जीमेल ऐप चलाता है:

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/asan से ASan-वाद्य पुस्तकालयों को /system/lib में सामान्य पुस्तकालयों की तुलना में प्राथमिकता दी जाती है।

यदि कोई बग पाया जाता है, तो ऐप क्रैश हो जाता है, और रिपोर्ट लॉग पर प्रिंट हो जाती है।

स्वच्छता_लक्ष्य

Android 7.0 और उच्चतर में ASan के साथ एक ही बार में संपूर्ण Android प्लेटफ़ॉर्म बनाने के लिए समर्थन शामिल है। (यदि आप Android 9 से बेहतर रिलीज़ बना रहे हैं, तो HWASan एक बेहतर विकल्प है।)

उसी बिल्ड ट्री में निम्नलिखित कमांड चलाएँ।

make -j42
SANITIZE_TARGET=address make -j42

इस मोड में, userdata.img में अतिरिक्त लाइब्रेरीज़ होती हैं और उन्हें डिवाइस पर भी फ्लैश किया जाना चाहिए। निम्न कमांड लाइन का उपयोग करें:

fastboot flash userdata && fastboot flashall

यह साझा पुस्तकालयों के दो सेट बनाता है: /system/lib में सामान्य (पहला मेक इनवोकेशन), और /data/asan/lib में ASan-इंस्ट्रूमेंटेड (दूसरा मेक इनवोकेशन)। दूसरे बिल्ड के निष्पादनयोग्य पहले बिल्ड के निष्पादनयोग्य को अधिलेखित कर देते हैं। 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 के लिए मान्य नहीं है

इस तरह के निष्पादनयोग्य को SANITIZE_TARGET बिल्ड में छोड़ दिया जाता है, और पहले मेक इनवोकेशन का संस्करण /system/bin में छोड़ दिया जाता है।

इस तरह की लाइब्रेरी बिना ASan के बनाई जाती हैं। उनमें स्थिर पुस्तकालयों से कुछ एएसएएन कोड शामिल हो सकते हैं जिन पर वे निर्भर हैं।

सहायक दस्तावेज़