Daemon de verrouillage en direct Android (llkd)

Android 10 inclut le daemon de verrouillage en direct Android (llkd), conçu pour détecter et atténuer les interblocages du noyau. llkd fournit une implémentation autonome par défaut, mais vous pouvez Vous pouvez aussi intégrer le code llkd dans un autre service, soit dans le cadre de dans la boucle principale ou en tant que thread distinct.

Scénarios de détection

Le llkd comporte deux scénarios de détection: l'état persistant D ou Z, et l'état persistant la signature de la pile.

État D ou Z persistant

Si un fil de discussion est en état D (veille ininterrompue) ou Z (zombie) sans avancer progression pendant plus de ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms, la llkd tue le processus (ou le processus parent). Si une analyse ultérieure affiche même processus continue d'exister, le llkd confirme une condition de verrouillage en direct et panique le noyau de manière à fournir le rapport de bug le plus détaillé .

Le llkd inclut un watchdog automatique qui déclenche une alarme si llkd se verrouille. le chien de garde est est deux fois plus longue que le temps prévu pour passer dans la boucle principale. L'échantillonnage ro.llk_sample_ms

Signature de pile persistante

Pour les versions userdebug, le llkd peut détecter les verrouillages en direct du noyau à l'aide de l'objet persistant la vérification de la signature de la pile. Si un thread dans un état autre que Z a une couche persistante listé le symbole de noyau ro.llk.stack signalé depuis plus longtemps que ro.llk.timeout_ms ou ro.llk.stack.timeout_ms, llkd tue le processus. (même en cas de progression de la planification). Si une analyse ultérieure affiche même processus continue d'exister, le llkd confirme une condition de verrouillage en direct et panique le noyau de manière à fournir le rapport de bug le plus détaillé .

La vérification lldk persiste en continu lorsque la condition de verrouillage en direct existe et recherche les chaînes composées symbol+0x ou symbol.cfi+0x dans /proc/pid/stack sous Linux. La liste des symboles se trouve dans ro.llk.stack et par défaut est la liste de valeurs séparées par des virgules cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable

Les symboles doivent être rares et avoir une durée de vie suffisamment courte pour que, sur un système classique, n'est visible qu'une seule fois dans un échantillon au cours du délai d'expiration de ro.llk.stack.timeout_ms (les échantillons sont tous les ro.llk.check_ms). En raison d'un manque de la protection ABA, c'est le seul moyen d'éviter un faux déclencheur. Le symbole doit apparaître sous la fonction appelant le verrou qui pourrait entrer en conflit. Si le cadenas se trouve en dessous ou dans la fonction de symbole, le symbole apparaît dans tous les processus, pas seulement celui qui a provoqué le logo complet.

Couverture

L'implémentation par défaut de llkd ne surveille pas init, [kthreadd] ni [kthreadd] est généré. Pour que llkd couvre les threads générés par [kthreadd]:

  • Les pilotes ne doivent pas rester à l'état "D" persistant,

OU

  • Les pilotes doivent disposer de mécanismes pour récupérer le thread en cas de fermeture en externe. Par exemple, utilisez wait_event_interruptible() au lieu de wait_event()

Si l'une des conditions ci-dessus est remplie, la liste de blocage llkd peut être ajustée pour les composants du noyau. La vérification des symboles de pile implique un processus supplémentaire liste de blocage pour éviter le non-respect des règles sur les services qui bloquent ptrace opérations.

Propriétés Android

llkd répond à plusieurs propriétés Android (répertoriées ci-dessous).

  • Les propriétés nommées prop_ms sont exprimées en millisecondes.
  • Les propriétés qui utilisent une virgule (,) pour les listes doivent être précédées d'un séparateur pour : conserver l'entrée par défaut, puis ajouter ou soustraire des entrées avec le signe plus (facultatif) (+) et moins (-), respectivement. Pour ces listes, la chaîne false est synonyme de liste vide, et les entrées vides ou manquantes ont recours au la valeur par défaut spécifiée.

ro.config.low_ram

L'appareil est configuré avec une mémoire limitée.

ro.debuggable

L'appareil est configuré pour le débogage utilisateur ou le build eng.

ro.llk.sysrq_t

Si la propriété est eng, la valeur par défaut n'est pas ro.config.low_ram ni ro.debuggable. Si la valeur est true, videz tous les threads (sysrq t).

ro.llk.enable

Autoriser l'activation du daemon de verrouillage en direct. La valeur par défaut est false.

llk.enable

Évalué pour les builds d'ingénieur. La valeur par défaut est ro.llk.enable.

ro.kskutask.enable

Autorisez l'activation du daemon [khungtask]. La valeur par défaut est false.

kskutask.enable

Évalué pour les builds d'ingénieur. La valeur par défaut est ro.khungtask.enable.

ro.k.mlockall

Activer l'appel à mlockall(). La valeur par défaut est false.

ro.kskutask.timeout

Durée maximale : [khungtask]. La valeur par défaut est de 12 minutes.

ro.llk.timeout_ms

Limite de temps maximale D ou Z. La valeur par défaut est de 10 minutes. Doublez cette valeur pour définir watchdog de l'alarme pour llkd.

ro.llk.D.timeout_ms

D : durée maximale. La valeur par défaut est ro.llk.timeout_ms.

ro.llk.Z.timeout_ms

Limite de temps maximale Z. La valeur par défaut est ro.llk.timeout_ms.

ro.llk.stack.timeout_ms

Vérifie la limite de temps maximale des symboles de pile persistants. La valeur par défaut est ro.llk.timeout_ms Actif uniquement sur les builds userdebug ou eng.

ro.llk.check_ms

Échantillons de threads pour D ou Z. La valeur par défaut est de deux minutes.

ro.llk.stack

Vérifie les symboles de pile du noyau qui, s'ils sont présents de manière persistante, peuvent indiquer un le sous-système est verrouillé. La valeur par défaut est cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable de symboles de noyau séparés par une virgule. La vérification n'effectue pas de planification ultérieure ABA, sauf en interrogeant tous les ro.llk_check_ms de la période ro.llk.stack.timeout_ms. Les symboles de pile doivent donc être exceptionnellement rares et brèves (il est très peu probable qu'un symbole apparaisse de façon persistante échantillons de la pile). Recherche une correspondance pour symbol+0x ou symbol.cfi+0x dans le développement de la pile. Disponible uniquement sur userdebug ou eng builds; les problèmes de sécurité sur les builds d'utilisateur entraînent des privilèges limités empêcher cette vérification.

ro.llk.black.process

llkd ne surveille pas les processus spécifiés. La valeur par défaut est 0,1,2 (kernel, init et [kthreadd]) ainsi que les noms des processus init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1] Un processus peut être une référence comm, cmdline ou pid. Une option automatisée par défaut peut être supérieure à la taille de propriété maximale actuelle (92).

ro.llk.noir.parent

llkd ne surveille pas les processus dont les parents sont spécifiés. Par défaut correspond à 0,2,adbd&[setsid] (kernel, [kthreadd] et adbd uniquement pour les attaques setsid). L'esperluette (&) indique que le parent est uniquement ignoré en combinaison avec le processus enfant cible. Esperluette a été sélectionnée, car elle ne fait jamais partie d'un nom de processus ; Toutefois, un setprop dans le shell nécessite esperluette doit être échappée ou citée entre guillemets, bien que le fichier init rc, où il s'agit spécifié ne présente pas ce problème. Un processus parent ou cible peut être Référence comm, cmdline ou pid.

ro.llk.noir.uid

llkd ne surveille pas les processus correspondant aux UID spécifiés. Liste de numéros ou de noms UIS séparés par une virgule. La valeur par défaut est vide ou false.

ro.llk.black.process.stack

llkd ne surveille pas la pile de verrouillage en direct pour le sous-ensemble de processus spécifié signatures. La valeur par défaut est le nom des processus init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd Empêche la règle sepolicy de violation associée aux processus qui bloquent ptrace (car ils ne peuvent pas être cochée). Actif uniquement sur les builds userdebug et eng. Pour en savoir plus sur la compilation consultez l'article Compiler Android.

Problèmes architecturaux

  • Les propriétés sont limitées à 92 caractères (ce paramètre est ignoré pour les valeurs par défaut) défini dans le fichier include/llkd.h des sources).
  • Le daemon [khungtask] intégré est trop générique et génère des trajets avec du code reste trop souvent à l'état D. Passer à S rendrait les tâches impossibles (et resurresible par les conducteurs si nécessaire).

Interface de la bibliothèque (facultatif)

Vous pouvez éventuellement intégrer llkd dans un autre daemon privilégié à l'aide de l'interface C suivante à partir du composant libllkd:

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

Si un nom de thread est fourni, un thread est automatiquement généré, sinon l'appelant doit appeler llkCheckMilliseconds dans sa boucle principale. La fonction renvoie avant le prochain appel attendu de ce gestionnaire.