6 votos

¿Cómo hacer persistentes las reglas inyectadas de SELinux sin desempaquetar el boot.img?

Estoy trabajando en una aplicación que necesita acceso Root y tengo un dispositivo que está rooteado pero no con Magisk. Este dispositivo sólo tiene adb shell Root disponible. Por lo tanto, necesito una alternativa para llamar a la funcionalidad requerida sin el uso de Magisk u otras herramientas. Lo hice colocando mi ejecutable dentro del directorio del sistema y ejecutándolo como un demonio. Este demonio requiere acceso en alguna ubicación que está restringida por las políticas de SELinux.

He inyectado la política requerida con los siguientes comandos:

    sepolicy-inject -s init -t su -c process -p transition -l
    sepolicy-inject -s su -t system_file -c file -p entrypoint -l
    sepolicy-inject -s init -t su -c process -p rlimitinh -l
    sepolicy-inject -s init -t su -c process -p siginh -l
    sepolicy-inject -s su -t shell_exec -c file -p read -l
    sepolicy-inject -s su -t shell_exec -c file -p execute -l
    sepolicy-inject -s su -t shell_exec -c file -p getattr  -l
    sepolicy-inject -s su -t vendor_toolbox_exec -c file -p execute_no_trans -l
    sepolicy-inject -s init -t su -c process -p noatsecure -l
    sepolicy-inject -s su -t toolbox_exec -c file -p getattr -l
    sepolicy-inject -s su -t toolbox_exec -c file -p execute -l
    sepolicy-inject -s su -t system_file -c file -p execute_no_trans -l
    sepolicy-inject -s su -t storage_file -c dir -p search -l
    sepolicy-inject -s su -t storage_file -c lnk_file -p read -l
    sepolicy-inject -s su -t tmpfs -c dir -p search -l
    sepolicy-inject -s su -t mnt_user_file -c dir -p search -l
    sepolicy-inject -s su -t mnt_user_file -c lnk_file -p read -l
    sepolicy-inject -s su -t sdcardfs -c dir -p search -l
    sepolicy-inject -s su -t sdcardfs -c file -p append -l
    sepolicy-inject -s su -t toolbox_exec -c file -p read -l
    sepolicy-inject -s su -t toolbox_exec -c file -p open -l
    sepolicy-inject -s su -t sdcardfs -c file -p read -l
    sepolicy-inject -s su -t sdcardfs -c file -p write -l
    sepolicy-inject -s su -t sdcardfs -c file -p open -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p read -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p write -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p open -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p append -l

El problema es que no son persistentes después de reiniciar. Sé que puedo extraer boot.img y ramdisk, reemplazar /sepolicy con el nuevo archivo de políticas copiado de /sys/fs/selinux/policy, volver a empaquetar boot.img y flashear de nuevo.

Quiero hacerlo sin reflashear boot.img . ¿Hay alguna manera de ejecutar los comandos anteriores después de que Android termine de generar los archivos de SELinux?

He probado los siguientes archivos rc:

#/etc/init/custom.rc

# define service, use executable here if script not needed
service custom /system/bin/custom.sh

    # don't start unless explicitly asked to
    disabled

    # Use `seclabel u:r:magisk:s0` to run with unrestricted SELinux context to avoid avc denials
    # can also use "u:r:su:s0" on userdebug / eng builds if no Magisk
    # it's required if SELinux is enforcing and service needs access
    # to some system resources not allowed by default sepolicy
    seclabel u:r:su:s0

# start the service when boot is completed
on property:sys.boot_completed=1
    sepolicy-inject -s init -t su -c process -p transition -l
    sepolicy-inject -s su -t system_file -c file -p entrypoint -l
    sepolicy-inject -s init -t su -c process -p rlimitinh -l
    sepolicy-inject -s init -t su -c process -p siginh -l
    sepolicy-inject -s su -t shell_exec -c file -p read -l
    sepolicy-inject -s su -t shell_exec -c file -p execute -l
    sepolicy-inject -s su -t shell_exec -c file -p getattr  -l
    sepolicy-inject -s su -t vendor_toolbox_exec -c file -p execute_no_trans -l
    sepolicy-inject -s init -t su -c process -p noatsecure -l
    sepolicy-inject -s su -t toolbox_exec -c file -p getattr -l
    sepolicy-inject -s su -t toolbox_exec -c file -p execute -l
    sepolicy-inject -s su -t system_file -c file -p execute_no_trans -l
    sepolicy-inject -s su -t storage_file -c dir -p search -l
    sepolicy-inject -s su -t storage_file -c lnk_file -p read -l
    sepolicy-inject -s su -t tmpfs -c dir -p search -l
    sepolicy-inject -s su -t mnt_user_file -c dir -p search -l
    sepolicy-inject -s su -t mnt_user_file -c lnk_file -p read -l
    sepolicy-inject -s su -t sdcardfs -c dir -p search -l
    sepolicy-inject -s su -t sdcardfs -c file -p append -l
    sepolicy-inject -s su -t toolbox_exec -c file -p read -l
    sepolicy-inject -s su -t toolbox_exec -c file -p open -l
    sepolicy-inject -s su -t sdcardfs -c file -p read -l
    sepolicy-inject -s su -t sdcardfs -c file -p write -l
    sepolicy-inject -s su -t sdcardfs -c file -p open -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p read -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p write -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p open -l
    sepolicy-inject -s su -t media_rw_data_file -c file -p append -l
    start custom

pero no funciona porque creo que Android genera archivos SELinux después de que mi servicio personalizado se haya activado.

También he probado los comandos anteriores en onrestart opción de servicio init pero falló.

¿Alguna sugerencia?

0 votos

El tiempo es su único problema yo sugeriría comando de sueño

0 votos

He intentado añadir 5 minutos de sueño con sleep 300 después de on property:sys.boot_completed=1 pero el servicio se inicia instantáneamente en el arranque completo por lo que este comando no está funcionando como se esperaba.

4voto

Jack Wade Puntos 231

El init que ha definido no inyectará las reglas de política de SELinux por dos razones:

  • La sintaxis de sepolicy-inject comandos está incompleta; .rc no son scripts de shell. El sintaxis correcta sería:

    #/etc/init/custom.rc
    
    ...
    
    on property:sys.boot_completed=1
        exec - -- /system/bin/sepolicy-inject -s init -t su -c process -p transition -l
    
    ...
  • Esto ejecutará la sentencia con el contexto u:r:init.s0 . Pero la modificación de la política de SELinux requiere permiso load_policy es decir, hay que inyectar la regla sepolicy-inject -s init -t kernel -c security -p load_policy -l que de nuevo no se permitirá init . Leer ¿Qué contexto sepolítico permitirá que cualquier otro contexto acceda a él? para saber cómo se aplica SELinux en Android.

Así que usted está en el mismo el huevo o la gallina situación como al principio de su pregunta anterior . La política de SELinux sólo puede ser modificada con el contexto u:r:su:s0 que sólo está disponible a través de adb shell en userdebug construcciones de ROMs. O Root el dispositivo, por ejemplo, con Magisk, o reemplazar /sepolicy archivo en boot.img .

NOTA: No es necesario definir reglas como sepolicy-inject -s su ... como u:r:su:s0 ya es establecer permisividad en la política.

sepolicy Ubicaciones de los archivos:

En las versiones de Android anteriores a Treble, hay dos posibles ubicaciones definido para sepolicy archivo:

/sepolicy
/data/security/current/sepolicy

Como se ha dicho aquí :

El proceso de inicialización/recarga de Android buscará primero este archivo en: /data/security/current/sepolicy . Si no está presente, compruebe el directorio root: /sepolicy .

Sin embargo, sepolicy es cargado por init en el proceso de arranque muy temprano cuando /data no está montado. Como se ha dicho aquí :

Como sólo está montado el sistema de archivos root, elige /sepolicy en este momento. La otra vía es para las recargas dinámicas de la política en tiempo de ejecución.

Así que inicialmente /sepolicy está cargado con seguridad. Pero se puede poner modificado sepolicy en otras ubicaciones para ver si la política anterior es (o podría ser) sobrescrita en alguna etapa posterior del arranque. Es posible que tenga que copiar otros archivos también; este puesto podría ser útil. Nunca he probado esto.

En Oreo+ se carga una política monolítica desde /sepolicy si el dispositivo no es un dispositivo Treble (o si Magisk parcheado init para forzar la carga /sepolicy ). En los dispositivos de agudos /system , /vendor y /odm son montados por el kernel antes de iniciar init como se ha configurado en DTB. Aquí se carga una política de división precompilada desde /vendor/etc/selinux/precompiled_sepolicy si coincide con /system o la política se construye a partir de .cil archivos en /system/etc/selinux y /vendor/etc/selinux antes de la carga. Ver detalles aquí .

En ambas situaciones las cosas son mucho más complicadas de intentar que simplemente reemplazar /sepolicy archivo en boot.img Lo cual no es un gran problema en mi opinión. Se puede dd una copia de seguridad de su original boot.img a /sdcard que puede restaurarse en unos segundos en cualquier momento. Sin embargo, es necesario desbloquear el bootloader para arrancar un boot.img .
Tenga en cuenta que en los dispositivos con system-as-Root ( A/B u otros) ramdisk se traslada a system.img . Así que todos los archivos que antes formaban parte de boot.img (excepto el núcleo y la DTB) forman ahora parte de system partición.

0 votos

Gracias por sus excelentes conocimientos. Ahora, Estoy tratando de pack/unpack boot.img y frente a un problema: stackoverflow.com/questions/57425339/ ¿Puede ayudarnos en esto?

0 votos

Tengo un dispositivo con ROM userdebug que tiene políticas de dispositivo divididas para soportar agudos pero no soy capaz de parchear las políticas requeridas. Por favor, ayúdame a identificar el problema: Android.stackexchange.com/questions/218911/

2voto

Tim Bodeit Puntos 101

Sé que la pregunta se formuló hace bastante tiempo, pero como hace poco intenté hacer algo parecido y este post fue uno de los más visitados en Google, quiero compartir mi experiencia reciente para ayudar a los demás.

Tenga en cuenta que esta respuesta se centrará únicamente en los dispositivos Android 9 a 13 y Treble.

Si queremos saber cómo modificar las políticas de SELinux, creo que es bueno entender primero cómo se cargan las políticas en primer lugar.

SELinux en el proceso de arranque

En una fase temprana del proceso de arranque de Android y después de montar la mayoría de las particiones, init intentará cargar las políticas SELinux desde un archivo sepolicy monolítico que se encuentra en /odm/etc/selinux/precompiled_sepolicy o /vendor/etc/selinux/precompiled_sepolicy . Si init nota que el dispositivo se actualiza desincronizado, init recompilará las políticas de SELinux basándose en .cil que se pueden encontrar en varios sitios.

Encontrará todos los detalles en los comentarios del init/selinux.cpp y mirando la implementación, pero aquí hay un resumen de los pasos exactos tomados por init :

  1. Encuentra el archivo sepolicy a utilizar:
    • si /odm/etc/selinux/precompiled_sepolicy existe, utilícelo como archivo sepolicy para utilizar
    • de lo contrario, si /vendor/etc/selinux/precompiled_sepolicy existe, utilícelo como archivo sepolicy para utilizar
    • de lo contrario, si no existe ninguna de las anteriores, deténgase aquí, recompile las políticas basándose en el .cil y cargar el archivo sepolicy recién compilado.
  2. Compruebe si el dispositivo se actualizó fuera de sincronización:
    • Compara /(odm|vendor)/etc/selinux/precompiled_sepolicy.plat_sepolicy_and_mapping.sha256 y /system/etc/selinux/plat_sepolicy_and_mapping.sha256
    • Compara /(odm|vendor)/etc/selinux/precompiled_sepolicy.system_ext_sepolicy_and_mapping.sha256 y /system_ext/etc/selinux/system_ext_sepolicy_and_mapping.sha256
    • Compara /(odm|vendor)/etc/selinux/precompiled_sepolicy.product_sepolicy_and_mapping.sha256 y /product/etc/selinux/product_sepolicy_and_mapping.sha256
    • (En Android 13) Comparar /(odm|vendor)/etc/selinux/precompiled_sepolicy.apex_sepolicy.sha256 y /dev/selinux/apex_sepolicy.sha256
    • si alguno de los pares de archivos anteriores no coincide, deténgase aquí, vuelva a compilar las políticas basándose en el archivo .cil y cargar el archivo sepolicy recién compilado.
  3. Si todo es correcto, cargue el archivo sepolicy precompilado ( /odm/etc/selinux/precompiled_sepolicy o /vendor/etc/selinux/precompiled_sepolicy )

La compilación de las políticas basadas en la .cil es el siguiente:

  1. Obtener la última versión de las políticas compatibles con el vendor versión ( /vendor/etc/selinux/plat_sepolicy_vers.txt Obsérvese que init no mira el archivo en el /odm partición)
  2. Reúna la .cil para compilar:
    • /system/etc/selinux/mapping/{vendor_version}.cil
    • /system/etc/selinux/mapping/{vendor_version}.compat.cil
    • /system_ext/etc/selinux/system_ext_sepolicy.cil
    • /system_ext/etc/selinux/mapping/{vendor_version}.cil
    • /product/etc/selinux/product_sepolicy.cil
    • /product/etc/selinux/mapping/{vendor_version}.cil
    • /vendor/etc/selinux/plat_pub_versioned.cil
    • /vendor/etc/selinux/vendor_sepolicy.cil o si no existe: /vendor/etc/selinux/nonplat_sepolicy.cil
    • /odm/etc/selinux/odm_sepolicy.cil
  3. Compile los archivos anteriores con secilc a /dev/sepolicy.XXXXXX
  4. Políticas de carga de /dev/sepolicy.XXXXXX

Modificación permanente de las políticas de SELinux

Ahora que entendemos cómo init carga las políticas, es fácil ver cómo se podrían añadir permanentemente nuevas políticas al sistema:

  • Añadir directamente las políticas a /odm/etc/selinux/precompiled_sepolicy o /vendor/etc/selinux/precompiled_sepolicy con sepolicy-inject :

    sepolicy-inject -s su -t system_file -c file -p entrypoint -P /vendor/etc/selinux/precompiled_sepolicy -o /vendor/etc/selinux/precompiled_sepolicy
  • Visite init cree que el dispositivo se actualiza fuera de sincronización (Mediante la modificación de uno de los .sha256 o borrando los archivos de sepolicy precompilados) y modificar uno de los anteriores .cil archivos

Tenga en cuenta que en ambos casos, necesitará tener un acceso de lectura-escritura a la partición que desea modificar ( /vendor , /odm y/o /system ). Estas particiones se montan normalmente como de sólo lectura, por lo que tendrá que:

  • Vuelve a montarlos como lectura-escritura si tienes acceso Root (ya sea porque tu dispositivo está rooteado, o usando adb root en un userdebug Android build)
  • Arrancar en modo recuperación, montar las particiones como lectura-escritura y modificarlas en recuperación.

Si no quieres tener que volver a montar las particiones cada vez que quieras cambiar las políticas SELinux, puedes añadir algunas reglas SELinux para permitir init para cargar nuevas políticas, resolviendo así el problema del huevo y la gallina (como se menciona en esta excelente respuesta ) que tuvo con su init guión. Puedes encontrar qué reglas de SELinux son necesarias buscando violaciones de SELinux (errores avc) en los registros del dispositivo al iniciarse:

adb logcat | grep avc

Con ello, podrá disponer de un init que carga nuevas políticas con sepolicy-inject .

PreguntAndroid.com

PreguntAndroid es una comunidad de usuarios de Android en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X