Questo argomento è stato trattato in systemsAndNetworksSecurity
Introduzione a SELinux
SELinux (Security Enhanced Linux) è un meccanismo di access control aggiuntivo rispetto al Discretionary Access Control built-in in Linux. È parte del kernel Linux e consente l’uso di diversi Access Control (MAC, RBAC…).
Perché usare SELinux?
Molti deamon vengono eseguiti come root, oppure hanno privilegi significativi nel sistema. Degli errori in questi deamon possono facilmente portare a information leakage o, peggio, portare a vulnerabilità sfruttabili, anche da remoto. Persino se l’amministratore non consentisse utenti privilegiati, l’interazione utente-deamon può sempre introdurre potenziali rischi per la sicurezza, anche se gli utenti devono poter interagire con le applicazioni per avere un sistema funzionante. Senza meccanismi come SELinux, l’amministratore lascia la sicurezza del sistema alla mercè dei suoi utenti.
Mandatory Access Control
Il controllo degli accessi basato su MAC fornisce all’amministratore il controllo totale di cosa è permesso sul sistema e cosa no. SELinux realizza questa funzione supportando un approccio basato su policy che determinano cosa i processi possono o non possono fare e applicando questa policy a livello del kernel Linux. Il sistema operativo applica il controllo accessi, definito unicamente dalle regole abilitate dal sistema o dall’amministratore, mentre utenti e processi non hanno il permesso di cambiare le regole di sicurezza e circonvenire il controllo degli accessi stesso.
Un esempio è il file shadow. Un sistema di MAC può essere configurato per permettere solo a un numero limitato di processi di leggere e scrivere il file. Usando un MAC, un utente loggato come root non può accedere direttamente al file o spostarlo e non può nemmeno cambiarvi gli attributi.
Linux Security Module: Implementazioni
Esistono diverse applicazioni del Linux Security Module e SELinux non è l’unica:
- SELinux: sfrutta un modello di sicurezza basato su attributi in cui gli identificativi di sicurezza per i file sono conservati come attributi estesi nel file system;
- AppArmor: usano un modello di sicurezza basato su path in cui le politiche sono associate a percorsi piuttosto che sulla base di attributi;
- TOMOYO Linux: un sistema MAC che costruisce automaticamente delle politiche di sicurezza sulla base del comportamento delle applicazioni, usando primariamente i percorsi anziché etichette;
- Linux Lockdown: mira a bloccare il kernel per evitare tampering e l’esecuzione di codice non autorizzato e viene implementato via SELinux, AppArmor o altri file di politiche LSM.

LSM Hooks
Concetto importante: Complete Mediation
Il principio della complete mediation è fondamentale: attraverso questo principio, si impedisce che un soggetto possa svolgere direttamente un’operazione del kernel (kernel operation) su un oggetto interno del kernel. Il principio della complete mediation stabilisce che ogni tentativo di modifica degli oggetti interni al kernel deve essere soggetto ai controlli del sistema di sicurezza e viene approvato solo se questi sono soddisfatti.
LSM media l’accesso agli oggetti del kernel disponendo degli hooks nel codice del kernel immediatamente prima dell’accesso. Gli hooks LSM nel kernel Linux si occupano di mediare l’accesso agli oggetti interni del kernel come inodes, tasks, file, dispositivi e IPC. I moduli di sicurezza come SELinux possono usare questi hook generici per implementare un controllo degli accessi avanzato come moduli indipendenti del kernel.
Un esempio di come questo accade:
LSM Hooks: A “Mom, Can I Have a Cookie?” Analogy 🍪
Imagine the Linux kernel is a parent, and a program on your computer is a child. The child wants to do something, like get a cookie from the cookie jar. The cookie jar is a resource, like a file or a network connection.
The Child Asks: The child (your program) goes to the parent (the kernel) and says, “Mom, can I have a cookie?” This is called a system call.
Parent’s First Check (DAC): The parent first thinks about its own rules. “Is it after dinner? Did you finish your homework?” This is like Linux’s regular permission system, Discretionary Access Control (DAC). If the answer is no, the child can’t have the cookie.
The Security Guard Check (LSM Hook): But even if the parent’s rules say it’s okay, there’s a new rule in the house. The parent must also ask a special security guard who is always watching. This security guard is the Linux Security Module (LSM), for example, SELinux. The moment the parent is about to hand over the cookie, a hook stops the action and forces the parent to check with the guard.
The Guard’s Decision: The security guard (SELinux) has its own separate list of very strict rules (the security policy). It doesn’t care if it’s after dinner; it checks its list. The list might say, “This child is only allowed ‘healthy snack’ type cookies on Wednesdays.” The guard looks at the child and the cookie and makes a final “Yes” or “No” decision.
Final Answer: The parent (kernel) only gives the cookie to the child if both its own rules passed and the security guard gave a “Yes”.
The LSM hook is that mandatory step where the parent is forced to stop and ask the security guard for permission, ensuring no request ever slips by without this extra check.
A More Technical Look at LSM Hooks
Now, let’s translate that analogy into more technical terms. The LSM framework integrates security modules directly into the kernel’s decision-making process for resource access.
The Process Flow
The entire process happens in a specific order whenever a program needs to access a kernel resource.
System Call Initiation: An application running in user space needs to perform an operation that requires kernel-level privileges, such as opening a file (
open()) or creating a network socket (socket()). To do this, it makes a system call, which transfers control to the kernel space.Initial Kernel Checks: The kernel first performs standard error checking, like validating the arguments passed with the system call.
Discretionary Access Control (DAC) Check: Next, the kernel enforces the standard Linux permissions. It checks if the user ID (UID) and group ID (GID) of the process have the required permissions (read, write, execute) for the target resource. If this check fails, access is immediately denied.
LSM Hook Interception: If the DAC check passes, the process isn’t over. Just before the kernel code would grant access to the resource (like an inode, a task, or a file object), it hits an LSM hook. This hook is a function call that passes the access request details—the subject (the process trying to act) and the object (the resource being acted upon)—to the active security module, such as SELinux.
Security Module Decision: SELinux (or another LSM) then evaluates the request based on its own loaded security policy. It looks at the security labels (called contexts) of the subject and the object and checks its rule database to see if a rule exists that explicitly allows that specific action (e.g., “allow
httpd_ttoname_bindontcp_socketof typehttp_port_t”). It then returns a simple grant or deny decision to the kernel.Final Enforcement: The kernel receives the decision from the LSM. If access was granted, the system call proceeds, and the application gets access to the resource. If it was denied, the kernel blocks the operation and returns an error (e.g., “Permission denied”) to the user-space application.
This mechanism ensures complete mediation, a core security principle where every single access request to a kernel object is intercepted and validated against a central security policy, leaving no gaps or bypasses.

L’attivazione di SELinux in un sistema non riguarda solo l’attivazione del modulo LSM nel kernel1. L’implementazione di SELinux contiene almeno:
- SELinux kernel subsystem: implementato attraverso LSM;
- librerie: usate da applicazioni che hanno bisogno di interagire con SELinux;
- utilities: usate da amministratori per interagire con SELinux;
- policies: usate per definire la politica di access control stessa.
Context: definizione e uso
Quando SELinux deve decidere se permettere o negare una particolare azione, compie una decisione basata sul contesto del soggetto e dell’oggetto. I contesti (contexts) sono menzionati nella politica che SELinux applica; il contesto di ciascun processo è ciò che identifica il processo in SELinux.
SELinux non considera la process ownership di Linux e non considera come è chiamato il processo, quale PID abbia o sotto quale account viene eseguito. L’unica cosa importante è quale sia il contesto del processo, rappresentato ad amministratori e utenti come etichetta, utilizzata al posto del processo reale e metadati del file per l’access control. Sebbene l’utilizzo di percorsi possa essere più facile da comprendere per gli amministratori, non consente di tenere le informazioni sul contesto vicino alla risorsa: ad esempio, se una directory è spostata o viene smontata e montata nuovamente oppure se il processo ha una diversa vista dei file causa namespace, allora l’access control può comportarsi diversamente, considerando il percorso anziché il file.
Al contrario, il contesto rivela lo scopo del processo in una buona maniera. La stessa applicazione può essere lanciata in contesti diversi, in base a come è stata avviata. Inoltre, il contesto consente di fare un’astrazione dell’oggetto stesso e si può applicare non solo a file reali, ma anche a risorse meno tangibili (pipes, sockets, oggetti di database)2.
Il contesto può essere recuperato con il comando id. Utilizzando l’opzione -Z si possono visualizzare il contesto dell’utente corrente e, quindi, del processo stesso quando eseguito da quell’utente.
Label
Un’etichetta SELinux ha il seguente formato:
sysadm_u:sysadm_r:sysadm_t:s0-s0:c0.c1024e indica:
sysadm_u: l’utente SELinux;sysadm_r: il ruolo in SELinux;sysadm_t: il tipo in SELinux (anche dominio), tipicamente responsabile per la mancata concessione del permesso;s0-s0:c0.c1023: il livello di sensibilità (formatoMLS:MCS), gestisce il MAC nei modelli MLS (Multi-Level Security - gerarchico) e MCS (Multi-Category Security - non gerarchico)3.
Lettura degli attributi
I contesti di SELinux sono allineati con quelli di LSM e sono esposti allo user space in maniera standardizzata, quindi un utente può facilmente fare query per il contesto; è possibile ritrovarli nel pseudo filesystem proc, usando:
ls /proc/$$/attro, nel caso di processi con più subtasks:
ls /proc/<pid>/<task>/<taskid>/attrche mostrerà o nulla, o un contesto SELinux. Quando nulla è mostrato, vuol dire che l’applicazione non ha esplicitamente impostato un contesto per quello scopo e verrà dedotto o dalla policy o ereditato dal genitore.
I diversi file sono:
current, che mostra il contesto SELinux del processo;exec, che mostra il contesto SELinux che verrà assegnato all’esecuzione di un’applicazione tramite quella di cui si sta visualizzando l’attributo (if a running application were to start or “execute” another program, the value found in its ownexecfile dictates the SELinux security context the new program would be given.) - tipicamente vuoto;fscreate, mostra il contesto che verrà assegnato ai file creati dal processo - tipicamente vuoto;keycreate, mostra il contesto che verrà assegnato alle chiavi (crittografiche, NdA) in cache nel kernel (kernel keyrings) dell’applicazione - tipicamente vuoto;prev, mostra il contesto precedente al processo in analisi, tipicamente il contesto del processo genitore;sockcreate, mostra il contesto che verrà assegnato alla prossima socket creata dal processo - tipicamente vuoto.
SELinux Type Enforcement
SELinux è un sistema di MAC basato su Type Enforcement (Type Enforcement mandatory access control system), dunque il fattore fondamentale su cui si basa il modello di sicurezza è il tipo; questo attributo controlla le interazioni permesse a un processo, sia con se stesso (cosa il processo internamente può fare), sia con altri tipi (accesso ad altre risorse, inclusi file e altri processi).
Con questo tipo di applicazione, SELinux può controllare il comportamento di un applicazione primariamente su come un’applicazione viene eseguita in primis.
Role-based Access Control (RBAC)
SELinux consente anche il supporto al controllo accesso basato su ruoli (Role-based Access Control). Il ruolo, in SELinux, definisce quali tipi possono essere acceduti dal contesto corrente.
I ruoli tipicamente assegnati sono:
user_r(restricted user): può eseguire solo processi con tipi specifici degli utenti finali4. Tipi con più privilegi, inclusi quelli per passare a un altro utente Linux, non sono permessi per questo ruoli;staff_r(staff user): generalmente ristretto alle stesse applicazioni dell’utente ristretto, ma può cambiare ruoli;sysadm_r(system administrator): altamente privilegiato, può svolgere compiti di amministrazione del sistema, anche se alcuni tipi di applicazioni per utenti finali potrebbero non essere permessi per motivi di sicurezza;secadm_r(security administrator): permette di cambiare la policy SELinux e la manipolazione dei controlli SELinux;system_r(system): privilegiato, supporta vari demoni e tipi dei processi di sistema. Il tipo di applicazione per l’utente finale e altri tipi amministrativi non sono permessi in questo ruolo;unconfined_r(unconfined): permette un numero limitato di tipi, ma questi tipi sono altamente privilegiati in quanto permettono di eseguire ogni applicazione lanciata da un utente in maniera più o meno senza limiti. Esistono anche altri ruoli comeguest_rexguest_r, in base alla distribuzione scelta.
User-based Access Control (UBAC)
SELinux supporta anche il controllo accessi basato su utenti, che ha una particolarità fondamentale: un utente in SELinux non è lo stesso utente del sistema operativo Linux in esecuzione; infatti, è possibile imporre che l’utente SELinux rimanga lo stesso anche se l’utente Linux cambia.
È possibile applicare un controllo accessi tale da garantire che gli utenti non possano alterare i permessi che sono stati loro accordati, quando ottengono accesso privilegiato.
Le definizioni degli utenti SELinux restringono anche quali ruoli un utente Linux può assumere. Un utente Linux viene prima assegnato ad un utente SELinux, che non deve necessariamente essere unico; più utenti Linux possono essere assegnati allo stesso utente SELinux. Una volta definito, quell’utente non può passare ad un ruolo SELinux non associato a quell’utente SELinux.

Multilevel Security (MLS)
La sensibilità, all’interno di un’etichetta SELinux, non è sempre presente. Quando c’è, permette la classificazione delle risorse e le restrizioni dell’accesso a quelle risorse basandosi su un’autorizzazione di sicurezza (security clearance).
L’etichetta include due parti: un valore per la confidenzialità (confidentiality value, il cui prefisso è s) e uno per la categoria (category value, il cui prefisso è c). Vengono utilizzati numeri da zero (livello più basso) fino a quello che l’amministratore di sistema decide sia il livello più alto. Le categorie, inoltre, permettono di assegnare risorse con una o più categorie e di definire il controllo degli accessi tra le varie categorie.
Questo può risultare utile in organizzazioni grandi, in cui i documenti possono essere classificati come interni, confidenziali, strettamente confidenziali… e questa funzione di SELinux può realizzare questa classificazione, assegnando ai processi alcuni livelli autorizzativi per quelle risorse.
In SELinux si segue il modello Bell-LaPadula, caratterizzato dalla regola no read up, no write down: sulla base del livello autorizzativo di un processo, quello stesso processo non può leggere qualcosa con un livello di confidenzialità più alto e non può scrivere (o comunicare) con risorse con un più basso livello di confidenzialità.
Policy di SELinux
Attivare SELinux non per forza implica l’avvio delle operazioni di enforcement. Se SELinux è abilitato e non riesce a trovare una policy, si rifiuterà di avviarsi perché sono le policy a definire il comportamento del sistema (cioè quello che SELinux dovrebbe permettere).
Le politiche di SELinux sono generalmente distribuite in una forma compilata, i policy modules, che sono poi aggregati in un singolo policy store e caricati in memoria per permettere a SELinux di applicare le regole all’interno del sistema.

Esistono tre metodi per scrivere ua policy SELinux:
- formato standard di SELinux (standard SELinux source format): un linguaggio human-readable e affermato;
- reference policy style, che estende il formato standard di SELinux con macro M4 per semplificare lo sviluppo di policy;
- SELinux common intermediate language (CIL): un formato principalmente computer-readable.
Standard SELinux format
allow httpd_t http_port_t : tcp_socket { name_bind };I diversi elementi che lo compongono:
- il soggetto (chi intraprende un’azione), che in questo caso sono i processi etichettati dal tipo
httpd_t; - la risorsa target o l’oggetto, che in questo caso è l’insieme delle socket TCP (
tcp_socket) etichettate con il tipohttpd_port_t(nel reference policy style, questo è implicito nel nome della funzione); - l’azione o il permesso, in questo caso l’azione di bind a una porta (
name_bind); - il risultato che la policy applica, in questo caso l’azione che è permessa (
allow).
Le regole sono salvare in file con estensione .te (type enforcement rules). Le interfacce e i template per le definizioni sono in formato .if e permettono a chi scrive le policy di usare facilmente le policy appena generate o per migliorare altre policy. Una terza estensione associata è .fc (file context expressions) e sono delle regole che assegnano delle etichette a delle risorse sul filesystem.
Permessi sconosciuti: cosa fare?
I permessi (read, open, lock) sono definiti sia nel kernel Linux che nelle policy stesse; può, però, accadere che il kernel supporti dei permessi che le policy correnti non comprendono ancora. Se ciò accade, allora SELinux può:
- permettere ogni azione correlata a permesso non noto (
allow); - rifiutare ogni azione correlata a un permesso non noto (
deny); - arrestarsi e fermare il sistema quando viene controllato un permesso non noto (
reject).
Il comportamento viene configurato mediante il valore deny_unknown e gli amministratori possono configurarselo nel file /etc/selinux/semanage.conf mediante la variabile handle-unknown.
Unconfined domains
I domini unconfined sono stati introdotti per permettere a SELinux di essere attivo su desktop e server su cui gli amministratori non vogliono restringere l’intero sistema, ma solo alcune applicazioni che vengono eseguite.
Quando abilitati, si avrà che ad alcuni contesti sarà permesso di fare quasi qualsiasi cosa vogliano, nei limiti del DAC tradizionale di Linux; solo un certo numero di domini sono limitati nelle loro azioni.
Con altri sistemi di MAC (come AppArmor), l’unconfinement è intrinsecamente parte della progettazione del sistema, dal momento in cui restringono solamente azioni per applicazioni o utenti ben noti. SELinux, d’altro canto, è progettato per essere un sistema MAC completo e necessita, quindi, di fornire controllo accessi anche per quelle applicazioni che non sono il focus principale degli amministratori di sicurezza.
È possibile controllare se i domini unconfined sono attivi sul sistema con seinfo, effettuando una query alla policy con cui si chiede se il tipo SELinux unconfined_t è definito:
seinfo -t unconfined_tStato globale di SELinux
Quando il processo di init del sistema carica la policy SELinux, il codice di SELinux stesso controlla lo stato che l’amministratore ha configurato:
- disabled: si avvia il sistema senza attivare SELinux;
- permissive: SELinux è attivo ma non applica le policy sul sistema, limitandosi a loggare ogni violazione delle policy e consentendo ogni azione (tipicamente usato per la host intrusion detection);
- enforcing: SELinux è attivo e applicherà la policy sul sistema. In caso di violazioni, queste sono riportate e le azioni rifiutate (tipicamente usato per la host intrusion prevention).
Bonus points
È importante rietichettare i file quando si passa dalla modalità disabled a una tra permissive o enforcing (ma non quando si passa da permissive e enforcing) o quando si effettua il reset della password. Viene effettuato col comando:
touch /.autorelabele può impiegare del tempo (lo stesso del check disk).
Esistono alcuni tools che consentono una gestione semplificata delle etichette SELinux, come chcon, semanage, restorecon per la modifica delle etichette, che vengono settate al momento della creazione del file. Inoltre, con i pacchetti RPM si possono impostare delle etichette come parte del processo di installazione (tipicamente per creare il contesto che poi l’applicazione userà). Il processo di login, invece, setta il default context, tipicamente unconfined.
Esempio d’uso delle utility:
# Impostazione di un contesto - httpd_sys_content_t ai contenuti della cartella /srv/webdata
semanage fcontext -a -t httpd_sys_content_t "/srv/webdata(/.*?)"
# Ripristino del contesto originale - alla creazione del file
restorecon -Rv /srv/webdata
# Cambio del contesto
chcon -t httpd_sys_content_t /var/www/html/test.html
# Cambio del contesto, ereditandolo da altra risorsa
chcon --reference /var/www/ siteEsistono anche altri tool che consentono un debug più agevole:
audit2allow: un tool che, leggendo dalla AVC (Access Vector Cache) gli eventi di log che causano un denial, si occupa di produrre delle policy che vanno a consentire le azioni per le quali è stato loggato il denial. Può compilare le nuove regole in un SELinux policy module package (estensione.pp), installabile tramitesemodule. Un esempio:# Lettura raw della AVC (per essere sicuri di una lettura corretta) e passaggio a audit2allow ausearch -c "httpd_t" --raw | audit2allow -M httpd_t
Installazione delle policy generate
semodule -i httpd_t.pp
- `setroubleshoot` installa una serie di tool per diagnosticare e risolvere problemi in SELinux.
---
SELinux rappresenta anche una misura di damage mitigation per gli zero-day attacks. Se un'applicazione, ad esempio, riuscisse a eseguire un processso di bash tramite un payload (RCE, *Remote Code Execution*):
- **senza SELinux**: il processo può accedere a tutte le risorse permesse dal DAC integrato;
- **con SELinux**: il processo è confinato nel suo contesto (ad esempio `httpd_t`) e non può accedere ad altre risorse (`/home` o anche directory più sensibili, come quelle di SSH), aprire socket etc, essendo vietato dalle policy del MAC.
Footnotes
-
L’attivazione del modulo SELinux senza l’uso di alcuna policy equivale ad avere il modulo SELinux spento. ↩
-
L’esempio può essere realizzato con:
- permettere al processo
httpddi fare bind della porta 80 TCP; - permettere ai processi etichettati con
httpd_tdi fare bind delle porte TCP etichettate comehttp_port_t.
Nel primo caso, non si può riutilizzare la policy quando il web server non usa
httpd; nel secondo caso, il binario può essere siaapache2che, ad esempioMyWebServer.pyo qualsiasi altra cosa, finché il processo sia etichettato comehttpd_t. ↩ - permettere al processo
-
Sono ulteriori criteri della politica, scarsamente utilizzati. MLS applica la confidenzialità stretta, considerando il principio No Read Up, No Write Down (in sostanza, un processo può leggere solamente oggetti che hanno lo stesso livello di sensibilità o più basso, mentre possono scrivere su oggetti a pari livelli di sensibilità o più alto); nei sistemi moderni si segue la Targeted Policy e, dunque, la funzionalità è disabilitata o semplificata (impostando a
s0-s0, il livello più “basso” e neutralizzando la gerarchia, spostando il focus sulle categorie). MCS lavora con un il principio di inclusione di insiemi: un processo può accedere ad un oggetto solo se il suo insieme di categorie domina - cioè include tutte le categorie - possedute dal file. La partec0.c1024denota la presenza di tutte le categorie e si è in regime di processo unconfined - tipico dei processi con privilegi di amministrazione. ↩ -
Questo tipo di processi è quello che, comunemente, identifica processi lanciati da utenti non amministratori per i task di tutti i giorni. ↩