Základní
rwxpro vlastníka / skupinu / ostatní znáš z minulé kapitoly. Jenže reálný systém potřebuje víc: jak může obyčejný uživatel změnit svoje heslo, když do souboru s hesly nesmí zapisovat? Jak nechat celý tým psát do jedné složky, aby se soubory neztrácely? Jak dát jednomu konkrétnímu kolegovi přístup, když on není ani vlastník, ani ve skupině? A jak dovolit programu obsadit port 80, aniž bys mu dal moc nad celým systémem? Tohle všechno řeší speciální bity, umask, ACL a capabilities — vrstvy, které klasickérwxdoplňují tam, kde samo nestačí.
Pár pojmů na úvod
- SUID (Set User ID) = bit na spustitelném souboru, který říká: „spusť mě s právy vlastníka
souboru, ne toho, kdo mě spouští". Proto může
passwdzapsat do systémového souboru s hesly. - SGID (Set Group ID) = obdoba pro skupinu. Na souboru běží program s právy skupiny souboru; na složce nová práva nedědíš — dědíš skupinu složky (skvělé pro sdílené adresáře).
- Sticky bit = bit na složce, který zamkne mazání: smazat soubor smí jen jeho vlastník
(nebo root), i když do složky můžou psát všichni. Klasika je
/tmp. - umask = maska, která z „plných" práv odečítá bity a tím určuje výchozí práva nově
vytvořených souborů a složek. Proto ti nový soubor vznikne jako
644a ne666. - ACL (Access Control List) = jemnější seznam práv nad rámec vlastník/skupina/ostatní — umí dát
rwxkonkrétnímu uživateli nebo konkrétní skupině, aniž bys sahal na vlastnictví. - Capabilities = rozdrobení všemocného roota na malé pravomoci (např. „smíš obsadit nízký port"). Program dostane jen ten střípek, který potřebuje, místo plné SUID-root moci.
Speciální bity: SUID, SGID, sticky
Vedle běžných devíti bitů (rwx × 3) má každý soubor ještě tři speciální bity. Mění se stejným
chmod, jen dostávají čtvrtou (nejlevější) číslici v osmičkovém zápisu, nebo se přidávají symbolicky.
| Bit | Symbolicky | Osmičkově | Kde dává smysl | Co dělá |
|---|---|---|---|---|
| SUID | u+s | 4000 | spustitelný soubor | běží s právy vlastníka souboru |
| SGID | g+s | 2000 | soubor / složka | soubor: běží s právy skupiny; složka: dědí skupinu |
| sticky | +t | 1000 | složka | smazat smí jen vlastník souboru |
SUID — proč vůbec existuje
Vezmi klasiku: každý uživatel si smí změnit svoje heslo příkazem passwd. Jenže hesla se ukládají do
/etc/shadow, kam smí zapisovat jen root. Jak to tedy funguje?
ls -l /usr/bin/passwd
# -rwsr-xr-x. 1 root root 33544 ... /usr/bin/passwd
# ^
# tady je 's' místo 'x' → SUID
To malé s v místě, kde bys čekal x u vlastníka, znamená SUID. Vlastníkem souboru je root,
takže když passwd spustí kdokoli, program po dobu běhu získá práva roota a smí do /etc/shadow
zapsat. Bez SUID by si běžný uživatel heslo nikdy nezměnil.
chmod u+s program # zapne SUID
chmod 4755 program # totéž osmičkově (4 = SUID, 755 = rwxr-xr-x)
💡 V
ls -lpoznáš SUID podlesv pozicixvlastníka. Když je tam velkéS, znamená to, že SUID je nastavený, ale vlastníkovi chybíx— bit je „nastražený", jenže vlastník soubor spustit nemůže, takže SUID je fakticky bezzubý (typicky chyba).
SGID na souboru vs na složce
Na souboru funguje SGID jako SUID, jen pro skupinu: program běží s právy skupiny souboru. Zajímavější a mnohem užitečnější je ale SGID na složce:
mkdir /srv/tym
chgrp vyvoj /srv/tym
chmod 2775 /srv/tym # 2 = SGID, 775 = rwxrwxr-x
Bez SGID by každý soubor, který si někdo v /srv/tym vytvoří, dostal jako skupinu jeho vlastní
skupinu. Kolega ze skupiny vyvoj by pak k němu nemusel mít přístup. Se SGID na složce každý nový
soubor zdědí skupinu vyvoj — celý tým na sebe navzájem vidí. To je základní stavební kámen
sdílených adresářů.
ls -ld /srv/tym
# drwxrwsr-x. 2 root vyvoj 4096 ... /srv/tym
# ^
# 's' ve skupinové části = SGID
Sticky bit — kdo smaže cizí soubor
Problém sdílené složky, kam smí psát všichni (rwxrwxrwx): kdokoli tam smí i smazat cizí soubor,
protože mazání je právo na složku, ne na soubor. Sticky bit to opraví:
ls -ld /tmp
# drwxrwxrwt. 20 root root ... /tmp
# ^
# 't' na konci = sticky bit
Se sticky bitem smí soubor smazat nebo přejmenovat jen jeho vlastník (a root). Proto do /tmp
zapisují všichni programy, ale nikdo tam nemůže mazat cizí dočasné soubory.
chmod +t /sdilena/slozka
chmod 1777 /sdilena/slozka # 1 = sticky, 777 = rwxrwxrwx
💡 Stejná logika jako u SUID: malé
t= sticky je nastavený a složka jde procházet; velkéT= sticky nastavený, ale chybíxpro ostatní (nastražený, ale prakticky nefunkční).
umask — odkud se berou výchozí práva
Když vytvoříš nový soubor (touch, >, editor), nikdo mu práva ručně nenastaví — a přesto nevznikne
s 777. O to se stará umask: maska, která z „maximálních" práv vypne (odmaskuje) některé bity.
Výchozí maxima jsou:
- soubory
666(rw-rw-rw-) — nové soubory nikdy nedostanouxautomaticky, to by bylo nebezpečné, - složky
777(rwxrwxrwx) — u složekx(procházení) dává smysl.
Od maxim se bity umasky vypnou (technicky je to bitová operace práva AND NOT umask, ne
aritmetické odčítání). Nejběžnější hodnota je 022:
umask # vypíše aktuální masku, typicky 0022
# Soubor: 666 bez bitů 022 = 644 → rw-r--r--
# Složka: 777 bez bitů 022 = 755 → rwxr-xr-x
⚠️ Model „odčítání" (666 − 022) vyjde správně jen pro masky ze sudých číslic. Pro liché to selže:
umask 133nedá „533", ale reálně644— protože bitxv základu666u souborů není, takže se nemá co „odečíst". Ber to jako vypínání bitů, ne matematiku.
Číslice 022 čti jako „vlastníkovi neber nic (0), skupině a ostatním ber právo zápisu (2)". Proto nový
soubor můžeš číst i psát ty, ostatní ho jen čtou. Kdybys chtěl přísnější nastavení:
umask 077 # soubory 600, složky 700 → vidí jen vlastník
umask 002 # soubory 664, složky 775 → skupina smí i zapisovat (sdílená práce)
🚩 umask nepřidává práva, jen odebírá. Nikdy z ní nevznikne
xu souboru, který by ho jinak neměl. Pozor taky na to, že jde o masku, ne o cílová práva:umask 022neznamená „práva 022", ale „odeber bity 022". To lidi pravidelně mate.
Trvalé nastavení dáš do ~/.bashrc (pro sebe) nebo do /etc/profile / /etc/login.defs (systémově).
ACL — když tři kategorie nestačí
Klasický model má jen tři místa: vlastník, jedna skupina, ostatní. Co když chceš, aby ke složce
měl přístup vlastník, skupina vyvoj a navíc jeden konkrétní člověk anna — ale nikdo jiný?
V základním modelu bys musel zakládat novou skupinu a přehazovat členství. ACL to řeší přímo:
getfacl soubor.txt # vypíše ACL (i klasická práva)
setfacl -m u:anna:rw soubor.txt # přidej uživateli anna právo rw
setfacl -m g:vyvoj:rx slozka # přidej skupině vyvoj právo rx
setfacl -x u:anna soubor.txt # odeber záznam pro annu
setfacl -b soubor.txt # smaž všechna ACL, zpět k čistým rwx
Že soubor má nějaké ACL navíc, poznáš v ls -l podle + za právy:
ls -l soubor.txt
# -rw-rw-r--+ 1 pepa vyvoj 12 ... soubor.txt
# ^
# '+' = na souboru jsou ACL
Pro sdílené složky se hodí výchozí ACL (default, přepínač -d) — nastaví, jaká práva zdědí
soubory nově vzniklé uvnitř složky:
setfacl -d -m g:vyvoj:rwx /srv/projekt # vše nové uvnitř zdědí rwx pro skupinu vyvoj
💡 ACL je nadstavba, ne náhrada. Klasické
rwxpořád platí; ACL jen přidává další záznamy. Používej je střídmě — pár cílených záznamů je fajn, deset překrývajících se pravidel je noční můra na audit.
Capabilities — rozdrobený root
Historicky se to řešilo brutálně: potřebuje program něco, co umí jen root? Dej mu SUID root a je z něj po dobu běhu všemocný. Jenže když v takovém programu najde útočník chybu, získá celého roota — protože program má úplně všechny pravomoci, i ty, které vůbec nepotřeboval.
Capabilities rozdělují roota na desítky malých pravomocí, které se přidělují samostatně. Klasický příklad: obsadit port pod 1024 smí normálně jen root. Místo SUID root stačí jedna capability:
getcap /usr/bin/ping
# /usr/bin/ping cap_net_raw=ep ← smí posílat raw pakety, nic víc
# (na řadě moderních distr už ping capability nemá a jede přes ICMP sockety — ověř; koncept ale platí)
# Nech webový server naslouchat na portu 80 bez roota:
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/muj-server
getcap /usr/local/bin/muj-server
Program dostane jen CAP_NET_BIND_SERVICE (smí na nízký port) a nic dalšího. Když ho někdo
zneužije, nedostane celého roota — jen tu jednu drobnou schopnost. To je zásadně bezpečnější než SUID root.
Pár užitečných capabilities:
| Capability | Co umožňuje |
|---|---|
CAP_NET_BIND_SERVICE | obsadit port < 1024 (třeba 80/443) |
CAP_NET_RAW | posílat raw/ICMP pakety (ping) |
CAP_CHOWN | měnit vlastníka souborů |
CAP_SYS_TIME | nastavovat systémový čas |
💡 Pravidlo: potřebuješ jednu schopnost roota → dej capability, ne SUID root. SUID root je kanón na vrabce a každá chyba v tom programu je pak eskalace na celého roota.
Jak najít nebezpečné soubory
SUID/SGID binárky jsou oblíbený cíl útočníků — pokud jich máš v systému moc nebo nějakou vlastní, je to riziko. Najdeš je podle bitů:
find / -perm -4000 -type f 2>/dev/null # všechny SUID soubory
find / -perm -2000 -type f 2>/dev/null # všechny SGID soubory
find / -perm -6000 -type f 2>/dev/null # SUID nebo SGID
find / -perm -0002 -type f 2>/dev/null # soubory zapisovatelné kýmkoli (world-writable)
-perm -4000 znamená „má nastavený aspoň bit 4000" (SUID). 2>/dev/null zahodí spoustu hlášek
o složkách, kam nemáš přístup. Seznam SUID binárek si projdi: systémové (passwd, sudo, mount)
tam patří; cokoli vlastního nebo neznámého je varovný signál.
Failure modes — časté omyly
- SUID na skript nebo vlastní binárku. Přímá cesta k eskalaci práv: útočník podstrčí vstup nebo zneužije chybu a spustí kód jako vlastník (často root). Jádro proto SUID na skriptech naštěstí ignoruje — ale u vlastních binárek platí. Nedávej SUID ničemu, co jsi pořádně neprověřil.
chmod 777jako univerzální lék. „Nejde to, tak dám 777" znamená „ať to smí číst, psát i spouštět úplně každý". Zdánlivě to problém vyřeší, ve skutečnosti otevře díru. Skoro vždy stačí správný vlastník, skupina a640/750— nebo cílené ACL.- Moc široká ACL.
setfacl -m u:kdokoli:rwxna kdejaký soubor je stejný hřích jako777, jen hůř vidět (schová se za+). ACL dávej úzce a pravidelně kontrolujgetfacl. - SUID root místo capability. Dát programu plného SUID roota, když potřebuje jen obsadit port,
je zbytečně velká plocha útoku. Použij
setcapa dej mu jen tu jednu schopnost. - Nepochopení umask. Lidi čtou
umask 022jako „práva budou 022". Je to maska, která se odečítá: z 666 → 644, z 777 → 755. Kdo to plete, diví se, proč mu soubory vznikají „jinak, než čekal".
🛠️ Cvičení
- Rozklíčuj
ls -l. Podívej se nals -l /usr/bin/passwd,ls -ld /tmpa nějakou vlastní složku. U každého urči, jestli má SUID, SGID nebo sticky bit, a podle čeho jsi to poznal. - Postav sdílenou složku. Vytvoř složku
/srv/tym, přiřaď jí nějakou skupinu a nastav ji tak, aby všechny nově vzniklé soubory uvnitř zdědily tuhle skupinu a nikdo nemohl mazat cizí soubory. Jaké dva speciální bity potřebuješ? - Ověř si umask. Zjisti svou aktuální
umask, pak vytvoř nový soubor a novou složku a zkontroluj jejich práva přesls -l. Sedí to na vzorec 666−maska (soubor) a 777−maska (složka)? - Dej práva jednomu člověku. Máš soubor, ke kterému má mít
rwnavíc jeden konkrétní uživatel, ale nechceš měnit vlastníka ani skupinu. Jak na to a jak si to pak ověříš? - Nahraď SUID capability. Chceš, aby tvůj vlastní server naslouchal na portu 80 bez roota. Jakou capability mu dáš a čím ji nastavíš? Proč je to lepší než SUID root?
Náčrt řešení — rozbal, až si cvičení zkusíš sám
- Čtení bitů —
passwdmá-rwsr-xr-x→sv pozicixvlastníka = SUID (běží jako root)./tmpmádrwxrwxrwt→tna konci = sticky (smaže jen vlastník). Vlastní složka typickydrwxr-xr-x→ žádný speciální bit. Pozor: velkéS/Tznamená, že bit je nastavený, ale chybí odpovídajícíx. - Sdílená složka —
mkdir /srv/tym,chgrp vyvoj /srv/tym,chmod 2775 /srv/tym(SGID = dědění skupiny) achmod +t /srv/tym(sticky = mazání jen vlastníkem). Dohromadychmod 3775. Potřebuješ tedy SGID (dědění skupiny) a sticky (ochrana před mazáním cizích souborů). - umask —
umaskvypíše masku (typicky0022). Potouch souboruvidíš644(666−022) a pomkdir slozka755(777−022). Sedí to na vzorec. Pozor:xu souboru nikdy nevznikne automaticky, i kdyby maska byla000→ soubor stejně666, ne777. - Právo pro jednoho —
setfacl -m u:anna:rw soubor.txtpřidá ACL záznam jen proannu, vlastnictví ani skupina se nemění. Ověříšgetfacl soubor.txt(uvidíš řádekuser:anna:rw-) a vls -lbude za právy+. Odebrat jdesetfacl -x u:anna soubor.txt. - Capability místo SUID —
sudo setcap 'cap_net_bind_service=+ep' /cesta/k/serveru, ověříšgetcap. Program pak smí obsadit port 80, ale nic víc. Lepší než SUID root proto, že při chybě v programu útočník nezíská celého roota, jen tu jednu drobnou schopnost (obsadit nízký port).
🧠 Otázky & odpovědi
K čemu je SUID bit a proč ho má passwd?
SUID říká: spusť tenhle program s právy vlastníka souboru, ne toho, kdo ho spouští. passwd
vlastní root a má SUID, takže když ho spustí libovolný uživatel, program po dobu běhu získá práva
roota a smí zapsat nové heslo do /etc/shadow (kam běžný uživatel nemá přístup). Bez SUID by si nikdo
kromě roota heslo nezměnil. V ls -l poznáš SUID podle s v pozici x vlastníka.
Jaký je rozdíl mezi SGID na souboru a na složce?
Na souboru je SGID jako SUID, jen pro skupinu — program běží s právy skupiny souboru. Na složce
dělá něco jiného a mnohem užitečnějšího: každý nově vytvořený soubor uvnitř zdědí skupinu složky
místo výchozí skupiny toho, kdo ho vytvořil. Díky tomu funguje sdílený adresář týmu — všichni na sebe
navzájem vidí. Nastavíš chmod g+s slozka nebo chmod 2775 slozka.
Co dělá sticky bit a kde ho poznám?
Sticky bit na složce zamkne mazání: soubor uvnitř smí smazat nebo přejmenovat jen jeho vlastník
(a root), i když do složky smí zapisovat kdokoli. Bez něj by v rwxrwxrwx složce mohl každý mazat cizí
soubory. Klasický příklad je /tmp — píšou tam všechny programy, ale nikdo nesmaže cizí dočasné
soubory. V ls -l ho poznáš podle t na konci práv (drwxrwxrwt). Nastavíš chmod +t nebo chmod 1777.
Jak umask určuje výchozí práva nových souborů?
umask je maska, která se odečítá od maximálních práv. Maxima jsou 666 pro soubory a 777 pro složky.
Při umask 022 vznikne soubor jako 644 (666−022) a složka jako 755 (777−022). Pozor na dvě věci:
umask práva jen odebírá, nikdy nepřidává, a x u souboru z ní nikdy nevznikne automaticky.
A hlavně — umask 022 neznamená práva 022, ale odečti bity 022. To je nejčastější zdroj zmatku.
Proč je capability lepší než SUID root?
SUID root dá programu po dobu běhu všechny pravomoci roota, i ty, které vůbec nepotřebuje. Když
v něm útočník najde chybu, získá celého roota. Capability rozdrobí roota na malé kousky a dá programu
jen ten jeden, který potřebuje — třeba CAP_NET_BIND_SERVICE (obsadit port pod 1024). Při zneužití
útočník dostane jen tu drobnou schopnost, ne celý systém. Nastavíš přes setcap, ověříš přes getcap.
