Android Live-LocK Daemon (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 ยืนยันเงื่อนไขการล็อกแบบสด และทำให้เคอร์เนลตื่นตระหนกในลักษณะที่ให้รายงานจุดบกพร่องที่มีรายละเอียดมากที่สุดสำหรับเงื่อนไข

llkd รวมถึงสุนัขเฝ้าบ้านที่เตือนถ้า llkd ล็อก; watchdog เพิ่มขึ้นเป็นสองเท่าของเวลาที่คาดว่าจะไหลผ่าน mainloop และการสุ่มตัวอย่างคือทุกๆ ro.llk_sample_ms

ลายเซ็นสแต็กถาวร

สำหรับ userdebug release นั้น llkd สามารถตรวจจับเคอร์เนล live-locks ได้โดยใช้การตรวจสอบลายเซ็นสแต็กแบบถาวร หากเธรดในสถานะใดๆ ยกเว้น 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 มีหน่วยเป็นมิลลิวินาที
  • คุณสมบัติที่ใช้เครื่องหมายจุลภาค (,) ตัวคั่นสำหรับรายการใช้ตัวคั่นนำหน้าเพื่อรักษารายการเริ่มต้น จากนั้นเพิ่มหรือลบรายการด้วยคำนำหน้าบวก (+) และลบ (-) ตามลำดับ สำหรับรายการเหล่านี้ สตริง "เท็จ" มีความหมายเหมือนกันกับรายการว่าง และรายการว่างหรือรายการที่ขาดหายไปจะใช้ค่าเริ่มต้นที่ระบุ

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

อนุญาตให้เปิดใช้งาน live-lock daemon ค่าเริ่มต้นเป็นเท็จ

llk.enable

ประเมินสำหรับการสร้าง eng ค่าเริ่มต้นคือ ro.llk.enable

ro.khungtask.enable

อนุญาตให้เปิดใช้งาน [khungtask] daemon ค่าเริ่มต้นเป็นเท็จ

khungtask.enable

ประเมินสำหรับการสร้าง eng ค่าเริ่มต้นคือ 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.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 สำหรับ zombie setsid เท่านั้น) ตัวคั่นเครื่องหมายและ (&) ระบุว่าพาเรนต์ถูกละเว้นร่วมกับกระบวนการลูกเป้าหมายเท่านั้น เครื่องหมายและถูกเลือกเนื่องจากไม่เคยเป็นส่วนหนึ่งของชื่อกระบวนการ อย่างไรก็ตาม setprop ในเชลล์ต้องการเครื่องหมาย ampersand เพื่อหลีกเลี่ยงหรืออ้างอิง แม้ว่าไฟล์ 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 ในลูปหลัก ฟังก์ชันส่งกลับช่วงเวลาก่อนการเรียกครั้งต่อไปที่คาดหวังไปยังตัวจัดการนี้