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:
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.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.
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:
type=AVC
Der Protokolltyp. Diesen finde ich nur in der Datei audit.log.
msg=audit(1384529907.797:27)
Der Zeitstempel in Sekunden seit epoch, also seit dem ersten Januar 1970. Diesen kann ich mit
date -d @1384529907
in ein besser lesbares Format umwandeln.avc
Nochmal der Protokolltyp, also ein AVC-Eintrag.
denied
Wie SELinux entschieden hat, entweder denied oder granted. Im permissive Mode steht hier ein denied, auch wenn die Operation dann ausgeführt wurde.
{ execute }
Die Operation, für die um Erlaubnis gefragt wurde. Das können auch mehrere Operationen sein.
for pid=2347
Die ID des Prozesses, der die Aktion ausführen wollte.
comm="hello"
Der Befehl (ohne Optionen und auf 15 Zeichen beschränkt), den der Prozess ausführt, dessen Operation abgewiesen wurde.
path="/lib/i686/cmov/libc-2.11.3.so"
Die Zieldatei der Operation. Dazu muss man wissen, dass /lib/i686/cmov/libc-2.11.3.so die Standard-C-Bibliothek ist, die das Programm hello als eine der ersten öffnet und mit mmap() und dem Argument
PROT_EXEC
in seinen Speicherbereich einblenden will.Das bedeutet, dass der execve() Systemaufruf bereits ausgeführt wurde, aber SELinux das Laden der Standard-C-Bibliothek unterbunden hat.
dev=sda1
Das Gerät (Dateisystem), auf dem sich die Zieldatei der Operation befindet.
ino=105872
Die Inodenummer auf dem Gerät. Um die entsprechende Datei zu finden, ermittle ich zunächst den Mountpoint des Gerätes und verwende dann
find
:# mntpnt="$(mount|grep sda1\ on|cut -f3 -d\ )" # find $mntpnt -xdev -inum 105872
scontext=unconfined_u:unconfined_r:haifux_t:s0-s0:c0.c1023
Der Quellcontext (source context) des Prozesses (die Domain).
tcontext=system_u:object_r:lib_t:s0 tclass=file
Der Zielkontext (target context) der Ressource, auf die zugegriffen werden soll, in diesem Fall die Datei.
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