Prima di leggere: prova a prevedere
Una cartella ha permessi r--r--r--, cioè leggibile da tutti e nient'altro. Dentro c'è un
file che tu puoi leggere. Secondo te ls sulla cartella funziona? E cat sul
file dentro? Scrivi le due previsioni prima di proseguire, perché la risposta è contro l'intuito di
quasi tutti e il valore dell'esercizio sta nel vedere dove sbagli.
Nella lezione precedente hai deciso dove vanno i file. Qui decidi chi li può toccare,
e il meccanismo ha una regola che su una cartella significa una cosa diversa da quella che significa
su un file. Chi non la conosce scrive chmod 777 e va avanti, e nel frattempo ha aperto
a tutti un dato che non doveva aprire.
Il problema: chmod 777 non è pigrizia, è un incidente rimandato
Quando un programma non riesce ad aprire un file, la ricetta che trovi in rete è dare tutti i permessi a tutti. Funziona sempre, e questo è il guaio: funziona anche quando il problema vero era un altro, quindi non ti insegna niente e ti lascia un file che qualunque utente del sistema può riscrivere. Su un server con un solo utente sembra innocuo. Su un server con un servizio web esposto, l'utente che può riscrivere quel file è anche chi riesce a far eseguire codice al servizio.
La strada che paga è capire i tre bit e le tre categorie, che sono nove combinazioni in tutto, e poi
saper leggere una riga di ls -l come si legge una frase. Dopo di che chmod
diventa una scelta e non una scaramanzia.
Tre bit, tre categorie, e una differenza che inganna
Ogni file ha un proprietario, un gruppo, e tre terne di permessi: una per il proprietario, una per
chi appartiene al gruppo, una per tutti gli altri. I tre bit sono lettura, scrittura, esecuzione,
scritti r, w, x, e in forma numerica valgono 4, 2 e 1. Quindi
640 è lettura e scrittura al proprietario, sola lettura al gruppo, niente agli altri.
Su una cartella i tre bit significano altro, e questo è il punto che rende la lezione necessaria.
r permette di elencare i nomi contenuti. w permette di
creare e cancellare voci. x permette di attraversare la cartella, cioè
di usarla come pezzo di un percorso. Sono indipendenti: puoi avere il diritto di leggere i nomi senza
poter raggiungere i file, e puoi avere il contrario.
Il comportamento misurato, su una cartella noexec portata a modo 444:
$ chmod 444 noexec
$ ls noexec
inner
$ cat noexec/inner/dato.txt
cat: noexec/inner/dato.txt: Permission denied
$ chmod 755 noexec
$ cat noexec/inner/dato.txt
contenuto
ls funziona, perché il bit r c'è e serve solo a elencare i nomi.
cat fallisce, perché per arrivare a inner il kernel deve attraversare
noexec, e per attraversare serve x. Il messaggio di errore parla del file,
non della cartella, e questo è il motivo per cui la diagnosi sbagliata è così comune: si guarda il
file, che ha i permessi giusti, e non si pensa a risalire il percorso.
La maschera che decide i permessi dei file che crei
Non scegli tu i permessi di un file nuovo: li sceglie il programma che lo crea, meno quello che la
umask toglie. La umask è una maschera di bit da sottrarre, non da
concedere, ed è la ragione per cui un file nuovo non nasce eseguibile anche se la cartella lo è.
$ umask
0002
$ umask -S
u=rwx,g=rwx,o=rx
$ (umask 022; touch f.txt; mkdir d)
$ stat -c '%n %A %a' f.txt d
f.txt -rw-r--r-- 644
d drwxr-xr-x 755
Con umask 022 il file nasce 644 e la cartella 755. La
differenza non è un capriccio: il sistema parte da 666 per i file e 777
per le cartelle, perché una cartella senza x sarebbe inservibile, e poi sottrae la
maschera. Il valore 0002 che trovi sopra è quello attivo sul mio utente, e dipende dalla
configurazione della distribuzione: la tua la leggi con umask senza argomenti.
I tre bit che quasi nessuno sa leggere
Oltre alle nove combinazioni ci sono tre bit speciali, e li riconosci perché cambiano una lettera
nell'output di ls -l. Se al posto della x del proprietario vedi una
s, il file ha il bit setuid: viene eseguito con l'identità del proprietario, non con la
tua. Se la s è al posto della x del gruppo è setgid. Se l'ultima
x è una t, la cartella ha lo sticky bit.
$ stat -c '%n %A %a %U' /usr/bin/passwd
/usr/bin/passwd -rwsr-xr-x 4755 root
$ stat -c '%n %A %a' /tmp
/tmp drwxrwxrwt 1777
passwd deve riscrivere /etc/shadow, che è di root, quindi gira
come root anche se lo lanci tu: è il setuid. /tmp è scrivibile da tutti,
e senza lo sticky bit chiunque potrebbe cancellare i file altrui; con lo sticky bit, dentro una
cartella scrivibile da tutti, puoi cancellare solo ciò che è tuo. Sono due soluzioni a due problemi
diversi, e si leggono entrambe dalla stessa colonna.
Esempio svolto: una cartella condivisa fra due persone
Il problema: due utenti dello stesso gruppo adm devono lavorare sugli stessi file in una
cartella comune. Ogni volta che uno crea un file, l'altro non riesce a modificarlo.
L'informazione che serve: quando crei un file, il suo gruppo è il tuo gruppo primario, non il gruppo della cartella che lo contiene. Quindi i file nascono nel gruppo personale di chi li crea, e il collega resta fuori. Il ragionamento: il permesso di gruppo è giusto, è il gruppo a essere sbagliato. Serve far ereditare il gruppo dalla cartella, e il bit che lo fa è il setgid.
$ mkdir sg2 && chgrp adm sg2 && chmod 2775 sg2
$ stat -c '%n %A %U:%G' sg2
sg2 drwxrwsr-x federicocalo:adm
$ touch sg2/con-setgid.txt && stat -c '%n %U:%G' sg2/con-setgid.txt
sg2/con-setgid.txt federicocalo:adm
$ mkdir sg3 && chgrp adm sg3 && chmod 775 sg3
$ touch sg3/senza-setgid.txt && stat -c '%n %U:%G' sg3/senza-setgid.txt
sg3/senza-setgid.txt federicocalo:federicocalo
La differenza è nelle ultime due righe. Con il setgid il file nasce nel gruppo adm, cioè
nel gruppo della cartella. Senza, nasce nel gruppo personale di chi lo ha creato, e il collega non
lo può scrivere nemmeno se i permessi dicono rw per il gruppo.
L'alternativa che ho considerato e scartato: cambiare la umask dei due utenti. Non
risolve, perché la umask agisce sui bit, non sul gruppo, e il problema qui è il
gruppo. L'avrei scoperto solo dopo aver cambiato la configurazione di due utenti, che è un costo
inutile e un cambiamento che resta nel sistema.
La verifica che chiude il caso è esattamente il confronto sopra: due cartelle identiche tranne un bit, e la colonna del gruppo che cambia. L'errore plausibile, quello in cui sarei caduto se avessi provato in fretta, è fare la prova con il proprio gruppo primario: se la cartella ha il tuo gruppo primario, i file ereditano quel gruppo comunque, con o senza setgid, e la prova non dimostra niente. Serve un gruppo secondario perché la differenza sia visibile.
Il caso negativo: un bit che sembra funzionare e non funziona
Guarda questo script e questi permessi, e dimmi che cosa stampa prima di leggere l'output. L'intento di chi lo ha scritto era avere uno script che gira come il suo proprietario.
$ cat s.sh
#!/bin/bash
id -u
$ chmod 4755 s.sh
$ stat -c '%n %A' s.sh
s.sh -rwsr-xr-x
$ ./s.sh
1000
I permessi mostrano la s, quindi il bit è stato impostato e ls lo conferma.
Eppure l'identità effettiva resta 1000, cioè la mia: il setuid su uno script
interpretato non ha effetto. L'esito l'ho misurato il 2026-10-30 su kernel
7.0.0-38-generic; il comando per rifare la misura è quello sopra, e la risposta che
conta è il numero che stampa id -u.
L'errore è plausibile perché tutto il resto del sistema ti dice che è andata bene: nessun messaggio,
nessun codice di uscita diverso da zero, e il bit visibile in ls -l. Lo riconosci da un
solo sintomo, cioè che il programma continua a non avere i privilegi che ti aspettavi. E lo risolvi
non insistendo sul bit, ma con uno strumento pensato per questo, come una regola di
sudo limitata a quel comando.
Esercizio 1, con un passaggio mancante
Hai un file di configurazione con credenziali, che il servizio deve leggere e nessun altro deve
vedere. Il servizio gira come utente svc. Completa la sequenza: il passaggio finale
manca e devi scriverlo tu.
$ stat -c '%n %A %a %U:%G' segreti.env
segreti.env -rw-rw-r-- 664 root:root
$ chown root:svc segreti.env
$ chmod ???? segreti.env
Esercizio 2, autonomo: trova i file setuid del tuo sistema
Elenca tutti i file con il bit setuid sotto /usr e, per i primi tre, spiega perché
hanno bisogno di privilegi elevati. Il comando che ti serve combina find con un
criterio sui permessi: cerca -perm nella pagina di manuale di find.
Criterio di successo: per ogni file che citi, la spiegazione nomina l'operazione precisa che
richiede privilegi, non una formula generica come «serve per il sistema».
Soluzioni commentate
Esercizio 1. Il passaggio mancante è chmod 640 segreti.env. Il
ragionamento, bit per bit: root resta proprietario e deve poter modificare il file, da
cui 6. Il gruppo è svc e il servizio deve solo leggere, da cui
4: dargli 6 significherebbe che un servizio compromesso può riscrivere le
proprie credenziali, che è una capacità che non gli serve. Agli altri 0, perché il
punto dell'esercizio è che nessun altro veda il contenuto.
Perché le alternative no. chmod 644 è l'errore più comune e lascia il file leggibile da
ogni utente del sistema: la terna finale non è «nessuno in particolare», è «tutti».
chmod 660 dà scrittura al gruppo senza motivo. chmod 600 sembra il più
sicuro e invece rompe il servizio, perché svc non è il proprietario e
resta fuori: è il caso in cui stringere troppo produce un guasto, e la lezione è che il permesso
giusto è il minimo che fa funzionare la cosa, non il minimo in assoluto.
Una verifica che vale la pena fare prima di considerare chiuso il lavoro: i permessi del file non
bastano se la cartella che lo contiene è attraversabile e leggibile da tutti e il nome del file
stesso rivela informazioni. Il percorso completo va controllato tutto, con lo stesso ragionamento
sulla x delle cartelle che hai visto all'inizio.
Esercizio 2. Il comando è
find /usr -perm -4000 -type f 2>/dev/null. Il -4000 con il meno davanti
significa «almeno questi bit», che è diverso da 4000 senza meno, cioè «esattamente
questi bit e nessun altro»: quest'ultimo non troverebbe quasi niente, perché un file setuid ha
sempre anche i bit di esecuzione. Sulla risposta di merito, passwd ha bisogno di
privilegi per riscrivere /etc/shadow, che è leggibile solo da root;
sudo per cambiare identità prima di eseguire il comando richiesto; i programmi di
montaggio per chiamare l'operazione di mount, che il kernel riserva a chi ha la capacità
corrispondente. Se per un file del tuo elenco non riesci a nominare l'operazione, quel file merita
una verifica: un binario setuid senza una ragione dichiarabile è il primo posto dove guarderei
durante un'analisi di sicurezza.
Domande per fissare il concetto
Perché il sistema parte da 666 per i file e da 777 per le cartelle, prima
di applicare la umask? Che cosa succederebbe a /tmp se gli togliessero lo
sticky bit, e quale attacco diventerebbe possibile? E se un collega ti dice che per far funzionare
un upload ha dato 777 alla cartella del server web, quale domanda gli fai per capire
quale dei tre bit gli serviva davvero?
Che cosa adesso sai fare
Sai leggere una riga di ls -l e dire chi può fare cosa, compresi i tre bit speciali che
cambiano una lettera nella colonna dei permessi. Sai che su una cartella x significa
attraversare e non eseguire, e sai diagnosticare un Permission denied risalendo il percorso
invece di guardare solo il file. Sai scegliere il modo minimo che fa funzionare un servizio, e sai
che stringere oltre quel minimo produce un guasto invece di sicurezza.
La verifica concreta: prendi un file di configurazione con credenziali su una macchina che gestisci e
controlla modo, proprietario e gruppo, e poi gli stessi tre dati su ogni cartella del suo percorso.
Se trovi un 777, adesso sai dire quale dei tre bit serviva davvero.