Linux sans magie #14 — Linux capabilities : donner un privilège précis sans passer par SUID root

Comprendre les Linux capabilities, leur différence avec SUID root, les commandes getcap/setcap et les risques de sécurité associés.

Sous Unix traditionnel, le modèle de privilèges semble simple : soit un processus est privilégié — historiquement root — soit il ne l’est pas.

Mais donner tous les privilèges de root à un programme qui n’a besoin que d’une opération particulière est excessif.

Linux dispose pour cela des capabilities : les privilèges traditionnellement associés à root sont découpés en unités indépendantes qui peuvent être accordées séparément.

L’objectif est le principe du moindre privilège : donner uniquement le privilège nécessaire.

root
 │
 ├── CAP_NET_ADMIN
 ├── CAP_NET_BIND_SERVICE
 ├── CAP_NET_RAW
 ├── CAP_CHOWN
 ├── CAP_SETUID
 └── ...

SUID root vs capability

Avec un exécutable SUID appartenant à root, le processus peut obtenir un UID effectif privilégié.

Une file capability permet au contraire d’associer à l’exécutable un ensemble beaucoup plus ciblé de privilèges lors de son exécution.

Ce n’est cependant pas une « version sans risque de SUID » : une capability puissante accordée à un programme vulnérable reste un vecteur d’élévation de privilèges.

Voir les capabilities d’un fichier

L’outil principal est :

getcap /chemin/vers/programme

Pour rechercher récursivement :

getcap -r /usr 2>/dev/null

C’est un bon réflexe d’audit : un binaire sans bit SUID peut malgré tout disposer de privilèges supplémentaires.

Exemple : CAP_NET_BIND_SERVICE

Une capability couramment rencontrée est :

CAP_NET_BIND_SERVICE

Elle autorise notamment la liaison à des ports Internet privilégiés, historiquement inférieurs à 1024.

Plutôt que d’accorder des privilèges beaucoup plus larges à un serveur qui n’a besoin que de cette opération, on peut donc lui attribuer ce privilège précis.

La syntaxe typique est :

sudo setcap 'cap_net_bind_service=+ep' ./programme

Puis :

getcap ./programme

On peut obtenir :

./programme cap_net_bind_service=ep

Ici, p correspond au jeu Permitted et e au bit Effective associé aux file capabilities.

Linux manipule plusieurs ensembles de capabilities — notamment permitted, effective, inheritable, bounding et ambient — mais leur fonctionnement détaillé dépasse le périmètre de cet article.

Retirer une file capability

Avant toute expérimentation, il faut savoir revenir en arrière :

sudo setcap -r ./programme

Puis vérifier :

getcap ./programme

Si aucune capability n’est affichée, l’attribut a bien été retiré.

Attention à CAP_SYS_ADMIN

Toutes les capabilities ne se valent pas.

CAP_SYS_ADMIN autorise un très grand nombre d’opérations d’administration système. Elle est tellement large qu’elle est souvent considérée comme une capability à éviter lorsqu’une capability plus précise suffit.

Attribuer :

CAP_SYS_ADMIN

à un programme simplement pour « le faire fonctionner » est généralement contraire au principe recherché.

Il faut identifier la capability réellement nécessaire.

Où Linux stocke-t-il ces informations ?

Contrairement aux permissions classiques affichées par :

ls -l

les file capabilities sont stockées dans un attribut étendu nommé :

security.capability

Elles ne sont donc pas directement visibles dans la représentation rwx.

C’est le même piège conceptuel que pour les ACL : ls -l ne raconte pas toujours toute l’histoire de la sécurité d’un fichier.

Capabilities ≠ absence de risque

Le principe du moindre privilège réduit la surface d’exposition, mais une capability reste un privilège.

Avant d’en attribuer une à un exécutable, il faut notamment vérifier :

ls -l ./programme
getcap ./programme

et se demander :

Qui peut modifier ou remplacer ce fichier ?

Accorder une capability sensible à un exécutable modifiable par un utilisateur non fiable peut créer une voie d’élévation de privilèges.

Les capabilities doivent donc être auditées au même titre que SUID et SGID.

Mini-lab sécurisé

L’objectif est uniquement d’observer le mécanisme sur une copie locale d’un binaire non critique.

mkdir -p ~/linux-sans-magie-capabilities
cp /bin/true ~/linux-sans-magie-capabilities/true-test
cd ~/linux-sans-magie-capabilities

Vérifier l’état initial :

getcap ./true-test

Attribuer une capability à cette copie :

sudo setcap 'cap_net_bind_service=+ep' ./true-test

Vérifier :

getcap ./true-test

Puis retirer la capability :

sudo setcap -r ./true-test
getcap ./true-test

Enfin, supprimer le répertoire de test :

cd
rm -rf ~/linux-sans-magie-capabilities

Le lab n’altère aucun binaire système.

À retenir

Le modèle classique :

utilisateur normal  ←────────→  root

peut être affiné avec les capabilities :

processus
   │
   └── seulement les privilèges nécessaires

Les commandes essentielles sont :

getcap fichier
sudo setcap 'capability=+ep' fichier
sudo setcap -r fichier

Linux ne supprime pas ici les privilèges historiquement associés à root : il permet de les découper et de les attribuer plus finement.

C’est une application directe du principe du moindre privilège.