LINUX:SELinux-Concept

De WIKI sur Linux (ADB)
Aller à la navigation Aller à la recherche

retour à SELinux


But

Rappelons que sous Unix tout est basé sur des fichiers. A chaque fichier est lié un Context SELinux.

Un utilisateur est lié à un utilisateur SELinux.

Cet utilisateur SELinux appartient à un ou plusieurs rôles.

Un rôle donne accès à divers domaines qui sont une des catégorie de type SELinux.

Et tout un immense ensemble de règles régissent les interactions entre ces divers contexts. Cet ensemble de règles définit la sécurité SELinux.


Context

Donc une des bases de la protection est de sécuriser les fichiers au sens large, processus compris.

On est habitué à une sécurité basée sur la propriété et les accès basics. La commande suivante:

ls -al /etc/passwd

donne:


-rw-r--r--. 1 root root 7453  7 jan 11:36 /etc/passwd

Ce fichier appartient à l'utilisateur "root" et au group "root". Le propriétaire a les droits de lecture et d'écriture alors que les autres n'ont que le droit de lecture.

SELinux ajoute une nouvelle couche. Cette couche permet de contrôler les accès d'une application aux fichiers.

Remarque très importante!!! Dès que cette troisième couche SELinux est activée, il faut la considérer impérativement comme des deux premières couches sinon on courre à des blocages.


SELinux ajoute des attributs à chaque fichier appelé "context".

Sa syntaxe est la suivante:

[User SELinux]:[Role]:[Type]:[Level]

où:

  • [User SELinux] : l'utilisateur SELinux. Chaque utilisateur Linux est lié à un utilisateur SELinux.
  • [Role] : le rôle SELinux. Il relie un utilisateur SELinux à un ensemble de type SELinux.
  • [Type] : le type d'attribut SELinux. Il défini le domaine d'un processus ou le type d'un fichier. Il permet de regrouper un ensemble de "fichiers,..." entre eux.
  • [Level] : le niveau de sécurité. Il est surtout utilisé par le niveau de protection "MLS" (Multi Level Security). Comme nous utilisons le niveau "Targeted", il est fixe "s0" et n'a pas d'impact spécial.

Cette suite d'attributs fonctionne comme une position dans un arbre où la base se situe au niveau de l'utilisateur.


Dans la pratique, diverses commandes comportent une option additionnelle "-Z" qui permet de connaitre ces attributs.

  • la commande "ls" pour les fichiers:
ls -alZ /etc/passwd

donne:


-rw-r--r--. 1 root root system_u:object_r:passwd_file_t:s0 7453  7 jan 11:36 /etc/passwd

  • la commande "ps" pour les processus:
ps axZ | grep passwd

donne:


unconfined_u:unconfined_r:passwd_t:s0-s0:c0.c1023 544774 pts/2 S+   0:00 passwd

  • la commande "netstat" pour les ports:
netstat -natpZ | grep httpd

donne:


tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      1368/httpd           system_u:system_r:httpd_t:s0   
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      1368/httpd           system_u:system_r:httpd_t:s0      
tcp        0      0 192.168.1.60:443        192.168.1.2:65097       ESTABLISHED 1477/httpd           system_u:system_r:httpd_t:s0    

  • la commande "id" pour la session:
id 

donne pour la session de l'utilisateur "staff":


uid=5004(staff) gid=100(users) groupes=100(users) contexte=user_u:user_r:user_t:s0

et

id -Z

donne:


user_u:user_r:user_t:s0

Pour le premier exemple concernant le fichier "/etc/passwd", ce context "system_u:object_r:passwd_file_t:s0" se décompose comme suit:

  • [User SELinux] : system_u
  • [Role] : object_r
  • [Type] : passwd_file_t
  • [Level] : s0

Par convention et pour pouvoir s'y retrouver, on ajoute des suffises spécifiques à chaque catégorie:

  • [User SELinux] : _u
  • [Role] : _r
  • [Type] : _t


Fcontext

Chaque fichier a un "Context". Par défaut, ils vont en recevoir un: "system_u:object_r:default_t:s0". Mais il est impératif que chaque fichier aie son propre context adapté selon sa fonction.

Il existe deux moyens pour effectuer cette liaison:

  • via les modules: Un module est un ensemble cohérent de déclaratives, de règles, de liaisons de contexts aux fichiers,... Ces modules sont majoritairement installés via les logiciels.
  • via les commandes de lignes pour des adaptations personnelles

Cette seconde approche peut être visualisée dans les fichiers du répertoire "/etc/selinux//targeted/contexts/files".

Pour avoir une liste complète, exécutez la commande suivante:

semanage fcontext -l

Et pour ceux personnalisés:

semanage fcontext -lC

Pour effectuer cette liaison, on passe par deux étapes:

  • l'ajout d'une définition; on utilise la commande:
semanage fcontext -a -t <type> <fichiers>

Par exemple:

semanage fcontext -a -t httpd_sys_content_t '/application/web(/.*)?'

Qui ajoute ("-a") le type "httpd_sys_content_t" à tous les fichiers et répertoires de l'arborescence "/application/web".

  • l'élimination ("-d") d'une définition; on utilise la commande:
semanage fcontext -d -t <type> <fichiers>

Par exemple:

semanage fcontext -d -t httpd_sys_content_t '/application/web(/.*)?'

Pour éliminer la définition précédente.

  • l'application de cette définition ou son retrait avec la commande suivante:
restorecon -RFv <fichiers>

Par exemple:

restorecon -RFv /application/web/

Si par après, on ajoute un fichier ou un répertoire et si leur "Context" ne suit pas, on réapplique cette définition avec cette même commande.


Types

De façon simple, nous avons deux grands groupes de "Types":

  • les Types ayant l'attribut "domain"; c'est sous un type de ceux-ci que tout process s'exécutera.
  • les autres Types appliqués aux fichiers (et quelques cas particuliers)

Une série de règles vont autoriser le Type Domain à utiliser les autres types.

Pour lister ces liaisons, utilisez la commande suivante:

seinfo -t -x

voici un extrait car leur nombre est très grand:


Types: 5188
  ...
  type passwd_t, application_domain_type, can_read_shadow_passwords, can_write_shadow_passwords, can_relabelto_shadow_passwords, nsswitch_domain, can_change_object_identity, can_system_change, corenet_unlabeled_type, domain, kernel_system_state_reader, netlabel_peer_type, syslog_client_type, pcmcia_typeattr_1;
  type passwd_exec_t, application_exec_type, entry_type, exec_type, file_type, non_auth_file_type, non_security_file_type;
  type passwd_file_t, file_type, non_auth_file_type, non_security_file_type;
  type shadow_t, file_type, security_file_type;
  ...

On remarque que le premier "passwd_t" a l'attribut "domain". Quand on exécute le programme "passwd", son process aura ce type.

Le second "passwd_exec_t" a l'attribut "exec_type". Il sera attribué au programme "/bin/passwd". Il aura les caractéristiques d'un exécutable. Il a aussi l'attribut "file_type" car c'est un fichier classique.

Le suivant "passwd_file_t" a l'attribut "file_type", Il est affecté au fichier "/etc/passwd".

Le dernier "shadow_t" a l'attribut "file_type", Il est affecté au fichier "/etc/shadow".

Une série de règles vont autoriser le type "passwd_t" à utiliser les trois autres.

Remarque: Je n'ai pas trouvé une définition exhaustive et complète de ces attributs ("domain, entry_type, exec_type, file_type,...") repris derrière le nom du type. Une ancienne URL en reprend quelques-unes, principales qui nous concernent directement: http://ftp.pasteur.fr/mirrors/centos-vault/4.2/docs/html/rhel-selg-en-4/rhlcommon-section-0048.html Dans les sources, on peut en déduire quelques caractéristiques.

La création de nouveaux types ne peut se faire qu'au travers de modules. Nous le verrons dans l'article suivant.


Rôles et Types

Un rôle SELinux est en liaison avec les types ayant l'attribut "domain". Un rôle a accès à divers types selon des règles.

Pour lister ces liaisons, utilisez la commande suivante:

seinfo -r -x

ou pour lister ceux du rôle "user_r":

seinfo -r user_r -x

qui donne:


Roles: 1
  role user_r types { abrt_helper_t alsa_home_t antivirus_home_t audio_home_t auth_home_t bluetooth_helper_t cache_home_t cdrecord_t chfn_t chkpwd_t chrome_sandbox_home_t chrome_sandbox_nacl_t chrome_sandbox_t chronyc_t config_home_t container_file_t container_home_t container_init_t container_kvm_t container_ro_file_t container_runtime_t container_t container_userns_t cronjob_t crontab_t cvs_home_t data_home_t dbus_home_t ddclient_t exim_t fdo_home_t fetchmail_home_t fsadm_t gconf_home_t gconfd_t gestion_t git_session_t git_user_content_t gkeyringd_gnome_home_t gnome_home_t gpg_agent_t gpg_helper_t gpg_pinentry_t gpg_secret_t gpg_t gstreamer_home_t home_bin_t home_cert_t httpd_user_script_t icc_data_home_t iceauth_home_t iceauth_t irc_home_t irc_t irc_tmp_t irssi_home_t irssi_t journalctl_t kismet_home_t kmod_t krb5_home_t loadkeys_t local_login_home_t lpr_t lvm_t mail_home_rw_t mail_home_t mailman_mail_t mandb_home_t mount_t mozilla_home_t mozilla_plugin_config_t mozilla_plugin_t mpd_home_t mpd_user_data_t mplayer_home_t mysqld_home_t namespace_init_t newrole_t nscd_t obex_t oddjob_mkhomedir_t oddjob_t openshift_var_lib_t pam_timestamp_t passwd_t ping_t policykit_auth_t policykit_grant_t polipo_cache_home_t polipo_config_home_t polipo_session_t postfix_postdrop_t postfix_postqueue_t pppd_t procmail_home_t ptchown_t pulseaudio_home_t pulseaudio_t qmail_inject_t qmail_queue_t rlogind_home_t rpcd_t rssh_ro_t rssh_rw_t sandbox_file_t sandbox_min_client_t sandbox_min_t sandbox_net_client_t sandbox_net_t sandbox_web_client_t sandbox_web_t sandbox_x_client_t sandbox_x_t sandbox_xserver_t screen_home_t setfiles_t smbmount_t spamc_home_t speech_dispatcher_home_t ssh_home_t ssh_t svirt_home_t svirt_socket_t svirt_t svirt_tcg_t systemd_home_t targetclid_home_t telepathy_cache_home_t telepathy_data_home_t telepathy_gabble_cache_home_t telepathy_gabble_t telepathy_idle_t telepathy_logger_cache_home_t telepathy_logger_data_home_t telepathy_logger_t telepathy_mission_control_cache_home_t telepathy_mission_control_data_home_t telepathy_mission_control_home_t telepathy_mission_control_t telepathy_msn_t telepathy_salut_t telepathy_sofiasip_t telepathy_stream_engine_t telepathy_sunshine_home_t telepathy_sunshine_t texlive_home_t thumb_home_t thumb_t traceroute_t tvtime_home_t uml_ro_t uml_rw_t updpwd_t user_dbusd_t user_fonts_cache_t user_fonts_config_t user_fonts_t user_gkeyringd_t user_home_dir_t user_home_t user_mail_t user_screen_t user_seunshare_t user_ssh_agent_t user_t user_tmp_t user_wine_t utempter_t virt_bridgehelper_t virt_content_t virt_home_t vlock_t vmtools_helper_t vmtools_t vmware_conf_t vmware_file_t wine_home_t wireshark_home_t xauth_home_t xauth_t xdm_home_t };

On remarque le grand nombre de liaisons.

Un autre plus réduit:

seinfo -r logadm_r -x

qui donne:


Roles: 1
  role logadm_r types { auditctl_t logadm_t };

Ces liaisons se font au travers de modules.


Utilisateur et Rôles

Un utilisateur SELinux a accès à divers rôles.

On peut lister la liaison entre les utilisateurs SELinux et les rôles SELinux par la commande:

semanage user -l

qui donne:


                Étiquetage MLS/       MLS/
Identité SELinux Préfixe    Niveau MCS Intervalle MCS                 Rôles SELinux
 
guest_u         user       s0         s0                             guest_r
root            user       s0         s0-s0:c0.c1023                 staff_r sysadm_r system_r unconfined_r
staff_u         user       s0         s0-s0:c0.c1023                 staff_r sysadm_r system_r unconfined_r
sysadm_u        user       s0         s0-s0:c0.c1023                 sysadm_r
system_u        user       s0         s0-s0:c0.c1023                 system_r unconfined_r
unconfined_u    user       s0         s0-s0:c0.c1023                 system_r unconfined_r
user_u          user       s0         s0                             user_r
xguest_u        user       s0         s0                             xguest_r

Ou:

seinfo -u -x

qui donne:


Users: 8
  user guest_u roles guest_r level s0 range s0;
  user root roles { staff_r sysadm_r system_r unconfined_r } level s0 range s0 - s0:c0.c1023;
  user staff_u roles { staff_r sysadm_r system_r unconfined_r } level s0 range s0 - s0:c0.c1023;
  user sysadm_u roles sysadm_r level s0 range s0 - s0:c0.c1023;
  user system_u roles { system_r unconfined_r } level s0 range s0 - s0:c0.c1023;
  user unconfined_u roles { system_r unconfined_r } level s0 range s0 - s0:c0.c1023;
  user user_u roles user_r level s0 range s0;
  user xguest_u roles xguest_r level s0 range s0;


La commande suivante permet de créer un utilisateur "administrateur_u" ayant le rôle "webadm_r":

semanage user -a -R webadm_r administrateur_u

Et pour l'éliminer, voici la commande:

semanage user -d administrateur_u


Utilisateurs Linux et SELinux

Un utilisateur Unix est repris comme un utilisateur SELinux donné. Et c'est grâce à cet utilisateur SELinux qu'il pourra avoir accès à diverses fonctionnalités du système au travers des règles SELinux sous jacentes.

On peut lister la liaison entre les utilisateurs Linux et les utilisateurs SELinux par la commande:

semanage login -l

qui donne:


Nom pour l’ouverture de session Identité SELinux     Intervalle MLS/MCS   Service
 
__default__          unconfined_u         s0-s0:c0.c1023       *
admin                user_u               s0                   *
root                 unconfined_u         s0-s0:c0.c1023       *
staff                user_u               s0                   *

Si un utilisateur Linux n'est pas repris, il est lié à l'utilisateur SELinux par défaut "__default__".


La commande suivante permet d'effectuer cette liaison:

semanage login -a -s user_u staff

Ici on lie l'utilisateur Linux "staff" à l'utilisateur SELinux "user_u".

Et pour l'éliminer, voici la commande:

semanage login -d -s user_u staff


Règles d'accès

Après avoir défini toutes les composantes du contexte, il faut aborder les règles d'accès qui les relient et qui sont à la base de la sécurité. Sans règle permettant l'accès à une quelconque fonctionnalité, tout accès est interdit.

Il y a différents types d'accès; nous abordons la principale. Elle a la forme suivante:

allow [type source] [type cible]:[classe d'accès] { [permission] [permission]... }

  • [type source]: type qui demande l'accès d'attribut "domain"; c'est un processus
  • [type cible]: type dont on demande l'accès à une de ses ressources
  • [classe d'accès]: classe d'accès
  • [permission]: permission demandée parmi celles de la classe d'accès

On va donner deux exemples afin de l'illustrer en correspondance des "fcontext" cités plus haut.

  • le type "passwd_t" correspond à un processus "passwd" qui veut modifier les noms d'utilisateurs Unix
  • le type "passwd_exec_t" est lié au fichier exécutable "/bin/passwd" lancé par le processus
  • le type "passwd_file_t" est lié au fichier "/etc/passwd" contenant les informations sur les utilisateurs Unix

Une première règle:

allow passwd_t passwd_exec_t:file { execute open read };

On demande de lancer un processus de type "passwd_t" ayant l'attrinut "domain". On veut lancer le programme "/bin/passwd" qui est de type "passwd_exec_t" exécutable. On demande à ce fichier des permissions de la classe "file" pour l'ouvrir ("open"), le lire ("read") afin de pouvoir l'exécuter ("execute").

Autre exemple lié:

allow passwd_t passwd_file_t:file { append open read write };

Ce processus "passwd_t" lancé a besoin de pouvoir manipuler le fichier "/etc/passwd" de type "passwd_exec_t". Il a besoin d'avoir diverses permissions de la classe "file": "open" pour l'ouvrir, "read" pour le lire, "append" et "write" pour pouvoir modifier et ajouter du contenu.

Dans la réalité, ces règles comprennent d'autres permissions et règles non présentées pour simplifier l'exposé. On veut faire comprendre le principe.

La création de nouvelles règles ne peut se faire qu'au travers de modules. Nous le verrons dans l'article suivant.


Common, Class et leurs permissions

Chaque type peut être associé à diverses classes d'objets nommé "Class". Chacun de ces objets perssède diverses méthodes d'accès aucun est associé une permissions. Il se fait que certains objets possèdent les mêmes ensembles de permissions. Afin de simplifier la programmation, ces groupes de permissions sont regroupés sous un même nom appelés "Common". La "Class" concernée par un "Common", héritera des permissions de ce "Common".


Par exemple la "Class" "dir" qui concerne les accès aux répertoires, hérite du "Common" "file" auquel s'ajoute d'autres permissions.


common file
{
 ioctl
 read
 write
 create
 getattr
 setattr
 lock
 relabelfrom
 relabelto
 append
 unlink
 link
 rename
 execute
 swapon
 quotaon
 mounton
}

et


class dir
inherits file
{
 add_name
 remove_name
 reparent
 search
 rmdir
}

de même la "Class" "file" hérite aussi du "Common" "file" et de deux autres permissions:


class file
inherits file
{
 entrypoint
 execute_no_trans
}

On peut avoir une liste de ces "Common" et de ces "Class" à l'URL: https://selinuxproject.org/page/ObjectClassesPerms


La commande suivante:

seinfo --common -x

donne la liste des "Common" et de leurs permissions.

La commande suivante:

seinfo --class -x

donne la liste des "Class" et de leurs permissions.

On peut également les retrouver en parcourant l'arborescence "/sys/fs/selinux/class".


Type Port

Il existe un Type SELinux spécial. Leurs noms se terminent par "_port_t". Ils contiennent une liste de n° de ports réseaux TCP ou UDP par protocols.

Par exemple, le Type "http_port_t" possède l'information suivante:


tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000

ou pour le Type "mysqld_port_t":


tcp      1186, 3306, 63132-63164

On peut avoir une liste complête grâce à la commande suivante:

semanage port -l

On peut ajouter un port à un de ces types. Par exemple, on peut ajouter le port "1234" au protocol "ssh":

semanage port -a -t ssh_port_t -p tcp 1234


Il existe nombre de règles qui donne la permission pour qu'un programme puisse utiliser un protocole pour autant qu'il utilise un des ports repris dans la liste. Avant d'ajouter un port, il faut bien vérifier cette nécessité. Par exemple, si le service SSHD écoute sur le port "1234" et non "22" comme habituellement, il n'est pas nécessaire d'ajouter ce port. De façon analogue, le service Web HTTPD n'est pas concerné par cette liste de ports "http_port_t" au niveau de l'écoute ("LISTEN"); il ne concernent que les connexions clients qu'il veux effectuer vers un autre serveur.


Boolean

Un autre ensemble de paramètres sont les "Boolean" qui prennent les valeurs "True" et "False" (ou "on" et "off" ou "1" ou "0").

On peut afficher une liste complête grâce à la commande suivante:

semanage boolean -l

ou

seinfo --bool -x

ou

getsebool -a

On peut également les retrouver en parcourant le répertoire "/sys/fs/selinux/booleans".


On peut changer leur valeur. Par exemple, la commande suivante active le "Boolean" "httpd_can_network_connect_db":

setsebool -P httpd_can_network_connect_db on

Les deux exemples suivantes de règles illustrent l'utilisation conjointe d'un "Boolean" et d'un Type Port:

allow httpd_php_t mysqld_port_t:tcp_socket name_connect; [ httpd_can_network_connect_db' ]:True
allow httpd_php_t mysqld_port_t:tcp_socket { recv_msg send_msg }; [ httpd_can_network_connect_db ]:True

Si le Boolean "httpd_can_network_connect_db" est activé, la règle est activée et un script PHP lancé par le service Web HTTPD, peut effectuer une connexion TCP et des échanges vers une base de données MySql pour autant qu'elle utilise un des ports TCP repris dans la liste; usuellement, on utilise le port TCP 3306. Si ce n'est pas le cas, il faut ajouter le port utilisé à la liste sinon l'accès sera refusé.

Petite remarque, pour effectuer cette connexion vers le serveur MySql, on peut utiliser la fonction PHP "mysqli_connect()". Si pour la variable HOST, on utilise la valeur "localhost", le script va s'adapter et utiliser un socket local Unix et non TCP; dans ce cas, le "Boolean" "httpd_can_network_connect_db" peut être positionné sur "off". Par contre, si on utilise la valeur "127.0.0.1", ce sera un socket TCP qui sera utilisé et le "Boolean" "httpd_can_network_connect_db" devra être positionné sur "on".


Dans un souci de sécurité, on limite les accès; il ne faut pas activer un "Boolean" si ce n'est pas nécessaire.

Par exemple, les "Boolean" "httpd_graceful_shutdown" ou "httpd_can_network_connect" seront positionnés sur "off" car habituellement le service Web HTTPD ne fera pas de lui-même une connexion vers un autre serveur Web. Cet URL sera transmise au client (par exemple Firefox) qui fera cette connexion. Attention, le second "Boolean" a une portée plus large car il s'adresse à tous les ports sans limitation. Bien sûr tout dépend du logiciel utilisé.




retour à SELinux