Android Live-ล็อคภูต (llkd)

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 ในเชลล์ต้องการให้เครื่องหมายแอมเปอร์แซนด์เป็นอักขระหลีกหรือเครื่องหมายคำพูด แม้ว่าไฟล์ 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 ในลูปหลัก ฟังก์ชันส่งคืนช่วงเวลาก่อนการเรียกครั้งถัดไปที่คาดไว้ไปยังตัวจัดการนี้