<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>SELinux on My personal blog</title>
        <link>https://www.matteobianchi.eu/tags/selinux/</link>
        <description>Recent content in SELinux on My personal blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en</language>
        <lastBuildDate>Tue, 05 May 2026 09:00:00 +0200</lastBuildDate><atom:link href="https://www.matteobianchi.eu/tags/selinux/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>SELinux</title>
        <link>https://www.matteobianchi.eu/p/selinux/</link>
        <pubDate>Tue, 05 May 2026 09:00:00 +0200</pubDate>
        
        <guid>https://www.matteobianchi.eu/p/selinux/</guid>
        <description>&lt;img src="https://www.matteobianchi.eu/p/selinux/cover.png" alt="Featured image of post SELinux" /&gt;&lt;h2 id=&#34;perché-conta&#34;&gt;Perché conta
&lt;/h2&gt;&lt;p&gt;Tutto ciò che abbiamo visto finora è &lt;strong&gt;controllo discrezionale&lt;/strong&gt;: il proprietario di una risorsa
decide, e root scavalca ogni controllo. Il limite è evidente — se un servizio che gira come root (o un
processo che ottiene root) viene compromesso, il DAC non lo ferma. Il &lt;strong&gt;controllo d&amp;rsquo;accesso obbligatorio
(MAC)&lt;/strong&gt; aggiunge una politica di sistema che vale &lt;em&gt;sopra&lt;/em&gt; il DAC e che &lt;strong&gt;nemmeno root può aggirare&lt;/strong&gt;:
anche se un processo è root, può fare solo ciò che la politica SELinux consente al suo &lt;em&gt;tipo&lt;/em&gt;. È un
confinamento potentissimo — e la risposta sbagliata, &lt;code&gt;setenforce 0&lt;/code&gt;, è anche la più diffusa.&lt;/p&gt;
&lt;h2 id=&#34;lidea-etichette-e-tipi&#34;&gt;L&amp;rsquo;idea: etichette e tipi
&lt;/h2&gt;&lt;p&gt;In SELinux ogni processo e ogni risorsa hanno un&amp;rsquo;&lt;strong&gt;etichetta (context)&lt;/strong&gt;, e la politica definisce quali
interazioni tra etichette sono permesse. Il campo che conta di più è il &lt;strong&gt;type&lt;/strong&gt; (type enforcement).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ls -Z /var/www/html/index.html     &lt;span class=&#34;c1&#34;&gt;# contesto del file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# unconfined_u:object_r:httpd_sys_content_t:s0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#                       ^^^^^^^^^^^^^^^^^^^^ il TYPE: &amp;#34;contenuto web per httpd&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ps -eZ &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep nginx                &lt;span class=&#34;c1&#34;&gt;# contesto del processo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# system_u:system_r:httpd_t:s0 ...  ← il processo web gira nel type httpd_t&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;La politica dice, in sostanza: &amp;ldquo;un processo &lt;code&gt;httpd_t&lt;/code&gt; può leggere file &lt;code&gt;httpd_sys_content_t&lt;/code&gt;&amp;rdquo;. Se il
web server (confinato in &lt;code&gt;httpd_t&lt;/code&gt;) viene compromesso, &lt;strong&gt;non&lt;/strong&gt; può leggere &lt;code&gt;/etc/shadow&lt;/code&gt;
(&lt;code&gt;shadow_t&lt;/code&gt;) o scrivere ovunque: la politica glielo vieta, root o no.&lt;/p&gt;
&lt;h2 id=&#34;i-tre-modi&#34;&gt;I tre modi
&lt;/h2&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;getenforce                     &lt;span class=&#34;c1&#34;&gt;# Enforcing | Permissive | Disabled&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;setenforce &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;# Enforcing: applica la politica (OBIETTIVO)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;setenforce &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;                   &lt;span class=&#34;c1&#34;&gt;# Permissive: NON applica, ma LOGGA le violazioni (per diagnosi)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Enforcing   → la politica è applicata (produzione)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Permissive  → non blocca ma registra cosa bloccherebbe → usalo per DIAGNOSTICARE, non come resa
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Disabled    → SELinux spento (da evitare: perdi anche le etichette)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Il riflesso sbagliato è passare a &lt;code&gt;Disabled&lt;/code&gt; al primo problema. Quello giusto è passare a &lt;code&gt;Permissive&lt;/code&gt;
&lt;em&gt;temporaneamente&lt;/em&gt; per vedere &lt;em&gt;cosa&lt;/em&gt; verrebbe bloccato, capirlo, correggere la politica, e tornare a
&lt;code&gt;Enforcing&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;il-troubleshooting-che-non-spaventa&#34;&gt;Il troubleshooting che non spaventa
&lt;/h2&gt;&lt;p&gt;Quando &amp;ldquo;qualcosa non funziona e sospetto SELinux&amp;rdquo;, il flusso è preciso:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 1. le negazioni finiscono nell&amp;#39;audit log&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ausearch -m avc -ts recent            &lt;span class=&#34;c1&#34;&gt;# mostra gli Access Vector Cache denial recenti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 2. sealert spiega in linguaggio umano e suggerisce la soluzione&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sealert -a /var/log/audit/audit.log
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 3. spesso basta un booleano o un contesto giusto, non disabilitare tutto&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Due aggiustamenti coprono la maggioranza dei casi:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# A) BOOLEANI: interruttori predefiniti per comportamenti comuni&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;getsebool -a &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep httpd                     &lt;span class=&#34;c1&#34;&gt;# es: httpd_can_network_connect&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;setsebool -P httpd_can_network_connect on     &lt;span class=&#34;c1&#34;&gt;# -P = persistente&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# B) CONTESTI: dare l&amp;#39;etichetta giusta a file in percorsi non standard&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;semanage fcontext -a -t httpd_sys_content_t &lt;span class=&#34;s2&#34;&gt;&amp;#34;/srv/web(/.*)?&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;restorecon -Rv /srv/web                        &lt;span class=&#34;c1&#34;&gt;# riapplica i contesti&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;quando-serve-una-regola-nuova-audit2allow&#34;&gt;Quando serve una regola nuova: audit2allow
&lt;/h2&gt;&lt;p&gt;Se un&amp;rsquo;applicazione legittima ha bisogno di un accesso che nessun booleano copre, si genera un &lt;strong&gt;modulo
di policy&lt;/strong&gt; dai denial — senza disabilitare nulla.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ausearch -m avc -ts recent &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; audit2allow -M myapp_local
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;semodule -i myapp_local.pp        &lt;span class=&#34;c1&#34;&gt;# installa il modulo: concede SOLO ciò che serviva&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Attenzione: &lt;code&gt;audit2allow&lt;/code&gt; va usato con criterio — concedi solo ciò che è davvero legittimo, non tutto
ciò che l&amp;rsquo;app prova a fare (potrebbe provare anche cose che è giusto bloccare).&lt;/p&gt;


&lt;details&gt;
&lt;summary&gt;&lt;strong&gt;Domanda:&lt;/strong&gt; SELinux ha la fama di rompere le applicazioni e di essere complicatissimo. Visto che ho già DAC stretto, capabilities e sandboxing systemd, non è più pragmatico disabilitarlo e vivere sereni?&lt;/summary&gt;
&lt;p&gt;È il ragionamento più comune e anche quello che butta via la protezione più forte proprio quando
servirebbe di più. Partiamo dalla fama: SELinux &#34;rompe le app&#34; quasi sempre perché i file sono nel posto
sbagliato (contesto errato) o manca un booleano — due cose che si diagnosticano in minuti con
&lt;code&gt;ausearch&lt;/code&gt; e &lt;code&gt;sealert&lt;/code&gt; e si risolvono con un comando, senza disabilitare niente. La
complessità vera (scrivere policy da zero) non ti riguarda nel 95% dei casi: usi la policy mirata della
distribuzione e la ritocchi con booleani e contesti. Ora il punto sostanziale: DAC stretto, capabilities
e sandboxing systemd sono ottimi, ma hanno un limite comune — operano dentro il modello discrezionale e,
soprattutto, dipendono dal fatto che &lt;em&gt;tu&lt;/em&gt; li abbia configurati correttamente per ogni servizio.
SELinux aggiunge qualcosa che gli altri non danno: un confinamento &lt;em&gt;obbligatorio&lt;/em&gt;, definito a
livello di sistema, che vale anche contro un processo che è diventato root e che resta in piedi anche
dove ti sei dimenticato di sandboxare. Il caso che conta è questo: un servizio ha una vulnerabilità che
permette l&#39;esecuzione di codice e magari un&#39;escalation a root. Il DAC a quel punto non ferma più nulla
(root scavalca tutto), e se quel servizio non l&#39;avevi sandboxato con systemd, l&#39;attaccante è libero. Con
SELinux in enforcing, invece, il processo resta confinato nel suo type: il web server compromesso, anche
da root, non può leggere /etc/shadow né scrivere fuori dalle sue directory, perché la policy non lo
prevede per &lt;code&gt;httpd_t&lt;/code&gt;. È esattamente la difesa che interviene quando tutte le altre hanno
ceduto. Disabilitarlo per &#34;vivere sereni&#34; significa rinunciare all&#39;unico strato che un attaccante con
root non può semplicemente aggirare — in cambio di non dover imparare due comandi. Il pragmatismo vero è
tenerlo in enforcing e imparare il flusso di troubleshooting: è molto meno lavoro di quanto la sua fama
suggerisca, e copre proprio lo scenario peggiore.&lt;/p&gt;
&lt;/details&gt;


&lt;h2 id=&#34;conclusione&#34;&gt;Conclusione
&lt;/h2&gt;&lt;p&gt;SELinux impone una politica di sistema che confina ogni processo al suo type e che nemmeno root
scavalca; il segreto è non disabilitarlo ma usare &lt;code&gt;Permissive&lt;/code&gt; per diagnosticare, booleani e contesti
per correggere, &lt;code&gt;audit2allow&lt;/code&gt; per i casi residui. Esiste un secondo approccio al MAC, più semplice da
leggere e basato sui percorsi invece che sulle etichette: &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/apparmor/&#34; &gt;AppArmor&lt;/a&gt;,
prossimo capitolo.&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
