Demon blokady na żywo w systemie Android (llkd)

Zadbaj o dobrą organizację dzięki kolekcji Zapisuj i kategoryzuj treści zgodnie ze swoimi preferencjami.

Android 10 zawiera demona Android Live-Lock ( llkd ), który ma na celu wyłapywanie i łagodzenie zakleszczeń jądra. Komponent llkd zapewnia domyślną samodzielną implementację, ale możesz alternatywnie 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 (bezprzerwowego uśpienia) lub Z (zombie) bez postępu w przód przez czas dłuższy niż ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms , llkd zabija proces (lub proces nadrzędny ). Jeśli kolejne skanowanie wykaże, że ten sam proces nadal istnieje, llkd potwierdza stan blokady na żywo i panikuje jądro w sposób, który zapewnia najbardziej szczegółowy raport o błędzie dla tego stanu.

llkd zawiera własny watchdog, który alarmuje, jeśli llkd się zablokuje; watchdog jest dwukrotnie dłuższy niż oczekiwany czas przepływu przez pętlę główną, a próbkowanie odbywa się co ro.llk_sample_ms .

Trwała sygnatura stosu

W wydaniach userdebug, llkd może wykrywać blokady na żywo jądra za pomocą trwałego sprawdzania sygnatur stosu. Jeśli wątek w dowolnym stanie z wyjątkiem Z ma trwały wymieniony symbol jądra ro.llk.stack , który jest zgłaszany przez czas dłuższy niż ro.llk.timeout_ms lub ro.llk.stack.timeout_ms , llkd zabija 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 panikuje jądro w sposób, który zapewnia najbardziej szczegółowy raport o błędzie dla tego stanu.

Sprawdzanie lldk trwa nieprzerwanie, gdy istnieje warunek blokady na żywo i szuka złożonych ciągów " symbol+0x" lub " symbol.cfi+0x" w /proc/pid/stack w systemie Linux. Lista symboli znajduje się w ro.llk.stack i domyślnie jest to rozdzielana przecinkami lista „ 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 w okresie czasu ro.llk.stack.timeout_ms (próbki występują co ro.llk.check_ms ). Ze względu na brak ochrony ABA jest to jedyny sposób, aby zapobiec fałszywemu wyzwalaniu. Funkcja symbolu musi pojawić się poniżej funkcji wywołującej blokadę, która mogłaby rywalizować. Jeśli blokada jest poniżej lub w funkcji symbolu, symbol pojawia się we wszystkich procesach, których to dotyczy, a nie tylko w tym, który spowodował blokadę.

Zasięg

Domyślna implementacja llkd nie monitoruje spawnów init , [kthreadd] ani [kthreadd] . Aby llkd [kthreadd] -powstałe wątki:

  • Kierowcy nie mogą pozostawać w stałym stanie D,

LUB

  • Sterowniki muszą mieć mechanizmy do odzyskania wątku, jeśli zostanie on zabity zewnętrznie. Na przykład użyj wait_event_interruptible() zamiast wait_event() .

Jeśli spełniony jest jeden z powyższych warunków, czarną listę llkd można dostosować, aby obejmowała składniki jądra. Sprawdzanie symboli stosu obejmuje dodatkową czarną listę procesów, aby zapobiec naruszeniom sepolityki w usługach, które blokują operacje ptrace .

Właściwości Androida

llkd odpowiada na kilka właściwości systemu Android (wymienionych poniżej).

  • Właściwości o nazwie prop_ms są podawane w milisekundach.
  • Właściwości, które używają separatora przecinkowego (,) dla list, używają wiodącego separatora, aby zachować domyślny wpis, a następnie dodają lub odejmują wpisy z opcjonalnymi odpowiednio przedrostkami plus (+) i minus (-). W przypadku tych list ciąg „false” jest równoznaczny z pustą listą, a puste lub brakujące wpisy odnoszą się do określonej wartości domyślnej.

ro.config.low_ram

Urządzenie jest skonfigurowane z ograniczoną pamięcią.

ro.debuggable

Urządzenie jest skonfigurowane do kompilacji userdebug lub 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 prawda, zrzuć wszystkie wątki ( sysrq t ).

ro.llk.włącz

Zezwól na włączenie demona blokady na żywo. Wartość domyślna to fałsz.

llk.włącz

Oceniane pod kątem kompilacji inżynierskich. Domyślnie jest to ro.llk.enable .

ro.khungtask.enable

Zezwól na włączenie demona [khungtask] . Wartość domyślna to fałsz.

chungtask.włącz

Oceniane pod kątem kompilacji inżynierskich. 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

D lub Z maksymalny limit czasu. Wartość domyślna to 10 minut. Podwój tę wartość, aby ustawić alarm alarmowy 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 czas trwania symboli stosu. Wartość domyślna to ro.llk.timeout_ms . Aktywne tylko w przypadku kompilacji userdebug lub eng .

ro.llk.check_ms

Próbki wątków dla D lub Z. Domyślnie dwie minuty.

ro.llk.stack

Sprawdza symbole stosu jądra, które jeśli są stale obecne, mogą wskazywać, że podsystem jest zablokowany. Domyślnie cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable lista oddzielonych przecinkami symboli jądra. Sprawdzenie nie wykonuje harmonogramu ABA w przód, z wyjątkiem odpytywania każdego ro.llk_check_ms w okresie ro.llk.stack.timeout_ms , więc symbole stosu powinny być wyjątkowo rzadkie i ulotne (jest wysoce nieprawdopodobne, aby symbol był stale wyświetlany we wszystkich próbki stosu). Sprawdza dopasowanie " symbol+0x" lub " symbol.cfi+0x" w rozwinięciu stosu. Dostępne tylko w kompilacjach userdebug lub eng ; obawy dotyczące bezpieczeństwa w kompilacjach użytkownika skutkują ograniczonymi uprawnieniami, które uniemożliwiają to sprawdzenie.

ro.llk.proces.czarnej listy

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ć referencją comm , cmdline lub pid . Zautomatyzowana wartość domyślna może być większa niż bieżący maksymalny rozmiar właściwości wynoszący 92.

ro.llk.czarna lista.rodzic

llkd nie obserwuje procesów, które mają określonego rodzica(ów). Wartość domyślna to 0,2,adbd&[setsid] ( kernel , [kthreadd] i adbd tylko dla setsid zombie ). Separator ampersand (&) określa, że ​​rodzic jest ignorowany tylko w połączeniu z docelowym procesem potomnym. Ampersand został wybrany, ponieważ nigdy nie jest częścią nazwy procesu; jednakże setprop w powłoce wymaga znaku &, aby był chroniony lub cytowany, chociaż plik init rc , w którym jest to zwykle określone, nie ma tego problemu. Proces nadrzędny lub docelowy może być referencją comm , cmdline lub pid .

ro.llk.czarna lista.uid

llkd nie obserwuje procesów, które pasują do podanego(ych) identyfikatora(ów). Lista numerów UID lub nazw rozdzielonych przecinkami. Wartość domyślna to pusta lub fałsz.

ro.llk.czarna lista.stos.procesów

llkd nie monitoruje określonego podzbioru procesów pod kątem sygnatur stosu blokad na żywo. Domyślnie są to nazwy procesów init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd . Zapobiega naruszeniom sepolityki związanym z procesami blokującymi ptrace (ponieważ nie można ich sprawdzić). Aktywny tylko w przypadku kompilacji userdebug i eng . Aby uzyskać szczegółowe informacje na temat typów kompilacji, zobacz Budowanie 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 zbyt często uruchamia kod sterownika, który znajduje się w stanie D. Przełączenie na S sprawiłoby, że zadanie (zadania) byłoby możliwe do zabicia (i w razie potrzeby wskrzeszone przez kierowców).

Interfejs biblioteki (opcjonalnie)

Możesz opcjonalnie włączyć llkd do innego uprzywilejowanego demona, używając 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 podano nazwę wątku, wątek automatycznie się odradza, w przeciwnym razie wywołujący musi wywołać llkCheckMilliseconds w swojej pętli głównej. Funkcja zwraca okres czasu przed następnym oczekiwanym wywołaniem tego modułu obsługi.