newrole -r role_r -t domaine_t
(il n'y a généralement qu'un seul domaine possible pour un rôle donné et le paramètre -t
est donc souvent inutile). Cette commande demande à l'utilisateur son mot de passe afin de l'authentifier. Cette caractéristique empêche tout programme de pouvoir changer de rôle de manière automatique. De tels changements ne peuvent avoir lieu que s'ils sont prévus dans l'ensemble de règles.
ssh
est étiqueté avec ssh_exec_t
et lorsque le programme est démarré, il bascule automatiquement dans le domaine ssh_t
). Ce mécanisme de changement automatique de domaine permet de ne donner que les droits nécessaires au bon fonctionnement de chaque programme et est à la base de SELinux.
apt install selinux-basics selinux-policy-default
installera automatiquement les paquets nécessaires pour configurer un système SELinux.
selinux-policy-default
contient un ensemble de règles standards. Par défaut, l'ensemble de règles ne restreint les accès que pour certains services très exposés. Les sessions utilisateur ne sont pas restreintes et il n'y a donc que peu de risques que SELinux bloque des opérations légitimes des utilisateurs. En revanche, cela permet d'apporter un surcroît de sécurité pour les services système fonctionnant sur la machine. Pour obtenir l'équivalent des anciennes règles « strictes », il faut simplement désactiver le module unconfined
(la gestion des modules est détaillée plus loin).
fixfiles relabel
.
selinux=1 security=selinux
au noyau Linux. Le paramètre audit=1
active les traces SELinux qui enregistrent les différentes opérations qui ont été refusées. Enfin, le paramètre enforcing=1
permet de mettre en application l'ensemble des règles : en effet, par défaut SELinux fonctionne en mode permissive où les actions interdites sont tracées mais malgré tout autorisées. Il faut donc modifier le fichier de configuration du chargeur de démarrage GRUB pour ajouter les paramètres désirés. Le plus simple pour cela est de modifier la variable GRUB_CMDLINE_LINUX
dans /etc/default/grub
et d'exécuter update-grub
. Au démarrage suivant, SELinux sera actif.
selinux-activate
automatise ces opérations et permet de forcer un étiquetage au prochain redémarrage, ce qui évite d'avoir des fichiers non étiquetés créés alors que SELinux n'était pas encore actif et que l'étiquetage était en cours.
semodule
. En outre, il faut pouvoir définir les rôles accessibles à chaque utilisateur ; pour cela c'est la commande semanage
qu'il faudra utiliser.
/etc/selinux/default/
. Contrairement à ce qui se pratique d'habitude avec les fichiers de configuration de /etc/
, ces fichiers ne doivent pas être modifiés manuellement. Il faut les manipuler en utilisant les programmes prévus pour cela.
/usr/share/selinux/default/
. Pour activer un de ces modules dans la configuration courante, il faut employer semodule -i module.pp.bz2
. L'extension pp.bz2
signifie policy package que l'on pourrait traduire par « paquet de règles » (comprimé avec bzip2).
semodule -r module
retire un module de la configuration courante. Enfin, la commande semodule -l
liste les modules qui sont actuellement installés. La commande inclut également le numéro de version du module.
#
semodule -i /usr/share/selinux/default/abrt.pp.bz2
#
semodule -l
abrt 1.5.0 Disabled accountsd 1.1.0 acct 1.6.0 [...]
#
semodule -e abrt
#
semodule -d accountsd
#
semodule -l
abrt 1.5.0 accountsd 1.1.0 Disabled acct 1.6.0 [...]
#
semodule -r abrt
#
semodule -l
accountsd 1.1.0 Disabled acct 1.6.0 [...]
semodule
recharge immédiatement la nouvelle configuration, sauf si l'on utilise l'option -n
. Signalons également que le programme modifie par défaut la configuration courante (celle indiquée par la variable SELINUXTYPE
dans /etc/selinux/config
) mais qu'on peut en modifier une autre grâce à l'option -s
.
semanage
.
-a
pour ajouter, -d
pour supprimer, -m
pour modifier, -l
pour lister et -t
pour indiquer un type (ou domaine).
semanage login -l
liste les correspondances existantes entre identifiants d'utilisateurs et identités SELinux. Si un utilisateur n'a pas de correspondance explicite, il aura l'identité indiquée en face de __default__
. La commande semanage login -a -s user_u utilisateur
va associer l'identité user_u à l'utilisateur. Enfin, semanage login -d utilisateur
va retirer la correspondance affectée à l'utilisateur.
#
semanage login -a -s user_u rhertzog
#
semanage login -l
Login Name SELinux User MLS/MCS Range Service __default__ unconfined_u SystemLow-SystemHigh * rhertzog user_u SystemLow * root unconfined_u SystemLow-SystemHigh * system_u system_u SystemLow-SystemHigh * #
semanage login -d rhertzog
semanage user -l
liste les correspondances entre identité SELinux et rôles possibles. Ajouter une nouvelle identité nécessite de préciser d'une part les rôles correspondants et d'autre part, un préfixe d'étiquetage qui définira le type affecté aux fichiers personnels (/home/utilisateur/*
). Le préfixe est à choisir entre user
, staff
et sysadm
. Un préfixe « staff
» donnera des fichiers typés staff_home_dir_t
. La commande créant une identité est semanage user -a -R rôles -P préfixe identité
. Enfin, une identité peut être supprimée avec semanage user -d identité
.
#
semanage user -a -R 'staff_r user_r' -P staff test_u
#
semanage user -l
Labeling MLS/ MLS/ SELinux User Prefix MCS Level MCS Range SELinux Roles root sysadm SystemLow SystemLow-SystemHigh staff_r sysadm_r system_r staff_u staff SystemLow SystemLow-SystemHigh staff_r sysadm_r sysadm_u sysadm SystemLow SystemLow-SystemHigh sysadm_r system_u user SystemLow SystemLow-SystemHigh system_r test_u staff SystemLow SystemLow staff_r user_r unconfined_u unconfined SystemLow SystemLow-SystemHigh system_r unconfined_r user_u user SystemLow SystemLow user_r #
semanage user -d test_u
/srv/www/
accessible au serveur web, on pourrait exécuter semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"
, puis restorecon -R /srv/www/
. La première commande enregistre la nouvelle règle d'étiquetage et la seconde restaure les bonnes étiquettes en fonction des règles enregistrées.
semanage port -m -t http_port_t -p tcp 8080
.
getsebool
permet de consulter l'état de ces options (getsebool booléen
affiche une option et getsebool -a
les affiche toutes). La commande setsebool booléen valeur
change la valeur courante d'une option. L'option -P
rend le changement permanent, autrement dit la nouvelle valeur sera celle par défaut et sera conservée au prochain redémarrage. L'exemple ci-dessous permet au serveur web d'accéder aux répertoires personnels des utilisateurs (utile dans le cas où ils ont des sites web personnels dans ~/public_html/
par exemple).
#
getsebool httpd_enable_homedirs
httpd_enable_homedirs --> off #
setsebool -P httpd_enable_homedirs on
#
getsebool httpd_enable_homedirs
httpd_enable_homedirs --> on
/usr/share/doc/selinux-policy-doc/html/
) et des fichiers exemples permettant de créer de nouveaux modules. Installons ces fichiers pour les étudier de plus près :
$
cp /usr/share/doc/selinux-policy-doc/Makefile.example Makefile
$
cp /usr/share/doc/selinux-policy-doc/example.fc ./
$
cp /usr/share/doc/selinux-policy-doc/example.if ./
$
cp /usr/share/doc/selinux-policy-doc/example.te ./
.te
est le plus important : il définit les règles à proprement parler. Le fichier .fc
définit les « contextes des fichiers », autrement dit les types affectés aux fichiers relatifs à ce module. Les informations du .fc
sont utilisées lors de l'étiquetage des fichiers sur le disque. Enfin, le fichier .if
définit l'interface du module ; il s'agit d'un ensemble de « fonctions publiques » qui permettent à d'autres modules de s'interfacer proprement avec celui en cours de création.
myapp_domtrans
) sert à contrôler qui a le droit d'exécuter l'application et la seconde (myapp_read_log
) fournit un droit de lecture sur les fichiers de logs de l'application.
.te
. Il faut donc déclarer tous les types employés (avec la macro gen_require
) et employer les directives standards pour attribuer des droits. Notons toutefois qu'il est possible d'employer des interfaces fournies par d'autres modules. La prochaine section en dévoilera plus sur la manière d'exprimer ces droits.
Exemple 14.3. Fichier example.if
## <summary>Myapp example policy</summary> ## <desc> ## <p> ## More descriptive text about myapp. The <desc> ## tag can also use <p>, <ul>, and <ol> ## html tags for formatting. ## </p> ## <p> ## This policy supports the following myapp features: ## <ul> ## <li>Feature A</li> ## <li>Feature B</li> ## <li>Feature C</li> ## </ul> ## </p> ## </desc> # ######################################## ## <summary> ## Execute a domain transition to run myapp. ## </summary> ## <param name="domain"> ## Domain allowed to transition. ## </param> # interface(`myapp_domtrans',` gen_require(` type myapp_t, myapp_exec_t; ') domtrans_pattern($1,myapp_exec_t,myapp_t) ') ######################################## ## <summary> ## Read myapp log files. ## </summary> ## <param name="domain"> ## Domain allowed to read the log files. ## </param> # interface(`myapp_read_log',` gen_require(` type myapp_log_t; ') logging_search_logs($1) allow $1 myapp_log_t:file r_file_perms; ')
example.te
:
policy_module(myapp,1.0.0) ######################################## # # Declarations # type myapp_t; type myapp_exec_t; domain_type(myapp_t) domain_entry_file(myapp_t, myapp_exec_t) type myapp_log_t; logging_log_file(myapp_log_t) type myapp_tmp_t; files_tmp_file(myapp_tmp_t) ######################################## # # Myapp local policy # allow myapp_t myapp_log_t:file { read_file_perms append_file_perms }; allow myapp_t myapp_tmp_t:file manage_file_perms; files_tmp_filetrans(myapp_t,myapp_tmp_t,file)
Le module doit être identifié par son nom et par son numéro de version. Cette directive est requise.
| |
Si le module introduit de nouveaux types, il doit les déclarer avec des directives comme celle-ci. Il ne faut pas hésiter à créer autant de types que nécessaires, plutôt que distribuer trop de droits inutiles.
| |
Ces interfaces précisent que le type myapp_t est prévu pour être un domaine de processus et qu'il doit être employé pour tout exécutable étiqueté par myapp_exec_t . Implicitement, cela ajoute un attribut exec_type sur ces objets. Sa présence permet à d'autres modules de donner le droit d'exécuter ces programmes : ainsi, le module userdomain va permettre aux processus de domaine user_t , staff_t et sysadm_t de les exécuter. Les domaines d'autres applications confinées n'auront pas le droit de l'exécuter, sauf si les règles prévoient des droits similaires (c'est le cas par exemple pour dpkg avec le domaine dpkg_t ).
| |
logging_log_file est une interface fournie par la reference policy qui sert à indiquer que les fichiers étiquetés avec le type précisé en paramètre sont des fichiers de logs et doivent bénéficier des droits associés (par exemple ceux permettant à logrotate de les manipuler).
| |
La directive allow est la directive de base qui permet d'autoriser une opération. Le premier paramètre est le domaine du processus qui sera autorisé à effectuer l'opération. Le second décrit l'objet qu'un processus du domaine aura le droit de manipuler. Ce paramètre prend la forme « type:genre » où type est son type SELinux et où genre décrit la nature de l'objet (fichier, répertoire, socket, fifo, etc.). Enfin, le dernier paramètre décrit les permissions (les opérations qui sont autorisées).
Les permissions se définissent comme des ensembles d'opérations autorisées et prennent la forme { operation1 operation2 } . Il est également possible d'employer des macros qui correspondent aux ensembles de permissions les plus utiles. Le fichier /usr/share/selinux/devel/include/support/obj_perm_sets.spt permet de les découvrir.
La page web suivante fournit une liste relativement exhaustive des genres d'objet (object classes) et des permissions que l'on peut accorder :
|
avc: denied { read write } for pid=1876 comm="syslogd" name="xconsole" dev=tmpfs ino=5510 scontext=system_u:system_r:syslogd_t:s0 tcontext=system_u:object_r:device_t:s0 tclass=fifo_file permissive=1
Tableau 14.1. Analyse d'une trace SELinux
Message | Description |
---|---|
avc: denied | Une opération a été refusée. |
{ read write } | Cette opération requérait les permissions read et write . |
pid=1876 | Le processus ayant le PID 1876 a exécuté l'opération (ou essayé de l'exécuter). |
comm="syslogd" | Le processus était une instance de la commande syslogd . |
name="xconsole" | L'objet visé s'appelait xconsole . Dans certains cas on peut aussi avoir une variable « path », avec un chemin d'accès complet. |
dev=tmpfs | Le périphérique stockant l'objet est de type tmpfs . Pour un disque réel, nous pourrions voir la partition contenant l'objet (exemple : « sda3 »). |
ino=5510 | L'objet est identifié par le numéro d'inode 5510. |
scontext=system_u:system_r:syslogd_t:s0 | C'est le contexte de sécurité courant du processus qui a exécuté l'opération. |
tcontext=system_u:object_r:device_t:s0 | C'est le contexte de sécurité de l'objet cible. |
tclass=fifo_file | L'objet cible est un fichier FIFO. |
allow syslogd_t device_t:fifo_file { read write }
. Ce processus est automatisable et c'est ce que propose la commande audit2allow
du paquet policycoreutils. Une telle démarche ne sera utile que si les objets impliqués sont déjà correctement étiquetés selon ce qu'il est souhaitable de cloisonner. Dans tous les cas, il faudra relire attentivement les règles pour les vérifier et les valider par rapport à votre connaissance de l'application. En effet, bien souvent cette démarche donnera des permissions plus larges que nécessaires. La bonne solution est souvent de créer de nouveaux types et d'attribuer des permissions sur ces types uniquement. Il arrive également qu'un échec sur une opération ne soit pas fatal à l'application, auquel cas il peut être préférable d'ajouter une règle dontaudit
qui supprime la génération de la trace malgré le refus effectif.
example.if
, example.fc
et example.te
) sont conformes aux règles que l'on veut créer, il suffit d'invoquer make NAME=devel
pour générer un module dans le fichier example.pp
(que l'on peut immédiatement charger avec semodule -i example.pp
). Si plusieurs modules sont définis, make
créera tous les fichiers .pp
correspondants.