Android 10 inclut le démon Android Live-LocK ( llkd
), conçu pour détecter et atténuer les blocages du noyau. Le composant llkd
fournit une implémentation autonome par défaut, mais vous pouvez également intégrer le code llkd
dans un autre service, soit dans le cadre de la boucle principale, soit en tant que thread séparé.
Scénarios de détection
Le llkd
propose deux scénarios de détection : état D ou Z persistant et signature de pile persistante.
État D ou Z persistant
Si un thread est dans l'état D (veille ininterrompue) ou Z (zombie) sans progression pendant plus de ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms
, le llkd
tue le processus (ou le processus parent). ). Si une analyse ultérieure montre que le 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 bogue le plus détaillé pour la condition.
Le llkd
comprend un chien de garde automatique qui déclenche une alarme si llkd
se bloque ; le chien de garde est le double du temps prévu pour parcourir la boucle principale et l'échantillonnage est tous ro.llk_sample_ms
.
Signature de pile persistante
Pour les versions userdebug, llkd
peut détecter les verrous actifs du noyau en utilisant la vérification persistante de la signature de la pile. Si un thread dans n'importe quel état sauf Z a un symbole de noyau ro.llk.stack
persistant qui est signalé depuis plus longtemps que ro.llk.timeout_ms
ou ro.llk.stack.timeout_ms
, le llkd
tue le processus (même s'il y a un transfert vers l'avant). progression de la planification). Si une analyse ultérieure montre que le 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 bogue le plus détaillé pour la condition.
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 le fichier /proc/pid/stack
sous Linux. La liste des symboles se trouve dans ro.llk.stack
et est par défaut la liste séparée par des virgules de " cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
".
Les symboles doivent être suffisamment rares et de courte durée pour que sur un système typique, la fonction ne soit vue qu'une seule fois dans un échantillon pendant le délai d'expiration de ro.llk.stack.timeout_ms
(les échantillons se produisent tous ro.llk.check_ms
). En raison du manque de protection ABA, c’est le seul moyen d’éviter un faux déclenchement. Le symbole fonction doit apparaître en dessous de la fonction appelant le verrou qui pourrait rivaliser. Si le verrou se trouve en dessous ou dans la fonction symbole, le symbole apparaît dans tous les processus concernés, pas seulement celui qui a provoqué le blocage.
Couverture
L'implémentation par défaut de llkd
ne surveille pas les spawns init
, [kthreadd]
ou [kthreadd]
. Pour que llkd
couvre les threads générés par [kthreadd]
:
- Les conducteurs ne doivent pas rester dans un état D persistant,
OU
- Les pilotes doivent disposer de mécanismes pour récupérer le thread s'il est supprimé en externe. Par exemple, utilisez
wait_event_interruptible()
au lieu dewait_event()
.
Si l'une des conditions ci-dessus est remplie, la liste noire llkd
peut être ajustée pour couvrir les composants du noyau. La vérification des symboles de pile implique une liste noire de processus supplémentaire pour éviter les violations de politique de sécurité sur les services qui bloquent les opérations ptrace
.
Propriétés Android
Le llkd
répond à plusieurs propriétés Android (répertoriées ci-dessous).
- Les propriétés nommées
prop_ms
sont en millisecondes. - Les propriétés qui utilisent un séparateur virgule (,) pour les listes utilisent un séparateur de début pour conserver l'entrée par défaut, puis ajoutent ou soustraient des entrées avec les préfixes facultatifs plus (+) et moins (-), respectivement. Pour ces listes, la chaîne "false" est synonyme de liste vide, et les entrées vides ou manquantes recourent à la valeur par défaut spécifiée.
ro.config.low_ram
L'appareil est configuré avec une mémoire limitée.
ro.déboguable
L'appareil est configuré pour userdebug ou eng build.
ro.llk.sysrq_t
Si la propriété est "eng", la valeur par défaut n'est pas ro.config.low_ram
ou ro.debuggable
. Si c'est vrai, videz tous les threads ( sysrq t
).
ro.llk.activer
Autoriser l'activation du démon live-lock. La valeur par défaut est fausse.
llk.activer
Évalué pour les versions anglaises. La valeur par défaut est ro.llk.enable
.
ro.khungtask.enable
Autoriser le démon [khungtask]
à être activé. La valeur par défaut est fausse.
khungtask.activer
Évalué pour les versions anglaises. La valeur par défaut est ro.khungtask.enable
.
ro.llk.mlockall
Activer l'appel à mlockall()
. La valeur par défaut est fausse.
ro.khungtask.timeout
[khungtask]
délai maximum. La valeur par défaut est de 12 minutes.
ro.llk.timeout_ms
Délai maximum D ou Z. La valeur par défaut est de 10 minutes. Doublez cette valeur pour définir le chien de garde d'alarme pour llkd
.
ro.llk.D.timeout_ms
D délai maximum. La valeur par défaut est ro.llk.timeout_ms
.
ro.llk.Z.timeout_ms
Délai maximum Z. La valeur par défaut est ro.llk.timeout_ms
.
ro.llk.stack.timeout_ms
Vérifie la durée 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
Exemples de fils de discussion 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 qu'un sous-système est verrouillé. La valeur par défaut est cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable
liste de symboles du noyau séparés par des virgules. La vérification n'effectue pas de planification avancée ABA, sauf en interrogeant chaque ro.llk_check_ms
pendant la période ro.llk.stack.timeout_ms
, les symboles de pile doivent donc être exceptionnellement rares et éphémères (il est très peu probable qu'un symbole apparaisse de manière persistante dans tous les fichiers). échantillons de la pile). Vérifie une correspondance pour " symbol+0x"
ou " symbol.cfi+0x"
dans l'expansion de la pile. Disponible uniquement sur les builds userdebug ou eng ; les problèmes de sécurité sur les builds utilisateur entraînent des privilèges limités qui empêchent cette vérification.
ro.llk.blacklist.process
Le llkd
ne surveille pas les processus spécifiés. La valeur par défaut est 0,1,2
( kernel
, init
et [kthreadd]
) plus les noms 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 valeur par défaut automatisée peut être supérieure à la taille de propriété maximale actuelle de 92.
ro.llk.liste noire.parent
Le llkd
ne surveille pas les processus qui ont le(s) parent(s) spécifié(s). La valeur par défaut est 0,2,adbd&[setsid]
( kernel
, [kthreadd]
et adbd
uniquement pour zombie setsid
). Un séparateur esperluette (&) spécifie que le parent est ignoré uniquement en combinaison avec le processus enfant cible. L'esperluette a été sélectionnée car elle ne fait jamais partie d'un nom de processus ; cependant, un setprop
dans le shell nécessite que l'esperluette soit échappée ou citée, bien que le fichier init rc
où cela est normalement spécifié n'ait pas ce problème. Un processus parent ou cible peut être une référence comm
, cmdline
ou pid
.
ro.llk.blacklist.uid
Le llkd
ne surveille pas les processus qui correspondent au(x) uid(s) spécifié(s). Liste de numéros ou de noms d'uid séparés par des virgules. La valeur par défaut est vide ou fausse.
ro.llk.blacklist.process.stack
llkd
ne surveille pas le sous-ensemble spécifié de processus pour les signatures de pile de verrouillage en direct. La valeur par défaut est les noms de processus init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd
. Empêche la violation de la politique de sécurité associée aux processus qui bloquent ptrace
(car ceux-ci ne peuvent pas être vérifiés). Actif uniquement sur les builds userdebug et eng . Pour plus de détails sur les types de build, reportez-vous à Building Android .
Préoccupations architecturales
- Les propriétés sont limitées à 92 caractères (ceci est cependant ignoré pour les valeurs par défaut définies dans le fichier
include/llkd.h
des sources). - Le démon intégré
[khungtask]
est trop générique et se déclenche trop sur le code du pilote qui se trouve dans l'état D. Passer à S rendrait les tâches tuables (et ressuscitables par les pilotes si nécessaire).
Interface de bibliothèque (facultatif)
Vous pouvez éventuellement incorporer le llkd
dans un autre démon privilégié en utilisant l'interface C suivante 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 apparaît automatiquement, sinon l'appelant doit appeler llkCheckMilliseconds
dans sa boucle principale. La fonction renvoie la période de temps avant le prochain appel attendu à ce gestionnaire.