SELinux- und Chroot-Systemaufruf

TL; DR: Dies ist eine Frage zum letzten Schritt in einem tragbaren, entwicklerorientierten Rooting-Prozess, der auf allen Android-Geräten funktioniert. Es basiert nicht auf einem Exploit – es ist etwas, was wir als Entwickler rechtlich und moralisch auf unseren eigenen Maschinen tun dürfen. Wenn ich eine Antwort erhalte und es schaffe, in meinem Debian zu chrooten, werde ich einen prägnanten Blog-Beitrag erstellen, der alle Schritte dieses Prozesses für alle anderen Entwickler aufführt, die Root-Zugriff auf ihre Tablets wünschen - und nicht auf zweifelhafte Herkunft vertrauen wollen "Ein-Klick-Roots", die Gott-weiß-was mit ihren Maschinen machen (Botnet-Mitglieder?) ... Die einzigen Abhängigkeiten sind die Kernelquellen der Maschine (zu deren Bereitstellung der Hersteller gesetzlich verpflichtet ist) und das Boot-Partitions-Image (boot.img), das zu 99 % in den vom Hersteller bereitgestellten Over-the-Air-Updates enthalten ist oder einzeln als eigenständiges Flash-fähiges Image heruntergeladen werden kann.

So verging eine Woche, in der ich meine gesamte Freizeit auf meinem neuen Android-Tablet verbrachte.

Und es ist mir fast vollständig gelungen, einen tragbaren, entwicklerorientierten Prozess zu erstellen, um Root in meinem Android 5.0.2-Tablet zu erreichen.

Aber eine Sache fehlt noch – ich kann keine Chroot erstellen (die ich brauche, um mein debootstrap-ed Debian auszuführen!)

Was ich bisher gemacht habe

  1. Zuerst habe ich einen kleinen Patch in den (vom Hersteller bereitgestellten) Kernelquellen meines Tablets durchgeführt und dann meinen eigenen Kernel kompiliert - wo ich die Prüfungen zum Ändern des SELINUX-Erzwingungsmodus deaktiviert habe . Speziell...

Im 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. Ich habe dann meine initrd-Images so geändert, dass sie Folgendes /default.propenthalten: ro.secure=0undro.debuggable=1

  2. Da es bei meinem Hersteller initrd.imgfehlte, habe ich auch su.cvon https://android.googlesource.com/platform/system/extras/+/master/su/ kompiliert und die resultierende Binärdatei unter platziert /sbin/su, wobei ich darauf geachtet habe, dass sie auf SUID root ( chmod 04755 /sbin/su) gesetzt ist. .

Danach habe ich den neuen Kernel und die neue initrd gepackt, wie ich es in Episode 2 meines vorherigen Posts erklärt habe - und von meinem eigenen Image gebootet:

adb reboot boot-loader ; fastboot boot myboot.img

Also bist du root?

Ja, es schien zunächst erfolgreich zu sein:

$ 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

Und ich habe jetzt root erreicht:

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

Ich bin mir zu 100% sicher, dass ich root bin - nicht nur, weil ides so steht, sondern weil ich auch Dinge tun kann, die normale Prozesse definitiv nicht können:

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)

Und siehe da – endlich kann ich Raw-Partitionen aus meinem Tablet auslesen!

Und SELinux ist tatsächlich im "down, dog"-Modus:

root@K01E_2:/ # getenforce                                                     
Permissive

Aber ... es gibt immer noch Dinge, die ich nicht tun kann:

root@K01E_2:/ # mkdir /my_mnt

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

Das heißt, ich kann meine EXT4-fs-formatierte zweite Partition meiner externen SD-Karte nicht mounten.

Ich kann auch nicht zu meinem schönen debootstrap-ed Debian chrooten:

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

Liegt es an SELinux?

Ich weiß nicht - ich bin neu (sehr neu - eine Woche alt) bei SELinux. Ich dachte, wenn Sie es in den Ruhezustand versetzen (mit getenforce"Permissive" melden), stört es nicht mehr ...

Anscheinend lag ich falsch. Wir gehen wieder in den Kaninchenbau ...

Könnte es an meinem Prozesskontext liegen?

Denken Sie daran, dass idzurückgegeben wurde ... "uid=0(root) gid=0(root)... context=u:r:shell:s0 "

Kann ich diesen Kontext ändern? Kann ich mich als Root und so von wegbewegen shell? Und wenn ja, wozu wechseln?

Die Antwort auf die erste Frage lautet 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

Gut. Aber welcher Kontext erlaubt es mir, mountund chroot?

Wenn ich etwas mehr über SELinux lese, analysiere ich auf meinem Hauptcomputer die /sepolicyDatei im Stammverzeichnis von 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, mehrere Möglichkeiten! Besonders das kernelscheint vielversprechend zu sein:

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

Verflixt.

Wer zum Teufel hindert mich daran chroot?

Jeder Ratschlag ist willkommen...

Antworten (1)

Wer zum Teufel hindert mich am Chrooten?

Es war nicht SELinux - das war eine wilde Gänsejagd ( getenforcedie Rückkehr von "Permissive" bedeutet, dass SELinux tatsächlich nicht mehr im Bild ist).

Der Übeltäter – nach dem Hinzufügen einer ganzen Reihe von in den Kernel-Quellen, um die Fehler von beiden und printknachzuvollziehen – stellte sich als Capabilities heraus . Genauer gesagt, das "Capability Bounding Set" von Android - Sie können alles über Ihr ( ) lesen und ich gestehe, ich habe mich noch nie damit beschäftigt - meine alltäglichen UNIX-Aufgaben hingen davon ab und ich hatte keine Ahnung ... probieren Sie es aus Ihre Linux-Box, um es selbst zu sehen:chrootmountmanman 7 capabilities

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

Sehen? Ping ist nicht länger SUID-Root - es verwendet Informationen , die in den erweiterten Attributen des Dateisystems gespeichert sind, um zu wissen, dass es Zugriff auf die Raw-Sockets-Schicht hat (damit es seine ICMP-Sache ausführen kann - also auf IP-Ebene).

Wie auch immer, ich schweife ab – der Operationspunkt in meinem Kernel, an dem ich das „Drop My Capabilities Set“ gestoppt habe – in einer wohl ekelhaften „Lasst sie alle einmarschieren“-Manier – war dies ( 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;
}

Das bedeutet, dass Fähigkeiten NIEMALS verloren gehen - in der Tat eine sehr sichere Konfiguration :-)

$ 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

Hallo, mein süßer Debian :-)

Oh, und "Root checker" funktioniert auch - ich habe "su.c" ausgeschnitten, damit jeder in meinem Tablet root werden kann:

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;
  //}

Jetzt, wo es funktioniert, muss ich dafür sorgen, dass es richtig funktioniert - dh nur meinen termuxund Terminal EmulatorBenutzern erlauben, und aufzurufen su, chrootund nicht alle und ihre Großmutter hereinzulassen :-)

Erfordert diese Root-Methode nicht die Fähigkeit, Ihren eigenen Kernel zu flashen? Und dazu ist ein entsperrter Bootloader erforderlich. An diesem Punkt können Sie auch einfach eine benutzerdefinierte Wiederherstellung flashen und auf diese Weise root werden.
@1110101001 Für den Bootloader: offensichtlich ja. Zur benutzerdefinierten Wiederherstellung: Für mein Tablet gibt es so etwas (noch) nicht - ich bin jetzt aber in der Lage, eine zu erstellen ;-)
@ 1110101001: Und noch etwas - Sie sagten "Fähigkeit zum Flashen" - ich habe mein Boot-Image nicht auf das Tablet geflasht, ich boote nur davon: fastboot boot my.img. Ich glaube, die Rooting-Community nennt das ein Tethering -Rooting :-) Und natürlich könnte ich es flashen - wenn ich wollte.