GWP-ASan เป็นฟีเจอร์ตัวจัดสรรหน่วยความจำแบบเนทีฟที่ช่วยค้นหา ใช้หลังใช้ฟรี และ การล้นบัฟเฟอร์ฮีป ข้อบกพร่อง ชื่อไม่เป็นทางการของตัวย่อชื่อ "GWP-ASan Will ระบุสถานที่ตั้ง SAN" เลิกชอบ HWASan หรือ แก้ไขข้อบกพร่อง Malloc GWP-ASan ไม่ต้องมีแหล่งที่มาหรือการรวบรวมใหม่ (กล่าวคือ ทำงานร่วมกับ ที่สร้างไว้ล่วงหน้า) และทำงานได้ทั้งในกระบวนการ 32 บิตและ 64 บิต (แต่การขัดข้อง 32 บิต มีข้อมูลการแก้ไขข้อบกพร่องน้อยลง) หัวข้อนี้สรุปสิ่งที่คุณต้องทำเพื่อเปิดใช้ฟีเจอร์นี้ใน แอป GWP-ASan มีให้บริการในแอปที่กำหนดเป้าหมายเป็น Android 11 (API ระดับ 30) ขึ้นไป
ภาพรวม
GWP-ASan เปิดใช้อยู่ในแอปพลิเคชันระบบและแพลตฟอร์มที่เลือกแบบสุ่มบางรายการ ไฟล์ปฏิบัติการเมื่อเริ่มต้นกระบวนการ (หรือเมื่อไซโกตแยก) เปิดใช้ GWP-ASan ใน แอปของคุณเองเพื่อช่วยคุณค้นหาข้อบกพร่องที่เกี่ยวกับหน่วยความจำ และเพื่อเตรียมแอปของคุณให้พร้อม การรองรับของ ARM Memory gtag Extension (MTE) กลไกการสุ่มตัวอย่างการจัดสรรยังให้ความน่าเชื่อถือกับ การแกล้งตาย
เมื่อเปิดใช้แล้ว GWP-ASan จะสกัดกั้นการจัดสรรฮีปเพียงบางส่วนที่เลือกแบบสุ่ม แล้วนำไปวางลงในพื้นที่พิเศษที่จะดักจับฮีปที่ตรวจจับได้ยาก ข้อบกพร่องของหน่วยความจำ หากมีผู้ใช้จำนวนมากพอ อัตราการสุ่มตัวอย่างต่ำนี้จะ ค้นหาข้อบกพร่องด้านความปลอดภัยของหน่วยความจำฮีปที่ไม่ได้พบผ่านการทดสอบทั่วไป ตัวอย่างเช่น GWP-ASan พบว่า ข้อบกพร่องจำนวนมาก ในเบราว์เซอร์ Chrome (ซึ่งส่วนใหญ่ยังอยู่ในมุมมองที่จำกัด)
GWP-ASan รวบรวมข้อมูลเพิ่มเติมเกี่ยวกับการจัดสรรทั้งหมดที่ โดยตรง ข้อมูลนี้จะพร้อมใช้งานเมื่อ GWP-ASan ตรวจพบความปลอดภัยของหน่วยความจํา ของคุณ และถูกนำไปไว้ในรายงานข้อขัดข้องของระบบโดยอัตโนมัติ ซึ่งสามารถ ช่วยในการแก้ไขข้อบกพร่องอย่างมาก (ดูตัวอย่าง)
GWP-ASan ออกแบบมาเพื่อให้ไม่มีค่าใช้จ่ายในการดำเนินการ CPU ที่สำคัญ GWP-ASan มีการใช้โอเวอร์เฮดของ RAM แบบคงที่ซึ่งมีขนาดเล็กเมื่อเปิดใช้งาน ค่าใช้จ่ายในการดำเนินการดังกล่าวจะกำหนดโดย ระบบ Android และปัจจุบันมีขนาดประมาณ 70 กิบิไบต์ (KiB) สำหรับแต่ละ ที่ได้รับผลกระทบ
เลือกใช้แอปของคุณ
แอปในระดับต่อกระบวนการสามารถเปิดใช้ GWP-ASan ได้โดยใช้
android:gwpAsanMode
ในไฟล์ Manifest ของแอป ตัวเลือกต่อไปนี้
รองรับ
ปิดใช้เสมอ (
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 ในแอปของคุณ ซึ่งมีสิ่งต่อไปนี้ระบบปฏิบัติการจะจอง RAM ในปริมาณคงที่สำหรับ GWP-ASan ประมาณ 70KiB สำหรับแต่ละกระบวนการที่ได้รับผลกระทบ (เปิดใช้ GWP-ASan หากแอปของคุณไม่ได้มีความสำคัญมากต่อการเพิ่มหน่วยความจำ )
GWP-ASan สกัดกั้นส่วนย่อยของการจัดสรรฮีปที่เลือกแบบสุ่มและ วางลงในพื้นที่พิเศษที่สามารถตรวจจับความปลอดภัยของหน่วยความจำได้อย่างน่าเชื่อถือ การละเมิดดังกล่าว
เมื่อมีการละเมิดความปลอดภัยของหน่วยความจําในภูมิภาคพิเศษ GWP-ASan จะสิ้นสุดกระบวนการ
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 ที่กู้คืนได้
Android 14 (API ระดับ 34) ขึ้นไปรองรับ GWP-ASan ที่กู้คืนได้ ซึ่งช่วยให้
พบข้อบกพร่องใน
เวอร์ชันที่ใช้งานจริงโดยไม่ทำให้ประสบการณ์ของผู้ใช้แย่ลง เมื่อandroid:gwpAsanMode
คือ
ไม่ได้ระบุใน AndroidManifest.xml
แอปใช้การกู้คืนได้
GWP-ASan
GWP-ASan ที่กู้คืนได้จะแตกต่างจาก GWP-ASan พื้นฐานดังนี้
- GWP-ASan ที่กู้คืนได้จะเปิดใช้กับการเปิดตัวแอปประมาณ 1% เท่านั้น มากกว่าการเรียกใช้แอปพลิเคชันทุกครั้ง
- เมื่อตรวจพบข้อบกพร่องการใช้ฮีปหลังใช้ฟรีหรือฮีป-บัฟเฟอร์ล้นเกิน ข้อบกพร่องนี้
จะปรากฏในรายงานข้อขัดข้อง (Tombstone) รายงานข้อขัดข้องนี้พร้อมใช้งาน
ผ่านทาง
ActivityManager#getHistoricalProcessExitReasons
API แบบเดียวกับ GWP-ASan เดิม - GWP-ASan กู้คืนได้ แทนที่จะออกหลังจากบันทึกข้อมูลข้อขัดข้อง จึงอาจทำให้เกิดความเสียหายของหน่วยความจำ และแอปจะยังคงทำงานต่อไป แม้ว่ากระบวนการอาจดำเนินต่อไปตามปกติ แต่ลักษณะการทำงานของแอปไม่ได้แล้ว ที่ระบุ เนื่องจากหน่วยความจำเสียหาย แอปอาจขัดข้องในบางกรณี ในอนาคต ไม่เช่นนั้นอาจส่งผลกระทบต่อเนื่องโดยไม่มีผลกระทบต่อผู้ใช้
- GWP-ASan ที่กู้คืนได้ถูกปิดใช้หลังจากถ่ายโอนรายงานข้อขัดข้อง ดังนั้น แอปจะได้รับรายงาน GWP-ASan ที่กู้คืนได้เพียงรายการเดียวต่อการเปิดแอป 1 ครั้ง
- หากติดตั้งตัวแฮนเดิลสัญญาณที่กําหนดเองในแอป ระบบจะไม่เรียกใช้ตัวแฮนเดิลสัญญาณที่กำหนดเอง สัญญาณ 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 มักจะทำได้ยากในการจำลองซ้ำ อุปกรณ์ในเครือข่ายเดียวกัน
ในกรณีเหล่านี้ หากข้อบกพร่องส่งผลกระทบต่ออุปกรณ์ 64 บิต คุณควรใช้ 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 ไปใช้งานได้ที่ เอกสารประกอบเกี่ยวกับ LLC เพื่อเรียนรู้ ข้อมูลเพิ่มเติมเกี่ยวกับรายงานข้อขัดข้องของระบบ Android โปรดดู การวิเคราะห์ข้อขัดข้องของระบบ