SELinux: Warum erhalte ich die Fehlermeldung „Permission denied“, obwohl die Berechtigungen korrekt sind?

Linux 5 Min. Lesezeit

Auf AlmaLinux, Rocky Linux und anderen RHEL-basierten Systemen ist SELinux (Security-Enhanced Linux) standardmäßig aktiviert. Zusätzlich zu den üblichen Dateiberechtigungen (siehe: Dateiberechtigungen (chmod, chown) unter Linux) weist es jeder Datei, jedem Prozess und jedem Port ein Sicherheitslabel (Kontext) zu und lässt nur das zu, was die Richtlinien ausdrücklich erlauben. Wird beispielsweise der Webserver gehackt, verhindert SELinux, dass der Angreifer im Namen des Webservers auf andere Teile des Systems zugreifen kann.

Dies hat zur Folge, dass von den Standard-Einstellungen abweichende Konfigurationen (eigenes Webverzeichnis, nicht standardmäßiger Port, ausgehende Verbindungen des Webservers) den Fehler „Permission denied“ auslösen können, selbst wenn die chmod- und chown-Einstellungen korrekt sind. In solchen Fällen deaktivieren viele Nutzer SELinux, obwohl der Fehler in der Regel mit einem einzigen Befehl behoben werden kann.

Ubuntu und Debian verwenden nicht SELinux, sondern AppArmor; dort trifft dieser Artikel nicht zu. Auf cPanel-Servern muss SELinux deaktiviert sein, da cPanel dies nicht unterstützt.

Ist die Funktion aktiviert?

getenforce
sestatus
  • Enforcing (Durchsetzung): SELinux ist aktiv und blockiert regelwidrige Vorgänge.
  • Permissive: Verstöße werden lediglich protokolliert, jedoch nicht gesperrt.
  • „Disabled“: ist deaktiviert.

Ist SELinux die Ursache für den Fehler?

SELinux protokolliert jede Sperrung als AVC-Meldung. Die letzten Sperrungen:

sudo ausearch -m AVC -ts recent

Sollte gleichzeitig mit dem Fehler hier eine Zeile mit dem Vermerk „denied“ erscheinen, wird der Fehler durch SELinux verursacht. Ein typischer Eintrag:

type=AVC msg=audit(...): avc:  denied  { read } for  pid=1234 comm="httpd"
  name="index.html" scontext=system_u:system_r:httpd_t:s0
  tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file

Daraus lässt sich ableiten, dass der Webserver (httpd_t) die Datei „index.html“ nicht lesen konnte, da deren Tag „admin_home_t“ lautet (sie wurde im Stammverzeichnis erstellt).

ausearch liest das Protokoll nur dann automatisch ein, wenn Sie es über das Terminal ausführen. Geben Sie bei der Ausführung über ein Skript oder einen Cron-Job zusätzlich den Schalter --input-logs an (sudo ausearch --input-logs -m AVC -ts recent), andernfalls liest das Programm die Standardeingabe ein und gibt die Antwort <no matches> zurück. -ts recent bezieht sich auf die letzten 10 Minuten.

Als schnellen Test können Sie vorübergehend in den toleranten Modus wechseln; wenn der Fehler dadurch behoben wird, wurde er mit Sicherheit durch SELinux verursacht:

sudo setenforce 0   # Permissive
# ... próbálja ki újra ...
sudo setenforce 1   # vissza Enforcing módba

Das Programm „audit2why“ erläutert die Gründe für Sperrungen auch in verständlicher Sprache:

sudo ausearch -m AVC -ts recent | audit2why

Die folgenden Befehle „semanage“, „audit2why“ und „audit2allow“ sind im Paket „policycoreutils-python-utils-python-utils“ enthalten:

sudo dnf install policycoreutils-python-utils

1. Fehlerhafte Dateinamen

Der häufigste Fall: Eine Datei wurde an anderer Stelle erstellt (beispielsweise im Verzeichnis „/root“ oder „/home“) und anschließend mit dem Befehl „mv“ in das Webverzeichnis verschoben. Der Befehl „mv“ behält den ursprünglichen Dateinamen bei, sodass der Webserver die Datei nicht lesen kann. (Der Befehl „cp“ weist der Kopie den Dateinamen des Zielverzeichnisses zu.)

Tags anzeigen:

ls -Z /var/www/html

Zurücksetzen der Tags auf die Standardeinstellungen:

sudo restorecon -Rv /var/www/html

Auf einem Testrechner mit AlmaLinux 10 führte die Datei „index.html“, die im Verzeichnis „/root“ erstellt und anschließend mit dem Befehl „mv“ in das Webverzeichnis verschoben wurde, zu einem 403-Fehler. Im Protokoll war die Zugriffsverweigerung vermerkt, und nach dem Befehl „restorecon“ wurde die Seite mit dem Statuscode 200 geladen:

Fehlerhafte SELinux-Dateibeschriftung unter AlmaLinux 10: Laut „ls -Z“ lautet die Dateibeschriftung „admin_home_t“, der Webserver gibt einen 403-Fehler zurück, der Befehl „ausearch denied getattr“ zeigt den „httpd“-Prozess an, „restorecon“ korrigiert die Beschriftung auf „httpd_sys_content_t“, woraufhin die Antwort 200 lautet.

Eigenes Webverzeichnis

Sollte sich die Website nicht unter „/var/www“ befinden (z. B. unter „/srv/www“), legen Sie SELinux fest, dass es sich hierbei ebenfalls um Webinhalte handelt, und nehmen Sie anschließend folgende Kennzeichnungen vor:

sudo semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"
sudo restorecon -Rv /srv/www

Für jene Verzeichnisse, in die die Webanwendung auch schreiben muss (Uploads, Cache), stellen Sie bitte die Option „Schreibbar“ ein:

sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/wp-content/uploads(/.*)?"
sudo restorecon -Rv /var/www/html/wp-content/uploads

Die Tags können auch mit dem Befehl „chcon“ geändert werden, jedoch geht das so festgelegte Tag nach dem nächsten „restorecon“ oder einer vollständigen Neuvergabe von Tags verloren; für eine dauerhafte Einstellung ist „semanage fcontext“ die richtige Methode.

2. Logische Operatoren (Boolesche Operatoren)

Viele gängige Anforderungen lassen sich über die SELinux-Schalter erfüllen. Die Schalter für den Webserver lauten:

getsebool -a | grep httpd

Am häufigsten werden folgende Funktionen benötigt:

Weiterleitung Wann ist dies erforderlich?
httpd_can_network_connect PHP stellt eine externe Verbindung her (API-Aufrufe, cURL) oder leitet als Nginx-/Apache-Proxy Daten an eine Anwendung weiter (Node.js, Python)
httpd_can_network_connect_db PHP ist mit einer Datenbank verbunden, die sich auf einem anderen Server befindet
httpd_can_sendmail PHP versendet E-Mails mit der Funktion „mail()“
httpd_unified Der Webserver kann auch alle Webinhalte schreiben (bequem, aber weniger sicher)

Dauerhaft aktivieren (ohne den Parameter -P wird die Einstellung beim Neustart zurückgesetzt):

sudo setsebool -P httpd_can_network_connect on

Im Test versuchte ein PHP-Skript, mithilfe von cURL auf eine externe HTTPS-Seite zuzugreifen. Bei deaktiviertem Schalter (httpd_can_network_connect --> off, dies ist der Standardwert) gab cURL den Fehler 7 aus („Failed to connect to … port 443 … Could not connect to server“); nach der Aktivierung lautete die Antwort 200. In WordPress wird dies als Meldung „cURL-Fehler 7“ angezeigt (siehe: cURL-Fehler 28 und 60 in WordPress).

3. Nicht standardmäßige Ports

Wenn Sie einen Dienst nicht auf seinem Standardport ausführen, müssen Sie dies auch SELinux mitteilen. Das häufigste Beispiel ist die Änderung des SSH-Ports (siehe: Sicherheitseinstellungen für den SSH-Server): Wenn Sie dies versäumen, startet der „sshd“-Dienst nach einem Neustart nicht und Sie können sich möglicherweise vom Server aussperren.

sudo semanage port -a -t ssh_port_t -p tcp 2255

Bei einem Webserver (beispielsweise 8888 statt 8080):

sudo semanage port -a -t http_port_t -p tcp 8888

Die bereits freigegebenen Ports: sudo semanage port -l | grep -E "ssh|http".

4. Sonderregel, falls andere Lösungen nicht helfen

Sollte keine der oben genannten Lösungen helfen, erstellt „audit2allow“ aus den protokollierten Sperrungen ein individuelles Regelmodul:

sudo ausearch -m AVC -ts recent | audit2allow -M sajat_szabaly
sudo semodule -i sajat_szabaly.pp

Bitte überprüfen Sie vor der Installation die erstellte Datei „sajat_szabaly.te“ und lassen Sie nur das zu, was tatsächlich erforderlich ist.

Muss SELinux deaktiviert werden?

Wir raten davon ab. Sollte eine Anwendung dennoch nicht damit funktionieren, können Sie anstelle einer vollständigen Deaktivierung nur den betreffenden Dienst in den toleranten Modus versetzen, beispielsweise den Webserver:

sudo semanage permissive -a httpd_t

Sollten Sie SELinux dennoch deaktivieren müssen, bewirkt die Einstellung „SELINUX=disabled“ in der Datei „/etc/selinux/config“ ab AlmaLinux 9 keine vollständige Deaktivierung mehr; geben Sie stattdessen den entsprechenden Wert als Kernel-Parameter an und starten Sie den Server anschließend neu:

sudo grubby --update-kernel ALL --args selinux=0

Wenn Sie den Server später wieder einschalten, muss das gesamte Dateisystem neu gekennzeichnet werden (Befehl „sudo touch /.autorelabel“, gefolgt von einem Neustart), was einige Zeit in Anspruch nehmen kann.

Zurück: Linux-Artikel (62)