أسباب إضافة وضع علامات الذاكرة (MTE)؟
تعد أخطاء أمان الذاكرة، وهي أخطاء في التعامل مع الذاكرة في لغات البرمجة الأصلية، مشكلات شائعة في التعليمات البرمجية. تؤدي إلى حدوث ثغرات أمنية، فضلاً عن مشكلات الاستقرار.
قدَّم Armv9 إضافة وضع علامات الذاكرة (MTE)، وهي إضافة للأجهزة تتيح لك اكتشاف أخطاء "الاستخدام بعد تفريغها" و"تجاوز المخزن المؤقت" في رمزك الأصلي.
الحصول على الدعم
بدءًا من نظام التشغيل Android 13، تتوافق أجهزة محدَّدة مع إضافة وضع علامات الذاكرة (MTE). للتحقّق مما إذا كان جهازك يعمل مع تفعيل إضافة وضع علامات الذاكرة (MTE)، عليك تنفيذ الأمر التالي:
adb shell grep mte /proc/cpuinfo
إذا كانت النتيجة Features : [...] mte
، يعني ذلك أنّ جهازك يعمل مع تفعيل إضافة وضع علامات الذاكرة (MTE).
لا تفعِّل بعض الأجهزة إضافة وضع علامات الذاكرة (MTE) تلقائيًا، ولكنّها تسمح للمطوّرين بإعادة التشغيل مع تفعيل إضافة وضع علامات الذاكرة (MTE). وهذا ضبط تجريبي لا يُنصح به للاستخدام العادي لأنه قد يؤدي إلى انخفاض أداء الجهاز أو ثباته، ولكنه قد يكون مفيدًا لتطوير التطبيقات. وللوصول إلى هذا الوضع، انتقِل إلى خيارات المطوّرين > إضافة وضع علامات الذاكرة في تطبيق "الإعدادات". وإذا لم يكن هذا الخيار متوفرًا، يعني هذا أنّ جهازك لا يتيح تفعيل إضافة وضع علامات الذاكرة (MTE) بهذه الطريقة.
أوضاع تشغيل إضافة وضع علامات الذاكرة (MTE)
توفِّر إضافة وضع علامات الذاكرة (MTE) وضعَين: "المزامنة" و"ASYNC". ويوفّر وضع المزامنة معلومات تشخيصية أفضل، وبالتالي فهو أكثر ملاءمة لأغراض التطوير، في حين يتميّز وضع ASYNC بأداء عالي يتيح لك تفعيله للتطبيقات التي تم إصدارها.
الوضع المتزامن (مزامنة)
تم تحسين هذا الوضع لتصحيح الأخطاء مقارنةً بالأداء ويمكن استخدامه كأداة دقيقة للكشف عن الأخطاء، عندما تكون النفقات العامة ذات الأداء الأعلى مقبولة. عند تفعيل هذا الإعداد، تعمل ميزة MTE SYNC أيضًا كإجراء للحد من الأمان.
في حالة عدم تطابق العلامة، ينهي المعالج العملية عند التحميل المسيء أو يخزّن التعليمات باستخدام SIGSEGV (باستخدام si_code SEGV_MTESERR) ومعلومات كاملة حول الوصول إلى الذاكرة وعنوان الخطأ.
ويكون هذا الوضع مفيدًا أثناء الاختبار كبديل أسرع لتطبيق HWASan لا يتطلب منك إعادة تجميع الرمز البرمجي الخاص بك، أو في مرحلة الإنتاج، عندما يشكّل تطبيقك مساحة عرضة للهجوم. بالإضافة إلى ذلك، عندما يعثر وضع ASYNC (الموضّح أدناه) على خطأ، يمكن الحصول على تقرير خطأ دقيق باستخدام واجهات برمجة تطبيقات وقت التشغيل لتبديل التنفيذ إلى وضع المزامنة.
علاوةً على ذلك، عند التشغيل في وضع "المزامنة"، يسجّل تخصيص Android تتبُّع تسلسل استدعاء الدوال البرمجية لكل عملية تخصيص ومساحة عرض ويستخدمها لتقديم تقارير أخطاء أفضل تتضمن توضيحًا لخطأ في الذاكرة، مثل عمليات الاستخدام بعد تفريغها أو تجاوز المخزن المؤقت، وعمليات تتبُّع تسلسل استدعاء الدوال البرمجية لأحداث الذاكرة ذات الصلة (راجِع التعرُّف على تقارير إضافة وضع علامات الذاكرة (MTE) للحصول على مزيد من التفاصيل). توفِّر هذه التقارير مزيدًا من المعلومات السياقية وتسهّل تتبُّع الأخطاء وإصلاحها مقارنةً بوضع ASYNC.
الوضع غير المتزامن (ASYNC)
تم تحسين هذا الوضع لتحقيق مستوى أداء أعلى من دقة تقارير الأخطاء ويمكن استخدامه لرصد أخطاء أمان الذاكرة ذات المساحة الحرجة. في حالة عدم تطابق العلامة، يواصل المعالج التنفيذ حتى أقرب إدخال نواة (مثل استدعاء نظام أو مقاطعة مؤقت)، حيث ينهي العملية باستخدام SIGSEGV (الرمز SEGV_MTEAERR) بدون تسجيل عنوان الخطأ أو الوصول إلى الذاكرة.
يُعدّ هذا الوضع مفيدًا للحدّ من ثغرات أمان الذاكرة في عملية الإنتاج على قواعد رموز تم اختبارها جيدًا، حيث تكون كثافة أخطاء أمان الذاكرة منخفضة والتي يمكن تحقيقها باستخدام وضع "المزامنة" أثناء الاختبار.
تفعيل إضافة وضع علامات الذاكرة (MTE)
لجهاز واحد
لإجراء تجارب، يمكن استخدام تغييرات توافق التطبيق لضبط القيمة
التلقائية للسمة memtagMode
لتطبيق لا يحدّد
أي قيمة في البيان (أو يحدد "default"
).
ويمكن العثور على هذه الإعدادات ضمن النظام > الإعدادات المتقدّمة > خيارات المطوّرين > التغييرات في
التوافق مع التطبيقات في قائمة الإعدادات العامة. ويؤدي ضبط NATIVE_MEMTAG_ASYNC
أو NATIVE_MEMTAG_SYNC
إلى تفعيل إضافة وضع علامات الذاكرة (MTE) لتطبيق معيّن.
بدلاً من ذلك، يمكن ضبطها باستخدام الأمر am
على النحو التالي:
- في وضع المزامنة:
$ adb shell am compat enable NATIVE_MEMTAG_SYNC my.app.name
- بالنسبة إلى وضع ASYNC:
$ adb shell am compat enable NATIVE_MEMTAG_ASYNC my.app.name
في Gradle
يمكنك تفعيل إضافة وضع علامات الذاكرة (MTE) لجميع إصدارات تصحيح الأخطاء لمشروع Gradle من خلال
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application android:memtagMode="sync" tools:replace="android:memtagMode"/>
</manifest>
إلى app/src/debug/AndroidManifest.xml
. سيؤدي هذا الإجراء إلى إلغاء memtagMode
في ملف البيان
وذلك باستخدام المزامنة لإصدارات تصحيح الأخطاء.
يمكنك بدلاً من ذلك تفعيل إضافة وضع علامات الذاكرة (MTE) لجميع إصدارات نوع الإصدار المخصّص. لإجراء
ذلك، يجب إنشاء BuildType الخاص بك ووضع
XML إلى app/src/<name of buildType>/AndroidManifest.xml
.
لملف APK على أي جهاز متوافق
تكون إضافة وضع علامات الذاكرة (MTE) غير مفعَّلة تلقائيًا. ويمكن للتطبيقات التي تريد استخدام إضافة وضع علامات الذاكرة (MTE)
تنفيذ ذلك من خلال ضبط android:memtagMode
ضمن العلامة <application>
أو <process>
في AndroidManifest.xml
.
android:memtagMode=(off|default|sync|async)
عند ضبط السمة على علامة <application>
، تؤثر السمة في جميع العمليات التي يستخدمها التطبيق، ويمكن إلغاء هذه السمة للعمليات الفردية من خلال ضبط العلامة <process>
.
تشغيل تطبيقك
بعد تفعيل إضافة وضع علامات الذاكرة (MTE)، يمكنك استخدام تطبيقك واختباره كالمعتاد. إذا تم رصد مشكلة تتعلّق بأمان الذاكرة، يتعطّل تطبيقك مع عرض ضريح يشبه ما يلي (ملاحظة:
SIGSEGV
التي تتضمّن SEGV_MTESERR
للمزامنة أو SEGV_MTEAERR
لنظام ASYNC):
pid: 13935, tid: 13935, name: sanitizer-statu >>> sanitizer-status <<<
uid: 0
tagged_addr_ctrl: 000000000007fff3
signal 11 (SIGSEGV), code 9 (SEGV_MTESERR), fault addr 0x800007ae92853a0
Cause: [MTE]: Use After Free, 0 bytes into a 32-byte allocation at 0x7ae92853a0
x0 0000007cd94227cc x1 0000007cd94227cc x2 ffffffffffffffd0 x3 0000007fe81919c0
x4 0000007fe8191a10 x5 0000000000000004 x6 0000005400000051 x7 0000008700000021
x8 0800007ae92853a0 x9 0000000000000000 x10 0000007ae9285000 x11 0000000000000030
x12 000000000000000d x13 0000007cd941c858 x14 0000000000000054 x15 0000000000000000
x16 0000007cd940c0c8 x17 0000007cd93a1030 x18 0000007cdcac6000 x19 0000007fe8191c78
x20 0000005800eee5c4 x21 0000007fe8191c90 x22 0000000000000002 x23 0000000000000000
x24 0000000000000000 x25 0000000000000000 x26 0000000000000000 x27 0000000000000000
x28 0000000000000000 x29 0000007fe8191b70
lr 0000005800eee0bc sp 0000007fe8191b60 pc 0000005800eee0c0 pst 0000000060001000
backtrace:
#00 pc 00000000000010c0 /system/bin/sanitizer-status (test_crash_malloc_uaf()+40) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)
#01 pc 00000000000014a4 /system/bin/sanitizer-status (test(void (*)())+132) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)
#02 pc 00000000000019cc /system/bin/sanitizer-status (main+1032) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)
#03 pc 00000000000487d8 /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+96) (BuildId: 6ab39e35a2fae7efbe9a04e9bbb14331)
deallocated by thread 13935:
#00 pc 000000000004643c /apex/com.android.runtime/lib64/bionic/libc.so (scudo::Allocator<scudo::AndroidConfig, &(scudo_malloc_postinit)>::quarantineOrDeallocateChunk(scudo::Options, void*, scudo::Chunk::UnpackedHeader*, unsigned long)+688) (BuildId: 6ab39e35a2fae7efbe9a04e9bbb14331)
#01 pc 00000000000421e4 /apex/com.android.runtime/lib64/bionic/libc.so (scudo::Allocator<scudo::AndroidConfig, &(scudo_malloc_postinit)>::deallocate(void*, scudo::Chunk::Origin, unsigned long, unsigned long)+212) (BuildId: 6ab39e35a2fae7efbe9a04e9bbb14331)
#02 pc 00000000000010b8 /system/bin/sanitizer-status (test_crash_malloc_uaf()+32) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)
#03 pc 00000000000014a4 /system/bin/sanitizer-status (test(void (*)())+132) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)
allocated by thread 13935:
#00 pc 0000000000042020 /apex/com.android.runtime/lib64/bionic/libc.so (scudo::Allocator<scudo::AndroidConfig, &(scudo_malloc_postinit)>::allocate(unsigned long, scudo::Chunk::Origin, unsigned long, bool)+1300) (BuildId: 6ab39e35a2fae7efbe9a04e9bbb14331)
#01 pc 0000000000042394 /apex/com.android.runtime/lib64/bionic/libc.so (scudo_malloc+36) (BuildId: 6ab39e35a2fae7efbe9a04e9bbb14331)
#02 pc 000000000003cc9c /apex/com.android.runtime/lib64/bionic/libc.so (malloc+36) (BuildId: 6ab39e35a2fae7efbe9a04e9bbb14331)
#03 pc 00000000000010ac /system/bin/sanitizer-status (test_crash_malloc_uaf()+20) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)
#04 pc 00000000000014a4 /system/bin/sanitizer-status (test(void (*)())+132) (BuildId: 953fc93301472d0b72709b2b9a9f6f30)
Learn more about MTE reports: https://source.android.com/docs/security/test/memory-safety/mte-report
يمكنك الاطّلاع على فهم تقارير إضافة وضع علامات الذاكرة (MTE) في مستندات "المشروع مفتوح المصدر لنظام Android" (AOSP) للحصول على مزيد من التفاصيل. يمكنك أيضًا تصحيح أخطاء تطبيقك باستخدام "استوديو Android" ويتوقف برنامج تصحيح الأخطاء في السطر الذي يؤدي إلى الوصول غير الصالح إلى الذاكرة.
المستخدمون المتقدمون: استخدام إضافة وضع علامات الذاكرة (MTE) في التخصيص الخاص بك
لاستخدام إضافة وضع علامات الذاكرة (MTE) للذاكرة غير المخصّصة من خلال تخصيصات النظام العادية، تحتاج إلى تعديل التخصيص لوضع علامة على الذاكرة والمؤشرات.
يجب تخصيص صفحات التخصيص باستخدام PROT_MTE
في علامة prot
mmap
(أو mprotect
).
يجب محاذاة جميع التوزيعات ذات العلامات مع 16 بايت، حيث لا يمكن تعيين العلامات إلا للأجزاء التي يبلغ حجمها 16 بايت (المعروفة أيضًا باسم الحبيبات).
بعد ذلك، قبل عرض مؤشر، عليك استخدام تعليمات IRG
لإنشاء علامة عشوائية وتخزينها في المؤشر.
اتّبِع التعليمات التالية لوضع علامة على الذاكرة الأساسية:
STG
: وضع علامة على حبيبة واحدة بحجم 16 بايتST2G
: ضَع علامة على حبيبات بحجم 16 بايت.DC GVA
: سطر ذاكرة التخزين المؤقت للعلامة نفسه
بدلاً من ذلك، تؤدي التعليمات التالية أيضًا إلى عدم إعداد الذاكرة:
STZG
: علامة والإعداد بحبيبات واحدة بحجم 16 بايتSTZ2G
: علامة وبدء إعداد حبيبين بحجم 16 بايتDC GZVA
: العلامة وذاكرة التخزين المؤقت لإعدادها باستخدام العلامة نفسها
تجدر الإشارة إلى أنّ هذه التعليمات غير متاحة على وحدات المعالجة المركزية القديمة، لذا يجب تشغيلها بشكل مشروط عند تفعيل إضافة وضع علامات الذاكرة (MTE). يمكنك التحقق مما إذا كانت إضافة وضع علامات الذاكرة (MTE) مفعّلة لهذه العملية من عدمه:
#include <sys/prctl.h>
bool runningWithMte() {
int mode = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
return mode != -1 && mode & PR_MTE_TCF_MASK;
}
قد تجد أنّ عملية تنفيذ ملف تعريف الارتباط مفيدة كمرجع.
مزيد من المعلومات
يمكنك الاطّلاع على مزيد من المعلومات في دليل مستخدم MTE لنظام التشغيل Android الذي كتبه Arm.