Android Live-LocK Daemon (llkd)

Android 10 menyertakan Android Live-LocK Daemon ( llkd ), yang dirancang untuk menangkap dan mengurangi kebuntuan kernel. Komponen llkd menyediakan implementasi mandiri default, tetapi Anda juga dapat mengintegrasikan kode llkd ke layanan lain, baik sebagai bagian dari loop utama atau sebagai utas terpisah.

Skenario deteksi

llkd memiliki dua skenario deteksi: status D atau Z yang persisten, dan tanda tangan tumpukan yang persisten.

Status D atau Z yang persisten

Jika utas dalam status D (tidur tidak terputus) atau Z (zombie) tanpa kemajuan maju lebih lama dari ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms , llkd mematikan proses (atau proses induk ). Jika pemindaian berikutnya menunjukkan proses yang sama terus ada, llkd mengonfirmasi kondisi penguncian langsung dan membuat panik kernel dengan cara yang memberikan laporan bug paling rinci untuk kondisi tersebut.

llkd termasuk pengawas diri yang memberi alarm jika llkd terkunci; watchdog menggandakan waktu yang diharapkan untuk mengalir melalui mainloop dan pengambilan sampel adalah setiap ro.llk_sample_ms .

Tanda tangan tumpukan persisten

Untuk rilis debug pengguna, llkd dapat mendeteksi penguncian langsung kernel menggunakan pemeriksaan tanda tangan tumpukan persisten. Jika sebuah utas dalam status apa pun kecuali Z memiliki simbol kernel ro.llk.stack terdaftar yang terus-menerus yang dilaporkan lebih lama dari ro.llk.timeout_ms atau ro.llk.stack.timeout_ms , llkd mematikan proses (bahkan jika ada penerusan kemajuan penjadwalan). Jika pemindaian berikutnya menunjukkan proses yang sama terus ada, llkd mengonfirmasi kondisi penguncian langsung dan membuat panik kernel dengan cara yang memberikan laporan bug paling rinci untuk kondisi tersebut.

Pemeriksaan lldk berlanjut terus menerus ketika kondisi kunci langsung ada dan mencari string yang disusun " symbol+0x" atau " symbol.cfi+0x" di file /proc/pid/stack di Linux. Daftar simbol ada di ro.llk.stack dan default ke daftar yang dipisahkan koma dari " cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable ".

Simbol harus langka dan berumur pendek sehingga pada sistem tipikal fungsi hanya terlihat sekali dalam sampel selama periode waktu habis ro.llk.stack.timeout_ms (sampel muncul setiap ro.llk.check_ms ). Karena kurangnya perlindungan ABA, ini adalah satu-satunya cara untuk mencegah pemicu palsu. Fungsi simbol harus muncul di bawah fungsi yang memanggil kunci yang dapat bersaing. Jika kunci berada di bawah atau dalam fungsi simbol, simbol akan muncul di semua proses yang terpengaruh, bukan hanya proses yang menyebabkan penguncian.

liputan

Implementasi default llkd tidak memonitor init , [kthreadd] , atau [kthreadd] memunculkan. Untuk llkd untuk menutupi [kthreadd] -spawned threads:

  • Pengemudi tidak boleh tetap dalam status D yang persisten,

ATAU

  • Pengemudi harus memiliki mekanisme untuk memulihkan utas jika dimatikan secara eksternal. Misalnya, gunakan wait_event_interruptible() alih-alih wait_event() .

Jika salah satu kondisi di atas terpenuhi, daftar hitam llkd dapat disesuaikan untuk mencakup komponen kernel. Pemeriksaan simbol tumpukan melibatkan daftar hitam proses tambahan untuk mencegah pelanggaran kebijakan pada layanan yang memblokir operasi ptrace .

properti Android

llkd merespons beberapa properti Android (tercantum di bawah).

  • Properti bernama prop_ms dalam milidetik.
  • Properti yang menggunakan pemisah koma (,) untuk daftar menggunakan pemisah awal untuk mempertahankan entri default, lalu menambah atau mengurangi entri dengan prefiks plus (+) dan minus (-) opsional masing-masing. Untuk daftar ini, string "false" identik dengan daftar kosong, dan entri kosong atau hilang menggunakan nilai default yang ditentukan.

ro.config.low_ram

Perangkat dikonfigurasi dengan memori terbatas.

ro.debuggable

Perangkat dikonfigurasi untuk userdebug atau eng build.

ro.llk.sysrq_t

Jika propertinya adalah "eng", defaultnya bukan ro.config.low_ram atau ro.debuggable . Jika benar, buang semua utas ( sysrq t ).

ro.llk.enable

Izinkan daemon kunci langsung diaktifkan. Standarnya salah.

llk.enable

Dievaluasi untuk eng build. Standarnya adalah ro.llk.enable .

ro.khungtask.enable

Izinkan daemon [khungtask] diaktifkan. Standarnya salah.

khungtask.enable

Dievaluasi untuk eng build. Standarnya adalah ro.khungtask.enable .

ro.llk.mlockall

Aktifkan panggilan ke mlockall() . Standarnya salah.

ro.khungtask.timeout

[khungtask] batas waktu maksimum. Standarnya adalah 12 menit.

ro.llk.timeout_ms

D atau Z batas waktu maksimum. Standarnya adalah 10 menit. Gandakan nilai ini untuk menyetel pengawas alarm untuk llkd .

ro.llk.D.timeout_ms

D batas waktu maksimum. Standarnya adalah ro.llk.timeout_ms .

ro.llk.Z.timeout_ms

Z batas waktu maksimum. Standarnya adalah ro.llk.timeout_ms .

ro.llk.stack.timeout_ms

Memeriksa batas waktu maksimum simbol tumpukan persisten. Standarnya adalah ro.llk.timeout_ms . Aktif hanya pada userdebug atau eng build .

ro.llk.check_ms

Contoh utas untuk D atau Z. Standarnya adalah dua menit.

ro.llk.stack

Memeriksa simbol tumpukan kernel yang jika terus ada dapat menunjukkan subsistem terkunci. Standarnya adalah cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable daftar simbol kernel yang dipisahkan koma. Pemeriksaan tidak melakukan penjadwalan maju ABA kecuali dengan polling setiap ro.llk_check_ms selama periode ro.llk.stack.timeout_ms , jadi simbol tumpukan harus sangat langka dan cepat berlalu (sangat tidak mungkin simbol muncul terus-menerus di semua sampel tumpukan). Memeriksa kecocokan untuk " symbol+0x" atau " symbol.cfi+0x" dalam ekspansi tumpukan. Hanya tersedia di userdebug atau eng build ; masalah keamanan pada build pengguna mengakibatkan hak istimewa terbatas yang mencegah pemeriksaan ini.

ro.llk.blacklist.process

llkd tidak melihat proses yang ditentukan. Standarnya adalah 0,1,2 ( kernel , init , dan [kthreadd] ) ditambah nama proses init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1] . Suatu proses dapat berupa referensi comm , cmdline , atau pid . Default otomatis dapat lebih besar dari ukuran properti maksimum saat ini sebesar 92.

ro.llk.blacklist.parent

llkd tidak melihat proses yang memiliki induk yang ditentukan. Standarnya adalah 0,2,adbd&[setsid] ( kernel , [kthreadd] , dan adbd hanya untuk zombie setsid ). Pemisah ampersand (&) menetapkan bahwa induk diabaikan hanya dalam kombinasi dengan proses anak target. Ampersand dipilih karena tidak pernah menjadi bagian dari nama proses; namun, setprop di shell memerlukan ampersand untuk diloloskan atau dikutip, meskipun file init rc di mana ini biasanya ditentukan tidak memiliki masalah ini. Proses induk atau target dapat berupa referensi comm , cmdline , atau pid .

ro.llk.blacklist.uid

llkd tidak melihat proses yang cocok dengan uid yang ditentukan. Daftar nomor atau nama uid yang dipisahkan koma. Defaultnya kosong atau salah.

ro.llk.blacklist.process.stack

llkd tidak memantau subset proses yang ditentukan untuk tanda tangan tumpukan kunci langsung. Defaultnya adalah nama proses init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd . Mencegah pelanggaran kebijakan yang terkait dengan proses yang memblokir ptrace (karena ini tidak dapat diperiksa). Aktif hanya pada userdebug dan eng build . Untuk detail tentang tipe build, lihat Membangun Android .

Masalah arsitektur

  • Properti dibatasi hingga 92 karakter (namun, ini diabaikan untuk default yang ditentukan dalam file include/llkd.h di sources).
  • Daemon [khungtask] terlalu umum dan tersandung pada kode driver yang berada dalam status D terlalu banyak. Beralih ke S akan membuat tugas dapat dimatikan (dan dapat dihidupkan kembali oleh driver jika diperlukan).

Antarmuka perpustakaan (opsional)

Anda dapat secara opsional memasukkan llkd ke daemon istimewa lainnya menggunakan antarmuka C berikut dari komponen libllkd :

#include "llkd.h"
bool llkInit(const char* threadname) /* return true if enabled */
unsigned llkCheckMillseconds(void)   /* ms to sleep for next check */

Jika nama utas diberikan, utas secara otomatis muncul, jika tidak, pemanggil harus memanggil llkCheckMilliseconds di loop utamanya. Fungsi mengembalikan periode waktu sebelum panggilan yang diharapkan berikutnya ke handler ini.