Validierung von SELinux

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

Stellen Sie nach dem Anwenden einer neuen Richtlinie sicher, dass SELinux im richtigen Modus auf dem Gerät ausgeführt wird, indem Sie den Befehl getenforce ausgeben.

Dies gibt den globalen SELinux-Modus aus: entweder „Enforcing“ oder „Permissive“. Um den SELinux-Modus für jede Domäne zu bestimmen, müssen Sie die entsprechenden Dateien untersuchen oder die neueste Version von sepolicy-analyze mit dem entsprechenden Flag ( -p ) ausführen, das in /platform/system/sepolicy/tools/ vorhanden ist.

Leugnungen lesen

Suchen Sie nach Fehlern, die als Ereignisprotokolle an dmesg und logcat weitergeleitet werden und lokal auf dem Gerät angezeigt werden können. Hersteller sollten die SELinux-Ausgabe an dmesg auf diesen Geräten prüfen und die Einstellungen vor der öffentlichen Veröffentlichung im Permissivmodus verfeinern und schließlich in den Erzwingungsmodus wechseln. SELinux-Protokollmeldungen enthalten avc: und können daher leicht mit grep gefunden werden. Es ist möglich, die laufenden Ablehnungsprotokolle zu erfassen, indem Sie cat /proc/kmsg ausführen, oder Ablehnungsprotokolle vom vorherigen Start zu erfassen, indem cat /sys/fs/pstore/console-ramoops ausführen.

SELinux-Fehlermeldungen sind nach Abschluss des Startvorgangs ratenbegrenzt, um eine Überlastung der Protokolle zu vermeiden. Um sicherzustellen, dass Sie alle relevanten Meldungen sehen, können Sie dies deaktivieren, indem Sie adb shell auditctl -r 0 ausführen.

Mit dieser Ausgabe können Hersteller leicht erkennen, wenn Systembenutzer oder Komponenten gegen die SELinux-Richtlinien verstoßen. Hersteller können dieses schlechte Verhalten dann entweder durch Änderungen an der Software, der SELinux-Richtlinie oder beidem beheben.

Diese Protokollmeldungen geben insbesondere an, welche Prozesse im Erzwingungsmodus fehlschlagen würden und warum. Hier ist 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 folgendermaßen:

  • Das obige { connectto } stellt die ausgeführte Aktion dar. Zusammen mit der tclass am Ende ( unix_stream_socket ) erfahren Sie ungefähr, was mit was gemacht wurde. In diesem Fall wurde versucht, eine Verbindung zu einem Unix-Stream-Socket herzustellen.
  • Der scontext (u:r:shell:s0) sagt Ihnen, welcher Kontext die Aktion ausgelöst hat. In diesem Fall handelt es sich um etwas, das als Shell ausgeführt wird.
  • Der tcontext (u:r:netd:s0) teilt Ihnen den Kontext des Aktionsziels mit. In diesem Fall handelt es sich um einen unix_stream_socket, der netd gehört.
  • Der comm="ping" oben gibt Ihnen einen zusätzlichen Hinweis darauf, was zum Zeitpunkt der Ablehnung ausgeführt wurde. In diesem Fall ist es ein ziemlich guter Hinweis.

Ein anderes 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 Schlüsselelemente dieser Ablehnung:

  • Aktion – die versuchte Aktion wird in Klammern hervorgehoben, read write oder setenforce .
  • Akteur – Der scontext Eintrag (Quellkontext) stellt den Akteur dar, in diesem Fall den rmt_storage -Daemon.
  • Objekt – Der tcontext Eintrag (Zielkontext) stellt das Objekt dar, auf das reagiert wird, in diesem Fall kmem.
  • Ergebnis – Der tclass Eintrag (Zielklasse) gibt den Typ des Objekts an, auf das reagiert wird, in diesem Fall eine chr_file (Zeichengerät).

Dumping von Benutzer- und Kernel-Stacks

In einigen Fällen reichen die im Ereignisprotokoll enthaltenen Informationen nicht aus, um den Ursprung der Ablehnung genau zu bestimmen. Es ist oft nützlich, die Aufrufkette, einschließlich Kernel und Userspace, zu erfassen, um besser zu verstehen, warum die Ablehnung erfolgte.

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

Unterstützte Konfiguration

  • Linux-Kernel >= 5.10, insbesondere Android Common Kernel-Zweige Mainline und Android12-5.10 werden unterstützt. Der Android12-5.4- Zweig 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 . Für andere Kernel-Versionen können Sie die Commits dd81662 und 30969bc auswählen.
  • Es sollte möglich sein, das Ereignis, das Sie debuggen, zu reproduzieren. Startzeitereignisse werden mit simpleperf nicht unterstützt; Möglicherweise können Sie den Dienst jedoch trotzdem neu starten, um das Ereignis auszulösen.

Erfassen der Anrufkette

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 die Ablehnung verursacht hat. Danach sollte die Aufnahme gestoppt werden. In diesem Beispiel hätte das Beispiel mit Ctrl-c erfasst werden sollen:

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

Schließlich kann simpleperf report verwendet werden, um den erfassten Stacktrace zu überprüfen. Zum 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. Dadurch erhalten Sie einen besseren Überblick über den Codefluss, indem der Trace vom Userspace bis hinunter zum Kernel gestartet wird, wo die Ablehnung erfolgt. Weitere Informationen zu simpleperf finden Sie in der Referenz zu ausführbaren Simpleperf-Befehlen

Wechsel zu freizügig

Die SELinux-Erzwingung kann über ADB bei Userdebug- oder Eng-Builds deaktiviert werden. Schalten Sie dazu zunächst ADB auf Root um, indem Sie adb root ausführen. Führen Sie dann Folgendes aus, um die SELinux-Erzwingung zu deaktivieren:

adb shell setenforce 0

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

androidboot.selinux=permissive
androidboot.selinux=enforcing

Oder über bootconfig in Android 12:

androidboot.selinux=permissive
androidboot.selinux=enforcing

Verwendung von audit2allow

Das Tool audit2allow nimmt dmesg Ablehnungen entgegen und wandelt sie in entsprechende SELinux-Richtlinienanweisungen um. Dadurch kann die SELinux-Entwicklung erheblich beschleunigt werden.

Um es zu verwenden, führen Sie Folgendes aus:

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

Dennoch muss darauf geachtet werden, jede potenzielle Ergänzung auf übergreifende Berechtigungen hin zu prüfen. Wenn Sie beispielsweise audit2allow der zuvor gezeigten rmt_storage Verweigerung füttern, wird die folgende vorgeschlagene SELinux-Richtlinienanweisung angezeigt:

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

Dies würde rmt die Möglichkeit geben, in den Kernel-Speicher zu schreiben, was eine eklatante Sicherheitslücke darstellt. Oft sind die audit2allow Anweisungen nur ein Ausgangspunkt. Nach der Verwendung dieser Anweisungen müssen Sie möglicherweise die Quelldomäne und die Bezeichnung des Ziels ändern sowie geeignete Makros integrieren, um eine gute Richtlinie zu erhalten. Manchmal sollte die geprüfte Ablehnung überhaupt keine politischen Änderungen zur Folge haben; Vielmehr sollte die betreffende Anwendung geändert werden.