Android 10 มีเดรัมน์การล็อกแบบเรียลไทม์ของ Android (llkd
) ซึ่งออกแบบมาเพื่อตรวจหาและลดการล็อกคอร์เนล คอมโพเนนต์ llkd
มีการนําไปใช้แบบสแตนด์อโลนโดยค่าเริ่มต้น แต่คุณยังผสานรวมโค้ด llkd
เข้ากับบริการอื่นได้ ไม่ว่าจะเป็นส่วนหนึ่งของลูปหลักหรือเป็นเธรดแยกต่างหาก
สถานการณ์การตรวจจับ
llkd
มี 2 สถานการณ์การตรวจจับ ได้แก่ สถานะ D หรือ Z แบบถาวร และลายเซ็นสแต็กแบบถาวร
สถานะ D หรือ Z แบบถาวร
หากเธรดอยู่ในสถานะ D (การหยุดทำงานชั่วคราวแบบไม่หยุดชะงัก) หรือ Z (ซอมบี้) โดยไม่มีการดำเนินการใดๆ นานกว่า ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
วินาที llkd
จะหยุดกระบวนการ (หรือกระบวนการหลัก) หากการสแกนครั้งถัดไปพบว่ามีกระบวนการเดิมอยู่ llkd
จะยืนยันเงื่อนไขการล็อกอยู่และทำให้เคอร์เนลตกใจในลักษณะที่ให้รายงานข้อบกพร่องที่ละเอียดที่สุดสำหรับเงื่อนไขดังกล่าว
llkd
มี Watchdog ที่ส่งเสียงเตือนเมื่อ llkd
ล็อกไว้ Watchdog คือ 2 เท่าของเวลาที่คาดว่าจะไหลผ่าน Main Loop และการสุ่มตัวอย่างคือทุกๆ ro.llk_sample_ms
ลายเซ็นสแต็กแบบถาวร
สำหรับรุ่น userdebug 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
ใน 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 วิธีนี้จึงเป็นวิธีเดียวที่ป้องกันทริกเกอร์ที่ไม่ถูกต้องได้ สัญลักษณ์ function ต้องปรากฏใต้ฟังก์ชันที่เรียกใช้ล็อกที่อาจแย่งกัน หากล็อกอยู่ด้านล่างหรือในฟังก์ชันสัญลักษณ์ สัญลักษณ์จะปรากฏในกระบวนการทั้งหมดที่ได้รับผลกระทบ ไม่ใช่แค่กระบวนการที่ทำให้เกิดการค้าง
ความครอบคลุม
การใช้งาน llkd
เริ่มต้นจะไม่ตรวจสอบ init
, [kthreadd]
หรือ [kthreadd]
ที่เกิดจากกระบวนการ llkd
ครอบคลุมชุดข้อความที่เกิดจาก [kthreadd]
- ไดรเวอร์ต้องไม่อยู่ในสถานะ D ถาวร
หรือ
- ไดรเวอร์ต้องมีกลไกในการกู้คืนเธรดในกรณีที่มีการหยุดเธรดจากภายนอก เช่น ใช้
wait_event_interruptible()
แทนwait_event()
หากเป็นไปตามเงื่อนไขข้อใดข้อหนึ่งข้างต้น คุณสามารถปรับllkd
รายการที่ปฏิเสธให้ครอบคลุมคอมโพเนนต์เคอร์เนลได้ การตรวจสอบสัญลักษณ์สแต็กเกี่ยวข้องกับรายการที่ปฏิเสธกระบวนการเพิ่มเติมเพื่อป้องกันการละเมิดนโยบายความปลอดภัยในบริการที่บล็อกการดำเนินการ ptrace
พร็อพเพอร์ตี้ Android
llkd
จะตอบสนองต่อพร็อพเพอร์ตี้ Android หลายรายการ (แสดงอยู่ด้านล่าง)
- พร็อพเพอร์ตี้ชื่อ
prop_ms
อยู่ในหน่วยมิลลิวินาที - พร็อพเพอร์ตี้ที่ใช้ตัวคั่นคอมมา (,) สำหรับลิสต์จะใช้ตัวคั่นนำหน้าเพื่อเก็บรายการเริ่มต้นไว้ จากนั้นเพิ่มหรือลบรายการด้วยคำนำหน้าบวก (+) และลบ (-) ตามลำดับ (ไม่บังคับ) สําหรับรายการเหล่านี้ สตริง
false
จะตรงกับรายการว่าง และรายการที่ว่างเปล่าหรือไม่มีจะใช้ค่าเริ่มต้นที่ระบุ
ro.config.low_ram
อุปกรณ์ได้รับการกำหนดค่าให้มีหน่วยความจำจํากัด
ro.debuggable
อุปกรณ์ได้รับการกําหนดค่าสําหรับบิลด์ userdebug หรือ eng
ro.llk.sysrq_t
หากพร็อพเพอร์ตี้คือ eng
ค่าเริ่มต้นจะไม่เป็น ro.config.low_ram
หรือ ro.debuggable
หากเป็น true
ให้แสดงชุดข้อความทั้งหมด (sysrq t
)
ro.llk.enable
อนุญาตให้เปิดใช้ Daemon ล็อกแบบสด ค่าเริ่มต้นคือ false
llk.enable
ประเมินสำหรับบิลด์ eng ค่าเริ่มต้นคือ ro.llk.enable
ro.khungtask.enable
อนุญาตให้เปิดใช้ Daemon ของ [khungtask]
ค่าเริ่มต้นคือ false
khungtask.enable
ประเมินสำหรับบิลด์ eng ค่าเริ่มต้นคือ ro.khungtask.enable
ro.llk.mlockall
เปิดใช้การโทรหา mlockall()
ค่าเริ่มต้นคือ false
ro.khungtask.timeout
[khungtask]
กำหนดเวลาสูงสุด ค่าเริ่มต้นคือ 12 นาที
ro.llk.timeout_ms
ขีดจำกัดเวลาสูงสุด D หรือ Z ค่าเริ่มต้นคือ 10 นาที เพิ่มค่านี้เป็น 2 เท่าเพื่อตั้งค่าโปรแกรมตรวจสอบการตื่นขึ้นสำหรับ 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
ro.llk.check_ms
ตัวอย่างชุดข้อความสําหรับ D หรือ Z ค่าเริ่มต้นคือ 2 นาที
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
) ตัวคั่นแอมเพอร์แซนด์ (&) จะระบุว่าระบบจะไม่สนใจกระบวนการหลักเฉพาะในกรณีที่ใช้ร่วมกับกระบวนการย่อยเป้าหมายเท่านั้น เลือกเครื่องหมายแอมเปอร์แซนด์เนื่องจากไม่เคยเป็นส่วนหนึ่งของชื่อกระบวนการ แต่ 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
ป้องกันการละเมิดนโยบายความปลอดภัยที่เกี่ยวข้องกับกระบวนการที่บล็อก ptrace
(เนื่องจากไม่สามารถตรวจสอบได้) ใช้งานได้เฉพาะในเวอร์ชัน userdebug และ Enging โปรดดูรายละเอียดเกี่ยวกับประเภทบิลด์ที่หัวข้อการสร้าง Android
ข้อกังวลด้านสถาปัตยกรรม
- พร็อพเพอร์ตี้มีอักขระได้ไม่เกิน 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
ในลูปหลัก ฟังก์ชันนี้จะแสดงผลระยะเวลาก่อนการเรียกใช้ตัวแฮนเดิลนี้ครั้งถัดไปที่คาดไว้