SELinux: miért kapok "Permission denied" hibát, ha a jogosultságok rendben vannak?

AlmaLinux, Rocky Linux és más RHEL alapú rendszereken alapból be van kapcsolva a SELinux (Security-Enhanced Linux). A megszokott fájljogosultságokon (lásd: Fájljogosultságok (chmod, chown) Linuxon) felül minden fájlhoz, folyamathoz és porthoz egy biztonsági címkét (context) rendel, és csak azt engedi, amit a szabályzat kifejezetten megenged. Ha például a webszervert feltörik, a SELinux megakadályozza, hogy a támadó a webszerver nevében a rendszer más részeihez hozzáférjen.

Ennek az ára, hogy a szokásostól eltérő beállítások (saját webkönyvtár, nem szabványos port, a webszerver kimenő kapcsolatai) „Permission denied” hibát adhatnak, akkor is, ha a chmod és chown beállítások helyesek. Ilyenkor sokan kikapcsolják a SELinuxot, pedig a hiba általában egyetlen paranccsal javítható.

Ubuntu és Debian nem SELinuxot, hanem AppArmort használ; ott ez a cikk nem érvényes. cPanel szervereken a SELinuxnak kikapcsolva kell lennie, mert a cPanel nem támogatja.

Be van-e kapcsolva?

getenforce
sestatus
  • Enforcing: a SELinux működik, és tiltja a szabálysértő műveleteket.
  • Permissive: csak naplózza a szabálysértéseket, de nem tiltja őket.
  • Disabled: ki van kapcsolva.

A SELinux okozza a hibát?

A SELinux minden tiltást AVC üzenetként naplóz. A legutóbbi tiltások:

sudo ausearch -m AVC -ts recent

Ha a hibával egy időben itt megjelenik egy denied sor, a hibát a SELinux okozza. Egy jellemző bejegyzés:

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

Ebből kiolvasható, hogy a webszerver (httpd_t) nem olvashatta az index.html fájlt, mert annak címkéje admin_home_t (a root könyvtárában jött létre).

Gyors próbaként ideiglenesen engedékeny módba is kapcsolhat; ha így a hiba megszűnik, biztosan a SELinux okozta:

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

Az audit2why program emberi nyelven is elmagyarázza a tiltások okát:

sudo ausearch -m AVC -ts recent | audit2why

A lenti semanage, audit2why és audit2allow parancsok a policycoreutils-python-utils csomagban vannak:

sudo dnf install policycoreutils-python-utils

1. Hibás fájlcímkék

A leggyakoribb eset: egy fájlt máshol hozott létre (például a /root vagy a /home könyvtárban), majd az mv paranccsal áthelyezte a webkönyvtárba. Az mv megtartja az eredeti címkét, így a webszerver nem olvashatja. (A cp a célkönyvtár címkéjét adja a másolatnak.)

A címkék megtekintése:

ls -Z /var/www/html

A címkék visszaállítása az alapértelmezésre:

sudo restorecon -Rv /var/www/html

Saját webkönyvtár

Ha a weboldal nem a /var/www alatt van (például /srv/www), adja meg a SELinuxnak, hogy ez is webtartalom, majd állítsa be a címkéket:

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

Azokra a könyvtárakra, ahová a webalkalmazásnak írnia is kell (feltöltések, gyorsítótár), az írható címkét állítsa be:

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

A chcon paranccsal is módosíthatók a címkék, de az így beállított címke a következő restorecon vagy teljes újracímkézés után elvész; tartós beállításhoz a semanage fcontext a helyes módszer.

2. Kapcsolók (booleans)

Sok gyakori igényt a SELinux kapcsolókkal enged meg. A webszerverre vonatkozó kapcsolók:

getsebool -a | grep httpd

A leggyakrabban szükségesek:

Kapcsoló Mikor kell?
httpd_can_network_connect a PHP külső kapcsolatot nyit (API hívások, cURL), vagy az Nginx/Apache proxyként továbbít egy alkalmazásnak (Node.js, Python)
httpd_can_network_connect_db a PHP egy másik szerveren lévő adatbázishoz kapcsolódik
httpd_can_sendmail a PHP a mail() függvénnyel levelet küld
httpd_unified a webszerver minden webtartalmat írhat is (kényelmes, de kevésbé biztonságos)

Bekapcsolás tartósan (a -P nélkül újraindításkor visszaáll):

sudo setsebool -P httpd_can_network_connect on

3. Nem szabványos portok

Ha egy szolgáltatást nem az alapértelmezett portján futtat, azt a SELinuxnak is jelezni kell. A leggyakoribb példa az SSH port módosítása (lásd: SSH szerver biztonsági beállításai): ha ezt kihagyja, az sshd újraindítás után nem indul el, és kizárhatja magát a szerverről.

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

Webszerver esetén (például 8080 helyett 8888):

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

A már engedélyezett portok: sudo semanage port -l | grep -E "ssh|http".

4. Egyedi szabály, ha más nem segít

Ha a fentiek egyike sem megoldás, az audit2allow a naplózott tiltásokból egyedi szabálymodult készít:

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

Telepítés előtt nézze meg a létrehozott sajat_szabaly.te fájlt, és csak azt engedje, amire valóban szükség van.

Ki kell kapcsolni a SELinuxot?

Nem javasoljuk. Ha egy alkalmazás mégsem működik vele, a teljes kikapcsolás helyett csak az adott szolgáltatást teheti engedékeny módba, például a webszervert:

sudo semanage permissive -a httpd_t

Ha mégis ki kell kapcsolnia, AlmaLinux 9-től a /etc/selinux/config fájlban beállított SELINUX=disabled már nem kapcsolja ki teljesen; ehelyett a kernel paramétereként adja meg, majd indítsa újra a szervert:

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

Ha később újra bekapcsolja, a teljes fájlrendszert újra kell címkézni (sudo touch /.autorelabel, majd újraindítás), ami hosszabb ideig tarthat.