يتضمن Android 10 برنامج Android Live-LockK Daemon ( llkd
)، والذي تم تصميمه لاكتشاف حالات الجمود في kernel وتخفيفها. يوفر مكون llkd
تطبيقًا افتراضيًا مستقلاً، ولكن يمكنك بدلاً من ذلك دمج كود llkd
في خدمة أخرى، إما كجزء من الحلقة الرئيسية أو كسلسلة منفصلة.
سيناريوهات الكشف
يحتوي llkd
على سيناريوهين للكشف: حالة D أو Z المستمرة، وتوقيع المكدس المستمر.
حالة D أو Z المستمرة
إذا كان الخيط في حالة D (السكون غير المنقطع) أو Z (الزومبي) مع عدم وجود تقدم للأمام لفترة أطول من ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
، فسيقوم llkd
بقتل العملية (أو العملية الأصلية) ). إذا أظهر الفحص اللاحق أن نفس العملية لا تزال موجودة، فإن llkd
يؤكد حالة القفل المباشر ويثير الذعر في النواة بطريقة توفر تقرير الأخطاء الأكثر تفصيلاً للحالة.
يتضمن llkd
جهاز مراقبة ذاتيًا ينبهك في حالة قفل llkd
؛ الوكالة الدولية للطاقة هي ضعف الوقت المتوقع للتدفق عبر الحلقة الرئيسية وأخذ العينات هو كل ro.llk_sample_ms
.
توقيع المكدس المستمر
بالنسبة لإصدارات userdebug، يمكن لـ llkd
اكتشاف الأقفال المباشرة لـ kernel باستخدام التحقق المستمر من توقيع المكدس. إذا كان هناك مؤشر ترابط في أي حالة باستثناء Z يحتوي على رمز kernel ro.llk.stack
المستمر الذي تم الإبلاغ عنه لمدة أطول من ro.llk.timeout_ms
أو ro.llk.stack.timeout_ms
، فسيقوم llkd
بقتل العملية (حتى لو كان هناك إعادة توجيه) تقدم الجدولة). إذا أظهر الفحص اللاحق أن نفس العملية لا تزال موجودة، فإن llkd
يؤكد حالة القفل المباشر ويثير الذعر في النواة بطريقة توفر تقرير الأخطاء الأكثر تفصيلاً للحالة.
يستمر فحص lldk
بشكل مستمر عند وجود شرط القفل المباشر ويبحث عن السلاسل المكونة " symbol+0x"
أو " symbol.cfi+0x"
في ملف /proc/pid/stack
على Linux. قائمة الرموز موجودة في ro.llk.stack
والإعدادات الافتراضية هي القائمة المفصولة بفواصل " cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
".
يجب أن تكون الرموز نادرة وقصيرة العمر بدرجة كافية بحيث تظهر الوظيفة في النظام النموذجي مرة واحدة فقط في العينة خلال فترة المهلة ro.llk.stack.timeout_ms
(تحدث العينات كل ro.llk.check_ms
). ونظرًا لعدم وجود حماية ABA، فهذه هي الطريقة الوحيدة لمنع المشغل الخاطئ. يجب أن تظهر وظيفة الرمز أسفل الوظيفة التي تستدعي القفل الذي يمكن أن يتعامل معه. إذا كان القفل موجودًا أسفل أو في وظيفة الرمز، فسيظهر الرمز في جميع العمليات المتأثرة، وليس فقط العملية التي تسببت في القفل.
تغطية
التطبيق الافتراضي لـ llkd
لا يراقب عمليات ظهور init
أو [kthreadd]
أو [kthreadd]
. لكي يغطي llkd
[kthreadd]
- المواضيع المولدة:
- يجب ألا يبقى السائقون في حالة D المستمرة،
أو
- يجب أن يكون لدى برامج التشغيل آليات لاستعادة الخيط في حالة قتله خارجيًا. على سبيل المثال، استخدم
wait_event_interruptible()
بدلاً منwait_event()
.
إذا تم استيفاء أحد الشروط المذكورة أعلاه، فيمكن تعديل القائمة السوداء لـ llkd
لتشمل مكونات النواة. يتضمن التحقق من رمز المكدس قائمة سوداء إضافية للعمليات لمنع انتهاكات الخصوصية على الخدمات التي تمنع عمليات ptrace
.
خصائص الروبوت
يستجيب llkd
للعديد من خصائص Android (المدرجة أدناه).
- الخصائص المسماة
prop_ms
موجودة بالمللي ثانية. - الخصائص التي تستخدم الفاصلة (،) للقوائم تستخدم فاصلًا بادئًا للحفاظ على الإدخال الافتراضي، ثم تضيف أو تطرح الإدخالات مع بادئات الجمع (+) والناقص (-) الاختيارية على التوالي. بالنسبة لهذه القوائم، تكون السلسلة "خطأ" مرادفة لقائمة فارغة، وتلجأ الإدخالات الفارغة أو المفقودة إلى القيمة الافتراضية المحددة.
ro.config.low_ram
تم تكوين الجهاز بذاكرة محدودة.
ro.debuggable
تم تكوين الجهاز لـ userdebug أو eng build.
ro.llk.sysrq_t
إذا كانت الخاصية هي "eng"، فالقيمة الافتراضية ليست ro.config.low_ram
أو ro.debuggable
. إذا كان صحيحا، قم بتفريغ كافة المواضيع ( sysrq t
).
ro.llk.enable
السماح بتمكين البرنامج الخفي للقفل المباشر. الافتراضي خطأ.
llk.enable
تم تقييمه للبنيات الهندسية. الافتراضي هو ro.llk.enable
.
ro.khungtask.enable
السماح بتفعيل البرنامج الخفي [khungtask]
. الافتراضي خطأ.
kungtask.enable
تم تقييمه للبنيات الهندسية. الافتراضي هو ro.khungtask.enable
.
ro.llk.mlockall
تمكين الاتصال بـ mlockall()
. الافتراضي خطأ.
ro.khungtask.timeout
[khungtask]
الحد الأقصى للوقت. الافتراضي هو 12 دقيقة.
ro.llk.timeout_ms
D أو Z الحد الأقصى للوقت. الافتراضي هو 10 دقائق. قم بمضاعفة هذه القيمة لتعيين جهاز إنذار لـ llkd
.
ro.llk.D.timeout_ms
د الحد الأقصى للوقت. الافتراضي هو ro.llk.timeout_ms
.
ro.llk.Z.timeout_ms
Z الحد الأقصى للوقت. الافتراضي هو ro.llk.timeout_ms
.
ro.llk.stack.timeout_ms
التحقق من الحد الأقصى لرموز المكدس المستمرة. الافتراضي هو ro.llk.timeout_ms
. نشط فقط على userdebug أو eng builds .
ro.llk.check_ms
عينات من المواضيع لـ D أو Z. الافتراضي هو دقيقتين.
ro.llk.stack
التحقق من رموز مكدس kernel التي إذا كانت موجودة باستمرار يمكن أن تشير إلى أن النظام الفرعي مغلق. الافتراضي هو cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
قائمة مفصولة بفواصل لرموز kernel. لا يقوم الفحص بإجراء جدولة ABA للأمام إلا عن طريق استقصاء كل ro.llk_check_ms
خلال الفترة ro.llk.stack.timeout_ms
، لذا يجب أن تكون رموز المكدس نادرة بشكل استثنائي وعابرة (من غير المحتمل جدًا أن يظهر الرمز باستمرار في الكل عينات من المكدس). التحقق من تطابق " symbol+0x"
أو " symbol.cfi+0x"
في توسيع المكدس. متاح فقط على userdebug أو eng builds ؛ تؤدي المخاوف الأمنية المتعلقة ببنيات المستخدم إلى امتيازات محدودة تمنع هذا الفحص.
ro.llk.blacklist.process
لا يراقب llkd
العمليات المحددة. الافتراضي هو 0,1,2
( kernel
و init
و [kthreadd]
) بالإضافة إلى أسماء العمليات init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1]
. يمكن أن تكون العملية مرجعًا comm
أو cmdline
أو pid
. يمكن أن يكون الإعداد الافتراضي التلقائي أكبر من الحد الأقصى الحالي لحجم الخاصية وهو 92.
ro.llk.blacklist.parent
لا يراقب llkd
العمليات التي لها الأصل (الوالدين) المحددين. الافتراضي هو 0,2,adbd&[setsid]
( kernel
و [kthreadd]
و adbd
فقط لـ zombie setsid
). يحدد فاصل علامة العطف (&) أنه سيتم تجاهل الأصل فقط مع العملية الفرعية المستهدفة. تم تحديد علامة الضم لأنها لا تشكل أبدًا جزءًا من اسم العملية؛ ومع ذلك، فإن setprop
في الصدفة يتطلب الهروب من علامة الضم أو الاقتباس، على الرغم من أن ملف init rc
حيث يتم تحديد ذلك عادةً لا يحتوي على هذه المشكلة. يمكن أن تكون العملية الأصلية أو المستهدفة عبارة عن مرجع comm
أو cmdline
أو pid
.
ro.llk.blacklist.uid
لا يراقب llkd
العمليات التي تطابق المعرف (المعرفات) المحدد. قائمة مفصولة بفواصل من أرقام أو أسماء uid. الافتراضي فارغ أو خطأ.
ro.llk.blacklist.process.stack
لا يراقب llkd
المجموعة الفرعية المحددة من العمليات لتوقيعات مكدس القفل المباشر. الافتراضي هو أسماء العمليات init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
. يمنع انتهاك الخصوصية المرتبط بالعمليات التي تمنع ptrace
(حيث لا يمكن التحقق منها). نشط فقط على userdebug وeng builds . للحصول على تفاصيل حول أنواع البناء، راجع إنشاء Android .
المخاوف المعمارية
- تقتصر الخصائص على 92 حرفًا (ومع ذلك، يتم تجاهل هذا بالنسبة للإعدادات الافتراضية المحددة في ملف
include/llkd.h
في المصادر). - البرنامج الخفي
[khungtask]
المدمج عام جدًا ويتنقل عبر رمز برنامج التشغيل الموجود في الحالة D كثيرًا. سيؤدي التبديل إلى S إلى جعل المهمة (المهام) قابلة للقتل (وقابلة للإحياء بواسطة السائقين إذا لزم الأمر).
واجهة المكتبة (اختياري)
يمكنك اختياريًا دمج llkd
في برنامج خفي آخر ذي امتيازات باستخدام واجهة C التالية من مكون libllkd
:
#include "llkd.h"
bool llkInit(const char* threadname) /* return true if enabled */
unsigned llkCheckMillseconds(void) /* ms to sleep for next check */
إذا تم توفير اسم مؤشر الترابط، فسيتم نشر الخيط تلقائيًا، وإلا يجب على المتصل استدعاء llkCheckMilliseconds
في حلقته الرئيسية. تقوم الدالة بإرجاع الفترة الزمنية قبل الاستدعاء التالي المتوقع لهذا المعالج.