البرنامج الخفي لقفل 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، هذه هي الطريقة الوحيدة لمنع حدوث تشغيل خاطئ. يجب أن تظهر دالة الرمز أسفل الدالة التي تستدعي القفل الذي يمكن أن يتطابق. إذا كان القفل أسفل دالة الرمز أو في دالة الرمز، يظهر الرمز في جميع العمليات المتأثّرة، وليس فقط العملية التي أدّت إلى حدوث القفل.

التغطية

لا تتتبّع عملية التنفيذ التلقائية لـ 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.

cannot translate

[khungtask] الحد الأقصى لمدة الانتظار المدة التلقائية هي 12 دقيقة.

ro.llk.timeout_ms

الحد الأقصى للوقت المستغرق في الإجراء D أو Z والإعداد التلقائي هو 10 دقائق. يمكنك مضاعفة هذه القيمة لضبط مراقب المنبّه لـ llkd.

ro.llk.D.timeout_ms

D الحد الأقصى للوقت القيمة التلقائية هي 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 أو eng، لأنّ المخاوف الأمنية في عمليات التجميع من النوع user تؤدي إلى منح امتيازات محدودة تمنع إجراء هذا التحقّق.

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 فقط لحالة "العملية غير النشطة" setsid). يحدّد فاصل علامة "و" (&) أنّه يتم تجاهل العملية الرئيسية فقط مع العملية الفرعية المستهدَفة. تم اختيار علامة العطف لأنها ليست جزءًا من اسم عملية أبدًا، إلا أنّ علامة setprop في واجهة المستخدم تشترط إلغاء علامة العطف أو الاقتباس منها، علمًا أنّ ملف 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 في الحلقة الرئيسية. تعرِض الدالة المدة الزمنية قبل الطلب المتوقّع التالي لهذا المعالج.