Android 10 มี Android Live-LocK Daemon ( llkd
) ซึ่งออกแบบมาเพื่อตรวจจับและลดการหยุดชะงักของเคอร์เนล ส่วนประกอบ llkd
จัดให้มีการใช้งานแบบสแตนด์อโลนที่เป็นค่าเริ่มต้น แต่คุณสามารถเลือกรวมโค้ด llkd
เข้ากับบริการอื่นได้ ไม่ว่าจะเป็นส่วนหนึ่งของลูปหลักหรือเป็นเธรดแยกกัน
สถานการณ์การตรวจจับ
llkd
มีสถานการณ์การตรวจจับสองแบบ: สถานะ D หรือ Z แบบถาวร และลายเซ็นสแต็กแบบถาวร
สถานะ D หรือ Z ถาวร
หากเธรดอยู่ในสถานะ D (uninterruptible sleep) หรือ Z (zombie) โดยไม่มีความคืบหน้าในการส่งต่อนานกว่า ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
llkd
จะฆ่ากระบวนการ (หรือกระบวนการหลัก ). หากการสแกนครั้งต่อมาแสดงให้เห็นว่ากระบวนการเดิมยังคงมีอยู่ llkd
จะยืนยันเงื่อนไข live-lock และทำให้เคอร์เนลตื่นตระหนกในลักษณะที่ให้รายงานจุดบกพร่องที่มีรายละเอียดมากที่สุดสำหรับเงื่อนไขนั้น
llkd
มีโปรแกรมเฝ้าระวังตนเองที่จะแจ้งเตือนหาก llkd
ล็อคอยู่ watchdog เป็นสองเท่าของเวลาที่คาดว่าจะไหลผ่าน mainloop และการสุ่มตัวอย่างคือทุก ๆ ro.llk_sample_ms
ลายเซ็นสแต็กถาวร
สำหรับการเปิดตัว userdebug นั้น llkd
สามารถตรวจจับเคอร์เนล live-lock ได้โดยใช้การตรวจสอบลายเซ็นสแต็กแบบถาวร หากเธรดในสถานะใดๆ ยกเว้น Z มีสัญลักษณ์เคอร์เนล ro.llk.stack
ที่แสดงอยู่ถาวร ซึ่งมีการรายงานนานกว่า ro.llk.timeout_ms
หรือ ro.llk.stack.timeout_ms
llkd
จะฆ่ากระบวนการ (แม้ว่าจะมีการส่งต่อก็ตาม ความคืบหน้าของกำหนดการ) หากการสแกนครั้งต่อมาแสดงให้เห็นว่ากระบวนการเดิมยังคงมีอยู่ llkd
จะยืนยันเงื่อนไข live-lock และทำให้เคอร์เนลตื่นตระหนกในลักษณะที่ให้รายงานจุดบกพร่องที่มีรายละเอียดมากที่สุดสำหรับเงื่อนไขนั้น
การตรวจสอบ lldk
ยังคงมีอยู่อย่างต่อเนื่องเมื่อมีเงื่อนไข live lock และค้นหาสตริงที่ประกอบแล้ว " 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]
-spawned threads:
- ผู้ขับขี่จะต้องไม่อยู่ในสถานะ D ถาวร
หรือ
- ไดรเวอร์ต้องมีกลไกในการกู้คืนเธรดหากถูกปิดการทำงานจากภายนอก ตัวอย่างเช่น ใช้
wait_event_interruptible()
แทนwait_event()
หากตรงตามเงื่อนไขข้อใดข้อหนึ่งข้างต้น คุณจะสามารถปรับบัญชีดำ llkd
ให้ครอบคลุมส่วนประกอบเคอร์เนลได้ การตรวจสอบสัญลักษณ์สแต็กเกี่ยวข้องกับบัญชีดำกระบวนการเพิ่มเติมเพื่อป้องกันการละเมิดนโยบายแยกในบริการที่บล็อกการดำเนินการ 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
หากเป็นจริง ให้ดัมพ์เธรดทั้งหมด ( sysrq t
)
ro.llk.เปิดใช้งาน
อนุญาตให้เปิดใช้งาน live-lock daemon ค่าเริ่มต้นเป็นเท็จ
llk.เปิดใช้งาน
ได้รับการประเมินสำหรับการสร้างภาษาอังกฤษ ค่าเริ่มต้นคือ ro.llk.enable
ro.khungtask.เปิดใช้งาน
อนุญาตให้เปิดใช้งาน [khungtask]
daemon ค่าเริ่มต้นเป็นเท็จ
khungtask.เปิดใช้งาน
ได้รับการประเมินสำหรับการสร้างภาษาอังกฤษ ค่าเริ่มต้นคือ 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
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 builds เท่านั้น ข้อกังวลด้านความปลอดภัยในการสร้างผู้ใช้ส่งผลให้เกิดสิทธิ์ที่จำกัดซึ่งป้องกันการตรวจสอบนี้
ro.llk.blacklist.กระบวนการ
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
ไม่เฝ้าดูกระบวนการที่ตรงกับ uid ที่ระบุ รายการหมายเลขหรือชื่อ uid ที่คั่นด้วยเครื่องหมายจุลภาค ค่าเริ่มต้นว่างเปล่าหรือเป็นเท็จ
ro.llk.blacklist.process.stack
llkd
จะไม่มอนิเตอร์ชุดย่อยของกระบวนการที่ระบุสำหรับลายเซ็นสแต็กล็อกแบบสด ค่าดีฟอลต์คือชื่อกระบวนการ init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
ป้องกันการละเมิด sepolicy ที่เกี่ยวข้องกับกระบวนการที่บล็อก ptrace
(เนื่องจากไม่สามารถตรวจสอบได้) ใช้งานได้เฉพาะกับ userdebug และ eng builds สำหรับรายละเอียดเกี่ยวกับประเภทบิลด์ โปรดดูที่ การสร้าง Android
ข้อกังวลทางสถาปัตยกรรม
- คุณสมบัติจำกัดไว้ที่ 92 อักขระ (แต่จะถูกละเว้นสำหรับค่าดีฟอลต์ที่กำหนดไว้ในไฟล์
include/llkd.h
ในซอร์ส) -
[khungtask]
daemon ในตัวนั้นกว้างเกินไป และทริปโค้ดไดรเวอร์ที่อยู่ในสถานะ D มากเกินไป การเปลี่ยนไปใช้ S จะทำให้งานสามารถฆ่าได้ (และคนขับสามารถฟื้นคืนชีพได้หากจำเป็น)
อินเตอร์เฟซห้องสมุด (ไม่จำเป็น)
คุณสามารถเลือกรวม llkd
เข้ากับ daemon ที่มีสิทธิใช้งานอื่นได้โดยใช้อินเทอร์เฟซ C ต่อไปนี้จากคอมโพเนนต์ libllkd
:
#include "llkd.h"
bool llkInit(const char* threadname) /* return true if enabled */
unsigned llkCheckMillseconds(void) /* ms to sleep for next check */
หากมีการระบุชื่อเธรด เธรดจะวางไข่โดยอัตโนมัติ มิฉะนั้นผู้เรียกจะต้องเรียก llkCheckMilliseconds
ในลูปหลัก ฟังก์ชันส่งคืนช่วงเวลาก่อนการเรียกครั้งถัดไปที่คาดไว้ไปยังตัวจัดการนี้