|
|
by Denis Ducamp (11/11/2000)
La commande chroot permet de lancer un programme en restreignant ses accès
disques à une sous arborescence. En fait pour le processus, la racine du
disque est la racine de l'arborescence dans laquelle il a été restreint.
Il est possible de chrooter de nombreux services. L'exemple ci-dessous
correspond à la mise en cage d'un démon apache configuré en relais-inverse
(voir http://www.hsc.fr/ressources/breves/relais-inverse.html ) sur un
système Linux sous libc5 (slackware 4.0) avec un noyau 2.4.0-test4 .
apache étant installé et correctement configuré dans l'arborescence /www
(./configure ... --prefix=/www) , il faut construire la cage comme suit :
cd /www
ln -s . www
mkdir etc
. créer l'utilisateur et le groupe utilisé :
echo 'nobody:x:65534:100:nobody:/dev/null:' > etc/passwd
echo 'nogroup::-2:' > etc/group
. créer le fichier de résolution DNS :
cp /etc/resolv.conf etc/resolv.conf
. créer les fichier nécessaires à la localisation horaire :
cp /etc/localtime etc/localtime
mkdir -p usr/lib/zoneinfo
mkdir -p usr/share/zoneinfo
mkdir -p var/lib/zoneinfo
ln -s /etc/localtime var/lib/zoneinfo
ln -s /var/lib/zoneinfo/localtime usr/lib/zoneinfo
ln -s /var/lib/zoneinfo/localtime usr/share/zoneinfo
. créer les périphériques utilisés :
mkdir dev
mknod -m 666 dev/null -c 1 3
mknod -m 644 dev/urandom c 1 9
. copier les bibliothèques utilisées :
mkdir lib
cp /lib/libc.so.5 /lib/libm.so.5 /lib/ld-linux.so.1.9.9 lib
ln -s ld-linux.so.1.9.9 lib/ld-linux.so.1
ln -s ld-linux.so.1 lib/ld-linux.so
Pour savoir quelles sont les bibliothèques utilisées, utiliser ldd :
cd /www
ldd bin/httpd
libm.so.5 => /lib/libm.so.5 (0x4000b000)
libc.so.5 => /lib/libc.so.5 (0x40014000)
Il se peut, comme ici, qu'une bibliothèque soit manquante. Ici ld-linux.so.1
est nécessaire au chargement des bibliothèques dynamiques libc5. Sous
glibc2, le fichier nécessaire est ld-linux.so.2 alors qu'au format a.out il
s'agit du fichier ld.so .
Avec certains systèmes, certaines bibliothèques dynamiques sont chargées par
d'autres bibliothèques dynamiques sans apparaître avec la commande ldd. Même
si l'exécutable est statique, ces bibliothèques dynamiques doivent être
incluses dans la cage. Dans ce cas il est possible de recopier toutes les
bibliothèques dans la cage et d'exécuter le service durant quelques temps.
Pour savoir quelles bibliothèques ont été utilisées, la commande "ls -artlu"
permet de voir la date de dernier accès en lecture de chaque fichier; ceci
ne fonctionnant que si la partition n'est pas en lecture seule et que
l'enregistrement automatique de la date de dernier accès n'est pas
désactivé.
Lancer le relais par la commande suivante :
# cd /www
# chroot . ./bin/httpd
./bin/httpd: can't open cache '/etc/ld.so.cache'
Le message d'erreur ci-dessus est dû au système de chargement des
bibliothèques dynamiques et peut être ignoré.
Les commandes "chroot /www /www/bin/httpd" et "chroot /www /bin/httpd"
depuis le répertoire / sont également utilisables, mais je préfère
personnellement mettre l'oiseau dans la cage avant de fermer la porte ;-)
Il est possible de vérifier les fichiers ouverts par le relais avec le
programme lsof ftp://vic.cc.purdue.edu/pub/tools/unix/lsof/ :
httpd 5740 root cwd DIR 3,70 1024 225341 /www
httpd 5740 root rtd DIR 3,70 1024 225341 /www
httpd 5740 root txt REG 3,70 1382240 69673 /www/bin/httpd
httpd 5740 root mem REG 3,70 79508 43062 /www/lib/ld-linux.so.1.9.9
httpd 5740 root mem REG 3,70 32168 43031 /www/lib/libm.so.5
httpd 5740 root mem REG 3,70 614840 43060 /www/lib/libc.so.5
httpd 5740 root 0r CHR 1,3 116784 /www/dev/null
httpd 5740 root 1w CHR 1,3 116784 /www/dev/null
httpd 5740 root 2w REG 3,70 702 69889 /www/logs/error_log
httpd 5740 root 15w REG 3,70 702 69889 /www/logs/error_log
httpd 5740 root 16u inet 5475799 TCP *:443 (LISTEN)
httpd 5740 root 17w REG 3,70 8496 69890 /www/logs/ssl_engine_log
httpd 5740 root 18w REG 3,70 0 69895 /www/logs/ssl_mutex.5739
httpd 5740 root 19w REG 3,70 388 69891 /www/logs/access_log
httpd 5740 root 20w REG 3,70 388 69891 /www/logs/access_log
httpd 5740 root 21w REG 3,70 481 69893 /www/logs/ssl_request_log
httpd 5740 root 22w REG 3,70 0 69898 /www/logs/httpd.lock.5740 (deleted)
Les points remarquables sont :
. apache est chrooté dans /www (ligne rtd)
. les entrées et sorties standard sont redirigées dans /dev/null
. la sortie d'erreur est redirigée dans le fichier /logs/error_log
. le relais n'écoute que sur le port 443 en tcp
Sous Linux il est également possible d'utiliser l'arborescence /proc pour
vérifier cela :
# ls -l /proc/5740
total 198
-r--r--r-- 1 root root 0 Nov 11 15:51 cmdline
lrwxrwxrwx 1 root root 0 Nov 11 15:51 cwd -> /www
-r-------- 1 root root 0 Nov 11 15:51 environ
lrwxrwxrwx 1 root root 0 Nov 11 15:51 exe -> /www/bin/httpd
dr-x------ 2 root root 0 Nov 11 15:51 fd
-r--r--r-- 1 root root 0 Nov 11 15:51 maps
-rw------- 1 root root 0 Nov 11 15:51 mem
lrwxrwxrwx 1 root root 0 Nov 11 15:51 root -> /www
-r--r--r-- 1 root root 0 Nov 11 15:51 stat
-r--r--r-- 1 root root 0 Nov 11 15:51 statm
-r--r--r-- 1 root root 0 Nov 11 15:51 status
# ls -l /proc/5740/fd
total 11
lr-x------ 1 root root 64 Nov 11 15:52 0 -> /www/dev/null
l-wx------ 1 root root 64 Nov 11 15:52 1 -> /www/dev/null
l-wx------ 1 root root 64 Nov 11 15:52 15 -> /www/logs/error_log
lrwx------ 1 root root 64 Nov 11 15:52 16 -> socket:[5475799]
l-wx------ 1 root root 64 Nov 11 15:52 17 -> /www/logs/ssl_engine_log
l-wx------ 1 root root 64 Nov 11 15:52 18 -> /www/logs/ssl_mutex.5739
l-wx------ 1 root root 64 Nov 11 15:52 19 -> /www/logs/access_log
l-wx------ 1 root root 64 Nov 11 15:52 2 -> /www/logs/error_log
l-wx------ 1 root root 64 Nov 11 15:52 20 -> /www/logs/access_log
l-wx------ 1 root root 64 Nov 11 15:52 21 -> /www/logs/ssl_request_log
l-wx------ 1 root root 64 Nov 11 15:52 22 -> /www/logs/httpd.lock.5740 (deleted)
L'identité sous laquelle tourne le relais peut également être obtenue grâce
à l'arborescence /proc :
# ls -ld /proc/574?
dr-xr-xr-x 3 root root 0 Nov 11 15:55 /proc/5740
dr-xr-xr-x 3 nobody nogroup 0 Nov 11 15:55 /proc/5741
dr-xr-xr-x 3 nobody nogroup 0 Nov 11 15:55 /proc/5742
Dans le cas où le serveur ne voudrait pas se lancer dans la cage, il est
possible d'utiliser la commande suivante :
# cd /www
# strace -f chroot . ./bin/httpd > httpd.strace 2>&1
La commande strace permet de suivre les appels systèmes effectués par
l'application avec les valeurs de retour. En regardant plus particulièrement
les erreurs des appels à open, stat et lstat, il est possible de découvrir
la cause de l'erreur fatale, mais également la présence d'erreurs non
fatales (ex : l'absence du périphérique /dev/urandom).
L'option -f permet de spécifier qu'il est également nécessaire de suivre les
sous processus, sinon ici seul chroot serait surveillé.
Une difficulté couramment rencontrée lorsqu'un service est lancé chrooté se
trouve au niveau de la journalisation via le démon syslogd. Il est tout
d'abord nécessaire de créer un tube nommé :
# cd /www
# mkfifo -m 666 dev/null
Puis de relancer le démon syslogd en lui indiquant quelle autre source
d'évènements écouter :
# cd /
# /usr/sbin/syslogd -a /www/dev/null
Sous systèmes BSD, utiliser l'option -l à la place de l'option -a .
Il est possible de demander à apache de journaliser ses erreurs via syslogd
en changeant dans le fichier httpd.conf la ligne ErrorLog par :
ErrorLog syslog
Attention, il ne suffit pas de chrooter un démon, il est aussi nécessaire
qu'il tourne sous une identité non privilégiée. Ici apache change d'identité
dès qu'il n'a plus besoin d'être privilégié. bind fonctionne de la même
façon s'il est lancé avec les options -u et -g et se chroote lui-même avec
l'option -t .
Il est en effet possible pour tout processsus tournant en tant que root de
sortir de la cage dans laquelle il aura été restreint. Pour la description
de la technique la plus simple, voir
http://www.bpfh.net/simes/computing/chroot-break.html .
|