Daemon Live Lock di Android (LLKD)

Android 10 include il daemon Live Lock di Android (llkd), progettato per rilevare e mitigare i deadlock del kernel. llkd componente fornisce un'implementazione autonoma predefinita, ma puoi in alternativa integrare il codice llkd in un altro servizio, nell'ambito di il loop principale o come thread separato.

Scenari di rilevamento

In llkd sono previsti due scenari di rilevamento: stato D o Z permanente e la firma dello stack.

Stato D o Z permanente

Se un thread è in stato D (sonno senza interruzioni) o Z (zombie) senza inoltro di avanzamento per più di ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms, llkd termina il processo (o il processo padre). Se una scansione successiva mostra continua la stessa procedura, llkd conferma una condizione di Live Lock e mette in panico il kernel in modo da fornire la segnalazione di bug più dettagliata per il .

llkd include un watchdog automatico che si attiva se llkd si blocca. il watchdog è il doppio del tempo previsto per il flusso attraverso il mainloop e il campionamento è ogni ro.llk_sample_ms.

Firma stack permanente

Per le release userdebug, llkd può rilevare i live-lock del kernel utilizzando il controllo della firma dello stack. Se un thread in uno stato qualsiasi tranne Z ha un indirizzo simbolo del kernel ro.llk.stack elencato che è segnalato per più di ro.llk.timeout_ms o ro.llk.stack.timeout_ms, llkd interrompe il processo (anche in caso di avanzamento della pianificazione in avanti). Se una scansione successiva mostra continua la stessa procedura, llkd conferma una condizione di Live Lock e mette in panico il kernel in modo da fornire la segnalazione di bug più dettagliata per il .

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

I simboli dovrebbero essere rari e di breve durata che, in un sistema tipico, viene visualizzata una sola volta in un campione nel periodo di timeout di ro.llk.stack.timeout_ms (gli esempi si verificano ogni ro.llk.check_ms). Per mancanza della protezione ABA, questo è l'unico modo per evitare un falso trigger. Il simbolo deve essere visualizzata sotto la funzione che chiama il blocco che potrebbe competere. Se il lucchetto si trova sotto o nella funzione di simbolo, il simbolo appare in tutte le i processi, non solo quello che ha causato il logo completo.

Copertura

L'implementazione predefinita di llkd non monitora init, [kthreadd] o [kthreadd] germogli. Per consentire a llkd di coprire [kthreadd] thread visualizzati:

  • I driver non devono rimanere in stato D permanente

OPPURE

  • I driver devono disporre di meccanismi per recuperare il thread nel caso in cui venga interrotto all'esterno. Ad esempio, utilizza wait_event_interruptible() anziché wait_event().

Se una delle condizioni precedenti è soddisfatta, la lista bloccata llkd può essere modificata in per coprire i componenti del kernel. Il controllo dei simboli di stack comporta un processo aggiuntivo lista bloccata per evitare violazioni delle norme sui servizi che bloccano ptrace operazioni.

Proprietà Android

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

  • Le proprietà denominate prop_ms sono in millisecondi.
  • Le proprietà che utilizzano la virgola (,) come separatore per gli elenchi utilizzano un separatore iniziale per conserva la voce predefinita, quindi aggiungi o sottrai voci con il segno più facoltativo rispettivamente (+) e meno (-). Per questi elenchi, la stringa false è sinonimo di elenco vuoto, dove le voci vuote o mancanti ricorrono alla al valore predefinito specificato.

ro.config.low_ram

Il dispositivo è configurato con memoria limitata.

debuggable

Il dispositivo è configurato per il debug dell'utente o la build coinvolta.

ro.llk.sysrq_t

Se la proprietà è eng, il valore predefinito non è ro.config.low_ram o ro.debuggable. Se true, esegui il dump di tutti i thread (sysrq t).

ro.llk.enable

Consenti l'attivazione del daemon live-lock. Il valore predefinito è false.

llk.enable

Valutazione per le build di eng. Il valore predefinito è ro.llk.enable.

ro.khungtask.enable

Consenti l'abilitazione del daemon [khungtask]. Il valore predefinito è false.

khungtask.enable

Valutazione per le build di eng. Il valore predefinito è ro.khungtask.enable.

ro.llk.mlockall

Attiva la chiamata al numero mlockall(). Il valore predefinito è false.

ro.khungtask.timeout

Limite di tempo massimo: [khungtask]. Il valore predefinito è 12 minuti.

ro.llk.timeout_ms

Limite di tempo massimo D o Z. Il valore predefinito è 10 minuti. Raddoppia questo valore per impostare watchdog di sveglia per llkd.

ro.llk.D.timeout_ms

Limite di tempo massimo D. Il valore predefinito è ro.llk.timeout_ms.

ro.llk.Z.timeout_ms

Limite di tempo massimo Z. Il valore predefinito è ro.llk.timeout_ms.

ro.llk.stack.timeout_ms

Controlla il limite di tempo massimo per i simboli stack permanenti. Il valore predefinito è ro.llk.timeout_ms. Attivo solo su build di userdebug o build.

ro.llk.check_ms

Esempi di thread per D o Z. Il valore predefinito è due minuti.

ro.llk.stack

Controlla la presenza di simboli dello stack del kernel che, se presenti in modo permanente, possono indicare è bloccato. Il valore predefinito è cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable elenco separato da virgole di simboli del kernel. Nel controllo non viene eseguita la pianificazione dell'inoltro ABA (tranne con sondaggi ogni ro.llk_check_ms nel corso del periodo) ro.llk.stack.timeout_ms, quindi i simboli stack dovrebbero essere eccezionalmente rari e fugace (è molto improbabile che un simbolo compaia in modo persistente in esempi dello stack). Cerca una corrispondenza per symbol+0x o symbol.cfi+0x in espansione dello stack. Disponibile solo su userdebug o eng ; I problemi di sicurezza delle build degli utenti comportano privilegi limitati che impedire questo controllo.

ro.llk.blacklist.processo

llkd non monitora 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 automatico può essere superiore all'attuale dimensione massima della proprietà, pari a 92.

ro.llk.blacklist.parente

L'elemento llkd non controlla i processi per cui sono stati specificati gli elementi principali. Predefinita è 0,2,adbd&[setsid] (kernel, [kthreadd] e adbd solo per zombie setsid). Il separatore della e commerciale (&) specifica che il separatore principale viene ignorato solo in combinazione con il processo figlio di destinazione. E commerciale è stata selezionata perché non fa mai parte del nome di un processo; Tuttavia, un setprop nella shell richiede la e commerciale deve essere racchiusa tra caratteri di escape o tra virgolette, sebbene il file init rc in cui si trova normalmente specificato non presenta questo problema. Un processo principale o target 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 UIS. Il valore predefinito è vuoto o false.

ro.llk.blacklist.process.stack

llkd non monitora il sottoinsieme specificato di processi per lo stack di blocchi in tempo reale firme. Il valore predefinito è i nomi di processo init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd. Impedisce il sepolicy una violazione associata a procedure che bloccano ptrace (in quanto non possono essere selezionata). Attivo solo su build di userdebug ed eng. Per i dettagli sulla build consulta la sezione Creazione di Android.

Problemi di architettura

  • Le proprietà hanno un limite di 92 caratteri, che viene però ignorato per i valori predefiniti. definiti nel file include/llkd.h nelle origini).
  • Il daemon [khungtask] integrato è troppo generico e scatta sul codice conducente che rimane troppo nello stato D. Il passaggio a S renderebbe terminabili le attività (e recuperabili dai conducenti, se necessario).

Interfaccia libreria (facoltativa)

Facoltativamente, puoi incorporare llkd in un altro daemon con privilegi utilizzando 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 nome thread, viene generato automaticamente un thread, altrimenti il chiamante deve chiamare llkCheckMilliseconds nel suo loop principale. La funzione restituisce prima della successiva chiamata prevista a questo gestore.