23 votes

SELinux et appel système chroot

TL ; DR : Il s'agit d'une question sur l'étape finale, dans un processus d'enracinement portable, orienté développeur, qui fonctionne sur toutes les machines Android. Il n'est pas basé sur un exploit - c'est quelque chose que nous sommes légalement et moralement autorisés à faire, en tant que développeurs, sur nos propres machines. Si j'obtiens une réponse et que je parviens à faire un chroot dans ma Debian, je ferai un billet de blog concis détaillant toutes les étapes de ce processus pour tous les collègues développeurs qui veulent un accès Root à leurs tablettes - et qui ne veulent pas faire confiance aux "one-click-roots" d'origine douteuse qui font Dieu sait quoi à leurs machines (membres de botnet ?)... Les seules dépendances seront les sources du noyau de la machine (que le fabricant est légalement obligé de fournir) et l'image de la partition de démarrage ( boot.img ), qui se trouve 99% du temps dans les mises à jour Over-the-air fournies par le fabricant, ou téléchargeable individuellement sous forme d'image flash autonome.

Ainsi, une semaine s'est écoulée où j'ai passé tout mon temps libre sur ma nouvelle tablette Android.

Et j'ai presque entièrement réussi - en créant un processus portable, orienté développeur, pour obtenir Root dans ma tablette Android 5.0.2.

Mais il y a une chose qui manque encore - je ne peux pas faire un chroot (dont j'ai besoin pour exécuter ma debootstrap -ed Debian !)

Ce que j'ai fait jusqu'à présent

  1. Tout d'abord, j'ai effectué un correctif mineur dans les sources du noyau de ma tablette (fournies par le fabricant), puis j'ai compilé mon propre noyau - où j'ai désactivé les vérifications de la modification de l'adresse IP. Mode d'application de SELINUX . Plus précisément...

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. J'ai ensuite modifié les paramètres de mon image initrd. /default.prop à contenir : ro.secure=0 y ro.debuggable=1

  2. Depuis que mon fabricant initrd.img manquait, j'ai aussi compilé su.c de https://Android.googlesource.com/platform/system/extras/+/master/su/ et a placé le binaire résultant sous /sbin/su en s'assurant qu'il est défini comme SUID Root ( chmod 04755 /sbin/su ).

Après cela, j'ai empaqueté le nouveau noyau et le nouvel initrd, comme je l'ai expliqué dans l'épisode 2 de mon précédent post - et boosté par ma propre image :

adb reboot boot-loader ; fastboot boot myboot.img

Alors, tu es Root ?

Oui, cela semblait initialement être un succès :

$ 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

Et j'ai maintenant atteint 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

Je suis sûr à 100% que je suis Root - pas seulement parce que id le dit, mais parce que je peux aussi faire des choses que les processus normaux ne peuvent absolument pas faire :

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)

Et voilà, je peux enfin lire des partitions brutes sur ma tablette !

Et SELinux est en effet en mode "down, dog" :

root@K01E_2:/ # getenforce                                                     
Permissive

Mais... il y a todavía des choses que je ne peux pas faire :

root@K01E_2:/ # mkdir /my_mnt

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

C'est-à-dire que je ne peux pas monter la deuxième partition de ma carte SD externe, formatée en EXT4-fs.

Je n'arrive pas non plus à me connecter à ma belle debootstrap -ed Debian :

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

Est-ce à cause de SELinux ?

Je ne sais pas - je suis nouveau (très nouveau - une semaine) à SELinux. Je pensais que lorsque vous le mettez en veille ( getenforce rapportant "Permissif") il n'interfère plus...

Apparemment, j'avais tort. Nous retournons dans le terrier du lapin...

Cela pourrait-il être dû au contexte de mon processus ?

Rappelez-vous que id a retourné... "uid=0(Root) gid=0(Root)... context=u:r:shell:s0 "

Puis-je changer ce contexte ? Étant Root et tout, puis-je m'éloigner de shell ? Et si oui, vers quoi ?

La réponse à la première question est 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. Mais quel contexte me permettra de mount y chroot ?

En lisant un peu plus sur SELinux, de retour dans ma machine principale, j'analyse le fichier /sepolicy sur la racine de la 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 certain nombre de possibilités ! Surtout que kernel L'un d'entre eux semble prometteur :

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

Mince.

Qui diable m'empêche de chroot de l'UE ?

Tout conseil est le bienvenu...

12voto

Adrian Pirvulescu Points 3671

Qui diable m'empêche de faire un chrooting ?

Ce n'était pas SELinux - c'était une chasse à l'oie sauvage ( getenforce renvoyant "Permissive" signifie que SELinux n'est effectivement plus dans le coup).

Le coupable - après avoir ajouté un certain nombre de printk dans le source du noyau pour tracer les défaillances des deux chroot y mount - s'est avéré être capacités . Plus précisément, le "capability bounding set" (ensemble de capacités) d'Android - vous pouvez lire tout ce qui s'y rapporte via votre man ( man 7 capabilities ) et j'avoue que je n'ai jamais pris la peine de m'y intéresser - mes tâches UNIX quotidiennes en dépendaient et je n'en avais aucune idée... essayez ceci dans votre boîte linux pour voir par vous-même :

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

Vous voyez ? Ping n'est plus SUID Root - il utilise des informations stocké dans les attributs étendus du système de fichiers pour savoir qu'il a accès à la couche raw sockets (pour qu'il puisse faire son truc ICMP, c'est-à-dire au niveau IP).

Quoi qu'il en soit, je m'éloigne du sujet - le point de chirurgie dans mon noyau où j'ai arrêté le "laisser tomber mes capacités" - d'une manière sans doute dégoûtante, "les laisser tous entrer" - était ceci ( 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;
}

Cela signifie que les capacités ne sont JAMAIS abandonnées - une configuration très sûre, en effet :-)

$ 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

Bonjour, ma douce Debian :-)

Oh, et "Root checker" fonctionne aussi - j'ai coupé "su.c", donc tout le monde dans ma tablette peut devenir 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;
  //}

Maintenant qu'il fonctionne, je dois le faire fonctionner correctement, c'est-à-dire ne permettre qu'à ma termux y Terminal Emulator les utilisateurs à invoquer su y chroot et ne pas laisser entrer tout le monde et leur grand-mère :-)

androidalle.com

AndroidAlle est une communauté de androiders où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X