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.
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
.
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 sich in /platform/system/sepolicy/tools/
.
Leugnungen lesen
Suchen Sie nach Fehlern, die als Ereignisprotokolle an dmesg
und logcat
werden und lokal auf dem Gerät angezeigt werden können. Hersteller sollten die SELinux-Ausgabe an dmesg
auf diesen Geräten untersuchen und die Einstellungen vor der Veröffentlichung im Permissive-Modus und eventuellem Wechsel in den Enforcing-Modus verfeinern. SELinux-Protokollmeldungen enthalten avc:
und können daher leicht mit grep
gefunden werden. Es ist möglich, die laufenden Verweigerungsprotokolle durch Ausführen von cat /proc/kmsg
oder Verweigerungsprotokolle vom vorherigen Booten durch Ausführen von cat /sys/fs/pstore/console-ramoops
zu erfassen.
SELinux-Fehlermeldungen sind nach Abschluss des Bootvorgangs ratenbegrenzt, um eine Überschwemmung der Protokolle zu vermeiden. Um sicherzustellen, dass Sie alle relevanten Meldungen sehen, können Sie dies deaktivieren, indem Sie adb shell auditctl -r 0
.
Mit dieser Ausgabe können Hersteller leicht erkennen, wenn Systembenutzer oder -komponenten gegen die SELinux-Richtlinie 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 wie folgt:
- Das
{ connectto }
stellt die ausgeführte Aktion dar. Zusammen mit dertclass
am Ende (unix_stream_socket
) sagt es Ihnen ungefähr, was mit was gemacht wurde. In diesem Fall hat etwas versucht, eine Verbindung zu einem Unix-Stream-Socket herzustellen. - Der
scontext (u:r:shell:s0)
sagt Ihnen, welcher Kontext die Aktion initiiert hat. In diesem Fall läuft dies als Shell. - Der
tcontext (u:r:netd:s0)
teilt Ihnen den Kontext des Aktionsziels mit. In diesem Fall ist das ein unix_stream_socket im Besitz vonnetd
. - Das
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
(Quellkontext) stellt den Akteur dar, in diesem Fall den Daemonrmt_storage
. - Objekt – Der
tcontext
(Zielkontext) stellt das Objekt dar, auf das eingewirkt wird, in diesem Fall kmem. - Ergebnis – Der
tclass
(Zielklasse) gibt den Objekttyp an, auf den eingewirkt wird, in diesem Fall einechr_file
(Zeichengerät).
Sichern von Benutzer- und Kernel-Stacks
In einigen Fällen reichen die im Ereignisprotokoll enthaltenen Informationen nicht aus, um den Ursprung der Ablehnung zu bestimmen. Es ist oft nützlich, die Anrufkette einschließlich Kernel und Benutzerbereich zu sammeln, um besser zu verstehen, warum die Ablehnung aufgetreten ist.
Neuere Kernel definieren einen Tracepoint namens avc:selinux_audited
. Verwenden Sie Android simpleperf
, um diesen Ablaufverfolgungspunkt zu aktivieren und die Anrufkette zu erfassen.
Unterstützte Konfiguration
- Linux Kernel >= 5.10, insbesondere Android Common Kernel Branches 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 Ablaufverfolgungspunkt 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 aussuchen . - Es sollte möglich sein, das Ereignis, das Sie debuggen, zu reproduzieren. Startzeitereignisse werden bei Verwendung von simpleperf nicht unterstützt; Sie können den Dienst jedoch möglicherweise immer noch neu starten, um das Ereignis auszulösen.
Erfassen der Anrufkette
Der erste Schritt besteht darin, das Ereignis mit simpleperf record
:
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 Verweigerung verursacht hat. Danach sollte die Aufnahme gestoppt werden. In diesem Beispiel sollte das Beispiel mit Ctrl-c
erfasst werden:
^Csimpleperf I cmd_record.cpp:751] Samples recorded: 1. Samples lost: 0.
Schließlich kann der simpleperf report
verwendet werden, um den erfassten Stacktrace zu untersuchen. 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. Es gibt Ihnen einen besseren Überblick über den Codefluss, indem es den Trace vom Userspace bis hinunter zum Kernel startet, wo die Verweigerung stattfindet. Weitere Informationen zu simpleperf
finden Sie in der Referenz zu ausführbaren Simpleperf-Befehlen
Umschalten auf permissiv
Die SELinux-Erzwingung kann über ADB bei Userdebug- oder Eng-Builds deaktiviert werden. Schalten Sie dazu zuerst ADB auf root um, indem Sie adb root
. 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
Verwenden von audit2allow
Das audit2allow
Tool nimmt dmesg
Verweigerungen und wandelt sie in entsprechende SELinux-Richtlinienanweisungen um. Als solches kann es die SELinux-Entwicklung erheblich beschleunigen.
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 zu prüfen. Wenn Sie beispielsweise audit2allow
der zuvor gezeigten rmt_storage
Verweigerung füttern, führt dies zu der folgenden vorgeschlagenen SELinux-Richtlinienanweisung:
#============= shell ============== allow shell kernel:security setenforce; #============= rmt ============== allow rmt kmem_device:chr_file { read write };
Dies würde rmt
die Möglichkeit geben, Kernel-Speicher zu schreiben, eine eklatante Sicherheitslücke. Oft sind die audit2allow
Anweisungen nur ein Ausgangspunkt. Nachdem Sie diese Anweisungen verwendet haben, müssen Sie möglicherweise die Quelldomäne und die Bezeichnung des Ziels ändern sowie geeignete Makros einbauen, um zu einer guten Richtlinie zu gelangen. Manchmal sollte die untersuchte Verweigerung überhaupt nicht zu irgendwelchen Richtlinienänderungen führen; vielmehr sollte die fehlerhafte Anwendung geändert werden.