Android 10 zawiera demona Android Live-LocK ( llkd
), którego zadaniem jest wychwytywanie i łagodzenie zakleszczeń jądra. Komponent llkd
zapewnia domyślną, samodzielną implementację, ale alternatywnie można zintegrować kod llkd
z inną usługą, jako część głównej pętli lub jako oddzielny wątek.
Scenariusze wykrywania
llkd
ma dwa scenariusze wykrywania: trwały stan D lub Z oraz trwały podpis stosu.
Trwały stan D lub Z
Jeśli wątek znajduje się w stanie D (nieprzerwanego uśpienia) lub Z (zombie) i nie ma postępu w przód przez czas dłuższy niż ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
, llkd
kończy proces (lub proces nadrzędny ). Jeśli kolejne skanowanie wykaże, że ten sam proces nadal istnieje, llkd
potwierdza stan blokady na żywo i wywołuje panikę w jądrze w sposób zapewniający najbardziej szczegółowy raport o błędzie dla tego warunku.
llkd
zawiera funkcję samoobsługową, która alarmuje, jeśli llkd
się blokuje; watchdog jest dwukrotnie dłuższy od oczekiwanego czasu przepływu przez pętlę główną, a próbkowanie odbywa się co ro.llk_sample_ms
.
Trwały podpis stosu
W przypadku wersji userdebug, llkd
może wykryć blokady jądra przy użyciu trwałego sprawdzania podpisów stosu. Jeśli wątek w dowolnym stanie z wyjątkiem Z ma na liście trwały symbol jądra ro.llk.stack
, który jest raportowany dłużej niż ro.llk.timeout_ms
lub ro.llk.stack.timeout_ms
, llkd
kończy proces (nawet jeśli istnieje postęp planowania). Jeśli kolejne skanowanie wykaże, że ten sam proces nadal istnieje, llkd
potwierdza stan blokady na żywo i wywołuje panikę w jądrze w sposób zapewniający najbardziej szczegółowy raport o błędzie dla tego warunku.
Kontrola lldk
jest kontynuowana w sposób ciągły, gdy istnieje warunek blokady na żywo i szuka utworzonych ciągów " symbol+0x"
lub " symbol.cfi+0x"
w pliku /proc/pid/stack
w systemie Linux. Lista symboli znajduje się w ro.llk.stack
i domyślnie jest to lista rozdzielona przecinkami „ cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
”.
Symbole powinny być rzadkie i na tyle krótkotrwałe, aby w typowym systemie funkcja była widoczna tylko raz w próbce przez limit czasu ro.llk.stack.timeout_ms
(próbki pojawiają się co ro.llk.check_ms
). Ze względu na brak zabezpieczenia ABA jest to jedyny sposób zapobiegania fałszywemu wyzwalaniu. Funkcja symboliczna musi pojawić się poniżej funkcji wywołującej blokadę, która może konkurować. Jeśli blokada znajduje się poniżej lub w funkcji symbolu, symbol pojawia się we wszystkich procesach, których to dotyczy, a nie tylko w tym, który spowodował zablokowanie.
Zasięg
Domyślna implementacja llkd
nie monitoruje pojawiania się init
, [kthreadd]
ani [kthreadd]
. Aby llkd
obejmował wątki utworzone przez [kthreadd]
:
- Kierowcy nie mogą pozostawać w trwałym stanie D,
LUB
- Sterowniki muszą mieć mechanizmy umożliwiające odzyskanie wątku w przypadku jego zabicia zewnętrznie. Na przykład użyj
wait_event_interruptible()
zamiastwait_event()
.
Jeśli spełniony jest jeden z powyższych warunków, czarną listę llkd
można dostosować tak, aby obejmowała komponenty jądra. Sprawdzanie symboli stosu obejmuje dodatkową czarną listę procesów, która zapobiega naruszeniom zasad separacyjnych w usługach blokujących operacje ptrace
.
Właściwości Androida
llkd
reaguje na kilka właściwości Androida (wymienionych poniżej).
- Właściwości o nazwie
prop_ms
są podawane w milisekundach. - Właściwości, które używają separatora przecinka (,) dla list, używają separatora początkowego, aby zachować wpis domyślny, a następnie dodają lub odejmuje wpisy z opcjonalnymi przedrostkami odpowiednio plus (+) i minus (-). W przypadku tych list ciąg „false” jest równoznaczny z pustą listą, a puste lub brakujące wpisy korzystają z określonej wartości domyślnej.
ro.config.low_ram
Urządzenie zostało skonfigurowane z ograniczoną pamięcią.
ro.debugowalne
Urządzenie jest skonfigurowane do debugowania użytkownika lub kompilacji eng.
ro.llk.sysrq_t
Jeśli właściwość to „eng”, wartością domyślną nie jest ro.config.low_ram
ani ro.debuggable
. Jeśli to prawda, zrzuć wszystkie wątki ( sysrq t
).
ro.llk.enable
Zezwól na włączenie demona blokady na żywo. Wartość domyślna to fałsz.
llk.włącz
Oceniony pod kątem kompilacji eng. Wartość domyślna to ro.llk.enable
.
ro.khungtask.enable
Zezwól na włączenie demona [khungtask]
. Wartość domyślna to fałsz.
khungtask.włącz
Oceniony pod kątem kompilacji eng. Wartość domyślna to ro.khungtask.enable
.
ro.llk.mlockall
Włącz wywołanie mlockall()
. Wartość domyślna to fałsz.
ro.khungtask.timeout
[khungtask]
maksymalny limit czasu. Wartość domyślna to 12 minut.
ro.llk.timeout_ms
Maksymalny limit czasu D lub Z. Wartość domyślna to 10 minut. Podwój tę wartość, aby ustawić watchdog alarmu dla llkd
.
ro.llk.D.timeout_ms
D maksymalny limit czasu. Wartość domyślna to ro.llk.timeout_ms
.
ro.llk.Z.timeout_ms
Z maksymalny limit czasu. Wartość domyślna to ro.llk.timeout_ms
.
ro.llk.stack.timeout_ms
Sprawdza maksymalny limit czasu symboli stosu trwałego. Wartość domyślna to ro.llk.timeout_ms
. Aktywne tylko w przypadku debugowania użytkownika lub kompilacji eng .
ro.llk.check_ms
Przykłady wątków dla D lub Z. Wartość domyślna to dwie minuty.
ro.llk.stack
Sprawdza symbole stosu jądra, które, jeśli są stale obecne, mogą wskazywać, że podsystem jest zablokowany. Wartość domyślna to cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
lista symboli jądra rozdzielonych przecinkami. Kontrola nie wykonuje planowania ABA w przód, z wyjątkiem odpytywania co ro.llk_check_ms
w okresie ro.llk.stack.timeout_ms
, więc symbole stosu powinny być wyjątkowo rzadkie i ulotne (jest bardzo mało prawdopodobne, aby symbol pojawiał się stale we wszystkich próbki stosu). Sprawdza dopasowanie dla " symbol+0x"
lub " symbol.cfi+0x"
podczas rozszerzania stosu. Dostępne tylko w kompilacjach userdebug lub eng ; obawy dotyczące bezpieczeństwa kompilacji użytkowników powodują ograniczone uprawnienia, które uniemożliwiają tę kontrolę.
ro.llk.blacklist.process
llkd
nie obserwuje określonych procesów. Wartość domyślna to 0,1,2
( kernel
, init
i [kthreadd]
) plus nazwy procesów init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1]
. Proces może być odwołaniem comm
, cmdline
lub pid
. Automatyczna wartość domyślna może być większa niż bieżący maksymalny rozmiar właściwości wynoszący 92.
ro.llk.blacklist.parent
llkd
nie obserwuje procesów, które mają określonych rodziców. Wartość domyślna to 0,2,adbd&[setsid]
( kernel
, [kthreadd]
i adbd
tylko w przypadku setsid
zombie). Separator ampersand (&) określa, że element nadrzędny jest ignorowany tylko w połączeniu z docelowym procesem potomnym. Wybrano znak ampersand, ponieważ nigdy nie jest on częścią nazwy procesu; jednakże setprop
w powłoce wymaga znaku ampersandu umieszczonego w cudzysłowie lub znaku ucieczki, chociaż w pliku init rc
, w którym jest to zwykle określone, ten problem nie występuje. Procesem nadrzędnym lub docelowym może być odwołanie do comm
, cmdline
lub pid
.
ro.llk.blacklist.uid
llkd
nie obserwuje procesów pasujących do określonych identyfikatorów UID. Rozdzielana przecinkami lista numerów UID lub nazw. Wartość domyślna jest pusta lub fałszywa.
ro.llk.blacklist.process.stack
llkd
nie monitoruje określonego podzbioru procesów pod kątem podpisów stosu blokad na żywo. Domyślnie są to nazwy procesów init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
. Zapobiega naruszeniom sepolicy związanym z procesami blokującymi ptrace
(ponieważ nie można ich sprawdzić). Aktywne tylko w przypadku debugowania użytkownika i kompilacji eng . Aby uzyskać szczegółowe informacje na temat typów kompilacji, zobacz Tworzenie systemu Android .
Obawy architektoniczne
- Właściwości są ograniczone do 92 znaków (jednak jest to ignorowane w przypadku wartości domyślnych zdefiniowanych w pliku
include/llkd.h
w źródłach). - Wbudowany demon
[khungtask]
jest zbyt ogólny i powoduje zbyt częste uruchamianie kodu sterownika, który znajduje się w stanie D. Przełączenie na S spowodowałoby, że zadania można byłoby zabić (i w razie potrzeby wskrzesić je kierowcy).
Interfejs biblioteki (opcjonalnie)
Opcjonalnie możesz włączyć llkd
do innego uprzywilejowanego demona, korzystając z następującego interfejsu C z komponentu libllkd
:
#include "llkd.h"
bool llkInit(const char* threadname) /* return true if enabled */
unsigned llkCheckMillseconds(void) /* ms to sleep for next check */
Jeśli zostanie podana nazwa wątku, wątek pojawi się automatycznie, w przeciwnym razie osoba wywołująca będzie musiała wywołać llkCheckMilliseconds
w swojej głównej pętli. Funkcja zwraca okres czasu przed następnym oczekiwanym wywołaniem tej procedury obsługi.