23 votos

Llamada al sistema SELinux y chroot

TL; DR: Esta es una pregunta sobre el paso final, en un proceso de rooting portátil, orientado a los desarrolladores, que funciona en todas las máquinas Android. No se basa en ningún exploit - es algo que se nos permite hacer legal y moralmente, como desarrolladores, a nuestras propias máquinas. Si obtengo una respuesta y consigo hacer chroot dentro de mi Debian, haré una entrada de blog concisa detallando todos los pasos de este proceso para todos los compañeros desarrolladores que quieran acceso Root a sus tabletas - y no quieran confiar en "one-click-roots" de dudoso origen que hacen Dios sabe qué a sus máquinas (¿miembros de botnets?)... 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 el 99% de las veces se encuentra dentro de las actualizaciones Over-the-air proporcionadas por el fabricante, o se puede descargar individualmente como una imagen independiente que se puede flashear.

Así, pasó una semana en la que pasé todo mi tiempo libre en mi nueva tablet Android.

Y lo he conseguido casi por completo: crear un proceso portátil, orientado a los desarrolladores, para conseguir el Root en mi tablet Android 5.0.2.

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

Lo que he hecho hasta ahora

  1. Primero, hice un parche menor en las fuentes del kernel de mi tablet (proporcionadas por el fabricante), y luego compilé mi propio kernel - donde deshabilité las comprobaciones para cambiar Modo de aplicación de SELINUX . En concreto...

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é la imagen de mi initrd /default.prop para contener: ro.secure=0 y ro.debuggable=1

  2. Desde que mi fabricante initrd.img se lo perdió, también compilé su.c de https://Android.googlesource.com/platform/system/extras/+/master/su/ y colocamos el binario resultante en /sbin/su asegurándose de que está configurado como SUID Root ( chmod 04755 /sbin/su ).

Después de eso, empaqué el nuevo kernel y el nuevo initrd, como expliqué en el episodio 2 de mi post anterior - y arrancado de mi propia imagen:

adb reboot boot-loader ; fastboot boot myboot.img

Entonces, ¿eres Root?

Sí, inicialmente parecía 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 conseguido Root:

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 sólo porque id lo 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 por fin puedo leer las particiones en bruto de mi tablet.

Y SELinux está, efectivamente, en modo "abajo, perro":

root@K01E_2:/ # getenforce                                                     
Permissive

Pero... hay todavía 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 2ª partición formateada en EXT4-fs de mi tarjeta SD externa.

También no puedo chroot a mi encantadora debootstrap -ed Debian:

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

¿Es por culpa de SELinux?

No sé - soy nuevo (muy nuevo - una semana) en SELinux. Pensé que cuando se pone a dormir ( getenforce reportando "Permiso") ya no interfiere...

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

¿Podría ser por el contexto de mi proceso?

Recuerda que id devuelve... "uid=0(Root) gid=0(Root)... context=u:r:shell:s0 "

¿Puedo cambiar ese contexto? Siendo Root y todo eso, ¿puedo alejarme de shell ? Y si es así, ¿a qué se traslada?

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á mount y chroot ?

Leyendo un poco más sobre SELinux, de vuelta en mi máquina principal, analizo el /sepolicy en root del 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 ...
...

Vale, ¡una serie de posibilidades! Especialmente que kernel uno 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

Maldita sea.

¿Quién diablos me está bloqueando chroot ¿?

Cualquier consejo será bienvenido...

12voto

Adrian Pirvulescu Puntos 3671

¿Quién diablos me está bloqueando el chroot?

No fue SELinux - eso fue una búsqueda inútil ( getenforce devolver "Permisivo" significa que SELinux ya no está en el panorama).

El culpable - después de añadir un buen número de printk en la fuente del kernel para rastrear los fallos de ambos chroot y mount - resultó ser capacidades . Más concretamente, el "conjunto de capacidades" de Android -puede leer todo sobre ellas a través de su man ( man 7 capabilities ) y confieso que nunca antes me había molestado en investigarlos - mis tareas cotidianas de UNIX dependían de ellos y no tenía ni idea... prueba esto en tu caja de linux para comprobarlo:

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

¿Ves? Ping ya no es SUID Root - utiliza la información almacenado en los atributos extendidos del sistema de archivos para saber que tiene acceso a la capa de sockets sin procesar (para que pueda hacer su cosa de ICMP - a nivel de IP que es).

De todos modos, divago - el punto de cirugía en mi núcleo en el que dejé el "conjunto de mis capacidades" - de una manera discutiblemente repugnante, "que marchen todos" - fue este ( 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 no se pierden NUNCA - 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 - he cortado "su.c", por lo que todos en mi tablet puede 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, que sólo permita mi termux y Terminal Emulator usuarios para invocar su y chroot y no dejar entrar a todo el mundo y a su abuela :-)

0 votos

Sin embargo, ¿este método Root no requiere la capacidad de flashear tu propio kernel? Y para hacer eso se requiere un bootloader desbloqueado. En ese momento, es posible que simplemente flashear una recuperación personalizada y ganar Root de esa manera.

0 votos

@1110101001 Para el bootloader: obviamente, sí. Para el custom recovery: no existe (aún) para mi tablet - aunque ahora estoy en condiciones de crear uno ;-)

1 votos

@1110101001: Y una cosa más - dijiste "capacidad de flashear" - no he flasheado mi imagen de arranque a la tablet, sólo estoy arrancando desde ella: fastboot boot my.img . Creo que la comunidad del rooting llama a esto un atado rooting :-) Y por supuesto que podría flashearlo - si quisiera.

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