Android Live-Lock Daemon (llkd)

Android 10 enthält den Android Live-LocK Daemon ( llkd ), der darauf ausgelegt ist, Kernel-Deadlocks abzufangen und zu mildern. Die llkd Komponente stellt eine standardmäßige eigenständige Implementierung bereit, Sie können den llkd Code jedoch alternativ in einen anderen Dienst integrieren, entweder als Teil der Hauptschleife oder als separater Thread.

Erkennungsszenarien

Der llkd verfügt über zwei Erkennungsszenarien: Persistenter D- oder Z-Status und persistente Stack-Signatur.

Permanenter D- oder Z-Zustand

Wenn sich ein Thread im Zustand D (unterbrechungsfreier Ruhezustand) oder Z (Zombie) befindet und länger als ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms keinen Vorwärtsfortschritt aufweist, beendet der llkd den Prozess (oder den übergeordneten Prozess). ). Wenn ein nachfolgender Scan zeigt, dass derselbe Prozess weiterhin vorhanden ist, bestätigt der llkd einen Live-Lock-Zustand und versetzt den Kernel auf eine Weise in Panik, die den detailliertesten Fehlerbericht für den Zustand liefert.

Der llkd verfügt über einen Selbstüberwachungsmechanismus, der einen Alarm auslöst, wenn llkd abstürzt. Der Watchdog dauert doppelt so lange wie erwartet, um durch die Hauptschleife zu fließen, und die Abtastung erfolgt alle ro.llk_sample_ms .

Persistente Stack-Signatur

Bei Userdebug-Releases kann der llkd Kernel-Live-Sperren mithilfe einer dauerhaften Stapelsignaturprüfung erkennen. Wenn ein Thread in einem beliebigen Status außer Z ein dauerhaft aufgelistetes ro.llk.stack Kernelsymbol hat, das länger als ro.llk.timeout_ms oder ro.llk.stack.timeout_ms gemeldet wird, bricht der llkd den Prozess ab (auch wenn es eine Weiterleitung gibt). Planungsfortschritt). Wenn ein nachfolgender Scan zeigt, dass derselbe Prozess weiterhin vorhanden ist, bestätigt der llkd einen Live-Lock-Zustand und versetzt den Kernel auf eine Weise in Panik, die den detailliertesten Fehlerbericht für den Zustand liefert.

Die lldk Prüfung bleibt kontinuierlich bestehen, wenn die Live-Sperrbedingung vorliegt, und sucht unter Linux nach den zusammengesetzten Zeichenfolgen " symbol+0x" oder " symbol.cfi+0x" in der Datei /proc/pid/stack . Die Liste der Symbole befindet sich in ro.llk.stack und ist standardmäßig die durch Kommas getrennte Liste von „ cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable “.

Symbole sollten so selten und kurzlebig sein, dass die Funktion auf einem typischen System während des Timeout-Zeitraums von ro.llk.stack.timeout_ms nur einmal in einem Beispiel angezeigt wird (Beispiele treten alle ro.llk.check_ms auf). Aufgrund des fehlenden ABA-Schutzes ist dies die einzige Möglichkeit, einen Fehlauslöser zu verhindern. Die Symbolfunktion muss unter der Funktion erscheinen, die die Sperre aufruft, die konkurrieren könnte. Befindet sich die Sperre unterhalb oder in der Symbolfunktion, erscheint das Symbol in allen betroffenen Prozessen, nicht nur in dem, der die Sperre verursacht hat.

Abdeckung

Die Standardimplementierung von llkd überwacht die Spawns init , [kthreadd] oder [kthreadd] nicht. Damit der llkd [kthreadd] -generierte Threads abdeckt:

  • Treiber dürfen nicht in einem dauerhaften D-Zustand bleiben,

ODER

  • Treiber müssen über Mechanismen verfügen, um den Thread wiederherzustellen, falls er extern beendet wird. Verwenden Sie beispielsweise wait_event_interruptible() anstelle von wait_event() .

Wenn eine der oben genannten Bedingungen erfüllt ist, kann die llkd Blacklist angepasst werden, um Kernel-Komponenten abzudecken. Die Stapelsymbolprüfung umfasst eine zusätzliche Prozess-Blacklist, um Sepolicy-Verstöße bei Diensten zu verhindern, die ptrace Vorgänge blockieren.

Android-Eigenschaften

Der llkd reagiert auf mehrere Android-Eigenschaften (unten aufgeführt).

  • Eigenschaften mit dem Namen prop_ms werden in Millisekunden angegeben.
  • Eigenschaften, die für Listen das Komma-Trennzeichen (,) verwenden, verwenden ein führendes Trennzeichen, um den Standardeintrag beizubehalten, und fügen dann Einträge mit optionalen Plus- (+) bzw. Minus-Präfixen (-) hinzu oder subtrahieren sie. Für diese Listen ist die Zeichenfolge „false“ gleichbedeutend mit einer leeren Liste, und leere oder fehlende Einträge greifen auf den angegebenen Standardwert zurück.

ro.config.low_ram

Das Gerät ist mit begrenztem Speicher konfiguriert.

ro.debuggable

Das Gerät ist für Userdebug oder Eng Build konfiguriert.

ro.llk.sysrq_t

Wenn die Eigenschaft „eng“ ist, ist der Standardwert nicht ro.config.low_ram oder ro.debuggable . Wenn „true“, alle Threads sichern ( sysrq t ).

ro.llk.enable

Ermöglichen Sie die Aktivierung des Live-Lock-Daemons. Der Standardwert ist falsch.

llk.enable

Evaluiert für Motor-Builds. Der Standardwert ist ro.llk.enable .

ro.khungtask.enable

Ermöglichen Sie die Aktivierung des [khungtask] -Daemons. Der Standardwert ist falsch.

khungtask.enable

Evaluiert für Motor-Builds. Der Standardwert ist ro.khungtask.enable .

ro.llk.mlockall

Aufruf von mlockall() aktivieren. Der Standardwert ist falsch.

ro.khungtask.timeout

[khungtask] maximales Zeitlimit. Der Standardwert beträgt 12 Minuten.

ro.llk.timeout_ms

Maximale Zeitbegrenzung D oder Z. Der Standardwert beträgt 10 Minuten. Verdoppeln Sie diesen Wert, um den Alarm-Watchdog für llkd festzulegen.

ro.llk.D.timeout_ms

D maximale Zeitbegrenzung. Der Standardwert ist ro.llk.timeout_ms .

ro.llk.Z.timeout_ms

Z maximales Zeitlimit. Der Standardwert ist ro.llk.timeout_ms .

ro.llk.stack.timeout_ms

Überprüft das maximale Zeitlimit für persistente Stapelsymbole. Der Standardwert ist ro.llk.timeout_ms . Nur bei Userdebug- oder Eng-Builds aktiv .

ro.llk.check_ms

Beispiele für Threads für D oder Z. Der Standardwert beträgt zwei Minuten.

ro.llk.stack

Prüft auf Kernel-Stack-Symbole, die, wenn sie dauerhaft vorhanden sind, darauf hinweisen können, dass ein Subsystem blockiert ist. Der Standardwert ist cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable durch Kommas getrennte Liste von Kernelsymbolen. Bei der Prüfung wird kein Forward Scheduling ABA durchgeführt, es sei denn, es werden alle ro.llk_check_ms über den Zeitraum ro.llk.stack.timeout_ms abgefragt. Stapelsymbole sollten daher außergewöhnlich selten und flüchtig sein (es ist höchst unwahrscheinlich, dass ein Symbol insgesamt dauerhaft angezeigt wird). Proben des Stapels). Prüft, ob in der Stack-Erweiterung eine Übereinstimmung für " symbol+0x" oder " symbol.cfi+0x" vorliegt. Nur für Userdebug- oder Eng-Builds verfügbar ; Sicherheitsbedenken bei Benutzer-Builds führen zu eingeschränkten Berechtigungen, die diese Überprüfung verhindern.

ro.llk.blacklist.process

Der llkd überwacht die angegebenen Prozesse nicht. Der Standardwert ist 0,1,2 ( kernel , init und [kthreadd] ) plus Prozessnamen init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1] . Ein Prozess kann eine comm , cmdline oder pid Referenz sein. Ein automatisierter Standardwert kann größer als die aktuelle maximale Eigenschaftsgröße von 92 sein.

ro.llk.blacklist.parent

Der llkd überwacht keine Prozesse, die die angegebenen übergeordneten Elemente haben. Der Standardwert ist 0,2,adbd&[setsid] ( kernel , [kthreadd] und adbd nur für Zombie- setsid ). Ein kaufmännisches Und-Trennzeichen (&) gibt an, dass der übergeordnete Prozess nur in Kombination mit dem untergeordneten Zielprozess ignoriert wird. Das kaufmännische Und wurde ausgewählt, da es niemals Teil eines Prozessnamens ist. Allerdings erfordert ein setprop in der Shell, dass das kaufmännische Und-Zeichen maskiert oder in Anführungszeichen gesetzt wird, obwohl dieses Problem in der init rc Datei, in der dies normalerweise angegeben wird, nicht auftritt. Ein übergeordneter oder Zielprozess kann eine comm , cmdline oder pid Referenz sein.

ro.llk.blacklist.uid

Der llkd überwacht keine Prozesse, die mit der/den angegebenen UID(s) übereinstimmen. Durch Kommas getrennte Liste von UID-Nummern oder -Namen. Der Standardwert ist leer oder falsch.

ro.llk.blacklist.process.stack

Der llkd überwacht die angegebene Teilmenge der Prozesse nicht auf Live-Lock-Stack-Signaturen. Standard sind die Prozessnamen init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd . Verhindert die Sepolicy-Verletzung im Zusammenhang mit Prozessen, die ptrace blockieren (da diese nicht überprüft werden können). Nur bei Userdebug- und Eng-Builds aktiv . Einzelheiten zu Build-Typen finden Sie unter Erstellen von Android .

Architektonische Bedenken

  • Eigenschaften sind auf 92 Zeichen beschränkt (dies wird jedoch für Standardwerte ignoriert, die in der Datei include/llkd.h in den Quellen definiert sind).
  • Der integrierte [khungtask] -Daemon ist zu allgemein und greift zu oft auf Treibercode zurück, der im D-Zustand herumliegt. Durch den Wechsel zu S könnten Aufgaben beendet werden (und bei Bedarf von Treibern wiederbelebt werden).

Bibliotheksschnittstelle (optional)

Sie können den llkd optional in einen anderen privilegierten Daemon integrieren, indem Sie die folgende C-Schnittstelle der libllkd Komponente verwenden:

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

Wenn ein Threadname angegeben wird, wird automatisch ein Thread erzeugt, andernfalls muss der Aufrufer llkCheckMilliseconds in seiner Hauptschleife aufrufen. Die Funktion gibt den Zeitraum vor dem nächsten erwarteten Aufruf dieses Handlers zurück.