Demonio Live-LocK de Android (llkd)

Android 10 incluye Android Live-LocK Daemon ( llkd ), que está diseñado para detectar y mitigar los bloqueos del kernel. El componente llkd proporciona una implementación independiente predeterminada, pero alternativamente puedes integrar el código llkd en otro servicio, ya sea como parte del bucle principal o como un hilo separado.

Escenarios de detección

El llkd tiene dos escenarios de detección: estado D o Z persistente y firma de pila persistente.

Estado D o Z persistente

Si un subproceso está en estado D (suspensión ininterrumpida) o Z (zombi) sin progreso hacia adelante durante más de ro.llk.timeout_ms or ro.llk.[D|Z].timeout_ms , el llkd mata el proceso (o el proceso principal). ). Si un escaneo posterior muestra que el mismo proceso continúa existiendo, el llkd confirma una condición de bloqueo activo y hace entrar en pánico al kernel de una manera que proporciona el informe de error más detallado para la condición.

El llkd incluye un dispositivo de vigilancia automático que emite una alarma si llkd se bloquea; El perro guardián es el doble del tiempo esperado para fluir a través del bucle principal y el muestreo es cada ro.llk_sample_ms .

Firma de pila persistente

Para las versiones de depuración de usuario, llkd puede detectar bloqueos activos del kernel mediante la verificación persistente de firmas de pila. Si un subproceso en cualquier estado excepto Z tiene un símbolo del kernel ro.llk.stack persistente en la lista que se informa por más tiempo que ro.llk.timeout_ms o ro.llk.stack.timeout_ms , el llkd finaliza el proceso (incluso si hay reenvío). avance de la programación). Si un escaneo posterior muestra que el mismo proceso continúa existiendo, el llkd confirma una condición de bloqueo activo y hace entrar en pánico al kernel de una manera que proporciona el informe de error más detallado para la condición.

La verificación lldk persiste continuamente cuando existe la condición de bloqueo activo y busca las cadenas compuestas " symbol+0x" o " symbol.cfi+0x" en el archivo /proc/pid/stack en Linux. La lista de símbolos está en ro.llk.stack y de forma predeterminada es la lista separada por comas de " cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable ".

Los símbolos deben ser lo suficientemente raros y de corta duración como para que en un sistema típico la función se vea solo una vez en una muestra durante el período de tiempo de espera de ro.llk.stack.timeout_ms (las muestras ocurren cada ro.llk.check_ms ). Debido a la falta de protección ABA, esta es la única forma de evitar un disparo falso. La función de símbolo debe aparecer debajo de la función que llama al bloqueo que podría competir. Si el bloqueo está debajo o en la función de símbolo, el símbolo aparece en todos los procesos afectados, no solo en el que causó el bloqueo.

Cobertura

La implementación predeterminada de llkd no monitorea las apariciones init , [kthreadd] o [kthreadd] . Para que el llkd cubra los hilos generados por [kthreadd] :

  • Los conductores no deben permanecer en un estado D persistente,

O

  • Los controladores deben tener mecanismos para recuperar el hilo en caso de que se cierre externamente. Por ejemplo, utilice wait_event_interruptible() en lugar de wait_event() .

Si se cumple una de las condiciones anteriores, la lista negra llkd se puede ajustar para cubrir los componentes del kernel. La verificación de símbolos de pila implica una lista negra de procesos adicional para evitar violaciones de la política de seguridad en los servicios que bloquean las operaciones ptrace .

Propiedades de Android

El llkd responde a varias propiedades de Android (enumeradas a continuación).

  • Las propiedades denominadas prop_ms están en milisegundos.
  • Las propiedades que utilizan el separador de coma (,) para las listas utilizan un separador inicial para conservar la entrada predeterminada y luego suman o restan entradas con prefijos opcionales más (+) y menos (-) respectivamente. Para estas listas, la cadena "falso" es sinónimo de una lista vacía, y las entradas en blanco o faltantes recurren al valor predeterminado especificado.

ro.config.low_ram

El dispositivo está configurado con memoria limitada.

ro.depurable

El dispositivo está configurado para depuración de usuario o compilación de ingeniería.

ro.llk.sysrq_t

Si la propiedad es "eng", el valor predeterminado no es ro.config.low_ram o ro.debuggable . Si es verdadero, descarte todos los subprocesos ( sysrq t ).

habilitar.rollk

Permitir que se habilite el demonio de bloqueo en vivo. El valor predeterminado es falso.

llk.enable

Evaluado para construcciones inglesas. El valor predeterminado es ro.llk.enable .

ro.khungtask.enable

Permitir que se habilite el demonio [khungtask] . El valor predeterminado es falso.

khungtask.enable

Evaluado para construcciones inglesas. El valor predeterminado es ro.khungtask.enable .

ro.llk.mlockall

Habilite la llamada a mlockall() . El valor predeterminado es falso.

ro.khungtask.tiempo de espera

[khungtask] límite de tiempo máximo. El valor predeterminado es 12 minutos.

ro.llk.timeout_ms

Plazo máximo D o Z. El valor predeterminado es 10 minutos. Duplique este valor para configurar el mecanismo de vigilancia de alarma para llkd .

ro.llk.D.timeout_ms

D plazo máximo. El valor predeterminado es ro.llk.timeout_ms .

ro.llk.Z.timeout_ms

Límite de tiempo máximo Z. El valor predeterminado es ro.llk.timeout_ms .

ro.llk.stack.timeout_ms

Comprueba el límite de tiempo máximo de símbolos de pila persistentes. El valor predeterminado es ro.llk.timeout_ms . Activo solo en compilaciones userdebug o eng .

ro.llk.check_ms

Muestras de subprocesos para D o Z. El valor predeterminado es dos minutos.

pila.rollk

Comprueba los símbolos de la pila del kernel que, si están presentes de forma persistente, pueden indicar que un subsistema está bloqueado. El valor predeterminado es cma_alloc,__get_user_pages,bit_wait_io,wait_on_page_bit_killable lista de símbolos del kernel separados por comas. La verificación no programa ABA hacia adelante, excepto sondeando cada ro.llk_check_ms durante el período ro.llk.stack.timeout_ms , por lo que los símbolos de la pila deben ser excepcionalmente raros y fugaces (es muy poco probable que un símbolo aparezca de manera persistente en todos muestras de la pila). Comprueba si hay una coincidencia para " symbol+0x" o " symbol.cfi+0x" en la expansión de la pila. Disponible solo en compilaciones userdebug o eng ; Los problemas de seguridad en las compilaciones de usuarios dan como resultado privilegios limitados que impiden esta verificación.

proceso.ro.llk.lista.negra.

El llkd no supervisa los procesos especificados. El valor predeterminado es 0,1,2 ( kernel , init y [kthreadd] ) más los nombres de proceso init,[kthreadd],[khungtaskd],lmkd,llkd,watchdogd, [watchdogd],[watchdogd/0],...,[watchdogd/get_nprocs-1] . Un proceso puede ser una referencia comm , cmdline o pid . Un valor predeterminado automatizado puede ser mayor que el tamaño máximo actual de propiedad de 92.

ro.llk.lista negra.padre

El llkd no supervisa los procesos que tienen los padres especificados. El valor predeterminado es 0,2,adbd&[setsid] ( kernel , [kthreadd] y adbd solo para zombie setsid ). Un separador comercial (&) especifica que el padre se ignora solo en combinación con el proceso hijo de destino. Se seleccionó el signo comercial porque nunca forma parte del nombre de un proceso; sin embargo, un setprop en el shell requiere que el signo comercial esté entre comillas o escape, aunque el archivo init rc donde normalmente se especifica esto no tiene este problema. Un proceso principal o de destino puede ser una referencia comm , cmdline o pid .

ro.llk.listanegra.uid

El llkd no supervisa los procesos que coinciden con los uid especificados. Lista separada por comas de números o nombres de uid. El valor predeterminado es vacío o falso.

pila.de.procesos.de.lista.negra.ro.llk

El llkd no monitorea el subconjunto de procesos especificado para buscar firmas de pila de bloqueo en vivo. El valor predeterminado son los nombres de proceso init,lmkd.llkd,llkd,keystore,ueventd,apexd,logd . Previene la violación de la política de seguridad asociada con procesos que bloquean ptrace (ya que no se pueden verificar). Activo solo en compilaciones userdebug y eng . Para obtener detalles sobre los tipos de compilación, consulte Compilación de Android .

Preocupaciones arquitectónicas

  • Las propiedades están limitadas a 92 caracteres (sin embargo, esto se ignora para los valores predeterminados definidos en el archivo include/llkd.h en las fuentes).
  • El demonio incorporado [khungtask] es demasiado genérico y se activa demasiado con el código del controlador que se encuentra en el estado D. Cambiar a S haría que las tareas se pudieran eliminar (y que los conductores pudieran resucitar si fuera necesario).

Interfaz de biblioteca (opcional)

Opcionalmente, puede incorporar llkd a otro demonio privilegiado utilizando la siguiente interfaz C del componente libllkd :

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

Si se proporciona un nombre de hilo, se genera un hilo automáticamente; de ​​lo contrario, la persona que llama debe llamar llkCheckMilliseconds en su bucle principal. La función devuelve el período de tiempo antes de la próxima llamada esperada a este controlador.