Appel système SELinux et chroot

21

TL; DR: Il s'agit d'une question sur la dernière étape, dans un processus d'enracinement portable, orienté développeur, qui fonctionne sur toutes les machines Android. Il n'est basé sur aucun 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 parviens à chrooter dans mon Debian, je ferai un article de blog concis détaillant toutes les étapes de ce processus pour tous les autres développeurs qui veulent un accès root à leurs tablettes - et ne veulent pas faire confiance à l'origine douteuse "racines en un clic" qui font Dieu sait quoi sur leurs machines (membres du botnet?) ... Les seules dépendances seront les sources du noyau de la machine (que le fabricant est légalement tenu de fournir) et l'image de la partition de démarrage (boot.img), soit 99% du temps dans les mises à jour Over-the-Air fournies par le fabricant, ou téléchargeables individuellement en tant qu'image autonome compatible Flash.

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

Et j'ai presque complètement réussi - à créer un processus portable, orienté développeur, pour atteindre la racine dans ma tablette Android 5.0.2.

Mais il manque encore une chose - je ne peux pas faire de chroot (dont j'ai besoin pour exécuter mon debootstrapDebian!)

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

  1. Tout d'abord, j'ai fait 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 pour changer le mode d'application de SELINUX . Plus précisément...

Dans 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 changé mes images initrd /default.proppour qu'elles contiennent: ro.secure=0etro.debuggable=1

  2. Comme mon fabricant le initrd.imgmanquait, j'ai également compilé à su.cpartir de https://android.googlesource.com/platform/system/extras/+/master/su/ et placé le binaire résultant sous /sbin/su, en m'assurant qu'il est défini sur SUID root ( chmod 04755 /sbin/su) .

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

adb reboot boot-loader ; fastboot boot myboot.img

Alors, tu es root?

Oui, il a d'abord semblé réussir:

$ 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 la racine:

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 - non seulement parce que je le dis id, mais parce que je peux aussi faire des choses que les processus normaux ne peuvent certainement pas:

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 les partitions brutes sur ma tablette!

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

root@K01E_2:/ # getenforce                                                     
Permissive

Mais ... il y a encore 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

Autrement dit, je ne peux pas monter ma 2e partition formatée EXT4-fs de ma carte SD externe.

Je ne peux pas non plus chrooter sur ma belle debootstrapDebian:

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 quand tu le mettais en veille ( getenforcesignalant "Permissif") ça n'interférait plus ...

Apparemment, j'avais tort. Au fond du terrier du lapin on repart ...

Serait-ce à cause de mon contexte de processus?

N'oubliez pas que idretourné ... "uid = 0 (root) gid = 0 (root) ... context = u: r: shell: s0 "

Puis-je changer ce contexte? Être root et tout, puis-je m'en éloigner shell? Et si oui, passez à 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 mountet chroot?

En lisant un peu plus sur SELinux, de retour sur ma machine principale, j'analyse le /sepolicyfichier à la racine du 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, plusieurs possibilités! Surtout que l' kernelon 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

Zut.

Qui diable me bloque- chroott-il?

Tous les conseils les plus bienvenus ...

ttsiodras
la source

Réponses:

12

Qui diable m'empêche de chrooter?

Ce n'était pas SELinux - c'était une chasse aux oies sauvages (le getenforceretour de "Permissive" signifie que SELinux n'est en effet plus sur la photo).

Le coupable - après avoir ajouté un certain nombre de printksources dans le noyau pour retracer les échecs des deux chrootet mount- s'est avéré être des capacités . Plus précisément, le «jeu de limites de capacités» d'Android - vous pouvez tout lire à leur sujet via votre man( man 7 capabilities) et j'avoue que je n'ai jamais pris la peine de les examiner - mes tâches UNIX quotidiennes dépendaient d'eux et je n'en avais aucune idée ... essayez ceci dans votre box 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......

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

Quoi qu'il en soit, je m'éloigne du sujet - le point de chirurgie dans mon noyau où j'ai arrêté le "jeu de mes capacités" - d'une manière sans doute dégoûtante, "laissez-les tous marcher de manière" - était-ce ( 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écurisée, 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 découpé "su.c", donc tout le monde sur 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 que cela fonctionne, je dois le faire fonctionner correctement - c'est-à-dire permettre uniquement à mes utilisateurs termuxet à moi Terminal Emulatord'invoquer suet chroot, et de ne pas laisser tout le monde et leur grand-mère entrer :-)

ttsiodras
la source
Cette méthode racine ne nécessite-t-elle pas la possibilité de flasher votre propre noyau? Et pour ce faire, il faut un chargeur de démarrage déverrouillé. À ce stade, vous pouvez tout aussi bien flasher une récupération personnalisée et vous enraciner de cette façon.
1110101001 du
@ 1110101001 Pour le chargeur de démarrage: évidemment, oui. Pour la récupération personnalisée: il n'y a rien de tel pour ma tablette - je suis maintenant en mesure d'en créer une ;-)
ttsiodras
1
@ 1110101001: Et une chose - vous avez dit « capacité de flash » - Je ne l' ai pas flashé mon image de démarrage à la tablette, je booter de lui: fastboot boot my.img. Je crois que la communauté d'enracinement appelle cela un enracinement captif :-) Et bien sûr, je pourrais le flasher - si je le voulais.
ttsiodras