GWP-আসান

GWP-ASan হল একটি নেটিভ মেমোরি অ্যালোকেটর বৈশিষ্ট্য যা ব্যবহার-পরবর্তী-মুক্ত এবং হিপ-বাফার-ওভারফ্লো বাগ খুঁজে পেতে সাহায্য করে। এর অনানুষ্ঠানিক নাম হল একটি পুনরাবৃত্ত সংক্ষিপ্ত রূপ, " G WP-ASan W ill P rovide A location SANity "। HWASan বা Malloc Debug এর বিপরীতে, GWP-ASan এর উৎস বা পুনর্সংকলনের প্রয়োজন হয় না (অর্থাৎ, প্রি-বিল্টের সাথে কাজ করে), এবং 32- এবং 64-বিট উভয় প্রক্রিয়াতেই কাজ করে (যদিও 32-বিট ক্র্যাশগুলিতে ডিবাগিং তথ্য কম থাকে)। এই বিষয়টি আপনার অ্যাপে এই বৈশিষ্ট্যটি সক্ষম করার জন্য আপনাকে কী কী পদক্ষেপ নিতে হবে তা রূপরেখা দেয়। GWP-ASan অ্যান্ড্রয়েড 11 (API লেভেল 30) বা তার বেশি টার্গেট করে এমন অ্যাপগুলিতে উপলব্ধ।

সংক্ষিপ্ত বিবরণ

প্রক্রিয়া শুরু হওয়ার পরে (অথবা জাইগোট যখন কাজ শুরু করে) কিছু এলোমেলোভাবে নির্বাচিত সিস্টেম অ্যাপ্লিকেশন এবং প্ল্যাটফর্ম এক্সিকিউটেবলে GWP-ASan সক্ষম করা হয়। মেমরি-সম্পর্কিত বাগ খুঁজে পেতে এবং ARM মেমরি ট্যাগিং এক্সটেনশন (MTE) সমর্থনের জন্য আপনার অ্যাপ প্রস্তুত করতে আপনার নিজস্ব অ্যাপে GWP-ASan সক্ষম করুন। বরাদ্দ নমুনা প্রক্রিয়া মৃত্যুর প্রশ্নের বিরুদ্ধেও নির্ভরযোগ্যতা প্রদান করে।

একবার সক্ষম হয়ে গেলে, GWP-ASan হিপ অ্যালোকেশনের একটি এলোমেলোভাবে নির্বাচিত উপসেটকে আটকায় এবং একটি বিশেষ অঞ্চলে রাখে যা হিপ মেমোরি করাপশন বাগগুলি সনাক্ত করতে কঠিন করে তোলে। পর্যাপ্ত ব্যবহারকারীর কারণে, এই কম স্যাম্পলিং হারও হিপ মেমোরি সুরক্ষা বাগগুলি খুঁজে পাবে যা নিয়মিত পরীক্ষার মাধ্যমে পাওয়া যাচ্ছে না। উদাহরণস্বরূপ, GWP-ASan Chrome ব্রাউজারে উল্লেখযোগ্য সংখ্যক বাগ খুঁজে পেয়েছে (যার মধ্যে অনেকগুলি এখনও সীমাবদ্ধ দৃশ্যের অধীনে রয়েছে)।

GWP-ASan যে সমস্ত বরাদ্দকে আটকায় সেগুলি সম্পর্কে অতিরিক্ত তথ্য সংগ্রহ করে। এই তথ্য তখন পাওয়া যায় যখন GWP-ASan মেমরি সুরক্ষা লঙ্ঘন সনাক্ত করে এবং স্বয়ংক্রিয়ভাবে নেটিভ ক্র্যাশ রিপোর্টে স্থাপন করা হয়, যা ডিবাগিংয়ে উল্লেখযোগ্যভাবে সহায়তা করতে পারে ( উদাহরণ দেখুন)।

GWP-ASan এমনভাবে ডিজাইন করা হয়েছে যাতে কোনও উল্লেখযোগ্য CPU ওভারহেড না লাগে। GWP-ASan সক্রিয় থাকাকালীন একটি ছোট, স্থির RAM ওভারহেড প্রবর্তন করে। এই ওভারহেডটি অ্যান্ড্রয়েড সিস্টেম দ্বারা নির্ধারিত হয় এবং বর্তমানে প্রতিটি প্রভাবিত প্রক্রিয়ার জন্য প্রায় 70 কিবিবাইট (KiB)।

আপনার অ্যাপটি নির্বাচন করুন

অ্যাপ ম্যানিফেস্টে android:gwpAsanMode ট্যাগ ব্যবহার করে প্রতি-প্রক্রিয়া স্তরের অ্যাপগুলির দ্বারা GWP-ASan সক্ষম করা যেতে পারে। নিম্নলিখিত বিকল্পগুলি সমর্থিত:

  • সর্বদা অক্ষম ( android:gwpAsanMode="never" ): এই সেটিংটি আপনার অ্যাপে GWP-ASan সম্পূর্ণরূপে অক্ষম করে এবং এটি নন-সিস্টেম অ্যাপগুলির জন্য ডিফল্ট।

  • ডিফল্ট ( android:gwpAsanMode="default" অথবা অনির্দিষ্ট): Android 13 (API লেভেল 33) এবং তার নিচের ভার্সন - GWP-ASan অক্ষম করা আছে। Android 14 (API লেভেল 34) এবং তার উপরের ভার্সন - পুনরুদ্ধারযোগ্য GWP-ASan সক্ষম করা আছে।

  • সর্বদা সক্রিয় ( android:gwpAsanMode="always" ): এই সেটিংটি আপনার অ্যাপে GWP-ASan সক্ষম করে, যার মধ্যে নিম্নলিখিতগুলি অন্তর্ভুক্ত রয়েছে:

    1. অপারেটিং সিস্টেমটি GWP-ASan অপারেশনের জন্য একটি নির্দিষ্ট পরিমাণ RAM সংরক্ষণ করে, প্রতিটি প্রভাবিত প্রক্রিয়ার জন্য প্রায় ~70KiB। (যদি আপনার অ্যাপ মেমরির ব্যবহার বৃদ্ধির প্রতি অত্যন্ত সংবেদনশীল না হয় তবে GWP-ASan সক্ষম করুন।)

    2. GWP-ASan হিপ অ্যালোকেশনের একটি এলোমেলোভাবে নির্বাচিত উপসেটকে আটকায় এবং তাদের একটি বিশেষ অঞ্চলে রাখে যা নির্ভরযোগ্যভাবে মেমরি সুরক্ষা লঙ্ঘন সনাক্ত করে।

    3. যখন বিশেষ অঞ্চলে মেমরি সুরক্ষা লঙ্ঘন ঘটে, তখন GWP-ASan প্রক্রিয়াটি বন্ধ করে দেয়।

    4. GWP-ASan ক্র্যাশ রিপোর্টে ত্রুটি সম্পর্কে অতিরিক্ত তথ্য প্রদান করে।

আপনার অ্যাপের জন্য বিশ্বব্যাপী GWP-ASan সক্ষম করতে, আপনার AndroidManifest.xml ফাইলে নিম্নলিখিতটি যোগ করুন:

<application android:gwpAsanMode="always">
  ...
</application>

অতিরিক্তভাবে, আপনার অ্যাপের নির্দিষ্ট সাবপ্রসেসের জন্য GWP-ASan স্পষ্টভাবে সক্ষম বা অক্ষম করা যেতে পারে। আপনি GWP-ASan থেকে স্পষ্টভাবে অপ্ট-ইন বা অপ্ট-আউট করা প্রক্রিয়াগুলি ব্যবহার করে কার্যকলাপ এবং পরিষেবাগুলিকে লক্ষ্য করতে পারেন। উদাহরণের জন্য নিম্নলিখিতটি দেখুন:

<application>
  <processes>
    <!-- Create the (empty) application process -->
    <process />

    <!-- Create subprocesses with GWP-ASan both explicitly enabled and disabled. -->
    <process android:process=":gwp_asan_enabled"
               android:gwpAsanMode="always" />
    <process android:process=":gwp_asan_disabled"
               android:gwpAsanMode="never" />
  </processes>

  <!-- Target services and activities to be run on either the GWP-ASan enabled or disabled processes. -->
  <activity android:name="android.gwpasan.GwpAsanEnabledActivity"
            android:process=":gwp_asan_enabled" />
  <activity android:name="android.gwpasan.GwpAsanDisabledActivity"
            android:process=":gwp_asan_disabled" />
  <service android:name="android.gwpasan.GwpAsanEnabledService"
           android:process=":gwp_asan_enabled" />
  <service android:name="android.gwpasan.GwpAsanDisabledService"
           android:process=":gwp_asan_disabled" />
</application>

পুনরুদ্ধারযোগ্য GWP-ASan

অ্যান্ড্রয়েড ১৪ (এপিআই লেভেল ৩৪) এবং উচ্চতর সংস্করণগুলি পুনরুদ্ধারযোগ্য GWP-ASan সমর্থন করে, যা ডেভেলপারদের ব্যবহারকারীর অভিজ্ঞতা হ্রাস না করে উৎপাদনে heap-buffer-overflow এবং heap-use-after-free বাগ খুঁজে পেতে সাহায্য করে। যখন android:gwpAsanMode একটি AndroidManifest.xml এ নির্দিষ্ট করা থাকে না, তখন অ্যাপটি পুনরুদ্ধারযোগ্য GWP-ASan ব্যবহার করে।

পুনরুদ্ধারযোগ্য GWP-ASan নিম্নলিখিত উপায়ে বেস GWP-ASan থেকে পৃথক:

  1. পুনরুদ্ধারযোগ্য GWP-ASan প্রতিটি অ্যাপ্লিকেশন লঞ্চের পরিবর্তে, প্রায় 1% অ্যাপ লঞ্চে সক্ষম।
  2. যখন একটি heap-use-after-free অথবা heap-buffer-overflow বাগ সনাক্ত করা হয়, তখন এই বাগটি ক্র্যাশ রিপোর্টে (tombstone) উপস্থিত হয়। এই ক্র্যাশ রিপোর্টটি ActivityManager#getHistoricalProcessExitReasons API এর মাধ্যমে পাওয়া যায়, যা মূল GWP-ASan এর মতোই।
  3. ক্র্যাশ রিপোর্ট ডাম্প করার পর বেরিয়ে আসার পরিবর্তে, Recoverable GWP-ASan মেমোরি করাপশন ঘটতে দেয় এবং অ্যাপটি চলতে থাকে। প্রক্রিয়াটি স্বাভাবিকভাবে চলতে থাকলেও, অ্যাপটির আচরণ আর নির্দিষ্ট করা হয় না। মেমোরি করাপশনের কারণে, অ্যাপটি ভবিষ্যতে কোনও নির্দিষ্ট সময়ে ক্র্যাশ হতে পারে, অথবা এটি ব্যবহারকারীর দৃষ্টিগোচর কোনও প্রভাব ছাড়াই চলতে পারে।
  4. ক্র্যাশ রিপোর্ট ডাম্প করার পরে পুনরুদ্ধারযোগ্য GWP-ASan অক্ষম করা হয়। অতএব, একটি অ্যাপ প্রতি অ্যাপ লঞ্চে শুধুমাত্র একটি পুনরুদ্ধারযোগ্য GWP-ASan রিপোর্ট পেতে পারে।
  5. যদি অ্যাপটিতে একটি কাস্টম সিগন্যাল হ্যান্ডলার ইনস্টল করা থাকে, তাহলে কখনই এমন SIGSEGV সিগন্যালের প্রয়োজন হয় না যা পুনরুদ্ধারযোগ্য GWP-ASan ত্রুটির ইঙ্গিত দেয়।

যেহেতু পুনরুদ্ধারযোগ্য GWP-ASan ক্র্যাশগুলি শেষ ব্যবহারকারীর ডিভাইসগুলিতে মেমরি দুর্নীতির প্রকৃত ঘটনা নির্দেশ করে, তাই আমরা উচ্চ অগ্রাধিকারের সাথে পুনরুদ্ধারযোগ্য GWP-ASan দ্বারা চিহ্নিত বাগগুলি পরীক্ষা এবং ঠিক করার পরামর্শ দিচ্ছি।

ডেভেলপার সহায়তা

এই বিভাগগুলিতে GWP-ASan ব্যবহার করার সময় কী কী সমস্যা দেখা দিতে পারে এবং কীভাবে সেগুলি সমাধান করা যায় তার রূপরেখা দেওয়া হয়েছে।

বরাদ্দ/বহির্ভূতকরণের চিহ্ন অনুপস্থিত

যদি আপনি এমন একটি নেটিভ ক্র্যাশ নির্ণয় করেন যেখানে বরাদ্দ/ডিলোকেশন ফ্রেম অনুপস্থিত বলে মনে হচ্ছে, তাহলে আপনার অ্যাপ্লিকেশনে সম্ভবত ফ্রেম পয়েন্টার অনুপস্থিত। GWP-ASan পারফরম্যান্সের কারণে বরাদ্দ এবং ডিলোকেশন ট্রেস রেকর্ড করতে ফ্রেম পয়েন্টার ব্যবহার করে এবং স্ট্যাক ট্রেস উপস্থিত না থাকলে তা খুলে ফেলতে অক্ষম।

arm64 ডিভাইসের জন্য ফ্রেম পয়েন্টারগুলি ডিফল্টরূপে চালু থাকে এবং arm32 ডিভাইসের জন্য ডিফল্টরূপে বন্ধ থাকে। যেহেতু অ্যাপ্লিকেশনগুলির libc-এর উপর নিয়ন্ত্রণ নেই, তাই (সাধারণত) GWP-ASan-এর পক্ষে 32-বিট এক্সিকিউটেবল বা অ্যাপের জন্য বরাদ্দ/ডিলোকেশন ট্রেস সংগ্রহ করা সম্ভব নয়। 64-বিট অ্যাপ্লিকেশনগুলিকে নিশ্চিত করা উচিত যে সেগুলি -fomit-frame-pointer দিয়ে তৈরি নয় যাতে GWP-ASan বরাদ্দ এবং ডিলোকেশন স্ট্যাক ট্রেস সংগ্রহ করতে পারে।

নিরাপত্তা লঙ্ঘনের পুনরুৎপাদন

GWP-ASan ব্যবহারকারীর ডিভাইসে হিপ মেমোরি সুরক্ষা লঙ্ঘন ধরার জন্য ডিজাইন করা হয়েছে। GWP-ASan ক্র্যাশ সম্পর্কে যতটা সম্ভব প্রসঙ্গ সরবরাহ করে (লঙ্ঘনের অ্যাক্সেস ট্রেস, কারণ স্ট্রিং এবং বরাদ্দ/ডিলোকেশন ট্রেস), তবে লঙ্ঘন কীভাবে ঘটেছে তা অনুমান করা এখনও কঠিন হতে পারে। দুর্ভাগ্যবশত, যেহেতু বাগ সনাক্তকরণ সম্ভাব্য, তাই GWP-ASan রিপোর্টগুলি প্রায়শই স্থানীয় ডিভাইসে পুনরুত্পাদন করা কঠিন।

এইসব ক্ষেত্রে, যদি বাগটি ৬৪-বিট ডিভাইসগুলিকে প্রভাবিত করে, তাহলে আপনার HWAddressSanitizer (HWASan) ব্যবহার করা উচিত। HWASan স্ট্যাক, হিপ এবং গ্লোবালগুলিতে নির্ভরযোগ্যভাবে মেমরি সুরক্ষা লঙ্ঘন সনাক্ত করে। HWASan দিয়ে আপনার অ্যাপ্লিকেশন চালানোর ফলে GWP-ASan দ্বারা রিপোর্ট করা একই ফলাফল নির্ভরযোগ্যভাবে পুনরুত্পাদন করতে পারে।

যেসব ক্ষেত্রে HWASan-এর অধীনে আপনার অ্যাপ্লিকেশন চালানো কোনও বাগ রুট-কজ করার জন্য যথেষ্ট নয়, সেক্ষেত্রে আপনার প্রশ্নযুক্ত কোডটি ফাজ করার চেষ্টা করা উচিত। আপনি GWP-ASan রিপোর্টের তথ্যের উপর ভিত্তি করে আপনার ফাজিং প্রচেষ্টাগুলিকে লক্ষ্য করতে পারেন, যা নির্ভরযোগ্যভাবে অন্তর্নিহিত কোড স্বাস্থ্য সমস্যাগুলি সনাক্ত করতে এবং প্রকাশ করতে পারে।

উদাহরণ

এই উদাহরণের নেটিভ কোডে একটি হিপ ইউজ-আফটার-ফ্রি বাগ রয়েছে:

#include <jni.h>
#include <string>
#include <string_view>

jstring native_get_string(JNIEnv* env) {
   std::string s = "Hellooooooooooooooo ";
   std::string_view sv = s + "World\n";

   // BUG: Use-after-free. `sv` holds a dangling reference to the ephemeral
   // string created by `s + "World\n"`. Accessing the data here is a
   // use-after-free.
   return env->NewStringUTF(sv.data());
}

extern "C" JNIEXPORT jstring JNICALL
Java_android11_test_gwpasan_MainActivity_nativeGetString(
    JNIEnv* env, jobject /* this */) {
  // Repeat the buggy code a few thousand times. GWP-ASan has a small chance
  // of detecting the use-after-free every time it happens. A single user who
  // triggers the use-after-free thousands of times will catch the bug once.
  // Alternatively, if a few thousand users each trigger the bug a single time,
  // you'll also get one report (this is the assumed model).
  jstring return_string;
  for (unsigned i = 0; i < 0x10000; ++i) {
    return_string = native_get_string(env);
  }

  return reinterpret_cast<jstring>(env->NewGlobalRef(return_string));
}

উপরের উদাহরণ কোড ব্যবহার করে পরীক্ষামূলকভাবে চালানোর জন্য, GWP-ASan সফলভাবে অবৈধ ব্যবহারটি ধরে ফেলেছে এবং নীচের ক্র্যাশ রিপোর্টটি ট্রিগার করেছে। GWP-ASan ক্র্যাশের ধরণ, বরাদ্দ মেটাডেটা এবং সংশ্লিষ্ট বরাদ্দ এবং ডিলোকেশন স্ট্যাক ট্রেস সম্পর্কে তথ্য প্রদান করে স্বয়ংক্রিয়ভাবে রিপোর্টটিকে উন্নত করেছে।

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint: 'google/sargo/sargo:10/RPP3.200320.009/6360804:userdebug/dev-keys'
Revision: 'PVT1.0'
ABI: 'arm64'
Timestamp: 2020-04-06 18:27:08-0700
pid: 16227, tid: 16227, name: 11.test.gwpasan  >>> android11.test.gwpasan <<<
uid: 10238
signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 0x736ad4afe0
Cause: [GWP-ASan]: Use After Free on a 32-byte allocation at 0x736ad4afe0

backtrace:
      #00 pc 000000000037a090  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::CheckNonHeapValue(char, art::(anonymous namespace)::JniValueType)+448)
      #01 pc 0000000000378440  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::CheckPossibleHeapValue(art::ScopedObjectAccess&, char, art::(anonymous namespace)::JniValueType)+204)
      #02 pc 0000000000377bec  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::Check(art::ScopedObjectAccess&, bool, char const*, art::(anonymous namespace)::JniValueType*)+612)
      #03 pc 000000000036dcf4  /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::CheckJNI::NewStringUTF(_JNIEnv*, char const*)+708)
      #04 pc 000000000000eda4  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (_JNIEnv::NewStringUTF(char const*)+40)
      #05 pc 000000000000eab8  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (native_get_string(_JNIEnv*)+144)
      #06 pc 000000000000edf8  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (Java_android11_test_gwpasan_MainActivity_nativeGetString+44)
      ...

deallocated by thread 16227:
      #00 pc 0000000000048970  /apex/com.android.runtime/lib64/bionic/libc.so (gwp_asan::AllocationMetadata::CallSiteInfo::RecordBacktrace(unsigned long (*)(unsigned long*, unsigned long))+80)
      #01 pc 0000000000048f30  /apex/com.android.runtime/lib64/bionic/libc.so (gwp_asan::GuardedPoolAllocator::deallocate(void*)+184)
      #02 pc 000000000000f130  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (std::__ndk1::_DeallocateCaller::__do_call(void*)+20)
      ...
      #08 pc 000000000000ed6c  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (std::__ndk1::basic_string<char, std::__ndk1::char_traits<char>, std::__ndk1::allocator<char> >::~basic_string()+100)
      #09 pc 000000000000ea90  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (native_get_string(_JNIEnv*)+104)
      #10 pc 000000000000edf8  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (Java_android11_test_gwpasan_MainActivity_nativeGetString+44)
      ...

allocated by thread 16227:
      #00 pc 0000000000048970  /apex/com.android.runtime/lib64/bionic/libc.so (gwp_asan::AllocationMetadata::CallSiteInfo::RecordBacktrace(unsigned long (*)(unsigned long*, unsigned long))+80)
      #01 pc 0000000000048e4c  /apex/com.android.runtime/lib64/bionic/libc.so (gwp_asan::GuardedPoolAllocator::allocate(unsigned long)+368)
      #02 pc 000000000003b258  /apex/com.android.runtime/lib64/bionic/libc.so (gwp_asan_malloc(unsigned long)+132)
      #03 pc 000000000003bbec  /apex/com.android.runtime/lib64/bionic/libc.so (malloc+76)
      #04 pc 0000000000010414  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (operator new(unsigned long)+24)
      ...
      #10 pc 000000000000ea6c  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (native_get_string(_JNIEnv*)+68)
      #11 pc 000000000000edf8  /data/app/android11.test.gwpasan/lib/arm64/libmy-test.so (Java_android11_test_gwpasan_MainActivity_nativeGetString+44)
      ...

অধিক তথ্য

GWP-ASan এর বাস্তবায়নের বিশদ সম্পর্কে আরও জানতে, LLVM ডকুমেন্টেশন দেখুন। অ্যান্ড্রয়েড নেটিভ ক্র্যাশ রিপোর্ট সম্পর্কে আরও জানতে, ডায়াগনোজিং নেটিভ ক্র্যাশ দেখুন।