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 eine Testgruppe 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. Verwenden Sie dazu den Befehl getenforce.

Dadurch wird der globale SELinux-Modus ausgegeben: entweder „Enforcing“ oder „Permissive“. Um den SELinux-Modus für jede Domain zu ermitteln, müssen Sie die entsprechenden Dateien untersuchen oder die aktuelle Version von sepolicy-analyze mit dem entsprechenden Flag (-p) ausführen, das in /platform/system/sepolicy/tools/ enthalten ist.

Ablehnungen lesen

Prüfen Sie auf Fehler, die als Ereignisprotokolle an dmesg und logcat weitergeleitet werden und lokal auf dem Gerät angezeigt werden können. Hersteller sollten die SELinux-Ausgabe für dmesg auf diesen Geräten prüfen und die Einstellungen vor der öffentlichen Veröffentlichung im zulässigen Modus und dem eventuellen Wechsel in den Erzwingungsmodus optimieren. SELinux-Logmeldungen enthalten avc: und können daher leicht mit grep gefunden werden. Sie können die aktuellen Ablehnungslogs mit cat /proc/kmsg oder Ablehnungslogs vom vorherigen Bootvorgang mit cat /sys/fs/pstore/console-ramoops erfassen.

SELinux-Fehlermeldungen werden nach dem Booten begrenzt, um zu verhindern, dass die Logs überflutet werden. Wenn Sie alle relevanten Nachrichten sehen möchten, können Sie diese Funktion mit adb shell auditctl -r 0 deaktivieren.

Anhand dieser Ausgabe können Hersteller leicht erkennen, wann Systemnutzer oder Komponenten gegen die SELinux-Richtlinie verstoßen. Hersteller können dieses unerwünschte Verhalten dann beheben, indem sie die Software, die SELinux-Richtlinie oder beides ändern.

Konkret geben diese Logmeldungen an, welche Prozesse im Erzwingungsmodus fehlschlagen würden 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

So interpretieren Sie diese Ausgabe:

  • Das { connectto } oben steht für die ausgeführte Aktion. Zusammen mit dem tclass am Ende (unix_stream_socket) wird ungefähr angegeben, was mit was gemacht wurde. In diesem Fall wurde versucht, eine Verbindung zu einem UNIX-Stream-Socket herzustellen.
  • Der scontext (u:r:shell:s0) gibt an, in welchem Kontext die Aktion initiiert wurde. In diesem Fall wird etwas als Shell ausgeführt.
  • tcontext (u:r:netd:s0) gibt den Kontext des Aktionsziels an. In diesem Fall ist das ein UNIX-Stream-Socket, der netd gehört.
  • Die 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 versuchte Aktion wird in Klammern hervorgehoben, read write oder setenforce.
  • Akteur: Der Eintrag scontext (Quellkontext) stellt den Akteur dar, in diesem Fall den rmt_storage-Daemon.
  • Objekt: Der Eintrag tcontext (Zielkontext) stellt das Objekt dar, auf das sich die Aktion bezieht, in diesem Fall „kmem“.
  • Ergebnis: Der Eintrag tclass (Zielklasse) gibt den Typ des Objekts an, auf das sich die Aktion bezieht. In diesem Fall ist es ein chr_file (Zeichengerät).

Nutzer- und Kernel-Stacks ausgeben

In einigen Fällen reichen die Informationen im Ereignisprotokoll nicht aus, um den Ursprung der Ablehnung zu ermitteln. Es ist oft hilfreich, die Aufrufkette, einschließlich Kernel und Nutzerbereich, zu erfassen, um besser nachvollziehen zu können, warum die Ablehnung erfolgt ist.

In aktuellen Kernels ist ein Tracepoint mit dem Namen avc:selinux_audited definiert. Verwenden Sie Android simpleperf, um diesen Tracepoint zu aktivieren und die Aufrufkette zu erfassen.

Unterstützte Konfiguration

  • Linux-Kernel >= 5.10, insbesondere Android Common Kernel-Zweige mainline und android12-5.10 werden unterstützt. Der Branch android12-5.4 wird ebenfalls unterstützt. Sie können simpleperf verwenden, um festzustellen, 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.
  • Das Ereignis, das Sie debuggen, sollte reproduzierbar sein. Boot-Zeit-Ereignisse werden von simpleperf nicht unterstützt. Sie können den Dienst jedoch möglicherweise neu starten, um das Ereignis auszulösen.

Aufrufkette 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"

Anschließend sollte das Ereignis ausgelöst werden, das die Ablehnung verursacht hat. Danach sollte die Aufnahme beendet werden. In diesem Beispiel sollte die Probe durch die Verwendung von Ctrl-c erfasst 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. So erhalten Sie einen besseren Überblick über den Codefluss, da der Trace im Nutzerbereich beginnt und bis zum Kernel reicht, wo die Ablehnung erfolgt. Weitere Informationen zu simpleperf finden Sie in der Referenz zu ausführbaren Simpleperf-Befehlen.

Auf „permissiv“ umstellen

Die SELinux-Durchsetzung kann mit adb auf Userdebug- oder Eng-Builds deaktiviert werden. Wechseln Sie dazu zuerst mit dem Befehl adb root zu ADB-Root. Führen Sie dann den folgenden Befehl aus, um die SELinux-Durchsetzung zu deaktivieren:

adb shell setenforce 0

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

androidboot.selinux=permissive
androidboot.selinux=enforcing

Oder über bootconfig in Android 12:

androidboot.selinux=permissive
androidboot.selinux=enforcing

audit2allow verwenden

Das audit2allow-Tool verwendet dmesg-Verweigerungen und konvertiert sie in entsprechende SELinux-Richtlinienanweisungen. Daher kann es die SELinux-Entwicklung erheblich beschleunigen.

Führen Sie Folgendes aus, um sie zu verwenden:

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

Dennoch muss jede potenzielle Ergänzung auf überzogene Berechtigungen geprüft werden. Wenn Sie audit2allow beispielsweise die oben gezeigte rmt_storage-Verweigerung übergeben, wird die folgende SELinux-Richtlinienanweisung vorgeschlagen:

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

Dadurch hätte rmt die Möglichkeit, in den Kernel-Speicher zu schreiben, was eine eklatante Sicherheitslücke darstellt. Oft sind die audit2allow-Aussagen 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 sollte die abgelehnte App nicht zu Richtlinienänderungen führen, sondern die betreffende App sollte geändert werden.