Posix Capabilities

Donner plus ou moins de privilèges à un utilisateur a et est toujours un casse tête sur un système d’exploitation. Autant, le fait que certaines actions nécessitent d’être root ne gène pas, autant certaines autres, la plupart du temps effectués par l’utilisateur, font paraître le passage en root comme une action supplémentaire superflue.

La méthode classique est d’avoir ces programmes en setuid root (+s):

$ ls -al /bin/ping
-rwsr-xr-x 1 root root 31020  4 oct.   2008 /bin/ping

Le souci, c’est qu’une vulnérabilité de ping peut devenir problèmatique, les Posix Capabilities permettent d’affiner un peu plus les droits donnés à un programme.

Installons tout d’abord le paquet fournissant les outils nécessaires, sous Arch Linux:

pacman -S libcap

Faisons un essai:
Copions l’exécutable (il perd son setuid lors de la copie):

sudo cp /bin/ping /bin/ping.x

Un test échouera au vu du manque de permission:

$ ping.x -c 1 127.0.0.1
ping: icmp open socket: Operation not permitted

Rajoutons à l’exécutable la capacité CAP_NET_RAW (en root)

sudo setcap cap_net_raw=ep /bin/ping.x

Un autre essai:

$ ping.x -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.064 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.064/0.064/0.064/0.000 ms

Les capacités disponibles sont détaillées dans man capabilities.
Les capacités peuvent être assignées à un processus et/ou un fichier (exécutable) en trois ensembles:

  • Permises (p): Capacités pouvant être acquises
  • Héritées (i): Capacités léguées
  • Effectives (e): Capacités acquises

En partant de ces trois ensembles, les capacités sont calculées pour chaque processus selon la logique suivante:

'=capacités calculées
p=capacités du processus
f=capacités du fichier
I=héritées, P=permises, E=effectives

pI' = pI
pP' = fP | (fI & pI)
pE' = pP' & fE

Un processus ne peut utiliser une capacité que si elle existe dans l’ensemble permis et effectif (d’où le "ep" sur l’exemple du ping.x)

Imaginons qu’on veuille restreindre le ping à certains utilisateurs, on a besoin de la capacité "cap_net_raw=ep" mais seulement à l’exécution de ping. D’après la logique de calcul:

  • ping.x doit avoir "cap_net_raw=ie"
  • Le processus appelant ping.x doit avoir "cap_net_raw=i"

Ainsi, pP' et pE' auront tous deux cap_net_raw.

Un test:

$ sudo setcap -r /bin/ping.x
$ getcap -v /bin/ping.x
/bin/ping.x
$ sudo setcap cap_net_raw=ie /bin/ping.x
$ getpcaps $$
Capabilities for `6263': =
$ ping.x -c 1 127.0.0.1
ping: icmp open socket: Operation not permitted
$ sudo capsh --caps="cap_net_raw=i" -- -c "su - $USER"
$ getpcaps $$
Capabilities for `6350': = cap_net_raw+i
$ ping.x -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.048 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.048/0.048/0.048/0.000 ms
$ 

Là, on a exécuté un shell en lui affectant une capacité (en utilisant le root), mais si on doit faire ceci à chaque fois, ça ne sert pas à grand chose… Ça tombe bien, c’était juste pour tester la faisabilité, voyons voir comment donner des permissions à un utilisateur.

Les capacités sont héritées par les processus fils, il suffit donc de doter le premier processus lancé par l’utilisateur des capactiés voulues, c’est là que rentre en action PAM [1] le module d’authentification sous linux.

Le paquet libcap sous Arch Linux apporte un module nommé pam_cap.so permettant de configurer ceci. Dans /etc/security/capability.conf:

cap_net_raw	tuxce
none *

Il faut aussi rajouter le module en question dans la configuration pam, /etc/pam.d/login:

auth		required	pam_cap.so

On teste en se loguant depuis une console texte:

host login: tuxce
Password: 
Last login: Tue Feb  9 14:08:55 CET 2010 on pts/2
[tuxce@host ~]$ getpcaps $$
Capabilities for `7601': = cap_net_raw+i
[tuxce@host ~]$ logout

Une alternative à pam_cap.so serait d’utiliser un soft comparable à sudo mais spécifique aux capacités, ça tombe bien, un des développeurs d’Arch Linux, Thomas Bächler alias brain0 a developpé l’outil capsudo qui permet en le configurant d’attribuer des droits à certains utilisateurs [2].

Vous pouvez télécharger le PKGBUILD suivant: capsudo-git-20100209-1.src.tar.gz
En prenant toujours l’exemple de ping, rajoutons ce qui suit à /etc/capsudoers:

[ping.x]
	command = /bin/ping.x
	allow_user_args = true
	caps = cap_net_raw
	users = tuxce

Assurons nous que /bin/ping.x ait "cap_net_raw+ei", puis:

$ capsudo ping.x -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.045 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.045/0.045/0.045/0.000 ms

Voilà, avec un mélange de tout ceci, on devrait être capable de donner des droits plus restreints aux exécutables sans pour autant leur permettre de prendre l’identité du root.

Reste la difficulté de deviner les capacités qu’il faut pour les programmes, deux possibilités, écumer le net pour trouver les capacités utilisées par tel ou tel programme, ou bien utiliser un module (nécéssitant certaines options du noyau) qui permet de logguer les demandes d’autorisations, ça fera l’objet d’un autre article, vous pouvez vous référer au wiki anglophone sur les capacités pour une liste non exhaustive.



Ressources:
Petite introduction à PAM (Artisan Numérique)
POSIX file capabilities: Parceling the power of root
Linux kernel capabilities FAQ
Using POSIX capabilities in Linux, part two (brain0)