Distorsion spatiale du système de fichier
Par Mickaël le 22 février 2009, 19h17 - Scripts - Lien permanent
Le monde du libre nous offre des outils afin de rendre les logiciels plus sûr, ou plutôt, de les tenir sous (un meilleur) contrôle avec un minimum d'efforts. Les systèmes de protection de type « jail » permettent d'isoler des processus du reste du système. Je vais ici parler seulement d'isolation du système de fichier, autrement dit de chroot.
Chrooter un dossier en y exécutant une commande donne à ce processus une vue partielle du système de fichier avec pour racine le dossier chrooté. Les dossiers parents de celui-ci sont donc invisibles et inaccessibles : ils n'existent pas pour le processus chrooté. Pour cela, le programme schroot semble être le plus facile d'utilisation.
La configuration de schroot est simple. Le fichier de configuration est /etc/schroot/schroot.conf. On peut également en créer dans le dossier /etc/schroot/chroot.d/ pour plus de clarté.
L'intérêt de schroot est de permettre à des utilisateurs non privilégiés d'utiliser la fonction chroot de Linux. Il faut simplement une configuration appropriée. La configuration la plus simple est la suivante :
[user-app] description=My Chrooted Application type=plain location=/srv/chroot/user-app priority=1 users=user
L'usage qui vas être fait est l'utilisation d'une application dans un espace restreint. Il y a ici un dossier /srv/chroot/user-app qui va contenir le système de fichier chrooté. Il faut donc le remplir en conséquent.
Pour faire un système minimal mais néanmoins nécessaire pour un bon fonctionnement dans un minimum de temps, le plus simple consiste à copier les application du système actuel pour les incorporer dans le petit nouveau. La plupart des binaires sont compilés en dynamique, ils dépendent donc de bibliothèques. L'astuce consiste donc à ne copier que les binaires et leur bibliothèques respectives, ou mieux, à les lier.
En tant que root, il faut alors créer le dossier racine avec les droits nécessaires :
# umask 022 # mkdir -p /srv/chroot/user-app # cd /srv/chroot/user-app
Il faut maintenant créer une arborescence minimale nécessaire à la plupart des logiciels (répertoire home, dossier /tmp) :
# mkdir home/user # chown user:user home/user # chmod o= home/user # mkdir tmp # chmod a+rwt tmp
Une petite analyse des exécutables permet de comprendre les dépendances principales, ici dans le cas du navigateur Firefox (Iceweasel pour Debian) à l'aide du shell ZSH :
# file =iceweasel /usr/bin/iceweasel: symbolic link to `../lib/iceweasel/iceweasel' # file /usr/lib/iceweasel/iceweasel /usr/lib/iceweasel/iceweasel: POSIX shell script text executable # less /usr/lib/iceweasel/iceweasel # file /usr/lib/iceweasel/firefox-bin /usr/lib/iceweasel/firefox-bin: symbolic link to `../xulrunner-1.9/xulrunner-stub' # file /usr/lib/xulrunner-1.9/xulrunner-stub /usr/lib/xulrunner-1.9/xulrunner-stub: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.8, stripped
Après ce petit périple il reste à copier les fichiers nécessaires. Si on reste sur la même partition, on a la possibilité de ne pas copier le contenu des fichiers, mais simplement de faire des liens directs ce qui permet d'économiser de l'espace (avec l'option -l ; seul les dossiers sont réellement créés) :
# mkdir -p usr/lib # cp -rLpl /usr/lib/iceweasel usr/lib # cp -rLpl /usr/lib/mozilla usr/lib # cp -rLpl /usr/lib/xulrunner-1.9 usr/lib
Il faut également faire attention de ne pas copier les liens symboliques, mais de les résoudre (option -L).
Comme nous a montré la commande file, il y a un script qui nécessite donc un shell :
# cp /bin/dash bin/sh
On passe maintenant à la copie des dépendances en bibliothèques. La commande ldd permet d'avoir les dépendances d'un binaire, mais il faut encore traiter toutes ces informations. Quelques commandes tuyautées permettent d'arranger ça. La méthode est un peut brute, mais j'ai bien dit en un minimum de temps
.
# ldd **/*(.) 2> /dev/null | sed -n '/^\s/p' | sed -nr 's,.*=> (/[^ ]+).*,\1,p' | sort | uniq | while read lib; do dir="`dirname \"$lib\"`"; mkdir -p "${dir/#\//}"; cp -puvl "$lib" "${dir/#\//}"; done
Ces commandes ont pour but de récupérer (approximativement) les bibliothèques nécessaires (ldd et sed) et de les lister une seule fois (sort et uniq). On peut alors créer les répertoires correspondants et y lier les bibliothèques. La majorités sont maintenant en place, mais il manque la plus importante :
# cp -pl /lib/ld-linux.so.2 lib/ld-linux.so.2
Après un premier test, il s'avère qu'il manque encore quelques fichiers...
# mkdir -p etc/fonts # cp /etc/fonts/fonts.conf etc/fonts # mkdir usr/share # cp -rLpl /usr/share/fonts usr/share # cp -rLpl /usr/lib/libgconf2-4/ usr/lib/ # cp -rLpl /usr/lib/pango usr/lib
Voila enfin une installation qui semble correcte, mais la résolution de nom peut tout de même être intéressante :
# cp -Lpl /etc/resolv.conf etc # cp -Lpl /lib/libnss_dns.so.2 lib # cp -Lpl /lib/libresolv.so.2 lib
Si on veut que le navigateur puisse jouer quelques notes de musique :
# mkdir dev # mount -o bind,rw /dev/snd dev/snd
Afin de permettre à un processus qui ne partage pas le même système de fichier, il est nécessaire d'autoriser les autres connexions que celle existante au serveur d'affichage :
% xhost +local:
On a maintenant les fichiers vitaux copiés. On peut donc lancer le logiciel en tant que simple utilisateur (en précisant l'affichage utilisé) avec :
% schroot -c user-app -d / -- /usr/lib/iceweasel/iceweasel --display=:0
Si une instance de Firefox était déjà lancée, alors une nouvelle fenêtre s'ouvrira dans la même session. Cela est dû au fait que les logiciels Mozilla n'ont qu'une seule instance principale et utilise une communication inter-processus. On peut prendre cette exemple pour mettre à la lumière les limites du simple chroot...
Il est cependant possible de démarrer une nouvelle session en la spécifiant à ce farceur de Firefox avec l'option -no-remote.
Voilà ce que voit cette instance du système de fichier (noter l'absence de certains répertoires habituels) :

Une configuration plus minutieuse permettrait d'ajouter les ressources nécessaires à certains plugins comme Java qui peut montrer des signes d'instabilité, mais ceci est suffisant pour montrer les possibilités de la réduction du système de fichier. On limite ainsi les risques de compromission qui peuvent survenir suite à un bogue du navigateur ou d'un module tel que Flash...
À titre d'information, en ayant un shell complet, ou encore mieux, un busybox, on peut se rendre compte des dépendances liées au système de fichiers, comme par exemple avec le /proc ou le /dev.
Afin d'améliorer la solution, il est possible de cloisonner les processus avec VServer ou OpenVZ ce qui apporte une isolation plus importante que simplement le système de fichier. Divers configurations de Linux peuvent également permettre d'ajouter des systèmes de sécurité à l'environnement, mais ceci est bien plus long à mettre en œuvre.