LINUX:SELinux-Module
But
Un module est un ensemble cohérent des différentes composantes de SELinux: Types, règles, Fcontext,... Il se présente sous une forme ayant beaucoup d'analogie avec un programme.
Listage
On peut lister tous les modules déjà intégrés dans la stratégie globale de sécurité de SELinux de la machine.
Voici la commande:
semanage module -l
ou
semodule -lfull
En voici un extrait:
Nom de module Priorité Langue BackupPC 400 pp amanda 100 pp apache 100 pp apcupsd 100 pp apm 100 pp application 100 pp arpwatch 100 pp auditadm 100 pp authconfig 100 pp ... my-gw 300 pp my-httpd-nagios 300 pp my-logrotate-wazuh 300 pp
En première colonne nous avons le nom du module et en seconde sa priorité.
On peut également les lister en parcourant le répertoire "/var/lib/selinux/targeted/active/modules".
Le nom du module doit être unique dans la stratégie globale de sécurité de SELinux de la machine. Au pire, si on installe un nouveau module portant le même nom qu'un module existant et ayant la même priorité, le nouveau module va écraser l'existant et l'ancien sera perdu. S'ils n'ont pas la même priorité, celui ayant la plus grande sera utilisée et l'autre inactivé. Vous comprendrez que si vous écrasez un module existant d'un paquet du système, vous aller perturber grandement l'exécution de ce logiciel.
Il est donc impératif de donner à nos modules un nom bien spécifique. Par exemple, on utilise un préfixe personnel tel "my-" ou "adebast-".
Etapes de mise en oeuvre
La constitution d'un module passe par trois étapes:
- la rédaction des sources du module; elles sont constituées de trois parties dans trois fichiers distincts.
- la compilation de ces sources.
- l'intégration de ce module dans la stratégie globale de sécurité de SELinux de la machine.
Sources
Elles sont constituées de trois fichiers. Tous les fichiers portent le même nom que celui du module. Ils se distinguent par leur extension.
- <nom du module>.te: C'est le fichier principal et nécessaire. Il contient le nom du module, les déclaratives des types, les classes, permissions, des attributs,... , des règles et d'appels de macros-interfaces globales ou personnelles.
- <nom du module>.if: Ce fichier contient les sources de macros-interfaces personnelles, locales. Elles ne sont pas nécessaire. Ce fichier sera vide dans notre cas car nous n'en créerons pas.
- <nom du module>.tc: Ce fichier contient les liaisons entre les "Context" et les fichiers ("Fcontext"). Il remplace la commande vue précédemment "semanage fcontext ...". Elle ne sont pas nécessaires, Ce fichier peut être vide. Il le sera lors de la mise en route de SELinux.
Source TE
Nous allons présenter sous forme d'un exemple, les composantes principales de la source TE du module. C'est cette structure que nous rencontrerons lors de la mise en route de SELinux. Si nous devions créer un module complet pour une application personnelle, il faudra y ajouter d'autres notions.
Voici un exemple de source; il a été conçu lors de l'intégration du programme Web de généalogie (voir l'article sur GeneWeb).
Ce fichier porte le nom "my-gw.te":
module my-gw 1.0; require { type httpd_sys_content_t; type init_t; class file { execute execute_no_trans map open read write append create lock setattr rename unlink }; } allow init_t httpd_sys_content_t:file { execute execute_no_trans open read write append create lock setattr map rename unlink };
Celui qui est habitué à la programmation y retrouvera les quelques grandes notions de base.
La première ligne définit le nom du module qui est le même que le nom du fichier hors extension: "my-gw".
Le second groupe concerne les déclaratives; dans ce cas, elles sont requises car elles doivent préexister dans la stratégie globale de sécurité de SELinux de la machine. Mais elles pourraient être nouvelles. On y retrouve les différentes composantes du "Context" expliquées dans l'article sur le Concept de SELinux.
Le dernier groupe reprend les règles.
Dans ce dernier groupe, toute utilisation d'une composante du "Concept" doit être repris dans la seconde partie déclarative sinon la compilation ne se fera pas.
Source IF
Ce fichier peut contenir des fonctions nommées "interfaces". Ces routines peuvent être appelées dans la source TE. Leur rôle est de rassembler diverses déclaratives et actions et ainsi de faciliter le travail de programmation. Dans ce fichier, ces fonctions sont personnelles; elle ne sont valables que pour ce module. Mais le système en fourni tout un ensemble. On peut les trouver sous le répertoire "/usr/share/selinux/devel/include". Leur description peut être consultée dans le répertoire "/usr/share/doc/selinux-policy/html". Elle est sous format HTML. Nous ne les utiliserons pas.
Source TC
Ce fichier contient les liaisons entre les "Context" et les fichiers ("Fcontext"). Il remplace la commande vue précédemment "semanage fcontext ...". Il n'est donc pas nécessaires. Nous l'utiliserons lors de la création d'un module lié à un programme personnel développé en exemple.
Voici cet exemple:
/gestion/bin/lireecrire.py -- gen_context(system_u:object_r:gestion_exec_t,s0) /gestion/data(/.*)? gen_context(system_u:object_r:gestion_data_t,s0)
Chaque ligne est constituée de trois zones:
- la zone de listage des fichiers
- le type de fichier: Il en existe plusieurs. Son absence désigne tout type de fichier; le code "--" désigne un fichier classique; le code "-d" désigne un répertoire;...
- la fonction "gen_context()" qui fournit le "Context"
Les commandes équivalentes sont:
semanage fcontext -a -t gestion_exec_t '/gestion/bin/lireecrire.py' semanage fcontext -a -t gestion_data_t '/gestion/data(/.*)?'
Création de sources
La manière usuelle est de créer ces fichiers à partir de rien à l'aide d'un éditeur de texte.
Mais il existe une autre manière que nous utiliserons abondamment. De prime abord, nous n'allons pas créer un module de notre cru. Nous serons confrontés à de multiples alertes bloquant un logiciel installé. Nous allons utiliser un outil qui permet de générer la source de type TE à partir de ces alertes.
A partir du fichier journal des audits, on extrait les lignes concernant les alertes qui concernent notre application.
Par exemple, voici les lignes générées lorsque nous voulions utiliser le programme GeneWeb:
type=AVC msg=audit(1702911730.037:105900): avc: denied { execute } for pid=903874 comm="(gwd)" name="gwd" dev="dm-1" ino=2497529 scontext=system_u:system_r:init_t:s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=file permissive=1 type=AVC msg=audit(1702911730.037:105901): avc: denied { read open } for pid=903874 comm="(gwd)" path="/web/geneweb/gw/gwd" dev="dm-1" ino=2497529 scontext=system_u:system_r:init_t:s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=file permissive=1 type=AVC msg=audit(1702911730.038:105903): avc: denied { execute_no_trans } for pid=903874 comm="(gwd)" path="/web/geneweb/gw/gwd" dev="dm-1" ino=2497529 scontext=system_u:system_r:init_t:s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=file permissive=1 type=AVC msg=audit(1702911730.038:105904): avc: denied { read } for pid=903874 comm="(gwd)" name="gwd" dev="dm-1" ino=2497529 scontext=system_u:system_r:init_t:s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=file permissive=1 type=AVC msg=audit(1702911730.040:105905): avc: denied { map } for pid=903874 comm="gwd" path="/web/geneweb/gw/gwd" dev="dm-1" ino=2497529 scontext=system_u:system_r:init_t:s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=file permissive=1 type=AVC msg=audit(1702911730.040:105906): avc: denied { execute } for pid=903874 comm="gwd" path="/web/geneweb/gw/gwd" dev="dm-1" ino=2497529 scontext=system_u:system_r:init_t:s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=file permissive=1 type=AVC msg=audit(1702911730.227:105907): avc: denied { open } for pid=903874 comm="gwd" path="/web/geneweb/gw/gwd" dev="dm-1" ino=2497529 scontext=system_u:system_r:init_t:s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=file permissive=1 type=AVC msg=audit(1702911835.650:105924): avc: denied { execute } for pid=904030 comm="(gwd)" name="gwd" dev="dm-1" ino=2497529 scontext=system_u:system_r:init_t:s0 tcontext=system_u:object_r:httpd_sys_content_t:s0 tclass=file permissive=1
Nous les mettons dans le fichier "gw.log".
Ensuite on fait appel au programme "audit2allow":
cat gw.log | audit2allow -M my-gw
Il va générer les fichiers "my-gw.te" et "my-gw.pp" correspondant au module "my-gw". Le contenu du fichier "my-gw.te" correspond à celui présenté ci-dessus sous la section "Source TE". Le second fichier correspond au module compilé.