Schreiben einer SELinux-Richtlinie

Das Android Open Source Project (AOSP) bietet eine solide Basisrichtlinie für die Anwendungen und Dienste, die allen Android-Geräten gemeinsam sind. Mitwirkende an AOSP verfeinern diese Richtlinie regelmäßig. Es wird erwartet, dass die Kernrichtlinie etwa 90–95 % der endgültigen Richtlinie auf dem Gerät ausmacht, während gerätespezifische Anpassungen die restlichen 5–10 % ausmachen. Dieser Artikel konzentriert sich auf diese gerätespezifischen Anpassungen, wie man gerätespezifische Richtlinien schreibt und einige der Fallstricke, die es dabei zu vermeiden gilt.

Geräteaufruf

Befolgen Sie beim Schreiben einer gerätespezifischen Richtlinie die folgenden Schritte.

Im zulässigen Modus ausführen

Wenn sich ein Gerät im Permissivmodus befindet, werden Ablehnungen protokolliert, aber nicht erzwungen. Der Permissivmodus ist aus zwei Gründen wichtig:

  • Der permissive Modus stellt sicher, dass das Einschalten der Richtlinie andere frühe Geräteeinschaltaufgaben nicht verzögert.
  • Eine erzwungene Ablehnung kann andere Ablehnungen überdecken. Beispielsweise umfasst der Dateizugriff normalerweise eine Verzeichnissuche, das Öffnen der Datei und das anschließende Lesen der Datei. Im Erzwingungsmodus würde nur die Verweigerung der Verzeichnissuche erfolgen. Der permissive Modus stellt sicher, dass alle Ablehnungen gesehen werden.

Der einfachste Weg, ein Gerät in den permissiven Modus zu versetzen, ist die Verwendung der Kernel-Befehlszeile . Dies kann zur BoardConfig.mk Datei des Geräts hinzugefügt werden: platform/device/<vendor>/<target>/BoardConfig.mk . Nachdem Sie die Befehlszeile geändert haben, führen Sie make clean und dann make bootimage und flashen Sie das neue Boot-Image.

Bestätigen Sie anschließend den zulässigen Modus mit:

adb shell getenforce

Zwei Wochen sind eine angemessene Zeitspanne, um im globalen Freizügigkeitsmodus zu sein. Nachdem Sie die meisten Ablehnungen behoben haben, kehren Sie in den Durchsetzungsmodus zurück und beheben Sie auftretende Fehler. Domains, die immer noch Ablehnungen hervorrufen, oder Dienste, die sich noch in der intensiven Entwicklung befinden, können vorübergehend in den Genehmigungsmodus versetzt werden, aber versetzen Sie sie so schnell wie möglich wieder in den Durchsetzungsmodus.

Frühzeitig durchsetzen

Im Durchsetzungsmodus werden Ablehnungen sowohl protokolliert als auch durchgesetzt. Es empfiehlt sich, Ihr Gerät so früh wie möglich in den Durchsetzungsmodus zu versetzen. Das Warten auf die Erstellung und Durchsetzung gerätespezifischer Richtlinien führt oft zu einem fehlerhaften Produkt und einer schlechten Benutzererfahrung. Beginnen Sie früh genug, um am Dogfooding teilzunehmen und sicherzustellen, dass die Funktionalität im realen Einsatz vollständig getestet wird. Ein frühzeitiger Beginn stellt sicher, dass Sicherheitsbedenken in Designentscheidungen einfließen. Umgekehrt ist die Erteilung von Berechtigungen ausschließlich auf der Grundlage beobachteter Ablehnungen ein unsicherer Ansatz. Nutzen Sie diese Zeit, um eine Sicherheitsüberprüfung der Geräte- und Dateifehler auf Verhalten durchzuführen, das nicht zulässig sein sollte.

Entfernen oder löschen Sie die vorhandene Richtlinie

Es gibt eine Reihe guter Gründe, auf einem neuen Gerät eine gerätespezifische Richtlinie von Grund auf zu erstellen, darunter:

Beheben Sie Ablehnungen von Kerndiensten

Von Kerndiensten generierte Ablehnungen werden in der Regel durch Dateikennzeichnung behoben. Zum Beispiel:

avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0”
dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0
tclass=chr_file permissive=1
avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs"
scontext=u:r:mediaserver:s0
tcontext=u:object_r:device:s0 tclass=chr_file permissive=1

wird durch die ordnungsgemäße Kennzeichnung /dev/kgsl-3d0 vollständig behoben. In diesem Beispiel ist tcontext device . Dies stellt einen Standardkontext dar, in dem alles in /dev die Bezeichnung „ Gerät “ erhält, sofern keine spezifischere Bezeichnung zugewiesen wird. Das einfache Akzeptieren der Ausgabe von audit2allow würde hier zu einer falschen und übermäßig freizügigen Regel führen.

Um ein solches Problem zu lösen, geben Sie der Datei eine spezifischere Bezeichnung, in diesem Fall gpu_device . Es sind keine weiteren Berechtigungen erforderlich, da der Medienserver in der Kernrichtlinie bereits über die erforderlichen Berechtigungen für den Zugriff auf das gpu_device verfügt .

Andere gerätespezifische Dateien, die mit in der Kernrichtlinie vordefinierten Typen gekennzeichnet werden sollten:

Im Allgemeinen ist es falsch, Berechtigungen für Standardbezeichnungen zu erteilen. Viele dieser Berechtigungen werden durch Neverallow- Regeln nicht zugelassen, aber auch wenn sie nicht ausdrücklich verboten sind, empfiehlt es sich, eine bestimmte Bezeichnung bereitzustellen.

Kennzeichnen Sie neue Dienste und adressieren Sie Ablehnungen

Init-gestartete Dienste müssen in ihren eigenen SELinux-Domänen ausgeführt werden. Das folgende Beispiel fügt den Dienst „foo“ in seine eigene SELinux-Domäne ein und erteilt ihm Berechtigungen.

Der Dienst wird im init. device .rc Datei als:

service foo /system/bin/foo
    class core
  1. Erstellen Sie eine neue Domain „foo“

    Erstellen Sie die Datei device/ manufacturer / device-name /sepolicy/foo.te mit folgendem Inhalt:

    # foo service
    type foo, domain;
    type foo_exec, exec_type, file_type;
    
    init_daemon_domain(foo)
    

    Dies ist die anfängliche Vorlage für die foo SELinux-Domäne, zu der Sie Regeln hinzufügen können, die auf den spezifischen Vorgängen basieren, die von dieser ausführbaren Datei ausgeführt werden.

  2. Beschriften Sie /system/bin/foo

    Fügen Sie Folgendes zu device/ manufacturer / device-name /sepolicy/file_contexts hinzu:

    /system/bin/foo   u:object_r:foo_exec:s0
    

    Dadurch wird sichergestellt, dass die ausführbare Datei ordnungsgemäß gekennzeichnet ist, sodass SELinux den Dienst in der richtigen Domäne ausführt.

  3. Erstellen und flashen Sie die Boot- und System-Images.
  4. Verfeinern Sie die SELinux-Regeln für die Domäne.

    Verwenden Sie Ablehnungen, um die erforderlichen Berechtigungen zu ermitteln. Das Tool audit2allow bietet gute Richtlinien, verwendet es jedoch nur als Grundlage für die Erstellung von Richtlinien. Kopieren Sie nicht einfach die Ausgabe.

Wechseln Sie zurück in den Durchsetzungsmodus

Es ist in Ordnung, Fehler im permissiven Modus zu beheben, aber wechseln Sie so früh wie möglich wieder in den erzwingenden Modus und versuchen Sie, dort zu bleiben.

Häufige Fehler

Hier finden Sie einige Lösungen für häufige Fehler, die beim Schreiben gerätespezifischer Richtlinien passieren.

Übermäßiger Gebrauch der Verneinung

Die folgende Beispielregel ähnelt dem Abschließen der Haustür, aber dem Offenlassen der Fenster:

allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms

Die Absicht ist klar: Jeder außer Drittanbieter-Apps kann Zugriff auf das Debug-Gerät haben.

Die Regel weist in mehrfacher Hinsicht Mängel auf. Der Ausschluss von untrusted_app lässt sich leicht umgehen, da alle Apps optional Dienste in der Domäne isolated_app ausführen können. Wenn dem AOSP neue Domänen für Apps von Drittanbietern hinzugefügt werden, haben diese ebenfalls Zugriff auf scary_debug_device . Die Regel ist zu freizügig. Die meisten Domänen profitieren nicht vom Zugriff auf dieses Debugging-Tool. Die Regel sollte so geschrieben sein, dass nur die Domänen zugelassen werden, die Zugriff benötigen.

Debugging-Funktionen in der Produktion

Debugfunktionen sollten weder in Produktionsbuilds noch in deren Richtlinien vorhanden sein.

Die einfachste Alternative besteht darin, die Debug-Funktion nur zuzulassen, wenn SELinux in eng/userdebug-Builds deaktiviert ist, wie z. adb root und adb shell setenforce 0 .

Eine weitere sichere Alternative besteht darin, Debug-Berechtigungen in eine userdebug_or_eng- Anweisung einzuschließen.

Explosion der Policengröße

Die Charakterisierung von SEAndroid Policies in the Wild beschreibt einen besorgniserregenden Trend bei der Zunahme der Anpassung von Geräterichtlinien. Die gerätespezifische Richtlinie sollte 5–10 % der gesamten auf einem Gerät ausgeführten Richtlinie ausmachen. Anpassungen im Bereich von über 20 % beinhalten mit ziemlicher Sicherheit überprivilegierte Domänen und tote Richtlinien.

Unnötig große Police:

  • Der Speicher wird doppelt beansprucht, da sich die Richtlinie auf der Ramdisk befindet und auch in den Kernel-Speicher geladen wird.
  • Verschwendet Speicherplatz, da ein größeres Bootimage erforderlich ist.
  • Beeinflusst die Suchzeiten für Laufzeitrichtlinien.

Das folgende Beispiel zeigt zwei Geräte, bei denen die herstellerspezifische Richtlinie 50 % und 40 % der geräteinternen Richtlinie ausmachte. Eine Neufassung der Richtlinie führte zu erheblichen Sicherheitsverbesserungen ohne Einbußen bei der Funktionalität, wie unten gezeigt. (Zum Vergleich sind die AOSP-Geräte Shamu und Flounder enthalten.)

Abbildung 1: Vergleich der gerätespezifischen Richtliniengröße nach Sicherheitsüberprüfung.

Abbildung 1 . Vergleich der gerätespezifischen Richtliniengröße nach Sicherheitsüberprüfung.

In beiden Fällen wurde die Richtlinie sowohl im Umfang als auch in der Anzahl der Berechtigungen drastisch reduziert. Die Verringerung der Richtliniengröße ist fast ausschließlich auf die Entfernung unnötiger Berechtigungen zurückzuführen, bei denen es sich bei vielen wahrscheinlich um von audit2allow generierte Regeln handelte, die der Richtlinie wahllos hinzugefügt wurden. Auch tote Domains waren bei beiden Geräten ein Problem.

Gewähren der dac_override-Fähigkeit

Eine dac_override Ablehnung bedeutet, dass der fehlerhafte Prozess versucht, auf eine Datei mit den falschen Unix-Benutzer-/Gruppen-/Weltberechtigungen zuzugreifen. Die richtige Lösung besteht fast nie darin, die Berechtigung dac_override zu erteilen. Ändern Sie stattdessen die Unix-Berechtigungen für die Datei oder den Prozess . Einige Domänen wie init , vold und installd benötigen tatsächlich die Möglichkeit, Unix-Dateiberechtigungen zu überschreiben, um auf die Dateien anderer Prozesse zuzugreifen. Eine ausführlichere Erklärung finden Sie im Blog von Dan Walsh .