Daemon ล็อกแบบสดของ Android (llkd)

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 ในลูปหลัก ฟังก์ชันนี้จะแสดงผลระยะเวลาก่อนการเรียกใช้ตัวแฮนเดิลนี้ครั้งถัดไปที่คาดไว้