SELinux prüfen

Android empfiehlt OEMs dringend, ihre SELinux-Implementierungen gründlich zu testen. Wenn Hersteller SELinux implementieren, sollten sie die neue Richtlinie zuerst auf einen Testpool von Geräten anwenden.

Prüfen Sie nach dem Anwenden einer neuen Richtlinie, ob SELinux auf dem Gerät im richtigen Modus ausgeführt wird. Geben Sie dazu den Befehl getenforce ein.

Damit wird der globale SELinux-Modus ausgegeben: entweder „Erzwingen“ oder „Moderat“. Um den SELinux-Modus für jede Domain zu ermitteln, müssen Sie die entsprechenden Dateien prüfen oder die neueste Version von sepolicy-analyze mit dem entsprechenden Flag (-p) ausführen, das in /platform/system/sepolicy/tools/ vorhanden ist.

Ablehnungen lesen

Prüfen Sie auf Fehler, die als Ereignisprotokolle an dmesg und logcat weitergeleitet und lokal auf dem Gerät angezeigt werden. Hersteller sollten die SELinux-Ausgabe an dmesg auf diesen Geräten prüfen und die Einstellungen vor der Veröffentlichung im permissiven Modus optimieren und gegebenenfalls in den Erzwingungsmodus wechseln. SELinux-Logmeldungen enthalten avc: und können daher leicht mit grep gefunden werden. Sie können die laufenden Ablehnungslogs durch Ausführen von cat /proc/kmsg oder Ablehnungslogs aus dem vorherigen Start mit cat /sys/fs/pstore/console-ramoops erfassen.

SELinux-Fehlermeldungen sind nach Abschluss des Bootvorgangs begrenzt, um ein Datenüberlastung der Logs zu vermeiden. Wenn Sie alle relevanten Nachrichten sehen möchten, können Sie diese Funktion deaktivieren, indem Sie adb shell auditctl -r 0 eingeben.

Anhand dieser Ausgabe können Hersteller leicht erkennen, ob Systemnutzer oder ‑komponenten gegen die SELinux-Richtlinie verstoßen. Hersteller können dieses Fehlverhalten dann beheben, entweder durch Änderungen an der Software, an der SELinux-Richtlinie oder an beiden.

Insbesondere geben diese Logeinträge an, welche Prozesse im Erzwingungsmodus fehlschlagen und warum. Hier ein Beispiel:

avc: denied  { connectto } for  pid=2671 comm="ping" path="/dev/socket/dnsproxyd"
scontext=u:r:shell:s0 tcontext=u:r:netd:s0 tclass=unix_stream_socket

Interpretieren Sie diese Ausgabe so:

  • Das { connectto } oben steht für die ausgeführte Aktion. Zusammen mit dem tclass am Ende (unix_stream_socket) gibt er an, was ungefähr damit gemacht wurde. In diesem Fall wurde versucht, eine Verbindung zu einem Unix-Stream-Socket herzustellen.
  • Die scontext (u:r:shell:s0) gibt Aufschluss darüber, in welchem Kontext die Aktion ausgelöst wurde. In diesem Fall wird dies als Shell ausgeführt.
  • tcontext (u:r:netd:s0) gibt den Kontext des Ziels der Aktion an. In diesem Fall ist das ein unix_stream_socket, dessen Eigentümer netd ist.
  • Das Symbol comm="ping" oben gibt Ihnen einen zusätzlichen Hinweis darauf, was zum Zeitpunkt der Ablehnung ausgeführt wurde. In diesem Fall ist das ein ziemlich guter Hinweis.

Ein weiteres Beispiel:

adb shell su root dmesg | grep 'avc: '

Ausgabe:

<5> type=1400 audit: avc:  denied  { read write } for  pid=177
comm="rmt_storage" name="mem" dev="tmpfs" ino=6004 scontext=u:r:rmt:s0
tcontext=u:object_r:kmem_device:s0 tclass=chr_file

Hier sind die wichtigsten Elemente dieser Ablehnung:

  • Aktion: Die gewünschte Aktion wird in Klammern markiert, read write oder setenforce.
  • Actor: Der Eintrag scontext (Quellkontext) stellt den Akteur dar, in diesem Fall den Daemon rmt_storage.
  • Objekt: Der Eintrag tcontext (Zielkontext) steht für das Objekt, auf das reagiert wird, in diesem Fall "kmem".
  • Ergebnis: Der Eintrag tclass (Zielklasse) gibt den Typ des Objekts an, auf das reagiert wird, in diesem Fall chr_file (Zeichengerät).

Nutzer- und Kernel-Stacks dumpen

In einigen Fällen reichen die Informationen im Ereignisprotokoll nicht aus, um die Ursache der Ablehnung zu ermitteln. Häufig ist es nützlich, die Aufrufkette, einschließlich Kernel und Userspace, zusammenzutragen, um besser zu verstehen, warum die Ablehnung aufgetreten ist.

Neuere Kernel definieren einen Tracepoint mit dem Namen avc:selinux_audited. Verwenden Sie Android simpleperf, um diesen Tracepoint zu aktivieren und die Aufrufkette zu erfassen.

Unterstützte Konfiguration

  • Linux-Kernel >= 5.10, insbesondere die Android Common Kernel-Branches mainline und android12-5.10 werden unterstützt. Der android12-5.4-Branch wird ebenfalls unterstützt. Mit simpleperf können Sie feststellen, ob der Tracepoint auf Ihrem Gerät definiert ist: adb root && adb shell simpleperf list | grep avc:selinux_audited. Bei anderen Kernelversionen können Sie die Commits dd81662 und 30969bc auswählen.
  • Es sollte möglich sein, das Ereignis zu reproduzieren, für das Sie eine Fehlerbehebung durchführen. Startzeitereignisse werden mit simpleperf nicht unterstützt. Sie können den Dienst aber möglicherweise neu starten, um das Ereignis auszulösen.

Aufrufabfolge erfassen

Der erste Schritt besteht darin, das Ereignis mit simpleperf record aufzuzeichnen:

adb shell -t "cd /data/local/tmp && su root simpleperf record -a -g -e avc:selinux_audited"

Dann sollte das Ereignis ausgelöst werden, das zur Ablehnung geführt hat. Danach sollte die Aufnahme beendet werden. In diesem Beispiel sollte das Sample mit Ctrl-c aufgenommen worden sein:

^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.

Schließlich kann simpleperf report verwendet werden, um den erfassten Stacktrace zu prüfen. Beispiel:

adb shell -t "cd /data/local/tmp && su root simpleperf report -g --full-callgraph"
[...]
Children  Self     Command  Pid   Tid   Shared Object                                   Symbol
100.00%   0.00%    dmesg    3318  3318  /apex/com.android.runtime/lib64/bionic/libc.so  __libc_init
       |
       -- __libc_init
          |
           -- main
              toybox_main
              toy_exec_which
              dmesg_main
              klogctl
              entry_SYSCALL_64_after_hwframe
              do_syscall_64
              __x64_sys_syslog
              do_syslog
              selinux_syslog
              slow_avc_audit
              common_lsm_audit
              avc_audit_post_callback
              avc_audit_post_callback

Die obige Aufrufkette ist eine einheitliche Kernel- und Userspace-Aufrufkette. Sie erhalten einen besseren Überblick über den Codefluss, da die Verfolgung vom Userspace bis hinunter zum Kernel gestartet wird, wo die Deaktivierung erfolgt. Weitere Informationen zu simpleperf finden Sie in der Referenz zu ausführbaren Simpleperf-Befehlen.

In Modus „Moderat“ wechseln

Die SELinux-Erzwigung kann mit adb bei Userdebug- oder eng-Builds deaktiviert werden. Wechseln Sie dazu zuerst von ADB zum Root. Führen Sie dazu adb root aus. Führen Sie dann folgenden Befehl aus, um die SELinux-Erzwingung zu deaktivieren:

adb shell setenforce 0

Oder in der Kernel-Befehlszeile (während der frühen Geräteeinrichtung):

androidboot.selinux=permissive
androidboot.selinux=enforcing

Oder über bootconfig in Android 12:

androidboot.selinux=permissive
androidboot.selinux=enforcing

audit2allow verwenden

Das audit2allow-Tool wandelt dmesg-Abweisungen in entsprechende SELinux-Richtlinien anweisungen um. Dadurch kann die SELinux-Entwicklung enorm beschleunigt werden.

Führen Sie folgenden Befehl aus, um sie zu verwenden:

adb pull /sys/fs/selinux/policy
adb logcat -b events -d | audit2allow -p policy

Dennoch müssen Sie jede potenzielle Ergänzung auf zu weitreichende Berechtigungen prüfen. Wenn Sie beispielsweise mit audit2allow die zuvor gezeigte Ablehnung rmt_storage übergeben, ergibt sich die folgende vorgeschlagene SELinux-Richtlinienanweisung:

#============= shell ==============
allow shell kernel:security setenforce;
#============= rmt ==============
allow rmt kmem_device:chr_file { read write };

Dadurch hätte rmt die Möglichkeit, Kernel-Speicher zu schreiben, was eine eklatante Sicherheitslücke darstellt. Häufig sind die audit2allow-Anweisungen nur ein Ausgangspunkt. Nachdem Sie diese Anweisungen verwendet haben, müssen Sie möglicherweise die Quelldomain und das Label des Ziels ändern sowie geeignete Makros einfügen, um eine gute Richtlinie zu erhalten. Manchmal führt die geprüfte Ablehnung nicht zu einer Richtlinienänderung. Stattdessen sollte die App geändert werden.