L'isolation ... avec `chroot`
-----------------------------

Depuis les premières versions d'Unix, il est possible de changer le répertoire
vu comme étant la racine du système de fichiers. En anglais : *change root*:
`chroot`. Le processus effectuant cette action ainsi que tous ses fils verront
donc une racine différente du reste du système.

::::: {.code}

Le noyau stocke le chemin de la racine courante dans les informations de notre
processus :

<div lang="en-US">
```c
// From linux/sched.h
struct task_struct {
    [...]
	/* Filesystem information: */
	struct fs_struct		*fs;
    [...]
};

// From linux/fs_struct.h
struct fs_struct {
	int users;
	spinlock_t lock;
	seqcount_spinlock_t seq;
	int umask;
	int in_exec;
	struct path root;
	struct path pwd;
};
```
</div>

Ici dans `root`.

On retrouve la racine exposée sous forme de lien symbolique dans
`/proc/$$/root`.

:::::

Pour se créer un environnement afin de changer notre racine, il va falloir
commencer par créer le dossier de notre nouvelle racine, peu importe où dans
l'arborescence :

<div lang="en-US">
```bash
mkdir newroot
```
</div>


Nous allons ensuite remplir ce dossier afin qu'il soit vraiment utilisable
comme une racine : rien n'est strictement obligatoire, on s'assure simplement
d'avoir de quoi bidouiller : un shell sera amplement suffisant pour commencer.

### `busybox`

Queques mots, pour commencer, à propos du projet Busybox : c'est un programme
couteau-suisse qui implémente tous les binaires vitaux pour avoir un système
fonctionnel et utilisable : `ls`, `sh`, `cat`, mais aussi `init`, `mdev` (un
`udev`-like, cela permet de découvrir les périphériques attachés afin de les
exposer dans `/dev` notamment). C'est un programme *linké* statiquement,
c'est-à-dire qu'il ne va pas chercher ni charger de bibliothèque dynamique à
son lancement. Il se suffit donc à lui-même dans un *chroot*, car il n'a pas de
dépendances. Nous pouvons donc tester notre première isolation :

<div lang="en-US">
```bash
cp $(which busybox) newroot/
chroot newroot /busybox ash
```
</div>

Nous voici donc maintenant dans un nouveau shell (il s'agit d'`ash`, le shell
de `busybox`).

::::: {.question}

#### Faut-il être `root` pour faire un `chroot` ? {-}

Oui, seul un utilisateur avec la *capability* `CAP_SYS_CHROOT` peut le faire !\

En fait, il est possible de duper le système avec un fichier `/etc/passwd` et
`/etc/shadow` que l'on maîtrise, et un binaire *setuid root* tel que `su` :
`su` pourra nous demander le mot de passe `root` ou d'un autre utilisateur,
mais comme on a la maîtrise du fichier `/etc/shadow`, on aura mis préalablement
une valeur qui nous arrange.

:::::

Jusque-là ... ça fonctionne, rien de surprenant ! Mais qu'en est-il pour
`bash` :

<div lang="en-US">
```
42sh$ cp $(which bash) newroot/
42sh# chroot newroot /bash
chroot: failed to run command 'bash': No such file or directory
```
</div>

De quel fichier est-il question ici ?


### `debootstrap`, `pacstrap`

`debootstrap` est le programme utilisé par l'installeur des distributions
Debian et ses dérivés. Il permet d'installer dans un dossier (en général, ce
dossier correspond au point de montage de la nouvelle racine choisie par
l'utilisateur lors de l'installation) le système de base.

<div lang="en-US">
```bash
debootstrap bullseye newroot/ http://httpredir.debian.org/debian/
```
</div>

`pacstrap` est le programme équivalent pour Arch Linux. Alors que `debootstrap`
peut s'utiliser depuis n'importe quel environnement ou distribution,
`pacstrap` nécessite d'avoir installé et configuré `pacman` (le gestionnaire de
paquets d'Arch Linux), ce qui est le cas si vous êtes sous Arch Linux ou ses
dérivés.

<div lang="en-US">
```bash
pacstrap newroot/
```
</div>

Dans les deux cas, nous nous retrouvons avec un dossier `newroot` contenant une
distribution complète minimale, dans laquelle nous pouvons entrer :

<div lang="en-US">
```bash
chroot newroot/ bash
```
</div>


### Gentoo

<http://gentoo.mirrors.ovh.net/gentoo-distfiles/releases/amd64/autobuilds/current-stage3-amd64-openrc/stage3-amd64-openrc-20211128T170532Z.tar.xz>

<div lang="en-US">
```bash
tar xpf stage3-amd64-*.tar.xz -C newroot/
```
</div>

::::: {.more}
L'avantage de télécharger l'archive de Gentoo est que l'on a déjà `gcc` dans un
environnement qui tient dans 200 MB.
:::::

Comme pour les autres distributions vues précédemment, nous pouvons entrer dans
notre nouvelle racine comme ceci :

<div lang="en-US">
```bash
chroot newroot/ bash
```
</div>


### Alpine

<https://dl-cdn.alpinelinux.org/alpine/v3.14/releases/x86_64/alpine-minirootfs-3.14.2-x86_64.tar.gz>

<div lang="en-US">
```bash
tar xpf alpine-minirootfs-*.tar.xz -C newroot/
```
</div>

Alpine se contentant de Busybox pour son système de base, nous n'avons pas
`bash`, mais on peut tout de même lancer `ash` :

<div lang="en-US">
```bash
chroot newroot/ ash
```
</div>


### Utiliser une image OCI ?

Pourquoi pas : nous avons réalisé précédemment un script pour interagir avec le
registre, c'est le moment de l'utiliser !

<div lang="en-US">
```bash
./registry_play.sh library/hello-world:latest
```
</div>

Si on se contente de l'image `hello-world`, on va pouvoir exécuter le binaire
principal :

<div lang="en-US">
```bash
chroot rootfs/ /hello
```
</div>

Bien sûr, des images de base comme `debian` ou `alpine` devraient fonctionner
également sans difficulté.
