Update 2018

This commit is contained in:
nemunaire 2018-11-06 14:44:59 +01:00
commit 5b03f090fe
10 changed files with 64 additions and 64 deletions

View file

@ -1,5 +1,5 @@
SOURCES_TUTO = tutorial.md setup.md cmpns.md docker-exec.md mountns.md rendu.md
SOURCES_LESSON = lesson.md namespaces.md networkns.md pidns.md userns.md
SOURCES_LESSON = lesson.md mount.md namespaces.md networkns.md pidns.md userns.md
PANDOCOPTS = --latex-engine=xelatex \
--standalone \

View file

@ -3,7 +3,7 @@ title: Virtualisation légère -- Linux Internals partie 2
subtitle: Support de cours
author: Pierre-Olivier *nemunaire* Mercier
institute: EPITA
date: Jeudi 2 novembre 2017
date: Mercredi 7 novembre 2018
...
Le but de cette seconde partie sur les mécanismes internes du noyau va nous

298
tutorial/4/mount.md Normal file
View file

@ -0,0 +1,298 @@
\newpage
Des particularités de `mount` {#mount}
=============================
## Les points de montage
Au premier abord, les points de montage dans l'arborescence d'un système de
fichiers n'ont pas l'air d'être remplis de notions complexes : un répertoire
peut être le point d'entrée d'un montage vers la partition d'un disque
physique... ou d'une partition virtuelle, comme nous l'avons vu dans la partie
précédente.
Mais avez-vous déjà essayé de monter la même partition d'un disque physique à
deux endroits différents de votre arborescence ?
Si pour plein de raisons on pouvait se dire que cela ne devrait pas être
autorisé, ce problème s'avère être à la base de beaucoup de fonctionnalités
intéressantes. Le noyau va finalement décorréler les notions de montage,
d'accès et d'accroches dans l'arborescence : et par exemple, une partition ne
sera plus forcément démontée après un appel à `umount(2)`, mais le sera
seulement lorsque cette partition n'aura plus d'accroches dans aucune
arborescence.
La commande `findmnt(1)`, des
[`util-linux`](https://www.kernel.org/pub/linux/utils/util-linux/) nous permet
d'avoir une vision arborescente des points de montage en cours d'utilisation.
<div lang="en-US">
```
TARGET SOURCE FSTYPE OPTIONS
/ /dev/sda1 ext4 rw,relatime,data=ordered
├─/proc proc proc rw,nosuid,nodev,noexec,relatime
├─/sys sysfs sysfs rw,nosuid,nodev,noexec,relatime
│ ├─/sys/kernel/security securityfs securityfs rw,nosuid,nodev,noexec,relatime
│ ├─/sys/firmware/efi/efivars efivarfs efivarfs ro,relatime
│ └─/sys/fs/cgroup cgroup_root tmpfs rw,nosuid,nodev,noexec,relatime,size=10240k,mode=755
│ ├─/sys/fs/cgroup/unified none cgroup2 rw,nosuid,nodev,noexec,relatime
│ ├─/sys/fs/cgroup/cpuset cpuset cgroup rw,nosuid,nodev,noexec,relatime,cpuset
│ ├─/sys/fs/cgroup/cpu cpu cgroup rw,nosuid,nodev,noexec,relatime,cpu
│ ├─/sys/fs/cgroup/cpuacct cpuacct cgroup rw,nosuid,nodev,noexec,relatime,cpuacct
│ ├─/sys/fs/cgroup/blkio blkio cgroup rw,nosuid,nodev,noexec,relatime,blkio
│ ├─/sys/fs/cgroup/memory memory cgroup rw,nosuid,nodev,noexec,relatime,memory
│ ├─/sys/fs/cgroup/devices devices cgroup rw,nosuid,nodev,noexec,relatime,devices
│ ├─/sys/fs/cgroup/freezer freezer cgroup rw,nosuid,nodev,noexec,relatime,freezer
│ ├─/sys/fs/cgroup/net_cls net_cls cgroup rw,nosuid,nodev,noexec,relatime,net_cls
│ ├─/sys/fs/cgroup/perf_event perf_event cgroup rw,nosuid,nodev,noexec,relatime,perf_event
│ ├─/sys/fs/cgroup/net_prio net_prio cgroup rw,nosuid,nodev,noexec,relatime,net_prio
│ └─/sys/fs/cgroup/pids pids cgroup rw,nosuid,nodev,noexec,relatime,pids
├─/dev devtmpfs devtmpfs rw,nosuid,size=10240k,nr_inodes=486250,mode=755
│ ├─/dev/pts devpts devpts rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=000
│ ├─/dev/shm tmpfs tmpfs rw
│ └─/dev/mqueue mqueue mqueue rw,nosuid,nodev,noexec,relatime
├─/home /dev/sda3 ext4 rw,nosuid,nodev,relatime,data=ordered
├─/run tmpfs tmpfs rw,nosuid,nodev,noexec,mode=755
└─/tmp tmpfs tmpfs rw,nosuid,nodev,noexec,relatime
```
</div>
## `bind`
Lorsque l'on souhaite monter à un deuxième endroit (ou plus) une partition, on
utilise le *bind mount* :
<div lang="en-US">
```
mount --bind olddir newdir
```
</div>
Lorsque l'on souhaite `chroot` dans un système complet (par exemple lorsqu'on
l'installe ou qu'on le répare via un *live CD*), il est nécessaire de dupliquer
certains points de montage, tels que `/dev`, `/proc` et `/sys`.
Sans monter ces partitions, vous ne serez pas en mesure d'utiliser le système
dans son intégralité : vous ne pourrez pas monter les partitions indiquées par
le `/etc/fstab`, vous ne pourrez pas utiliser `top` ou `ps`, `sysctl` ne pourra
pas accorder les paramètres du noyau, ...
Pour que tout cela fonctionne, nous aurons besoin, au préalable, d'exécuter les
commandes suivantes :
<div lang="en-US">
```
cd newroot
mount --bind /dev dev
mount --bind /proc proc
mount --bind /sys sys
```
</div>
En se `chroot`ant à nouveau dans cette nouvelle racine, tous nos outils
fonctionneront comme prévu.
Tous ? ... en fait non. Si l'on jette un œil à `findmnt(1)`, nous constatons
par exemple que `/sys/fs/cgroup` dans notre nouvelle racine est vide, alors que
celui de notre machine hôte contient bien les répertoires de nos *cgroups*.
`--bind` va se contenter d'attacher le système de fichiers (ou au moins une
partie de celui-ci) à un autre endroit, sans se préoccuper des points de
montages sous-jacents. Pour effectuer cette action récursivement, et donc
monter au nouvel emplacement le système de fichier ainsi que tous les points
d'accroche qu'il contient, il faut utiliser `--rbind`. Il serait donc plus
correct de lancer :
<div lang="en-US">
```
cd newroot
mount --rbind /dev dev
mount -t proc none proc
mount --rbind /sys sys
```
</div>
## Les montages parfumés
On distingue quatre variétés de répercution des montages pour un sous-arbre :
partagé, esclave, privé et non-attachable.
Chacun va agir sur la manière dont seront propagées les nouvelles accroches au
sein d'un système de fichiers attaché à plusieurs endroits.
### partagé -- *shared mount*
Dans un montage partagé, une nouvelle accroche sera propagée parmi tous les
systèmes de fichiers de ce partage (on parle de *peer group*).
<div lang="en-US">
```shell
# Création de notre répertoire de travail
mkdir /mnt/test-shared
# On s'assure que le dossier que l'on va utiliser pour nos tests utilise bien la politique shared
mount --make-shared /tmp
# Duplication de l'accroche, sans s'occuper des éventuels sous-accroches
mount --bind /tmp /mnt/test-shared
```
</div>
Si l'on attache un nouveau point de montage dans `/tmp` ou dans
`/mnt/test-shared`, avec la politique `shared`, l'accroche sera propagée :
<div lang="en-US">
```shell
mkdir /mnt/test-shared/toto
mount -t tmpfs none /mnt/test-shared/toto
```
</div>
Un coup de `findmnt` nous montre l'existence de deux nouveaux points de
montage. À `/mnt/test-shared/toto`, mais également à `/tmp/toto`.
### esclave -- *slave mount*
De la même manière que lorsque la propagation est partagée, cette politique
propagera, mais seulement dans un sens. Le point de montage déclaré comme
esclave ne propagera pas ses nouveaux points de montage à son *maître*.
<div lang="en-US">
```shell
# Suite de l'exemple précédent
cd /mnt/test-slave
# Duplication de l'accroche, sans s'occuper des éventuels sous-accroches
mount --bind /mnt/test-shared /mnt/test-slave
# On rend notre dossier esclave
mount --make-slave /mnt/test-slave
```
</div>
Si l'on effectue un montage dans `/mnt/test-shared` :
<div lang="en-US">
```shell
mkdir /mnt/test-shared/foo
mount -t tmpfs none /mnt/test-shared/foo
```
</div>
Le point de montage apparaît bien sous `/mnt/test-slave/foo`. Par contre :
<div lang="en-US">
```shell
mkdir /mnt/test-slave/bar
mount -t tmpfs none /mnt/test-slave/bar
```
</div>
Le nouveau point de montage n'est pas propagé dans `/mnt/test-shared/bar`.
### privé -- *private mount*
C'est le mode le plus simple : ici les points de montage ne sont tout
simplement pas propagés.
Pour forcer un point d'accroche à ne pas propager et à ne pas recevoir de
propagation, on utilise l'option suivante :
<div lang="en-US">
```shell
mount --make-private mountpoint
```
</div>
### non-attachable -- *unbindable mount*
Ce mode interdira tout tentative d'attache à un autre endroit.
<div lang="en-US">
```shell
mount --make-unbindable /mnt/test-slave
```
</div>
Il ne sera pas possible de faire :
<div lang="en-US">
```shell
mkdir /mnt/test-unbindable
mount --bind /mnt/test-slave /mnt/test-unbindable
```
</div>
### Parfums récursifs
Les options que nous venons de voir s'appliquent sur un point de montage. Il
existe les mêmes options pour les appliquer en cascade sur les points d'attache
contenus dans leur sous-arbre :
<div lang="en-US">
```
mount --make-rshared mountpoint
mount --make-rslave mountpoint
mount --make-rprivate mountpoint
mount --make-runbindable mountpoint
```
</div>
## `bind` de dossiers et de fichiers
Il n'est pas nécessaire que le point d'accroche que l'on cherche à dupliquer
pointe sur un point de montage (c'est-à-dire, dans la plupart des cas : une
partition ou un système de fichiers virtuel). Il peut parfaitement pointer sur
un dossier, et même sur un simple fichier, à la manière d'un *hardlink*, mais
que l'on pourrait faire entre plusieurs partitions et qui ne persisterait pas au
redémarrage.
Nous verrons dans la partie *namespace* réseau, une utilisation d'attache sur
un fichier.
## Déplacer un point de montage
À tout moment, il est possible de réorganiser les points de montage, en les
déplaçant. Comme cela se fait sans démonter de partition, il est possible de le
faire même si un fichier est en cours d'utilisation. Il faut cependant veiller
à ce que les programmes susceptibles d'aller chercher un fichier à l'ancien
emplacement soient prévenu du changement.
On utilise pour cela l'option `--move` de `mount(8)` :
<div lang="en-US">
```shell
mount --move olddir newdir
```
</div>
Par exemple :
<div lang="en-US">
```shell
mount --move /dev /newroot/dev
```
</div>
Il est courant de faire appel à cette option lorsque l'on souhaite changer la
racine de notre système de fichiers : par exemple pour passer de l'*initramfs*
au système démarré, de notre système hôte au système d'un conteneur, ...
## Aller plus loin
Voici quelques articles qui valent le détour, en lien avec les points de
montage :
* [Shared subtree](https://lwn.net/Articles/159077) et la
[documentation du noyau associée](https://kernel.org/doc/Documentation/filesystems/sharedsubtree.txt) ;
* [Mount namespaces and shared subtrees](https://lwn.net/Articles/689856) ;
* [Mount namespaces, mount propagation, and unbindable mounts](https://lwn.net/Articles/690679).

View file

@ -19,7 +19,7 @@ ne sont pas encore *containerisables* :
[le document fondateur](https://www.kernel.org/doc/ols/2006/ols2006v1-pages-101-112.pdf)
parle ainsi d'isoler les périphériques, ou encore l'horloge. Pour ce
dernier,
[un patch a même déjà été proposé](https://lwn.net/Articles/179825/).
[un patch a même déjà été proposé](https://lwn.net/Articles/766089/).
### L'espace de noms `mount` {#mount-ns}
@ -194,17 +194,17 @@ similaire à :
<div lang="en-US">
```c
#include <sched.h>
#include <sched.h>
#define STACKSIZE (1024*1024)
static char child_stack[STACKSIZE];
#define STACKSIZE (1024*1024)
static char child_stack[STACKSIZE];
int clone_flags = CLONE_CGROUP | CLONE_NEWNET | SIGCHLD;
int clone_flags = CLONE_CGROUP | CLONE_NEWNET | SIGCHLD;
pid_t pid = clone(do_execvp,
child_stack + STACKSIZE,
clone_flags,
&args);
pid_t pid = clone(do_execvp,
child_stack + STACKSIZE,
clone_flags,
&args);
```
</div>
@ -220,33 +220,33 @@ auquel on passe le *file descriptor* d'un des liens du dossier
<div lang="en-US">
```c
#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <stdlib.h>
#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <stdlib.h>
// ./a.out /proc/PID/ns/FILE cmd args...
// ./a.out /proc/PID/ns/FILE cmd args...
int main(int argc, char *argv[])
{
int fd = open(argv[1], O_RDONLY);
if (fd == -1)
{
perror("open");
int main(int argc, char *argv[])
{
int fd = open(argv[1], O_RDONLY);
if (fd == -1)
{
perror("open");
return EXIT_FAILURE;
}
if (setns(fd, 0) == -1)
{
perror("setns");
return EXIT_FAILURE;
}
execvp(argv[2], &argv[2]);
perror("execve");
return EXIT_FAILURE;
}
if (setns(fd, 0) == -1)
{
perror("setns");
return EXIT_FAILURE;
}
execvp(argv[2], &argv[2]);
perror("execve");
return EXIT_FAILURE;
}
}
```
</div>
@ -254,7 +254,7 @@ Dans un shell, on utilisera la commande `nsenter(1)` :
<div lang="en-US">
```shell
42sh# nsenter --uts=/proc/42/ns/uts /bin/bash
42sh# nsenter --uts=/proc/42/ns/uts /bin/bash
```
</div>
@ -276,8 +276,8 @@ persister après le dernier processus), on peut utiliser un `mount bind` :
<div lang="en-US">
```shell
42sh# touch /tmp/ns/myrefns
42sh# mount --bind /proc/<PID>/ns/mount /tmp/ns/myrefns
42sh# touch /tmp/ns/myrefns
42sh# mount --bind /proc/<PID>/ns/mount /tmp/ns/myrefns
```
</div>

View file

@ -14,9 +14,9 @@ environnement qui n'a plus qu'une interface de *loopback* :
<div lang="en-US">
```shell
42sh# unshare -n ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
42sh# unshare -n ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
```
</div>
@ -153,7 +153,7 @@ gourmande.
### VLAN
Il est possible d'attribuer juste une interface de VLAN, si l'on a switch
Il est possible d'attribuer juste une interface de VLAN, si l'on a un switch
supportant la technologie [802.1q](https://fr.wikipedia.org/wiki/IEEE_802.1Q).
<div lang="en-US">

View file

@ -11,11 +11,11 @@ comme l'`init`.
Contrairement aux autres *namespaces* où l'on peut demander à se séparer du
*namespace* en question à n'importe quel moment de l'exécution du processus,
via `unshare(2)` ou `setns(2)` par exemple, ici, le changement n'est valable
via `unshare(2)` ou `setns(2)` par exemple, ici, le changement ne sera valable
qu'après le prochain `fork(2)` (ou similaire).
L'espace de noms PID du processus courant n'est pas changé, afin que le
processus ne change pas de PID en cours de route (puisque fonction du
*namespace* dans lequel il se trouve).
En effet, l'espace de noms n'est pas changé, afin que le processus ne change
pas de PID en cours de route, puisqu'il dépend du *namespace* dans lequel il se
trouve.
## Isolons !
@ -65,12 +65,12 @@ Cette fois, `top` et `ps` nous rapportent bien que l'on est seul dans notre
## Arborescence à l'extérieur du *namespace*
Lors de notre première tentative de `top`, lorsque `/proc` était encore monté
sur le `procfs` de l'espace de noms initial : votre processus (au PID 1 dans
sur le `procfs` de l'espace de noms initial : notre processus (au PID 1 dans
son nouveau *namespace*) était présent dans l'arborescence de l'espace initial
avec un PID dans la continuité des autres processus, étonnant !
En fait, l'isolation consiste en une virtualisation des numéros du processus :
la plupart des processus du système intial ne sont pas accessibles, et ceux qui
la plupart des processus du système initial ne sont pas accessibles, et ceux qui
font partie de l'espace de noms créé disposent d'une nouvelle numérotation. Et
c'est cette nouvelle numérotation qui est montrée au processus.

View file

@ -26,9 +26,6 @@ sera pas pris en compte.
Par ailleurs, n'oubliez pas de répondre à
[l'évaluation du cours](https://www.epitaf.fr/moodle/mod/quiz/view.php?id=42).
Afin de m'aider à améliorer ce cours, je vous invite à remplir
[ce sondage anonyme](https://www.epitaf.fr/moodle/mod/quiz/view.php?id=44).
Tarball
-------
@ -40,8 +37,8 @@ Voici une arborescence type :
<div lang="en-US">
```
login_x-TP4/cmpns.sh
login_x-TP4/mydocker_exec.sh
login_x-TP4/myswitch_root.sh
login_x-TP4/cmpns.sh
login_x-TP4/mydocker_exec.sh
login_x-TP4/myswitch_root.sh
```
</div>

View file

@ -63,7 +63,7 @@ Nous allons utiliser des programmes issus des
[`procps-ng`](https://gitlab.com/procps-ng/procps) ainsi que ceux de la
[`libcap`](http://www.friedhoff.org/posixfilecaps.html).
Sous Debian et ses dérivés, ses paquets sont respectivement :
Sous Debian et ses dérivés, ces paquets sont respectivement :
* `util-linux`
* `procps`

View file

@ -3,7 +3,7 @@ title: Virtualisation légère -- TP n^o^ 4
subtitle: Linux Internals partie 2
author: Pierre-Olivier *nemunaire* Mercier
institute: EPITA
date: Jeudi 2 novembre 2017
date: Mercredi 7 novembre 2018
...
Le but de ce second TP sur les mécanismes internes du noyau va nous permettre
@ -11,7 +11,7 @@ d'utiliser les commandes et les appels systèmes relatifs aux *namespaces* ainsi
que d'appréhender la complexité des systèmes de fichiers.
Tous les exercices de ce TP sont à rendre à <virli@nemunai.re> au plus tard le
jeudi 9 novembre 2017 à 8 h 42.
mercredi 14 novembre 2017 à 12 h 42.
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
vous devrez m'envoyer vos rendus signés avec votre clef PGP. Pensez à

View file

@ -34,13 +34,16 @@ garder dans le nouvel espace, que les utilisateurs et les groupes utiles au
processus, en les renumérotant au passage si besoin.
### L'utilisateur -1 : *nobody*
### L'utilisateur -2 : *nobody*
Lorsque l'on arrive dans un nouvel espace, aucun utilisateur ni groupe n'est
défini. Dans cette situation, tous les identifiants d'utilisateur et de groupe,
renvoyés par le noyau sont à -1 ; valeur qui correspond en toute circonstance à
renvoyés par le noyau sont à -2 ; valeur qui correspond par convention à
l'utilisateur *nobody* et au groupe *nogroup*.
-1 étant réservé pour indiqué une erreur dans le retour d'une commande, ou la
non-modification d'un paramètres passé en argument d'une fonction.
### `uid_map` et `gid_map`
@ -56,7 +59,7 @@ Sur chaque ligne, on doit indiquer :
en question.
- L'identifiant marquant le début de la plage d'utilisateurs, pour le processus
affichant le fichier.
- La taille de la page.
- La taille de la plage.
Par exemple, le *namespace* `user` initial défini la correspondance suivante :