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 dertclass
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, dernetd
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
odersetenforce
. - Akteur – Der
scontext
Eintrag (Quellkontext) stellt den Akteur dar, in diesem Fall denrmt_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 einechr_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.