دیمون قفل زنده اندروید (llkd)

اندروید 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 است. The check doesn't do forward scheduling ABA except by polling every ro.llk_check_ms over the period ro.llk.stack.timeout_ms , so stack symbols should be exceptionally rare and fleeting (it is highly unlikely for a symbol to show up persistently in all نمونه های پشته). مطابقت را برای 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 در حلقه اصلی خود فراخوانی کند. این تابع دوره زمانی قبل از تماس مورد انتظار بعدی را به این کنترل کننده برمی گرداند.