Llamada de sistema SELinux y chroot

21

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

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

Y he tenido éxito casi por completo: en la creación de un proceso portátil orientado al desarrollador, para lograr la raíz en mi tableta Android 5.0.2.

Pero aún falta una cosa: no puedo hacer un chroot (¡lo que necesito para ejecutar mi debootstrapDebian editado!)

Lo que hice hasta ahora

  1. Primero, hice un parche menor en las fuentes del núcleo de mi tableta (proporcionadas por el fabricante), y luego compilé mi propio núcleo, donde desactivé las comprobaciones para cambiar el modo de aplicación 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é mis imágenes 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 debajo /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 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 logrado 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 solo porque lo iddice, 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á realmente 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 segunda partición formateada EXT4-fs de mi tarjeta SD externa.

Tampoco puedo hacer chroot con mi debootstrapDebian de encantadora lengua:

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 ( getenforceinformando "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 shell? Y si es así, ¿pasar 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

Bueno. Pero, ¿qué contexto me permitirá 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, una serie de posibilidades! Especialmente ese kernelparece 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 chroot?

Cualquier consejo es bienvenido ...

ttsiodras
fuente

Respuestas:

12

¿Quién diablos me está bloqueando?

No fue SELinux, fue una persecución salvaje ( getenforcedevolver "Permisivo" significa que SELinux ya no aparece en la imagen).

El culpable, después de agregar bastantes printkfuentes en el núcleo para rastrear las fallas de ambos chrooty mount, resultó ser 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 examinarlos: mis tareas diarias de UNIX dependían de ellos y no tenía idea ... intente esto en tu caja de linux para ver por ti mismo:

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

¿Ver? Ping ya no es la raíz SUID: utiliza la 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 de ICMP, a nivel de IP).

De todos modos, estoy divagando, el punto de cirugía en mi núcleo donde detuve el "conjunto de capacidades", de una manera posiblemente repugnante, "déjalos marchar a todos", 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 pierden, 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, hay que hacer que funcione correctamente - es decir Permitir que solo mis termuxy Terminal Emulatorlos usuarios invocan suy chroot, y no dejar que cada uno y su abuela en :-)

ttsiodras
fuente
Sin embargo, ¿este método raíz no requiere la capacidad de actualizar su propio núcleo? Y para hacer eso se requiere un gestor de arranque desbloqueado. En ese momento, también puede flashear una recuperación personalizada y obtener root de esa manera.
1110101001
@ 1110101001 Para el gestor de arranque: obviamente, sí. Para la recuperación personalizada: no existe tal cosa (todavía) para mi tableta, aunque ahora estoy en condiciones de crear una ;-)
ttsiodras
1
@ 1110101001: Y una cosa más - que ha dicho "capacidad de flash" - no he brilló mi imagen de arranque a la tableta, sólo estoy arrancando de ella: fastboot boot my.img. Creo que la comunidad de rooting llama a esto un rooting atado :-) Y, por supuesto, podría flashearlo, si quisiera.
ttsiodras