اندروید 10 شامل دیمون قفل زنده اندروید ( 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
هشدار می دهد. Watchdog دو برابر زمان مورد انتظار برای عبور از حلقه اصلی است و نمونه برداری هر ro.llk_sample_ms
است.
امضای پشته ای پایدار
برای نسخههای اشکالزدایی کاربر، llkd
میتواند قفلهای زنده هسته را با استفاده از بررسی دائمی امضای پشته شناسایی کند. اگر رشتهای در هر حالتی به جز Z دارای نماد هسته ro.llk.stack
لیست شده دائمی باشد که بیشتر از ro.llk.timeout_ms
یا ro.llk.stack.timeout_ms
گزارش شود، llkd
فرآیند را از بین میبرد (حتی اگر فوروارد وجود داشته باشد. برنامه ریزی پیشرفت). اگر اسکن بعدی نشان دهد که همان فرآیند همچنان وجود دارد، llkd
یک شرط قفل زنده را تأیید میکند و هسته را به گونهای وحشت میکند که جزئیات گزارش اشکال را برای شرایط ارائه میدهد.
بررسی lldk
زمانی که شرایط قفل زنده وجود داشته باشد به طور مداوم ادامه دارد و به دنبال رشته های تشکیل شده symbol+0x
یا symbol.cfi+0x
در فایل /proc/pid/stack
در لینوکس می گردد. فهرست نمادها در 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]
-spawned threads را بپوشاند:
- رانندگان نباید در حالت D پایدار بمانند،
یا
- درایورها باید مکانیزمی برای بازیابی نخ در صورت از بین رفتن خارجی داشته باشند. به عنوان مثال، به جای Wait_event
wait_event_interruptible()
wait_event()
استفاده کنید.
اگر یکی از شرایط بالا برآورده شود، llkd
denylist را می توان برای پوشش اجزای هسته تنظیم کرد. بررسی نماد پشته شامل یک فهرست رد فرآیند اضافی برای جلوگیری از نقض قوانین در سرویسهایی است که عملیات ptrace
مسدود میکنند.
خواص اندروید
llkd
به چندین ویژگی Android پاسخ می دهد (ذکر شده در زیر).
- ویژگی هایی با نام
prop_ms
بر حسب میلی ثانیه هستند. - ویژگی هایی که از جداکننده کاما (،) برای لیست ها استفاده می کنند، از یک جداکننده پیشرو برای حفظ ورودی پیش فرض استفاده می کنند، سپس ورودی ها را به ترتیب با پیشوندهای مثبت (+) و منهای (-) اضافه یا کم می کنند. برای این لیست ها، رشته
false
مترادف با یک لیست خالی است و ورودی های خالی یا گم شده به مقدار پیش فرض مشخص شده متوسل می شوند.
ro.config.low_ram
دستگاه با حافظه محدود پیکربندی شده است.
ro.debuggable
دستگاه برای userdebug یا eng build پیکربندی شده است.
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]
daemon فعال شود. پیش فرض false
است.
khungtask.enable
برای ساخت های مهندسی ارزیابی شده است. پیش فرض ro.khungtask.enable
است.
ro.llk.mlockall
فراخوانی به mlockall()
را فعال کنید. پیش فرض false
است.
ro.khungtask.timeout
[khungtask]
حداکثر محدودیت زمانی. پیش فرض 12 دقیقه است.
ro.llk.timeout_ms
حداکثر محدودیت زمانی D یا Z. پیش فرض 10 دقیقه است. این مقدار را دو برابر کنید تا alarm watchdog را برای 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 builds .
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 موجود است . نگرانی های امنیتی در ساخت های کاربر منجر به امتیازات محدودی می شود که از این بررسی جلوگیری می کند.
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
). یک جداکننده علامت (&) مشخص می کند که والد فقط در ترکیب با فرآیند فرزند هدف نادیده گرفته می شود. Ampersand انتخاب شد زیرا هرگز بخشی از نام فرآیند نیست. با این حال، یک setprop
در پوسته نیاز به خروج یا نقل قول از آمپرسند دارد، اگرچه فایل init rc
که در آن معمولاً مشخص شده است، این مشکل را ندارد. یک فرآیند والد یا هدف می تواند یک مرجع comm
، cmdline
یا pid
باشد.
ro.llk.blacklist.uid
llkd
فرآیندهایی را که با UIDهای مشخص شده مطابقت دارند تماشا نمی کند. فهرست اعداد یا نامهای UIS جدا شده با کاما. پیش فرض خالی یا false
است.
ro.llk.blacklist.process.stack
llkd
زیرمجموعه فرآیندهای مشخص شده را برای امضاهای پشته قفل زنده نظارت نمی کند. پیشفرض نامهای فرآیند init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
است. از نقض sepolicy مرتبط با فرآیندهایی که ptrace
مسدود می کنند، جلوگیری می کند (زیرا نمی توان آنها را بررسی کرد). فعال فقط در userdebug و eng builds . برای جزئیات بیشتر در مورد انواع ساخت، به ساخت اندروید مراجعه کنید.
دغدغه های معماری
- ویژگیها به 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
در حلقه اصلی خود فراخوانی کند. این تابع دوره زمانی قبل از تماس مورد انتظار بعدی را به این کنترل کننده برمی گرداند.