Demone Android Live-Lock (llkd)

Android 10 include Android Live-LocK Daemon ( llkd ), progettato per rilevare e mitigare i deadlock del kernel. Il componente llkd fornisce un'implementazione standalone predefinita, ma in alternativa è possibile integrare il codice llkd in un altro servizio, come parte del ciclo principale o come thread separato.

Scenari di rilevamento

llkd ha due scenari di rilevamento: stato D o Z persistente e firma dello stack persistente.

Stato D o Z persistente

Se un thread è in stato D (sospensione continua) o Z (zombie) senza avanzamento in avanti per più di ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms , llkd il processo (o il processo padre ). Se una scansione successiva mostra che lo stesso processo continua ad esistere, llkd conferma una condizione di blocco attivo e manda in panico il kernel in un modo che fornisce la segnalazione di bug più dettagliata per la condizione.

llkd include un self watchdog che si attiva se llkd blocca; watchdog è il doppio del tempo previsto per scorrere il mainloop e il campionamento è ogni ro.llk_sample_ms .

Firma dello stack persistente

Per le versioni di userdebug, llkd può rilevare i live-lock del kernel usando il controllo persistente della firma dello stack. Se un thread in qualsiasi stato tranne Z ha un simbolo del kernel ro.llk.stack elencato persistente che viene riportato per un periodo più lungo di ro.llk.timeout_ms o ro.llk.stack.timeout_ms , llkd il processo (anche se è presente avanzamento della programmazione). Se una scansione successiva mostra che lo stesso processo continua ad esistere, llkd conferma una condizione di blocco attivo e manda in panico il kernel in un modo che fornisce la segnalazione di bug più dettagliata per la condizione.

Il controllo lldk persiste continuamente quando esiste la condizione di blocco in tempo reale e cerca le stringhe composte " symbol+0x" o " symbol.cfi+0x" nel file /proc/pid/stack su Linux. L'elenco dei simboli è in ro.llk.stack e per impostazione predefinita è l'elenco separato da virgole di " cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable ".

I simboli dovrebbero essere abbastanza rari e di breve durata che su un sistema tipico la funzione viene vista solo una volta in un campione durante il periodo di timeout di ro.llk.stack.timeout_ms (i campioni si verificano ogni ro.llk.check_ms ). A causa della mancanza di protezione ABA, questo è l'unico modo per prevenire un falso trigger. Sotto la funzione che richiama il lucchetto che potrebbe contendere deve comparire il simbolo della funzione. Se il blocco è al di sotto o nella funzione simbolo, il simbolo compare in tutti i processi interessati, non solo in quello che ha causato il blocco.

Copertura

L'implementazione predefinita di llkd non monitora gli spawn di init , [kthreadd] o [kthreadd] . Affinché llkd copra i thread generati da [kthreadd] :

  • I conducenti non devono rimanere in uno stato D persistente,

O

  • I driver devono disporre di meccanismi per ripristinare il thread in caso di arresto esterno. Ad esempio, usa wait_event_interruptible() invece di wait_event() .

Se una delle condizioni di cui sopra è soddisfatta, la blacklist llkd può essere modificata per coprire i componenti del kernel. Il controllo del simbolo dello stack comporta un'ulteriore lista nera di processo per prevenire violazioni della sepolicy sui servizi che bloccano le operazioni di ptrace .

Proprietà Android

llkd risponde a diverse proprietà Android (elencate di seguito).

  • Le proprietà denominate prop_ms sono in millisecondi.
  • Le proprietà che utilizzano il separatore virgola (,) per gli elenchi utilizzano un separatore iniziale per mantenere la voce predefinita, quindi aggiungono o sottraggono voci con prefissi più (+) e meno (-) facoltativi rispettivamente. Per questi elenchi, la stringa "false" è sinonimo di un elenco vuoto e le voci vuote o mancanti ricorrono al valore predefinito specificato.

ro.config.low_ram

Il dispositivo è configurato con memoria limitata.

ro.debugging

Il dispositivo è configurato per userdebug o eng build.

ro.llk.sysrq_t

Se la proprietà è "eng", l'impostazione predefinita non è ro.config.low_ram o ro.debuggable . Se true, scarica tutti i thread ( sysrq t ).

ro.llk.enable

Consenti l'abilitazione del demone live-lock. L'impostazione predefinita è falsa.

llk.enable

Valutato per build inglesi. L'impostazione predefinita è ro.llk.enable .

ro.khungtask.enable

Consenti l'abilitazione del demone [khungtask] . L'impostazione predefinita è falsa.

khungtask.enable

Valutato per build inglesi. L'impostazione predefinita è ro.khungtask.enable .

ro.llk.mlockall

Abilita la chiamata a mlockall() . L'impostazione predefinita è falsa.

ro.khungtask.timeout

[khungtask] limite di tempo massimo. L'impostazione predefinita è 12 minuti.

ro.llk.timeout_ms

Tempo massimo D o Z. L'impostazione predefinita è 10 minuti. Raddoppia questo valore per impostare il watchdog di allarme per llkd .

ro.llk.D.timeout_ms

D limite di tempo massimo. L'impostazione predefinita è ro.llk.timeout_ms .

ro.llk.Z.timeout_ms

Z limite di tempo massimo. L'impostazione predefinita è ro.llk.timeout_ms .

ro.llk.stack.timeout_ms

Verifica il limite di tempo massimo per i simboli stack persistenti. L'impostazione predefinita è ro.llk.timeout_ms . Attivo solo su userdebug o build eng .

ro.llk.check_ms

Campioni di thread per D o Z. L'impostazione predefinita è due minuti.

ro.llk.stack

Verifica la presenza di simboli dello stack del kernel che, se presenti in modo persistente, possono indicare che un sottosistema è bloccato. L'impostazione predefinita è cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable elenco di simboli del kernel separati da virgole. Il controllo non esegue l'ABA di pianificazione in avanti se non effettuando il polling di ogni ro.llk_check_ms nel periodo ro.llk.stack.timeout_ms , quindi i simboli dello stack dovrebbero essere eccezionalmente rari e fugaci (è altamente improbabile che un simbolo venga visualizzato in modo persistente in tutti campioni della pila). Verifica la corrispondenza per " symbol+0x" o " symbol.cfi+0x" nell'espansione dello stack. Disponibile solo su userdebug o build eng ; i problemi di sicurezza sulle build degli utenti si traducono in privilegi limitati che impediscono questo controllo.

ro.llk.blacklist.process

llkd non controlla i processi specificati. Il valore predefinito è 0,1,2 ( kernel , init e [kthreadd] ) più i nomi dei processi init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1] . Un processo può essere un riferimento comm , cmdline o pid . Un valore predefinito automatizzato può essere maggiore dell'attuale dimensione massima della proprietà di 92.

ro.llk.blacklist.parent

llkd non controlla i processi che hanno i genitori specificati. Il valore predefinito è 0,2,adbd&[setsid] ( kernel , [kthreadd] e adbd only for zombie setsid ). Un separatore e commerciale (&) specifica che il genitore viene ignorato solo in combinazione con il processo figlio di destinazione. La e commerciale è stata selezionata perché non fa mai parte del nome di un processo; tuttavia, un setprop nella shell richiede che la e commerciale venga posta in escape o tra virgolette, sebbene il file init rc in cui questo è normalmente specificato non presenti questo problema. Un processo padre o di destinazione può essere un riferimento comm , cmdline o pid .

ro.llk.blacklist.uid

llkd non controlla i processi che corrispondono agli uid specificati. Elenco separato da virgole di numeri o nomi uid. L'impostazione predefinita è vuota o falsa.

ro.llk.blacklist.stack.di.processi

llkd non monitora il sottoinsieme di processi specificato per le firme dello stack di blocco attivo. L'impostazione predefinita è nomi processo init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd . Impedisce la violazione della sepolicy associata ai processi che bloccano ptrace (poiché non possono essere verificati). Attivo solo su userdebug e build eng . Per i dettagli sui tipi di build, fare riferimento a Creazione di Android .

Preoccupazioni architettoniche

  • Le proprietà sono limitate a 92 caratteri (tuttavia, questo viene ignorato per i valori predefiniti definiti nel file include/llkd.h nei sorgenti).
  • Il demone [khungtask] è troppo generico e scatta troppo sul codice del driver che si trova nello stato D. Il passaggio a S renderebbe le attività uccidibili (e ripristinabili dai conducenti se necessario).

Interfaccia della libreria (opzionale)

Puoi opzionalmente incorporare llkd in un altro demone privilegiato usando la seguente interfaccia C dal componente libllkd :

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

Se viene fornito un threadname, un thread viene generato automaticamente, altrimenti il ​​chiamante deve chiamare llkCheckMilliseconds nel suo ciclo principale. La funzione restituisce il periodo di tempo prima della successiva chiamata prevista a questo gestore.