2015-10-07 01:45:39 +00:00
|
|
|
|
\newpage
|
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
Utiliser les *namespace*s
|
|
|
|
|
-------------------------
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
### S'isoler dans un nouveau *namespace*
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
Si l'on voit l'isolation procurée par les *namespace*s en parallèle avec les
|
|
|
|
|
machines virtuelle, on peut se dire qu'il suffit d'exécuter un appel système
|
|
|
|
|
pour arriver dans un conteneur bien isolé. Cependant, le choix fait par les
|
|
|
|
|
développeurs de Linux a été de laisser le choix des espaces de noms dont on veut
|
|
|
|
|
se dissocier.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
L'intérêt principal de cette approche, exploitée bien après la mise en avant du
|
|
|
|
|
concept, est que l'utilisation des *namespace*s ne se limite pas seulement à
|
|
|
|
|
des machines virtuelles légères. On retrouve ainsi dans Google Chrome de
|
|
|
|
|
nombreuses utilisations des *namespace*s dans le simple but d'accroître la
|
|
|
|
|
sécurité de leur navigateur. Ainsi, les threads de rendu n'ont pas accès au
|
|
|
|
|
réseau et sont cloisonnés de manière transparente pour l'utilisateur.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
Nous allons voir dans cette partie plusieurs méthodes pour utiliser ces espaces
|
|
|
|
|
de noms.
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
#### Avec son coquillage\
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
|
|
|
|
De la même manière que l'on peut utiliser l'appel système `chroot(2)` depuis un
|
|
|
|
|
shell via la commande `chroot(1)`, la commande `unshare(1)` permet de faire le
|
2017-11-09 00:30:41 +00:00
|
|
|
|
nécessaire pour lancer l'appel système `unshare(2)`, puis, tout comme
|
2016-10-19 03:24:05 +00:00
|
|
|
|
`chroot(1)`, exécuter le programme passé en paramètre.
|
|
|
|
|
|
|
|
|
|
En fonction des options qui lui sont passées, `unshare(1)` va créer le/les
|
|
|
|
|
nouveaux *namespaces* et placer le processus dedans.
|
|
|
|
|
|
|
|
|
|
Par exemple, nous pouvons modifier sans crainte le nom de notre machine, si
|
2022-02-24 19:43:43 +00:00
|
|
|
|
nous sommes passés dans un autre *namespace* `UTS` :
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2018-11-16 01:38:41 +00:00
|
|
|
|
```
|
|
|
|
|
42sh# hostname --fqdn
|
|
|
|
|
koala.zoo.paris
|
|
|
|
|
42sh# sudo unshare -u /bin/bash
|
2019-11-03 17:54:22 +00:00
|
|
|
|
bash# hostname --fqdn
|
|
|
|
|
koala.zoo.paris
|
|
|
|
|
bash# hostname lynx.zoo.paris
|
|
|
|
|
bash# hostname --fqdn
|
|
|
|
|
lynx.zoo.paris
|
|
|
|
|
bash# exit
|
2018-11-16 01:38:41 +00:00
|
|
|
|
42sh# hostname --fqdn
|
|
|
|
|
koala.zoo.paris
|
2016-10-19 03:24:05 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-19 03:24:05 +00:00
|
|
|
|
|
2017-11-09 00:30:41 +00:00
|
|
|
|
Nous avons pu ici modifier le nom de la machine, sans que cela n'affecte notre
|
2016-10-19 03:24:05 +00:00
|
|
|
|
machine hôte.
|
|
|
|
|
|
2015-10-07 01:45:39 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
#### Les appels systèmes\
|
2016-10-20 01:17:42 +00:00
|
|
|
|
|
|
|
|
|
L'appel système par excellence pour contrôler l'isolation d'un nouveau
|
|
|
|
|
processus est `clone(2)`.
|
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
Ce *syscall*, propre à Linux, crée habituellement un nouveau processus (mais
|
|
|
|
|
aussi des threads) enfant de notre processus courant, comme `fork(2)` (qui lui
|
|
|
|
|
est un appel système POSIX) mais prend en plus de nombreux
|
|
|
|
|
paramètres. L'isolement ou non du processus se fait en fonction des *flags* qui
|
2022-02-24 19:43:43 +00:00
|
|
|
|
sont passés :
|
2016-10-20 01:17:42 +00:00
|
|
|
|
|
|
|
|
|
* `CLONE_NEWNS`,
|
|
|
|
|
* `CLONE_NEWUTS`,
|
|
|
|
|
* `CLONE_NEWIPC`,
|
|
|
|
|
* `CLONE_NEWPID`,
|
|
|
|
|
* `CLONE_NEWNET`,
|
|
|
|
|
* `CLONE_NEWUSER`,
|
2021-10-31 19:51:17 +00:00
|
|
|
|
* `CLONE_NEWCGROUP`,
|
|
|
|
|
* `CLONE_NEWTIME`.
|
2016-10-20 01:17:42 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
On peut bien entendu cumuler un ou plusieurs de ces *flags*, et les combiner
|
|
|
|
|
avec d'autres attendus par `clone(2)`.
|
2016-10-20 01:17:42 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
Ces mêmes *flags* sont utilisés lors des appels à `unshare(2)` ou `setns(2)`,
|
|
|
|
|
que nous verrons plus tard.
|
2016-10-20 01:17:42 +00:00
|
|
|
|
|
2017-11-09 00:30:41 +00:00
|
|
|
|
Pour créer un nouveau processus qui sera à la fois dans un nouvel espace de
|
2021-10-31 19:51:17 +00:00
|
|
|
|
noms réseau et dans un nouveau *namespace* `cgroup`, on écrirait un code C
|
2022-02-24 19:43:43 +00:00
|
|
|
|
semblable à :
|
2016-10-20 01:17:42 +00:00
|
|
|
|
|
2017-10-17 06:29:07 +00:00
|
|
|
|
<div lang="en-US">
|
2016-10-20 01:17:42 +00:00
|
|
|
|
```c
|
2018-11-16 01:38:41 +00:00
|
|
|
|
#include <sched.h>
|
2016-10-20 01:17:42 +00:00
|
|
|
|
|
2021-09-11 12:41:43 +00:00
|
|
|
|
#define STACKSIZE (1024 * 1024)
|
2018-11-16 01:38:41 +00:00
|
|
|
|
static char child_stack[STACKSIZE];
|
2016-10-20 01:17:42 +00:00
|
|
|
|
|
2018-11-16 01:38:41 +00:00
|
|
|
|
int clone_flags = CLONE_CGROUP | CLONE_NEWNET | SIGCHLD;
|
2016-10-20 01:17:42 +00:00
|
|
|
|
|
2021-09-11 12:41:43 +00:00
|
|
|
|
pid_t pid = clone(do_execvp, // First function executed by child
|
|
|
|
|
child_stack + STACKSIZE, // Assume stack grows downward
|
|
|
|
|
clone_flags, // clone specials flags
|
|
|
|
|
args); // Arguments to pass to do_execvp
|
2016-10-20 01:17:42 +00:00
|
|
|
|
```
|
2017-10-17 06:29:07 +00:00
|
|
|
|
</div>
|
2016-10-20 01:17:42 +00:00
|
|
|
|
|
2021-09-11 12:41:43 +00:00
|
|
|
|
Dans cet exemple, le processus fils créé disposera d'un nouvel espace de noms
|
|
|
|
|
pour les *CGroups* et disposera d'une nouvelle pile réseau.
|
|
|
|
|
|
|
|
|
|
Un exemple complet d'utilisation de `clone(2)` et du *namespace* `UTS` est
|
|
|
|
|
donné dans le `man` de l'appel système.
|
2016-10-20 01:17:42 +00:00
|
|
|
|
|
2015-10-07 01:45:39 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
##### `unshare`\
|
2015-10-07 01:45:39 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
L'appel système `clone(2)` va créer un nouveau processus, ou un nouveau
|
|
|
|
|
thread. Parfois, on souhaite faire entrer notre processus ou thread en cours
|
|
|
|
|
dans un nouvel espace de noms. Dans ce cas, on utilisera l'appel système
|
|
|
|
|
`unshare(2)`. Celui-ci prend uniquement en argument une liste de *flags* des
|
|
|
|
|
*namespace*s dont on souhaite se dissocier.
|
2015-10-07 01:45:39 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
::::: {.warning}
|
|
|
|
|
Le comportement de `unshare(2)` (ou `unshare(3)`) avec les *namespace*s *PID*
|
2022-02-24 19:43:43 +00:00
|
|
|
|
et *Time* n'est pas celui que l'on peut attendre !
|
2015-10-08 01:48:26 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
En effet, après avoir appelé `unshare`, le processus reste tout de même dans
|
|
|
|
|
son *namespace* *Time* ou *PID* d'origine, seuls ses enfants (après un appel à
|
|
|
|
|
`fork(2)` ou `clone(2)` par exemple) seront dans le nouveau *namespace*.
|
2015-10-08 01:48:26 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
Cela poserait trop de problème de faire changer le PID d'un processus en cours
|
|
|
|
|
d'exécution, de même qu'il serait impensable que la `CLOCK_MONOTONIC` puisse
|
|
|
|
|
faire un saut en avant ou en arrière. Alors le choix qui a été fait est que
|
|
|
|
|
seuls les fils créés après l'appel à `unshare(2)` seront concrètement dans le
|
|
|
|
|
nouveau *namespace*. C'est dans cette situation que `pid` et `pid_for_children`
|
|
|
|
|
peuvent être différents dans le dossier `/proc/<PID>/ns`.
|
2016-10-20 01:17:42 +00:00
|
|
|
|
|
2021-10-31 19:51:17 +00:00
|
|
|
|
On ne remarque pas cette bizarrerie avec `clone(2)`, car il crée déjà un
|
|
|
|
|
nouveau processus, son PID et sa `CLOCK_MONOTONIC` sont directement à la bonne
|
|
|
|
|
valeur dès l'exécution de la fonction `fn`.
|
|
|
|
|
:::::
|