البرنامج الخفي لقفل Android (llkd)

يتضمّن نظام التشغيل Android 10 برنامج Android live-lock daemon (llkd)، وهو مصمّم لرصد حالات التوقف المفاجئ لنظام التشغيل والحدّ منها. يقدّم المكوّن 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 تحتوي على رمز 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، تكون هذه الطريقة الوحيدة لمنع حدوث مشغّل خطأ. يجب أن يظهر الرمز function أسفل الدالة التي تستدعي القفل الذي يمكن أن يتعارض مع الرمز. إذا كان القفل أسفل دالة الرمز أو في دالة الرمز، يظهر الرمز في جميع العمليات المتأثّرة، وليس فقط العملية التي أدّت إلى حدوث القفل.

التغطية

لا تتتبّع عملية التنفيذ التلقائية لـ llkd عمليات إنشاء init أو [kthreadd] أو [kthreadd]. لكي يشمل llkd سلاسل المحادثات التي تم إنشاؤها من [kthreadd]، يجب اتّباع الخطوات التالية:

  • يجب ألا يظلّ السائقون في حالة D مستمرة.

أو

  • يجب أن تتضمّن برامج التشغيل آليات لاسترداد سلسلة المهام في حال تم إنهاء أدائها خارجيًا. على سبيل المثال، استخدِم wait_event_interruptible() بدلاً من wait_event().

في حال استيفاء أحد الشروط السابقة، يمكن تعديل قائمة الحظر llkd لتشمل مكوّنات النواة. يتضمن التحقّق من رموز الحزمة عملية إضافية لفحص القائمة المحظورة لمنع انتهاكات سياسة الأمان في الخدمات التي تحظر عمليات ptrace.

مواقع Android

يستجيب llkd لعدة سمات Android (مُدرَجة أدناه).

  • يتم قياس السمات التي تحمل الاسم prop_ms بالمللي ثانية.
  • إنّ المواقع التي تستخدم الفاصلة (,) كفاصل للقوائم تستخدم فاصلًا أوليًا للحفاظ على الإدخال التلقائي، ثم تضيف الإدخالات أو تطرحها باستخدام البادئات الاختيارية (+) و (-) على التوالي. بالنسبة إلى هذه القوائم، تكون السلسلة false مرادفة لقائمة فارغة، وتلجأ الإدخالات الفارغة أو المفقودة إلى القيمة التلقائية المحدّدة.

ro.config.low_ram

تم ضبط الجهاز على ذاكرة محدودة.

ro.debuggable

تم ضبط الجهاز على وضع userdebug أو وضع الإصدار الهندسي.

ro.llk.sysrq_t

إذا كانت السمة هي eng، لا تكون القيمة التلقائية هي ro.config.low_ram أو ro.debuggable. إذا كانت true، سيتم تفريغ جميع سلاسل المحادثات (sysrq t).

ro.llk.enable

السماح بتفعيل برنامج "الخادم الدائم لقفل الشاشة" القيمة التلقائية هي false.

llk.enable

يتم تقييمه بناءً على تصاميم الهندسة. القيمة التلقائية هي ro.llk.enable.

ro.khungtask.enable

السماح بتفعيل البرنامج الخفي "[khungtask]" القيمة التلقائية هي false.

khungtask.enable

يتم تقييمه بناءً على تصاميم الهندسة. القيمة التلقائية هي ro.khungtask.enable.

ro.llk.mlockall

فعِّل الاتصال بـ mlockall(). القيمة التلقائية هي false.

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.

ro.llk.check_ms

عيّنات من الخيوط لـ D أو Z المدة التلقائية هي دقيقتان.

ro.llk.stack

يتحقّق من رموز تسلسل استدعاء الدوال البرمجية للنواة التي يمكن أن تشير إلى أنّه تم قفل أحد الأنظمة الفرعية. الإعداد التلقائي هو cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable قائمة مفصولة بفواصل لرموزه. لا يُجري التحقّق جدولة مُسبَقة ABA إلا من خلال الاستطلاع كل ro.llk_check_ms خلال الفترة ro.llk.stack.timeout_ms، لذا من المفترض أن تكون رموز الحِزم نادرة بشكلٍ استثنائي ومرتَقة (من غير المرجّح أن يظهر رمز بشكلٍ مستمر في كل عيّنات الحزمة). تبحث عن مطابقة symbol+0x أو symbol.cfi+0x في توسيع الحزمة. هذه الميزة متاحة فقط في إصدارات userdebug أو الهندسة. تؤدي المخاوف الأمنية المتعلّقة بعمليات إنشاء المستخدمين إلى الحصول على امتيازات محدودة تمنع هذا الفحص.

ro.llk.block.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 فقط للزومبي setsid). ويحدّد فاصل علامة العطف (&) أنّه يتم تجاهل العنصر الرئيسي فقط مع العملية الفرعية المستهدفة. تم اختيار علامة العطف لأنّها لا تكون أبدًا جزءًا من اسم عملية، ومع ذلك، تتطلّب علامة setprop في القشرة استخدام علامة ESCAPE أو اقتباسات مع علامة العطف، على الرغم من أنّ ملف init rc الذي يتم فيه تحديد ذلك عادةً لا يواجه هذه المشكلة. يمكن أن تكون العملية الرئيسية أو الهدف مرجعًا comm أو cmdline أو pid.

ro.llk.blacklist.uid

لا يراقب llkd العمليات التي تتطابق مع المعرفات الفريدة المحددة. قائمة مفصولة بفواصل بأرقام أو أسماء UIS القيمة التلقائية هي فارغة أو false.

ro.llk.blacklist.process.stack

لا يراقب llkd المجموعة الفرعية المحدّدة من العمليات لتوقيعات حزمة القفل المباشرة. الإعداد التلقائي هو أسماء العمليات init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd. يمنع هذا الخيار انتهاك سياسة الأمان المرتبط بالعمليات التي تحظر ptrace (لأنّه لا يمكن فحصها). لا يكون مفعَّلاً إلا في إصدارات userdebug وeng. للتعرّف على تفاصيل عن أنواع الإصدارات، يُرجى الرجوع إلى مقالة إنشاء نظام التشغيل 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 في حلقة التنفيذ الرئيسية. تعرِض الدالة المدة الزمنية قبل الطلب المتوقّع التالي لهذا المعالج.