weidner/archives/2013/11/

Analyse von Zugriffsproblemen unter Linux (5) - SELinux

Nach den traditionellen Dateirechten im ersten, den erweiterten Dateiattributen im zweiten, den POSIX Capabilities im dritten und AppArmor im vorigen Teil, betrachte ich in diesem Artikel der kleinen Serie SELinux unter dem Aspekt der Fehlersuche.

SELinux ist, wie AppArmor ein Mandatory Access Control System. Das heißt, die Vergabe von Rechten unter dem Einflussbereich von SELinux liegt nicht im Ermessensspielraum des Benutzers, sondern wird vom System durch Richtlinien und Regeln vorgegeben.

SELinux besteht aus einem Kernelmodul, unterstützenden Werkzeugen und Konfigurationsdateien. Die Zugriffskontrolle kann damit sehr feinkörnig eingestellt werden. Dabei funktioniert SELinux völlig unabhängig von den traditionellen Benutzernamen und Gruppen.

Wie stelle ich fest, ob SELinux aktiv ist?

Um herauszufinden, ob auf dem untersuchten System SELinux läuft, schaue ich nach, ob es ein Verzeichnis /selinux/ gibt und ob dieses Dateien enthält. Der Befehl mount sollte anzeigen, dass an diesem Punkt im Dateisystem ein selinuxfs eingehängt ist:

$ mount | grep selinux
none on /selinux type selinuxfs (rw,relatime)

Mit sestatus bekomme ich erste Informationen über den Zustand von SELinux auf dem betrachteten System:

$ sudo sestatus
SELinux status:                 enabled
SELinuxfs mount:                /selinux
Current mode:                   enforcing
Mode from config file:          permissive
Policy version:                 24
Policy from config file:        default

Bei einem konkreten Problem bekomme ich erste Hinweise durch eine Kontextabfrage:

$ ls -Z /etc/fstab 
system_u:object_r:etc_t:s0 /etc/fstab
$ ps -Z
LABEL                             PID TTY          TIME CMD
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 1215 pts/0 00:00:00 bash
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 1359 pts/0 00:00:00 ps
$ id
uid=1000(mathias) gid=1000(mathias) \
Gruppen=1000(mathias),4(adm),24(cdrom),25(floppy),27(sudo),\
29(audio),30(dip),44(video),46(plugdev) \
Kontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

Betriebsmodi

SELinux kennt zwei Modi: Im Zwangsmodus (enforcing mode) verweigert der Kernel jede Aktion, für die SELinux die Erlaubnis verweigert. Im zulassenden Modus (permissive mode) gelten die Beschränkungen des traditionellen Rechtesystems, SELinux protokolliert nur verweigerte Aktionen.

Als root kann ich zwischen beiden Modi mit dem Programm setenforce umschalten.

# setenforce 0

schaltet in den permissive Mode.

# setenforce 1

schaltet in den enforcing Mode.

Mit dem Kernelparameter enforcing=0 kann ich den permissive Mode bereits beim Rechnerstart erzwingen. Damit kann ich einem System temporär wieder auf die Beine helfen, dessen Richtlinien und Regeln überhaupt kein Arbeiten mehr erlauben.

Konzepte

Eine Richtlinie (Policy) als Grundkonzept von SELinux ist eine Sammlung von Vereinbarungen und Regeln, die dem SELinux-Kern sagen, was erlaubt ist, was nicht und wie er sich in verschiedenen Situationen verhalten soll.

Dabei unterscheidet man zwischen gezielten Richtlinien (targeted policy), die nur wenige Anwendungen einschränken und strengen Richtlinien (strict policy), die versuchen, alle Aktivitäten des Rechners mit SELinux zu kontrollieren.

Richtlinien werden kompiliert und können als Binärmodule jederzeit ge- und entladen werden. Beim Start des Rechners lädt init eine Anfangsrichtlinie (initial policy).

Das zweite wichtige Konzept bei SELinux ist der Kontext. Jeder Prozess und Socket, jede Datei und Pipe ist mit einem Kontext markiert, den ich zum Beispiel mit ps -Z, oder ls -Z erfragen kann.

Der Kontext ist unabhängig von der traditionellen UNIX-UID oder -GID. Programme mit gesetztem SUID-Bit, su oder sudo ändern den Kontext nicht:

$ id
uid=1000(mathias) gid=1000(mathias)
...
Kontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

$ sudo id
uid=0(root) gid=0(root) Gruppen=0(root)
Kontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

Der Kontext besteht aus den drei Teilen Benutzer, Rolle und Typ. Den Typ nennt man bei Prozessen Domain. Alle drei Teile sind nur Namen, die erst durch die Regeln einer Richtlinie eine Bedeutung für SELinux bekommen.

Der Kontext von Dateien wird in den erweiterten Attributen gespeichert. Mit chcon kann ich den Kontext einer Datei temporär ändern. Für dauerhafte Änderungen verwende ich setfiles.

Auf Dateisystemen ohne erweiterte Attribute, wie VFAT, ISO, NFS oder Samba, bekommen alle Dateien einen einheitlichen Kontext, entsprechend den Optionen beim Einhängen mit mount.

Informationen zu verweigerten Zugriffen finden

Die wichtigste Eigenschaft von SELinux ist, dass es alle Aktionen protokollieren kann. Damit ist wirklich alles gemeint, also sowohl genehmigte Aktionen als auch abgewiesene Aktionen. Im laufenden Betrieb ist es in den meisten Fällen nicht notwendig, jede einzelne Aktion zu protokollieren, die abgewiesenen sind auf jeden Fall interessant.

Wo ich die Protokolle von SELinux finde, hängt von der benutzten Distribution ab, meist finde ich sie unterhalb von /var/log/. Läuft auf dem System der Linux Audit Dämon, finde ich die Protokolle in /var/log/audit/audit.log oder /var/log/audit.log. Andernfalls suche ich nach einer Datei avc.log.

Beim Betrachten der Audit-Protokolle gilt es ein paar Dinge im Kopf zu behalten:

  1. Nicht jede Ablehnung die ich in den Protokollen finde, stellt ein Problem dar. Einige sind nur kosmetischer Natur, sie treten auf, beeinflussen aber das Verhalten der Anwendung nicht. Diese Ablehnungen kann ich in den Regeln durch dontaudit Anweisungen von der Protokollierung ausnehmen.

  2. Ablehnungen werden protokolliert, wenn sie auftreten. Das bedeutet, dass ich jede Menge davon sehen werde von denen viele nichts mit dem Problem zu tun haben, das ich gerade untersuche.

  3. Wenn zu viele Ablehnungen hintereinander kommen, kann es vorkommen, dass der Linux-Kernel einige unterdrückt. Wenn das passiert taucht eine Nachricht auf, die angibt wie viele Meldungen unterdrückt wurden. Das heißt dann, dass ich im Log nicht alles finde, was SELinux gemeldet hat.

Logeinträge untersuchen

In den SELinux-Tutorials im Gentoo Wiki findet sich eine gute Anleitung zur Auswertung der SELinux Protokolle.

Betrachten wir als Beispiel eine Ablehnung im audit.log des Audit-Dämons, die ich am Text type=AVC am Zeilenanfang erkenne:

type=AVC \
msg=audit(1384529907.797:27): \
avc:  \
denied  \
{ execute } \
for pid=2347 \
comm="hello" \
path="/lib/i686/cmov/libc-2.11.3.so" \
dev=sda1 ino=105872 \
scontext=unconfined_u:unconfined_r:haifux_t:s0-s0:c0.c1023 \
tcontext=system_u:object_r:lib_t:s0 tclass=file

AVC steht für Access Vector Cache.

Die einzelnen Teile bedeuten:

Versteckte Ablehnungen

Ich hatte schon angedeutet, dass kosmetische Ablehnungen, welche normalerweise nicht das Verhalten einer Anwendung beeinflussen mit dontaudit Anweisungen von der Protokollierung ausgenommen werden können.

Sollte ich bei meiner Fehlersuche den Verdacht haben, dass eine dieser versteckten Ablehnungen mein Problem verursacht, schaue ich als erstes nach, wie viele es überhaupt gab:

# seinfo --stats|grep audit
   Auditallow:         19    Dontaudit:        4601

Möchte ich die versteckten Ablehnungen im Protokoll sehen, dann kann ich mit semodule die dontaudit Anweisungen deaktivieren:

# semodule --disable_dontaudit --build

Habe ich genug davon, aktiviere ich sie wieder:

# semodule --build

Damit habe ich einen Einstieg in die Fehlersuche bei Problemen mit SELinux gegeben. Natürlich kann man damit noch nicht alle Probleme lösen, doch sollte es zumindest bei den ersten Schritten helfen.

Dieser Text wird Teil des Buches Fehlersuche bei Linux-Servern und IP-Netzwerken, an dem ich momentan arbeite. Weitere Informationen zu diesem Buch finden sich unter http://buecher.mamawe.net/buecher/troubleshoot-linux-network/.

Posted 2013-11-22
Tags: