SELinux y llamada al sistema chroot

TL; DR: Esta es una pregunta sobre el paso final, en un proceso de enraizamiento portátil y orientado al desarrollador, que funciona en todas las máquinas Android. No se basa en ningún exploit: es algo que, como desarrolladores, estamos legal y moralmente autorizados a hacer con nuestras propias máquinas. Si obtengo una respuesta y me las arreglo para hacer chroot dentro de mi Debian, haré una publicación de blog concisa que detallará todos los pasos de este proceso para todos los compañeros desarrolladores que quieren acceso de root a sus tabletas, y no quieren confiar en el origen dudoso. "raíces de un clic" que hacen Dios sabe qué a sus máquinas (¿miembros de botnet?)... Las únicas dependencias serán las fuentes del kernel de la máquina (que el fabricante está legalmente obligado a proporcionar) y la imagen de la partición de arranque (boot.img), que está el 99 % de las veces dentro de las actualizaciones inalámbricas proporcionadas por el fabricante, o se puede descargar individualmente como una imagen flash independiente.

Entonces, pasó una semana en la que pasé todo mi tiempo libre en mi nueva tableta Android.

Y lo he logrado casi por completo: crear un proceso portátil orientado al desarrollador para lograr la raíz en mi tableta Android 5.0.2.

Pero todavía falta una cosa: no puedo hacer un chroot (¡que necesito para ejecutar mi debootstrap-ed Debian!)

lo que hice hasta ahora

  1. Primero, hice un parche menor en las fuentes del kernel de mi tableta (proporcionadas por el fabricante) y luego compilé mi propio kernel, donde deshabilité las comprobaciones para cambiar el modo de cumplimiento de SELINUX . Específicamente...

en security/selinux/selinuxfs.c:

...
if (new_value != selinux_enforcing) {
    /* Commented out by ttsiodras.
    length = task_has_security(current, SECURITY__SETENFORCE);
    if (length)
        goto out;
    */
    audit_log(current->audit_context, GFP_KERNEL, AUDIT_MAC_STATUS,
        "enforcing=%d old_enforcing=%d auid=%u ses=%u",
        new_value, selinux_enforcing,
  1. Luego cambié mi imagen initrd /default.proppara contener: ro.secure=0yro.debuggable=1

  2. Como a mi fabricante initrd.imgle faltaba, también compilé su.cdesde https://android.googlesource.com/platform/system/extras/+/master/su/ y coloqué el binario resultante en /sbin/su, asegurándome de que esté configurado como raíz SUID ( chmod 04755 /sbin/su) .

Después de eso, empaqueté el nuevo kernel y el nuevo initrd, como expliqué en el Episodio 2 de mi publicación anterior , y arranqué desde mi propia imagen:

adb reboot boot-loader ; fastboot boot myboot.img

Entonces, ¿eres root?

Sí, inicialmente pareció tener éxito:

$ adb shell

shell@K01E_2:/ $ id

uid=2000(shell) gid=2000(shell) groups=1004(input),1007(log),1011(adb),
1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),
3003(inet),3006(net_bw_stats) 
context=u:r:shell:s0

shell@K01E_2:/ $ ls -l /sbin/su /sbin/_su
-rwxr-xr-x root     root          131 2015-10-03 10:44 su
-rwsr-xr-x root     root         9420 2015-10-03 01:31 _su

(the _su is the binary I compiled, set to SUID root, and "su" is
 a script I wrote to tell "su" to add me to all these groups...)

shell@K01E_2:/ $ cat /sbin/su

#!/system/bin/sh
export PATH=/system/bin:$PATH
exec /sbin/_su 0,0,1000,1028,2000,2001,1004,1007,1011,1015,\
   1028,3001,3002,3003,3006

Y ahora he logrado la raíz:

shell@K01E_2:/ $ su

root@K01E_2:/ # id

uid=0(root) gid=0(root) 
groups=1000(system),1004(input),1007(log),1011(adb),
1015(sdcard_rw),1028(sdcard_r),1028(sdcard_r),2000(shell),2001(cache),
3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats) 
context=u:r:shell:s0

Estoy 100% seguro de que soy root, no solo porque idlo dice, sino porque también puedo hacer cosas que los procesos normales definitivamente no pueden:

root@K01E_2:/ # ls -l /dev/block/platform/msm_sdcc.1/by-name/boot
lrwxrwxrwx root root 2015-10-03 10:47 boot -> /dev/block/mmcblk0p16

root@K01E_2:/ # dd if=/dev/block/mmcblk0p16 of=/dev/null bs=1M
16+0 records in
16+0 records out
16777216 bytes transferred in 0.569 secs (29485441 bytes/sec)

He aquí que finalmente puedo leer particiones en bruto de mi tableta.

Y SELinux está de hecho en modo "abajo, perro":

root@K01E_2:/ # getenforce                                                     
Permissive

Pero... todavía hay cosas que no puedo hacer:

root@K01E_2:/ # mkdir /my_mnt

root@K01E_2:/ # mount -t ext4 /dev/block/mmcblk1p2 /my_mnt
mount: Operation not permitted

Es decir, no puedo montar mi segunda partición con formato EXT4-fs de mi tarjeta SD externa.

Tampoco puedo hacer chroot en mi encantador debootstrap-ed Debian:

root@K01E_2:/ # chroot /data/debian/ /bin/bash                             
chroot() fail
Operation not permitted

¿Es por SELinux?

No sé, soy nuevo (muy nuevo, una semana) en SELinux. Pensé que cuando lo pones a dormir ( getenforcereportando "Permisivo") ya no interfiere...

Aparentemente, estaba equivocado. Por la madriguera del conejo vamos de nuevo...

¿Podría ser debido al contexto de mi proceso?

Recuerde que iddevolvió... "uid=0(root) gid=0(root)... context=u:r:shell:s0 "

¿Puedo cambiar ese contexto? Siendo root y todo, ¿puedo alejarme de shell? Y si es así, ¿mover a qué?

La respuesta a la primera pregunta es runcon:

shell@K01E_2:/ $ runcon u:r:debuggerd:s0 /sbin/su

root@K01E_2:/ # id
uid=0(root) gid=0(root)... context=u:r:debuggerd:s0

Bien. Pero, ¿qué contexto me permitirá hacer mounty chroot?

Leyendo un poco más sobre SELinux, de vuelta en mi máquina principal, analizo el /sepolicyarchivo en la raíz de initrd.img:

linuxbox$ $ sesearch -A sepolicy | grep chroot
allow init_shell init_shell : capability { chown sys_chroot ...
allow init init : capability { chown dac_read_search sys_chroot ...
allow kernel kernel : capability { chown dac_override sys_chroot ... 
allow asus-dbug-d asus-dbug-d : capability { chown sys_chroot ...
...

OK, un número de posibilidades! Especialmente ese kernelque parece prometedor:

shell@K01E_2:/ $ runcon u:r:kernel:s0 /sbin/su

root@K01E_2:/ # id
uid=0(root) gid=0(root)... context=u:r:kernel:s0

root@K01E_2:/ # chroot /data/debian/ /bin/bash                             
chroot() fail
Operation not permitted

Maldito.

¿Quién diablos me está bloqueando de chrooting?

Cualquier consejo bienvenido...

Respuestas (1)

¿Quién diablos me está impidiendo hacer chroot?

No fue SELinux, fue una persecución inútil ( getenforcedevolver "Permisivo" significa que SELinux ya no está en la imagen).

El culpable, después de agregar un buen número de printkcódigo fuente del kernel para rastrear las fallas de ambos chroot, mountresultó ser las capacidades . Más específicamente, el "conjunto de límites de capacidad" de Android: puede leer todo sobre ellos a través de su man( man 7 capabilities) y confieso que nunca antes me había molestado en investigarlos: mis tareas diarias de UNIX dependían de ellos y no tenía ni idea ... intente esto en su caja de linux para ver por sí mismo:

$ getfattr -d -m - /sbin/ping
getfattr: Removing leading '/' from absolute path names
# file: sbin/ping
security.capability=0s......

¿Ver? Ping ya no es raíz SUID: utiliza información almacenada en los atributos extendidos del sistema de archivos para saber que tiene acceso a la capa de sockets sin procesar (para que pueda hacer lo que hace ICMP, en el nivel de IP).

De todos modos, me estoy desviando: el punto de cirugía en mi kernel donde detuve el "conjunto de soltar mis capacidades" - de una manera posiblemente repugnante, "dejemos que todos marchen" - fue esto ( security/commoncap.c):

static long cap_prctl_drop(struct cred *new, unsigned long cap)
{
    if (!capable(CAP_SETPCAP))
        return -EPERM;
    if (!cap_valid(cap))
        return -EINVAL;

    // ttsiodras: come in, everyone, the water's fine!
    //cap_lower(new->cap_bset, cap);
    return 0;
}

Esto significa que las capacidades NUNCA se eliminan; una configuración muy segura, de hecho :-)

$ adb shell

shell@K01E_2:/ $ su

root@K01E_2:/ # chroot /data/debian/ /bin/bash

root@localhost:/# export PATH=/bin:/sbin:/usr/bin:/usr/sbin:\
     /usr/local/bin:$PATH

root@localhost:/# cat /etc/issue
Debian GNU/Linux 8 \n \l

Hola, mi dulce Debian :-)

Ah, y "Root checker" también funciona: corté "su.c", para que todos en mi tableta puedan convertirse en root:

int main(int argc, char **argv)
{
  struct passwd *pw;
  uid_t uid, myuid;
  gid_t gid, gids[50];

  /* Until we have something better, only root and shell can use su. */
  myuid = getuid();
  //
  // ttsiodras - Oh no, you don't :-)
  //
  //if (myuid != AID_ROOT && myuid != AID_SHELL) {
  //    fprintf(stderr,"su: uid %d not allowed to su\n", myuid);
  //    return 1;
  //}

Ahora que funciona, debo hacer que funcione correctamente, es decir, permitir que solo mis usuarios termuxy yo invoquemos y , y no dejar entrar a todos ni a su abuela :-)Terminal Emulatorsuchroot

¿Sin embargo, este método raíz no requiere la capacidad de actualizar su propio kernel? Y para hacer eso requiere un gestor de arranque desbloqueado. En ese momento, también puede actualizar una recuperación personalizada y obtener la raíz de esa manera.
@ 1110101001 Para el cargador de arranque: obviamente, sí. Para la recuperación personalizada: no existe tal cosa (todavía) para mi tableta; sin embargo, ahora estoy en condiciones de crear una ;-)
@ 1110101001: Y una cosa más: dijiste "capacidad de flashear". No he mostrado mi imagen de arranque en la tableta, solo estoy arrancando desde ella: fastboot boot my.img. Creo que la comunidad de enraizamiento llama a esto un enraizamiento atado :-) Y, por supuesto, podría flashearlo, si quisiera.