Tuto 3 done
This commit is contained in:
parent
15236db9af
commit
8c402e6d65
Binary file not shown.
@ -1,6 +1,11 @@
|
||||
include ../pandoc-opts.mk
|
||||
|
||||
SOURCES = tutorial.md installation.md chroot.md pseudofs.md capabilities.md cgroups.md oom.md seccomp.md project-intro.md project-body.md project-rendu.md
|
||||
SOURCES = tutorial.md \
|
||||
intro.md installation.md pseudofs.md capabilities.md cgroups.md cgroups-influx.md \
|
||||
oom.md \
|
||||
seccomp.md \
|
||||
chroot-intro.md chroot.md chroot-ex-escape.md \
|
||||
project-rendu.md
|
||||
|
||||
|
||||
all: tutorial.pdf
|
||||
|
@ -1,16 +1,14 @@
|
||||
\newpage
|
||||
|
||||
Les *capabilities*
|
||||
==================
|
||||
|
||||
## Présentation
|
||||
------------------
|
||||
|
||||
Historiquement, dans la tradition UNIX, on distinguait deux catégories de
|
||||
processus :
|
||||
processus :
|
||||
|
||||
* les processus *privilégiés* : dont l'identifiant numérique de son utilisateur
|
||||
est 0 ;
|
||||
* les processus *non-privilégiés* : dont l'identifiant numérique de son
|
||||
* les processus *privilégiés* : dont l'identifiant numérique de son utilisateur
|
||||
est 0 ;
|
||||
* les processus *non-privilégiés* : dont l'identifiant numérique de son
|
||||
utilisateur n'est pas 0.
|
||||
|
||||
Lors des différents tests de permission fait par le noyau, les processus
|
||||
@ -21,24 +19,25 @@ Depuis Linux 2.2 (en 1998), les processus privilégiés peuvent activer ou
|
||||
désactiver des *capabilities*, chacune donnant accès à un groupe d'actions
|
||||
privilégiées au sein du noyau.
|
||||
|
||||
On trouve par exemple :
|
||||
On trouve par exemple :
|
||||
|
||||
* `CAP_CHOWN` : permet de modifier le propriétaire d'un fichier de manière
|
||||
arbitraire ;
|
||||
* `CAP_KILL` : permet de tuer n'importe quel processus ;
|
||||
* `CAP_SYS_BOOT` : permet d'arrêter ou de redémarrer la machine ;
|
||||
* `CAP_SYS_MODULE` : permet de charger et décharger des modules ;
|
||||
* et beaucoup d'autres, il y en a environ 39 en tout (ça dépend de la
|
||||
version du noyau) !
|
||||
* `CAP_CHOWN` : permet de modifier le propriétaire d'un fichier de manière
|
||||
arbitraire ;
|
||||
* `CAP_KILL` : permet de tuer n'importe quel processus ;
|
||||
* `CAP_SYS_BOOT` : permet d'arrêter ou de redémarrer la machine ;
|
||||
* `CAP_SYS_MODULE` : permet de charger et décharger des modules ;
|
||||
* et beaucoup d'autres, il y en a environ 41 en tout (ça dépend de la
|
||||
version du noyau) !
|
||||
|
||||
|
||||
### `ping`
|
||||
|
||||
Pour émettre un ping, il est nécessaire d'envoyer des paquets ICMP. À la
|
||||
différence des datagrammes UDP ou des segments TCP, il n'existe pas d'interface
|
||||
exposée par le noyau aux utilisateurs pour envoyer des paquets ICMP. Pour le
|
||||
faire, il est nécessaire de pouvoir écrire directement sur l'interface ; ça,
|
||||
seul le super-utilisateur peut le faire.
|
||||
différence des datagrammes UDP ou des segments TCP, il n'est pas forcément
|
||||
simple d'envoyer des paquets ICMP lorsque l'on est simple utilisateur, car
|
||||
l'usage du protocole ICMP dans une socket est restreint : il faut soit être
|
||||
super-utilisateur, soit que le noyau ait été configuré pour autoriser certains
|
||||
utilisateurs à envoyer des `ECHO_REQUEST`.
|
||||
|
||||
Pour permettre à tous les utilisateurs de pouvoir envoyer des ping, le
|
||||
programme est donc généralement *Setuid root*. Cela permet à n'importe quel
|
||||
@ -48,35 +47,88 @@ du programme.
|
||||
Les problèmes surviennent lorsque l'on découvre des vulnérabilités dans les
|
||||
programmes *Setuid root*. En effet, s'il devient possible pour un utilisateur
|
||||
d'exécuter du code arbitraire, ce code sera exécuté avec les privilèges de
|
||||
l'utilisateur *root* ! Dans le cas de `ping`, on se retrouverait alors à
|
||||
l'utilisateur *root* ! Dans le cas de `ping`, on se retrouverait alors à
|
||||
pouvoir lire l'intégralité de la mémoire, alors que l'on avait juste besoin
|
||||
d'écrire sur une interface réseau.
|
||||
|
||||
C'est donc à ce moment que les *capabilities* entrent en jeu : un processus (ou
|
||||
C'est donc à ce moment que les *capabilities* entrent en jeu : un processus (ou
|
||||
même un thread) privilégié peut décider, généralement à son lancement, de
|
||||
réduire ses *capabilities*, pour ne garder que celles dont il a réellement
|
||||
besoin. Ainsi, `ping` pourrait se contenter de `CAP_NET_RAW`.
|
||||
|
||||
::::: {.warning}
|
||||
Bien que ce paramètre existe [depuis
|
||||
2011](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=c319b4d76b9e583a5d88d6bf190e079c4e43213d),
|
||||
ce n'est que [depuis 2020](https://github.com/systemd/systemd/pull/13141) que les distributions comme Fedora et Ubuntu
|
||||
se mettent à fournir par défaut une configuration qui permette de se passer de
|
||||
*capabilities* pour lancer `ping`.\
|
||||
|
||||
## Les attributs de fichier étendus
|
||||
Si vous vous rendez compte que votre binaire `ping` est dans ce cas, testez
|
||||
depuis un conteneur, par exemple :
|
||||
|
||||
Une grosse majorité des systèmes de fichiers (ext[234], XFS, btrfs, ...)
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ docker run -it --rm alpine
|
||||
|
||||
(ctnr)# apk add --no-cache acl iputils
|
||||
(1/4) Installing libacl (2.2.53-r0)
|
||||
(2/4) Installing acl (2.2.53-r0)
|
||||
(3/4) Installing libcap (2.50-r0)
|
||||
(4/4) Installing iputils (20210202-r0)
|
||||
|
||||
(ctnr)# su -s/bin/ash daemon
|
||||
|
||||
(ctnr)$ _
|
||||
```
|
||||
</div>
|
||||
|
||||
Dans le conteneur le binaire `ping` est *setuid root*, vous pouvez faire des
|
||||
tests en retirant le *setuid* :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
(ctnr)# chmod u-s /bin/ping
|
||||
|
||||
(ctnr)$ ping epita.fr
|
||||
ping: socket: Operation not permitted
|
||||
```
|
||||
</div>
|
||||
|
||||
Puis en ajoutant la *capability* :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
(ctnr)# setcap cap_net_raw+p /bin/ping
|
||||
|
||||
(ctnr)$ ping epita.fr
|
||||
PING epita.fr (172.67.156.141) 56(84) bytes of data.
|
||||
```
|
||||
</div>
|
||||
|
||||
Vous vous retrouverez dans le scénario attendu, tout en pouvant agir sur le
|
||||
binaire `ping` sans avoir peur de casser votre distribution.
|
||||
:::::
|
||||
|
||||
|
||||
### Les attributs de fichier étendus
|
||||
|
||||
Une grosse majorité des systèmes de fichiers (ext[234], XFS, btrfs, ...)
|
||||
permet d'enregistrer, pour chaque fichier, des attributs (dits attributs
|
||||
*étendus*, par opposition aux attributs *réguliers* qui sont réservés à l'usage
|
||||
du système de fichiers).
|
||||
|
||||
Sous Linux, les attributs sont regroupés dans des espaces de noms :
|
||||
Sous Linux, les attributs sont regroupés dans des espaces de noms :
|
||||
|
||||
* *security* : espace utilisé par les modules de sécurité du noyau, tel que
|
||||
SELinux, ... ;
|
||||
* *system* : espace utilisé par le noyau pour stocker des objets système, tels
|
||||
que les ACL POSIX ;
|
||||
* *security* : espace utilisé par les modules de sécurité du noyau, tel que
|
||||
SELinux, ... ;
|
||||
* *system* : espace utilisé par le noyau pour stocker des objets système, tels
|
||||
que les ACL POSIX ;
|
||||
* *trusted*: espace dont la lecture et l'écriture est limité au
|
||||
super-utilisateur ;
|
||||
* *user* : modifiable sans restriction, à partir du moment où l'on est le
|
||||
super-utilisateur ;
|
||||
* *user* : modifiable sans restriction, à partir du moment où l'on est le
|
||||
propriétaire du fichier.
|
||||
|
||||
Par exemple, on peut définir un attribut sur un fichier comme cela :
|
||||
Par exemple, on peut définir un attribut sur un fichier comme cela :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
@ -88,14 +140,16 @@ user.foo="bar"
|
||||
```
|
||||
</div>
|
||||
|
||||
Encore plus fort, vous pouvez utiliser les ACL POSIX :
|
||||
En tant que simple utilisateur, vous ne pouvez pas modifier des attributs en
|
||||
dehors de l'espace *user*. Par contre, en *root*, vous pouvez définir et
|
||||
changer les ACL POSIX :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh$ sudo chown root:root toto && sudo chmod o-r toto
|
||||
42sh$ cat toto
|
||||
cat: toto: Permission denied
|
||||
42sh$ sudo setfattr -m u:$USER:r toto
|
||||
42sh$ sudo setfacl -m u:$USER:r toto
|
||||
42sh$ cat toto
|
||||
Hello World!
|
||||
```
|
||||
@ -104,7 +158,7 @@ Hello World!
|
||||
Bien que les droits UNIX traditionnels ne vous donnent pas accès au fichier,
|
||||
les ACL POSIX vous autorisent à le lire.
|
||||
|
||||
Vous pouvez voir ces attributs avec la commande :
|
||||
Vous pouvez voir ces attributs bruts avec la commande :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
@ -114,17 +168,19 @@ system.posix_acl_access=0sgAAEAD/////AgAEOgDAEAA/////xAABAD////8=
|
||||
```
|
||||
</div>
|
||||
|
||||
Il s'agit d'une représentation d'une structure du noyau, pas forcément très
|
||||
lisible en l'état. On utilisera `getfacl` pour la version lisible.
|
||||
|
||||
### `ping`
|
||||
|
||||
#### `ping`\
|
||||
|
||||
De la même manière que l'on peut définir de façon plus fine les droits d'accès
|
||||
par utilisateur, un attribut de l'espace de nom *security* peut être défini
|
||||
pour accroître les *capabilities* d'un processus lorsqu'il est lancé par un
|
||||
utilisateur non-privilégié. On peut alors voir le Setuid root comme
|
||||
l'utilisation de cet attribut auquel on accroîtrait l'ensemble des
|
||||
*capabilities*.
|
||||
utilisateur non-privilégié. On peut voir le *setuid root* comme l'utilisation
|
||||
de cet attribut, qui accroîtrait l'ensemble des *capabilities*.
|
||||
|
||||
Si votre distribution profite de ces attributs étendus, vous devriez obtenir :
|
||||
Si votre distribution profite de ces attributs étendus, vous devriez obtenir :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
@ -134,7 +190,8 @@ security.capability=0sAQAAAgAgAAAAAAAAAAAAAAAAAAA=
|
||||
```
|
||||
</div>
|
||||
|
||||
Ou, dans sa version plus lisible :
|
||||
Comme pour les ACL POSIX, une structure du noyau est enregistrée comme attribut
|
||||
du fichier ; et on peut l'afficher dans sa version plus lisible :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
@ -144,10 +201,10 @@ Ou, dans sa version plus lisible :
|
||||
</div>
|
||||
|
||||
|
||||
## Exercice : visualisateur de capabilities d'un processus {-}
|
||||
### Exercice : visualisateur de capabilities d'un processus {-}
|
||||
|
||||
Écrivons maintenant un programme permettant de voir les *capabilities*
|
||||
d'un processus :
|
||||
d'un processus :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
@ -179,24 +236,27 @@ inheritable: 0x0
|
||||
```
|
||||
</div>
|
||||
|
||||
Astuces : `capget(2)`, X-macros, ...
|
||||
Appelé sans argument, `view_caps` affichera les capabilities du processus
|
||||
courant.
|
||||
|
||||
Astuces : `capget(2)`, X-macros, ...
|
||||
|
||||
|
||||
## Pour aller plus loin {-}
|
||||
### Pour aller plus loin {-}
|
||||
|
||||
Je vous recommande la lecture des *man* suivants :
|
||||
Je vous recommande la lecture des *man* suivants :
|
||||
|
||||
* `capabilities(7)` : énumérant tous les capabilities, leur utilisation, etc. ;
|
||||
* `xattrs(7)` : à propos des attributs étendus.
|
||||
* `capabilities(7)` : énumérant tous les capabilities, leur utilisation, etc. ;
|
||||
* `xattrs(7)` : à propos des attributs étendus.
|
||||
|
||||
Et de ces quelques articles :
|
||||
Et de ces quelques articles :
|
||||
|
||||
* [Secure Your Containers with this One Weird Trick](https://www.redhat.com/en/blog/secure-your-containers-one-weird-trick)
|
||||
* [Linux Capabilities: Why They Exist and How They Work](https://blog.container-solutions.com/linux-capabilities-why-they-exist-and-how-they-work)
|
||||
* [Guidelines for extended attributes](https://www.freedesktop.org/wiki/CommonExtendedAttributes/)
|
||||
* [File-based capabilities](https://lwn.net/Articles/211883/)
|
||||
* [A bid to resurrect Linux capabilities](https://lwn.net/Articles/199004/)
|
||||
* [False Boundaries and Arbitrary Code Execution](https://forums.grsecurity.net/viewtopic.php?f=7&t=2522#p10271)
|
||||
|
||||
Pour revenir à Docker, par défaut, un certain nombre de *capabilities* sont
|
||||
désactivées par défaut ; vous pouvez en ajouter et en retirer via les arguments
|
||||
`--cap-add` et `--cap-drop` du `docker container run`.
|
||||
Pour revenir à Docker, un certain nombre de *capabilities* sont désactivées par
|
||||
défaut ; vous pouvez en ajouter et en retirer via les arguments `--cap-add` et
|
||||
`--cap-drop` du `docker container run`.
|
||||
|
87
tutorial/3/cgroups-influx.md
Normal file
87
tutorial/3/cgroups-influx.md
Normal file
@ -0,0 +1,87 @@
|
||||
### Exercice (obligatoire pour les SRS -- optionnel pour les GISTRE)
|
||||
|
||||
Poursuivons [notre script de monitoring](#script-monitoring) afin d'envoyer nos
|
||||
résultats vers InfluxDB : nous l'appellerons `./telegraf.sh`
|
||||
|
||||
#### Rappel d'InfluxDB\
|
||||
|
||||
Commençons par lancer le conteneur Docker d'InfluxDB (pour éviter de
|
||||
l'installer sur notre machine) :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
docker container run --name mytsdb -d -p 8086:8086 influxdb:1.8
|
||||
```
|
||||
</div>
|
||||
|
||||
Il nous faut ensuite créer une base de données pour y stocker nos
|
||||
métriques. Voici comment on s'était débrouillé précédemment pour interagir avec
|
||||
InfluxDB :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
docker container exec -i mytsdb influx <<EOF
|
||||
CREATE DATABASE metrics;
|
||||
SHOW DATABASES;
|
||||
EOF
|
||||
```
|
||||
</div>
|
||||
|
||||
Vérifiez que la base de données `metrics` a bien été créée.
|
||||
|
||||
|
||||
#### Monitoring vers InfluxDB\
|
||||
|
||||
Maintenant, envoyons nos données vers la base
|
||||
<https://docs.influxdata.com/influxdb/v1.8/guides/write_data/> :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
curl -i -XPOST 'http://localhost:8086/write?db=metrics' --data-binary \
|
||||
"$my_cgroup_name memory.usage_in_bytes=$(cat .../my_cgroup_name/memory.usage_in_bytes)"
|
||||
```
|
||||
</div>
|
||||
|
||||
Pour vérifier que les données ont bien été ajoutées, nous pouvons effectuer la
|
||||
requête suivante dans notre client `influx` :
|
||||
|
||||
<div lang="en-US">
|
||||
```sql
|
||||
SELECT * from "$my_cgroup_name";
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
#### Monitorer davantage de données\
|
||||
|
||||
Liste non exhaustive de données à monitorer :
|
||||
|
||||
* Nombre d'IOs effectué ;
|
||||
* nombre d'octets lus/écrits sur les disques ;
|
||||
* temps de calcul utilisé (`userspace`, `system`, tout confondu) ;
|
||||
* ...
|
||||
|
||||
Tous les cgroups existants dans le dernier noyau publié ont leur documentation
|
||||
accessible ici :
|
||||
|
||||
- v1 : <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/index.html>
|
||||
- v2 : <https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html>
|
||||
|
||||
|
||||
#### Permettre à l'utilisateur de monitorer des processus\
|
||||
|
||||
Maintenant, séparons notre script en deux parties afin qu'un utilisateur normal
|
||||
(non-root) puisse utiliser la partie monitoring de notre script.
|
||||
|
||||
Un premier script doit s'occuper de créer le(s) *cgroup*s et lui attribuer les
|
||||
bons droits, tandis que le deuxième va effectuer le monitoring, sans privilèges
|
||||
particuliers.
|
||||
|
||||
##### Exemple {-}
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ sudo ./telegraf_init.sh my_cgroup_name
|
||||
42sh$ ./telegraf.sh my_cgroup_name memhog 500
|
||||
```
|
||||
</div>
|
@ -1,26 +1,66 @@
|
||||
\newpage
|
||||
|
||||
Utiliser les *cgroup*s
|
||||
======================
|
||||
Les *cgroup*s
|
||||
-------------
|
||||
|
||||
Les *cgroup*s (pour *Control Group*s) permettent de collecter des statistiques
|
||||
sur des groupes de processus (appelés tâches) et de leur attribuer des
|
||||
propriétés. Par exemple, il est possible leur imposer des limites d'utilisation
|
||||
de ressources ou d'altérer leur comportement.
|
||||
sur des **groupes de processus** (voire même, des threads !) et de leur
|
||||
attribuer des propriétés. Il est par exemple possible de leur imposer des
|
||||
limites d'utilisation de ressources ou d'altérer leur comportement : quantité
|
||||
de RAM, temps CPU, bande passante, ...
|
||||
|
||||
Apparue dès [Linux
|
||||
2.6.24](https://kernelnewbies.org/Linux_2_6_24#Task_Control_Groups)
|
||||
(en 2008 !), les *cgroup*s sont répartis en différents sous-systèmes
|
||||
(*subsystem*), chacun étant responsable d'un type de ressources
|
||||
spécifique :
|
||||
|
||||
## Premiers tests
|
||||
- [`blkio` (`io` dans la v2)
|
||||
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/blkio-controller.html)
|
||||
limites et statistiques de bande passante sur les disques ;
|
||||
- `cpu` : cycles CPU minimum garantis ;
|
||||
- [`cpuacct` (inclus dans `cpu` dans la v2)
|
||||
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/cpuacct.html)
|
||||
statistiques du temps CPU utilisé ;
|
||||
- [`cpuset`
|
||||
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/cpusets.html)
|
||||
associe des tâches à un/des CPU particuliers (par exemple pour dédier un cœur
|
||||
du CPU à un programme, qui ne pourra alors utiliser que ce CPU et pas les
|
||||
autres) ;
|
||||
- [`devices`
|
||||
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/devices.html)
|
||||
règles de contrôle de création (`mknod`) et d'accès aux périphériques ;
|
||||
- [`freezer`
|
||||
:](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/freezer-subsystem.html)
|
||||
pour suspendre et reprendre l'exécution d'un groupe de tâches ;
|
||||
- [`hugetlb` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/hugetlb.html) statistiques et limitation de l'usage de la fonctionnalité `HugeTLB` (permettant d'obtenir des pages mémoires plus grande que 4 kB) ;
|
||||
- [`memory` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/memory.html) statistiques et limitation d'usage de la mémoire vive et de la *swap* ;
|
||||
- [`net_cls` (v1 seulement) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/net_cls.html) applique un `classid` à tous les paquets émis par les tâches du *cgroup*, pour filtrage par le pare-feu en sortie ;
|
||||
- [`net_prio` (v1 seulement) :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/net_prio.html) surcharge la valeur de l'option de priorité `SO_PRIORITY`, ordonant la file d'attente des paquets sortants ;
|
||||
- [`pids` :](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/pids.html) statistiques et limitation du nombre de processus ;
|
||||
- ...
|
||||
|
||||
Nous allons commencer par faire quelques tests avec le *cgroup* *freezer*, qui
|
||||
permet d'interrompre l'exécution d'un groupe de processus et de la reprendre.
|
||||
permet d'interrompre l'exécution d'un groupe de processus, puis de la reprendre
|
||||
lorsqu'on le décide.
|
||||
|
||||
|
||||
### Montage du *cgroup*
|
||||
### Montage du *freezer*
|
||||
|
||||
En fonction de la configuration de votre système, il est possible que les
|
||||
*cgroup*s ne soient pas montés au démarrage dans `/sys/fs/cgroup/`. Si vous n'avez
|
||||
pas de dossier `freezer` ou si celui-ci est vide, montez-le en suivant la
|
||||
procédure suivante :
|
||||
En fonction de la configuration de votre système, vous allez vous trouver dans
|
||||
l'une de ces trois situations :
|
||||
|
||||
- Votre dossier `/sys/fs/cgroup` contient à la fois des fichiers `cgroup.*` et
|
||||
éventuellement des dossiers : vous avez une distribution moderne qui utilise
|
||||
la nouvelle version des `cgroup`s.
|
||||
|
||||
- Votre dossier `/sys/fs/cgroup` contient d'autres dossiers au nom des
|
||||
sous-systèmes que l'on a listé ci-dessus : il s'agit des `cgroup`s v1.
|
||||
|
||||
- Votre dossier `/sys/fs/cgroup` est vide ou inexistant, vous pouvez choisir
|
||||
d'utiliser la version de votre choix :
|
||||
|
||||
Pour utiliser la v1 :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
@ -29,22 +69,55 @@ mount -t cgroup -o freezer none /sys/fs/cgroup/freezer/
|
||||
```
|
||||
</div>
|
||||
|
||||
Cette dernière commande monte l'arborescence de groupes relative à ce *cgroup*
|
||||
*freezer*. Tous les dossiers contenus dans cette racine sont donc des
|
||||
sous-groupes.
|
||||
|
||||
Pour utiliser la v2 :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
mkdir /sys/fs/cgroup/
|
||||
mount -t cgroup2 none /sys/fs/cgroup/
|
||||
```
|
||||
</div>
|
||||
|
||||
::::: {.question}
|
||||
Avant d'aller plus loin, notez que les exemples seront donnés pour les deux
|
||||
versions des `cgroup`s à chaque fois.
|
||||
|
||||
La principale différence entre les deux est la fusion des différents
|
||||
sous-systèmes au sein d'une même arborescence. Dans la première version, chaque
|
||||
sous-système disposait de sa propre arborescence et il fallait créer les
|
||||
groupes et associer les tâches pour chaque sous-système. Avec la seconde
|
||||
version, une seule création est nécessaire, quelque soit le nombre de
|
||||
sous-systèmes que l'on souhaite utiliser.
|
||||
:::::
|
||||
|
||||
|
||||
### Création d'un nouveau groupe
|
||||
|
||||
La première étape dans l'utilisation d'un *cgroup* est de créer un groupe.
|
||||
Les *cgroup*s sont organisé autour d'une arborescence de groupe, où chaque
|
||||
groupe est représenté par un dossier. Il peut bien évidemment y avoir des
|
||||
sous-groupes, en créant des dossiers dans les dossiers existants, etc.\
|
||||
|
||||
La première étape dans l'utilisation d'un *cgroup* est donc de créer un groupe.
|
||||
|
||||
Pour ce faire, il suffit de créer un nouveau dossier dans un groupe existant,
|
||||
par exemple la racine :
|
||||
par exemple la racine.
|
||||
|
||||
On commence par se rendre à la racine :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
mkdir /sys/fs/cgroup/freezer/virli/
|
||||
ls /sys/fs/cgroup/freezer/virli/
|
||||
cd /sys/fs/cgroup/freezer/ # v1
|
||||
cd /sys/fs/cgroup/ # v2
|
||||
```
|
||||
</div>
|
||||
|
||||
Puis on crée notre groupe :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
mkdir virli
|
||||
ls virli/
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -53,19 +126,50 @@ Nous avons maintenant un nouveau groupe de processus `virli` dans le *cgroup*
|
||||
propriétés de son (ses) père(s).
|
||||
|
||||
|
||||
### Sélection de contrôleur (v2 seulement)
|
||||
|
||||
Du fait de l'unification de tous les sous-systèmes, si vous utilisez la seconde
|
||||
version, vous allez devoir activer le ou les contrôleurs dont vous avez besoin
|
||||
(tandis que dans la première version, on se rendait dans l'arborescence du
|
||||
sous-système que l'on voulait).
|
||||
|
||||
Pour activer le contrôleur *memory* dans notre groupe `virli`, nous utilisons
|
||||
la commande suivante :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
echo "+memory" > virli/cgroup.subtree_control
|
||||
```
|
||||
</div>
|
||||
|
||||
::::: {.warning}
|
||||
Si vous obtenez l'erreur `No such file or directory`, c'est sans doute que vous
|
||||
avez les `cgroup`s v1 activé quelque part. Vous devriez plutôt utiliser la
|
||||
première version, le fait qu'elle soit active empêche l'utilisation de la v2 en
|
||||
parallèle.
|
||||
:::::
|
||||
|
||||
On peut contrôler les contrôleurs actifs en consultant le fichier
|
||||
`virli/cgroup.controllers`.
|
||||
|
||||
Le contrôleur *freezer* est activé par défaut, il n'y a pas besoin de
|
||||
l'activer.
|
||||
|
||||
|
||||
### Rattachement de processus
|
||||
|
||||
Pour le moment, ce nouveau groupe ne contient aucune tâche.
|
||||
Pour le moment, ce nouveau groupe ne contient aucun processus, comme le montre
|
||||
le fichier `cgroup.procs` de notre groupe. Ce fichier contient la liste des
|
||||
processus rattachés à notre *cgroup*.
|
||||
|
||||
Ouvrons un nouveau terminal (c'est lui que l'on va geler), et récupérons son
|
||||
PID : `echo $$`.
|
||||
|
||||
La liste des processus rattachés à un *cgroup* se trouve dans le fichier `task`
|
||||
du groupe. Pour ajouter une tâche à ce groupe, cela se passe de cette manière :
|
||||
Pour ajouter une tâche à ce groupe, cela se passe de cette manière :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
echo $PID > /sys/fs/cgroup/freezer/virli/tasks
|
||||
echo $PID > /sys/fs/cgroup/{,freezer/}virli/cgroup.procs
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -75,7 +179,7 @@ En validant cette commande, nous avons déplacé le processus dans ce groupe, il
|
||||
n'est alors plus dans aucun autre groupe (pour ce *cgroup*, il ne bouge pas
|
||||
dans les autres *cgroup*s).
|
||||
|
||||
Malgré l'utilisation de la redirection `>` (et non `>>`), il s'agit belle et
|
||||
Malgré l'utilisation de la redirection `>` (et non `>>`), il s'agit bel et
|
||||
bien d'un ajout au fichier et non d'un écrasement. Il faut garder en tête que
|
||||
le système de fichier est entièrement simulé et que certains comportements sont
|
||||
adaptés.
|
||||
@ -84,15 +188,15 @@ adaptés.
|
||||
### Consultation de l'état
|
||||
|
||||
En affichant le contenu du dossier `virli`, nous pouvions constater que
|
||||
celui-ci contenait déjà un certain nombre de fichiers. Certain d'entre-eux sont
|
||||
en lecture seule et permettent de lire des statistiques instantanées sur le
|
||||
groupe ; tandis que d'autres sont des propriétés que nous pouvons modifier.
|
||||
celui-ci contenait déjà un certain nombre de fichiers. Certains d'entre-eux
|
||||
sont en lecture seule et permettent de lire des statistiques instantanées sur
|
||||
le groupe ; tandis que d'autres sont des propriétés que nous pouvons modifier.
|
||||
|
||||
Nous pouvons consulter l'état de gel du groupe en affichant le contenu du
|
||||
fichier\
|
||||
`/sys/fs/cgroup/freezer/virli/freezer.state`.
|
||||
`/sys/fs/cgroup/freezer/virli/freezer.state` ou `/sys/fs/cgroup/virli/cgroup.freeze`.
|
||||
|
||||
Pour plus d'information sur les différents fichiers présents dans ce *cgroup*,
|
||||
Pour plus d'informations sur les différents fichiers présents dans ce *cgroup*,
|
||||
consultez
|
||||
[la documentation associée](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/freezer-subsystem.html).
|
||||
|
||||
@ -113,7 +217,8 @@ calcul à notre shell et ses fils :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
echo FROZEN > /sys/fs/cgroup/freezer/virli/freezer.state
|
||||
echo FROZEN > /sys/fs/cgroup/freezer/virli/freezer.state # v1
|
||||
echo 1 > /sys/fs/cgroup/virli/cgroup.freeze # v2
|
||||
```
|
||||
</div>
|
||||
|
||||
@ -122,57 +227,30 @@ l'exécution :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
echo THAWED > /sys/fs/cgroup/freezer/virli/freezer.state
|
||||
echo THAWED > /sys/fs/cgroup/freezer/virli/freezer.state # v1
|
||||
echo 0 > /sys/fs/cgroup/virli/cgroup.freeze # v2
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
## Exercice : script de monitoring
|
||||
### Exercice : script de monitoring {- #script-monitoring}
|
||||
|
||||
À nous maintenant de concevoir un script qui va enregistrer vers une base de
|
||||
données des statistiques issues des *cgroup*s.
|
||||
|
||||
|
||||
### Rappel d'InfluxDB
|
||||
|
||||
Commençons par lancer le conteneur Docker d'InfluxDB (pour éviter de
|
||||
l'installer sur notre machine) :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
docker container run --name mytsdb -d -p 8086:8086 influxdb
|
||||
```
|
||||
</div>
|
||||
|
||||
Il nous faut ensuite créer une base de données pour y stocker nos
|
||||
métriques. Voici comment on s'était débrouillé dans un précédent TP pour
|
||||
interagir avec InfluxDB :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
docker container exec -i mytsdb influx <<EOF
|
||||
CREATE DATABASE metrics;
|
||||
SHOW DATABASES;
|
||||
EOF
|
||||
```
|
||||
</div>
|
||||
|
||||
Vérifiez que la base de données `metrics` a bien été créée.
|
||||
|
||||
|
||||
### Monitoring instantané vers la console
|
||||
données des statistiques issues des *cgroup*s, tel `telegraf`.
|
||||
|
||||
Dans un premier temps, commençons par afficher dans la console, la quantité de
|
||||
mémoire utilisée par le groupe monitoré.
|
||||
|
||||
::::: {.code}
|
||||
Vous pouvez utiliser un programme comme
|
||||
[`memhog`](https://virli.nemunai.re/memhog.c) pour remplir rapidement votre
|
||||
mémoire.
|
||||
:::::
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh# mkdir /sys/fs/cgroup...
|
||||
42sh$ echo $$ | sudo tee /sys/fs/cgroup.../tasks
|
||||
42sh$ echo $$ | sudo tee /sys/fs/cgroup.../cgroup.procs
|
||||
42sh# ./monitor group_name memhog 500
|
||||
~~~ 13595 ~~~ Current memory usage: 75194368/550502400 (13%)
|
||||
~~~ 13595 ~~~ Current memory usage: 150290432/550502400 (27%)
|
||||
@ -185,79 +263,26 @@ mémoire.
|
||||
```
|
||||
</div>
|
||||
|
||||
::::: {.warning}
|
||||
Si vous n'avez pas le *cgroup* *memory*, il est possible qu'il ne soit pas
|
||||
activé par défaut par votre système. Si vous êtes dans ce cas, essayez
|
||||
d'ajouter `cgroup_enable=memory` à la ligne de commande de votre noyau.
|
||||
:::::
|
||||
|
||||
|
||||
### Monitoring vers InfluxDB
|
||||
### Fixer des limites {#Fixer-des-limites}
|
||||
|
||||
Maintenant, envoyons nos données vers la base
|
||||
<https://docs.influxdata.com/influxdb/v1.6/guides/writing_data/> :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
curl -i -XPOST 'http://localhost:8086/write?db=metrics' --data-binary \
|
||||
"$my_cgroup_name memory.usage_in_bytes=$(cat .../my_cgroup_name/memory.usage_in_bytes)"
|
||||
```
|
||||
</div>
|
||||
|
||||
Pour vérifier que les données ont bien été ajoutées, nous pouvons effectuer la
|
||||
requête suivante dans notre client `influx` :
|
||||
|
||||
<div lang="en-US">
|
||||
```sql
|
||||
SELECT * from "$my_cgroup_name";
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
### Monitorer davantage de données
|
||||
|
||||
Liste non exhaustive de données à monitorer :
|
||||
|
||||
* Nombre d'IOs effectué ;
|
||||
* nombre d'octets lu/écrit sur les disques ;
|
||||
* temps de calcul utilisé ;
|
||||
* trafic réseau généré ;
|
||||
* ...
|
||||
|
||||
Tous les cgroups existants dans le dernier noyau publié ont leur documentation
|
||||
accessible ici :
|
||||
<https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v1/index.html>
|
||||
|
||||
|
||||
### Permettre à l'utilisateur de monitorer des processus
|
||||
|
||||
Maintenant, séparons notre script en deux parties afin qu'un utilisateur normal
|
||||
(non-root) puisse utiliser la partie monitoring de notre script.
|
||||
|
||||
Un premier script doit s'occuper de créer le(s) *cgroup*s et lui attribuer les
|
||||
bons droits, tandis que le deuxième va effectuer le monitoring, sans privilèges
|
||||
particuliers.
|
||||
|
||||
#### Exemple
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ sudo ./monitor_init my_cgroup_name
|
||||
42sh$ ./monitor my_cgroup_name memhog 500
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
## Fixer des limites
|
||||
|
||||
Au delà de la simple consultation, les *cgroup*s peuvent servir à limiter la
|
||||
quantité de ressources mise à disposition à un groupe de processus.
|
||||
Au-delà de la simple consultation, les *cgroup*s peuvent servir à limiter la
|
||||
quantité de ressources mises à disposition à un groupe de processus.
|
||||
|
||||
Pour définir une limite, nous allons écrire la valeur dans le fichier
|
||||
correspondant à une valeur limite, comme par exemple
|
||||
`memory.max_usage_in_bytes`, qui limite le nombre d'octets que notre groupe de
|
||||
processus va pouvoir allouer au maximum :
|
||||
`memory.max_usage_in_bytes`/`memory.max`, qui limite le nombre d'octets que
|
||||
notre groupe de processus va pouvoir allouer au maximum :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
# cgroup v1
|
||||
42sh$ cat /sys/fs/cgroup/memory/virli/memory.max_usage_in_bytes
|
||||
0
|
||||
# 0 = Aucune limite
|
||||
@ -268,21 +293,26 @@ processus va pouvoir allouer au maximum :
|
||||
```
|
||||
</div>
|
||||
|
||||
Chaque *cgroup*s défini de nombreux indicateurs et possède de nombreux
|
||||
<div lang="en-US">
|
||||
```
|
||||
# cgroup v2
|
||||
42sh$ cat /sys/fs/cgroup/virli/memory.max
|
||||
max
|
||||
# max = Aucune limite
|
||||
42sh$ echo 4M > /sys/fs/cgroup/virli/memory.max
|
||||
# Maintenant, la limite est à 4MB, vérifions...
|
||||
42sh$ cat /sys/fs/cgroup/virli/memory.max
|
||||
4194304
|
||||
```
|
||||
</div>
|
||||
|
||||
Chaque *cgroup*s définit de nombreux indicateurs et possède de nombreux
|
||||
limiteurs, n'hésitez pas à consulter la documentation associée à chaque
|
||||
*cgroup*.
|
||||
|
||||
|
||||
## Pour aller plus loin {-}
|
||||
### Pour aller plus loin {-}
|
||||
|
||||
Pour tout connaître en détails, [la série d'articles de Neil Brown sur les
|
||||
Control groups](https://lwn.net/Articles/604609/) est excellente !
|
||||
|
||||
Depuis les noyaux 4.5, il est possible d'utiliser la nouvelle version du
|
||||
pseudo système de fichiers des *CGroup*s. Le principal changement vient du
|
||||
regroupement au sein d'une seule hiérarchie des différents *CGroup*s que l'on
|
||||
avait dans la v1. Davantage d'informations sont disponibles :
|
||||
|
||||
* [Understanding the new control groups API](https://lwn.net/Articles/679786/)
|
||||
;
|
||||
* [Kernel Document about Control Group v2](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html).
|
||||
Control groups](https://lwn.net/Articles/604609/) est excellente ! Plus [cet
|
||||
article sur la version 2](https://lwn.net/Articles/679786/).
|
||||
|
28
tutorial/3/chroot-ex-escape.md
Normal file
28
tutorial/3/chroot-ex-escape.md
Normal file
@ -0,0 +1,28 @@
|
||||
## Exercice (SRS seulement) {-}
|
||||
|
||||
Écrivons maintenant un programme dont le seul but est de s'échapper du `chroot` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
make escape
|
||||
echo bar > ../foo
|
||||
chroot .
|
||||
```
|
||||
</div>
|
||||
|
||||
Dans le nouvel environnement, vous ne devriez pas pouvoir faire :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
cat ../foo
|
||||
```
|
||||
</div>
|
||||
|
||||
Mais une fois votre programme `escape` exécuté, vous devriez pouvoir !
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
(chroot) 42sh# ./escape
|
||||
bash# cat /path/to/foo
|
||||
```
|
||||
</div>
|
12
tutorial/3/chroot-intro.md
Normal file
12
tutorial/3/chroot-intro.md
Normal file
@ -0,0 +1,12 @@
|
||||
\newpage
|
||||
|
||||
En route vers la contenerisation
|
||||
================================
|
||||
|
||||
Nous avons vu un certain nombre de fonctionnalités offertes par le noyau Linux
|
||||
pour limiter ou autoriser ou contraindre différents usages des ressources de
|
||||
notre machine.
|
||||
|
||||
Il est temps maintenant de commencer à parler d'isolation, mais ... cela fait
|
||||
déjà beaucoup à digérer pour aujourd'hui, alors on va se contenter de parler
|
||||
d'un mécanisme que vous connaissez sans doute déjà.
|
@ -1,18 +1,15 @@
|
||||
\newpage
|
||||
|
||||
L'isolation ... du pauvre
|
||||
=========================
|
||||
L'isolation ... à 1 € ?
|
||||
-----------------------
|
||||
|
||||
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.
|
||||
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.\
|
||||
|
||||
|
||||
## Mise en place de l'environnement
|
||||
|
||||
Pour se créer un environnement afin de changer notre racine, il va falloir
|
||||
commencer par créer le dossier de notre nouvelle racine :
|
||||
commencer par créer le dossier de notre nouvelle racine, peu importe où dans
|
||||
l'arborescence :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
@ -20,13 +17,21 @@ 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
|
||||
*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\ :
|
||||
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
|
||||
@ -35,8 +40,11 @@ chroot newroot /busybox ash
|
||||
```
|
||||
</div>
|
||||
|
||||
Jusque là ... ça fonctionne, rien de surprenant ! Mais qu'en est-il pour
|
||||
`bash` :
|
||||
Nous voici donc maintenant dans un nouveau shell (il s'agit d'`ash`, le shell
|
||||
de `busybox`).
|
||||
|
||||
Jusque là ... ça fonctionne, rien de surprenant ! Mais qu'en est-il pour
|
||||
`bash` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
@ -46,10 +54,10 @@ chroot: failed to run command ‘bash’: No such file or directory
|
||||
```
|
||||
</div>
|
||||
|
||||
De quel fichier est-il question ici ?
|
||||
De quel fichier est-il question ici ?
|
||||
|
||||
|
||||
### `debootstrap`
|
||||
### `debootstrap`, `pacstrap`
|
||||
|
||||
`debootstrap` est le programme utilisé par l'installeur des distributions
|
||||
Debian et ses dérivées. Il permet d'installer dans un dossier (en général, ce
|
||||
@ -58,54 +66,76 @@ l'utilisateur lors de l'installation) le système de base.
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
debootstrap buster newroot/ http://httpredir.debian.org/debian/
|
||||
debootstrap bullseye newroot/ http://httpredir.debian.org/debian/
|
||||
```
|
||||
</div>
|
||||
|
||||
`pacstrap` est le programme équivalent pour Archlinux.
|
||||
|
||||
|
||||
### *stage3*
|
||||
|
||||
Les distributions *à l'ancienne* proposent encore de télécharger leur système
|
||||
de base sous forme de tarball\ :
|
||||
`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ées.
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
wget http://gentoo.mirrors.ovh.net/gentoo-distfiles/releases/amd64/autobuilds/current-stage3-amd64/stage3-amd64-20201104T214503Z.tar.xz
|
||||
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>
|
||||
|
||||
|
||||
### Archives *stage3*, *miniroot*
|
||||
|
||||
Les distributions *à l'ancienne* proposent de télécharger leur système de base
|
||||
sous forme de tarball :
|
||||
|
||||
|
||||
#### Gentoo\
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
wget http://gentoo.mirrors.ovh.net/gentoo-distfiles/releases/amd64/autobuilds/current-stage3-amd64/stage3-amd64-20210630T214504Z.tar.xz
|
||||
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 300 MB.
|
||||
environnement qui tient dans 200 MB.
|
||||
:::::
|
||||
|
||||
|
||||
## Exercice {-}
|
||||
|
||||
Écrivons maintenant un programme dont le seul but est de s'échapper du `chroot` :
|
||||
Comme pour les autres distributions vues précédemment, nous pouvons entrer dans
|
||||
notre nouvelle racine comme ceci :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
make escape
|
||||
echo bar > ../foo
|
||||
chroot .
|
||||
chroot newroot/ bash
|
||||
```
|
||||
</div>
|
||||
|
||||
Dans le nouvel environnement, vous ne devriez pas pouvoir faire :
|
||||
|
||||
#### Alpine\
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
cat ../foo
|
||||
wget https://dl-cdn.alpinelinux.org/alpine/v3.14/releases/x86_64/alpine-minirootfs-3.14.2-x86_64.tar.gz
|
||||
tar xpf alpine-minirootfs-*.tar.xz -C newroot/
|
||||
```
|
||||
</div>
|
||||
|
||||
Mais une fois votre programme `escape` exécuté, vous devriez pouvoir !
|
||||
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">
|
||||
```
|
||||
(chroot) 42sh# ./escape
|
||||
bash# cat /path/to/foo
|
||||
```bash
|
||||
chroot newroot/ ash
|
||||
```
|
||||
</div>
|
||||
|
@ -1,13 +1,12 @@
|
||||
\newpage
|
||||
|
||||
Prérequis
|
||||
=========
|
||||
---------
|
||||
|
||||
## Noyau Linux
|
||||
### Noyau Linux
|
||||
|
||||
Ce TP requiert un noyau Linux, dans sa version 3.8 au minimum. Il doit de plus
|
||||
être compilé avec les options suivantes (lorsqu'elles sont disponibles pour
|
||||
votre version) :
|
||||
Pour pouvoir suivre les exemples et faire les exercices qui suivent, vous aurez
|
||||
besoin d'un noyau Linux récent (une version 5.x sera très bien). Il doit de
|
||||
plus être compilé avec les options suivantes (lorsqu'elles sont disponibles
|
||||
pour votre version) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
@ -31,7 +30,7 @@ General setup --->
|
||||
</div>
|
||||
|
||||
|
||||
### Vérification via `menuconfig`
|
||||
#### Vérification via `menuconfig`\
|
||||
|
||||
L'arbre ci-dessous correspond aux options qui seront *built-in* (signalées par
|
||||
une `*`) ou installées en tant que module (signalées par un `M`). En effet,
|
||||
@ -42,7 +41,7 @@ Pour parcourir l'arbre des options du noyau, il est nécessaire d'avoir les
|
||||
sources de celui-ci. Les dernières versions stables et encore maintenues sont
|
||||
disponibles sur la page d'accueil de <https://kernel.org>.
|
||||
|
||||
Dans les sources, on affiche la liste des options avec la commande :
|
||||
Dans les sources, on affiche la liste des options avec la commande :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
@ -51,7 +50,7 @@ make menuconfig
|
||||
</div>
|
||||
|
||||
|
||||
### Vérification via `/boot/config-xxx`
|
||||
#### Vérification via `/boot/config-xxx`\
|
||||
|
||||
Les distributions basées sur Debian ont pour habitude de placer le fichier de
|
||||
configuration ayant servi à compiler le noyau et ses modules dans le dossier
|
||||
@ -60,7 +59,7 @@ fichiers initial (`initramfs-xxx`) et des symboles de débogage
|
||||
`System.map-xxx`.
|
||||
|
||||
Ce fichier répertorie toutes les options qui ont été activées. Par rapport à
|
||||
l'arbre présenté ci-dessus, vous devriez trouver :
|
||||
l'arbre présenté ci-dessus, vous devriez trouver :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
@ -81,7 +80,7 @@ CONFIG_CGROUP_NET_CLASSID=y
|
||||
</div>
|
||||
|
||||
|
||||
### Vérification via `/proc/config.gz`
|
||||
#### Vérification via `/proc/config.gz`\
|
||||
|
||||
Dans la plupart des autres distributions, la configuration est accessible à
|
||||
travers le fichier `/proc/config.gz`. Comme vous ne pouvez pas écrire dans
|
||||
@ -91,12 +90,12 @@ Vous devez retrouver les mêmes options que celles de la section précédente.
|
||||
|
||||
|
||||
|
||||
## Présence des en-têtes
|
||||
### Présence des en-têtes
|
||||
|
||||
Si vous utilisez un noyau standard fourni par votre distribution, les options
|
||||
requises seront a priori déjà sélectionnées et vous n'aurez donc pas à compiler
|
||||
votre propre noyau. Néanmoins, durant ce TP, nous allons nous interfacer avec
|
||||
le noyau, il est donc nécessaire d'avoir les en-têtes de votre noyau.
|
||||
votre propre noyau. Néanmoins, nous allons nous interfacer avec le noyau, il
|
||||
est donc nécessaire d'avoir les en-têtes de votre noyau.
|
||||
|
||||
Sous Debian, vous pouvez les installer via le paquet au nom semblable à
|
||||
`linux-headers`. Le paquet porte le même nom sous Arch Linux et ses dérivés.
|
||||
|
12
tutorial/3/intro.md
Normal file
12
tutorial/3/intro.md
Normal file
@ -0,0 +1,12 @@
|
||||
\newpage
|
||||
|
||||
Statistiques et contrôle des processus
|
||||
======================================
|
||||
|
||||
Maintenant que nous avons pu voir en détail comment utiliser Docker, nous
|
||||
allons tâcher d'apprendre comment il fonctionne en nous penchant sur un certain
|
||||
nombre de fonctionnalités de Linux.
|
||||
|
||||
Dans un premier temps, nous allons aborder la manière dont le noyau Linux
|
||||
permet de contrôler les processus : que ce soit en collectant des informations
|
||||
sur eux ou en imposant certaines restrictions.
|
@ -15,7 +15,7 @@ mémoire est donc utilisée de manière plus efficace.
|
||||
<https://www.kernel.org/doc/html/latest/vm/overcommit-accounting.html>.
|
||||
|
||||
Mais évidemment, cela peut donner lieu à des situations où le noyau n'est plus
|
||||
en mesure de trouver de bloc physiquement disponible, alors qu'ils avaient
|
||||
en mesure de trouver de blocs physiquement disponibles, alors qu'ils avaient
|
||||
effectivement été alloués au processus. Pour autant, ce n'est pas une raison
|
||||
pour tuer ce processus, car il est peut-être vital pour le système (peut-être
|
||||
est-ce `init` qui est en train de gérer le lancement d'un nouveau daemon). On
|
||||
@ -31,18 +31,19 @@ l'*Out-Of-Memory killer*.
|
||||
Selon un algorithme dont on raconte qu'il ne serait pas basé entièrement sur
|
||||
l'aléatoire[^oom-algo], un processus est tiré au sort (plus un processus occupe
|
||||
de mémoire et plus il a de chance d'être tiré au sort) par l'OOM killer. Le
|
||||
sort qui lui est réservé est tout simplement une mort brutale. Pour permettre
|
||||
sort qui lui est réservé est tout simplement une mort brutale, pour permettre
|
||||
au système de disposer à nouveau de mémoire disponible. Si cela n'est pas
|
||||
suffisant, un ou plusieurs autres processus peuvent être tués à tour de rôle,
|
||||
jusqu'à ce que le système retrouve sa sérénité.
|
||||
|
||||
[^oom-algo]: <https://linux-mm.org/OOM_Killer>
|
||||
|
||||
## Esquiver l'OOM killer
|
||||
|
||||
Au sein d'un *cgroup* *memory*, le fichier `memory.oom_control` peut être
|
||||
utilisé afin de recevoir une notification du noyau avant que l'OOM-killer
|
||||
ne s'attaque à un processus de ce groupe.
|
||||
## Esquiver l'OOM killer ?
|
||||
|
||||
Au sein d'un *cgroup* *memory*, les fichiers `memory.oom_control` (v1) ou
|
||||
`memory.events` (v2) peuvent être utilisé afin de recevoir une notification du
|
||||
noyau avant que l'OOM-killer ne s'attaque à un processus de ce groupe.
|
||||
|
||||
Grâce à cette notification, il est possible de figer le processus pour
|
||||
l'envoyer sur une autre machine. Et ainsi libérer la mémoire avant que l'OOM
|
||||
@ -50,3 +51,11 @@ killer ne passe.
|
||||
|
||||
Jetez un œil à [cet article parru sur LWN](https://lwn.net/Articles/590960/) à
|
||||
ce sujet.
|
||||
|
||||
|
||||
## À vous de jouer {-}
|
||||
|
||||
Continuons l'exercice précédent où nous avions [fixé les
|
||||
limites](#Fixer-des-limites) de mémoire que pouvez réserver les processus de
|
||||
notre groupe. Que se passe-t-il alors si `memhog` dépasse la quantité de
|
||||
mémoire autorisée dans le `cgroup` ?
|
||||
|
@ -1,7 +1,25 @@
|
||||
\newpage
|
||||
|
||||
Rendu
|
||||
=====
|
||||
|
||||
Est attendu d'ici le TP suivant :
|
||||
|
||||
- le rendu des exercice de ce TP ;
|
||||
- vos réponses à [l'évaluation du cours](https://virli.nemunai.re/quiz/14).
|
||||
|
||||
Pour les GISTRE (et en bonus pour les SRS), [un
|
||||
projet](https://virli.nemunai.re/project-2.pdf) est à rendre pour le 13
|
||||
novembre. Consultez les modalités de rendu sur le sujet directement.
|
||||
|
||||
|
||||
## Modalité de rendu
|
||||
|
||||
Un service automatique s'occupe de réceptionner vos rendus, de faire les
|
||||
vérifications nécessaires et de vous envoyer un accusé de réception (ou de
|
||||
En tant que personnes sensibilisées à la sécurité des échanges électroniques,
|
||||
vous devrez m'envoyer vos rendus signés avec votre clef PGP.
|
||||
|
||||
Un service automatique s'occupe de réceptionner vos rendus, de faire des
|
||||
vérifications élémentaires et de vous envoyer un accusé de réception (ou de
|
||||
rejet).
|
||||
|
||||
Ce service écoute sur l'adresse <virli@nemunai.re>, c'est donc à cette adresse
|
||||
@ -9,8 +27,10 @@ et exclusivement à celle-ci que vous devez envoyer vos rendus. Tout rendu
|
||||
envoyé à une autre adresse et/ou non signé et/ou reçu après la correction ne
|
||||
sera pas pris en compte.
|
||||
|
||||
Par ailleurs, n'oubliez pas de répondre à
|
||||
[l'évaluation du cours](https://virli.nemunai.re/quiz/6).
|
||||
Afin d'orienter correctement votre rendu, ajoutez une balise `[TP3]` au sujet
|
||||
de votre courriel. N'hésitez pas à indiquer dans le corps du message votre
|
||||
ressenti et vos difficultés ou bien alors écrivez votre meilleure histoire
|
||||
drôle si vous n'avez rien à dire.
|
||||
|
||||
|
||||
## Tarball
|
||||
@ -25,15 +45,13 @@ pour chaque exercice) :
|
||||
<div lang="en-US">
|
||||
```
|
||||
login_x-TP3/
|
||||
login_x-TP3/escape.c
|
||||
login_x-TP3/escape.c # SRS
|
||||
login_x-TP3/procinfo.sh
|
||||
login_x-TP3/suspend_schedule.sh
|
||||
login_x-TP3/view_caps.c
|
||||
login_x-TP3/monitor.sh
|
||||
login_x-TP3/monitor_init.sh
|
||||
login_x-TP3/telegraf.sh # SRS
|
||||
login_x-TP3/telegraf_init.sh # SRS
|
||||
login_x-TP3/syscall_filter.c
|
||||
```
|
||||
</div>
|
||||
|
||||
Les premières étapes du projet ne sont pas à rendre et feront l'objet
|
||||
d'un rendu à part.
|
||||
|
@ -1,14 +1,14 @@
|
||||
\newpage
|
||||
|
||||
Pseudos systèmes de fichiers
|
||||
============================
|
||||
----------------------------
|
||||
|
||||
## Rappels sur les points de montage
|
||||
### Rappels sur les points de montage
|
||||
|
||||
Les systèmes Unix définissent le système de fichiers comme étant un arbre
|
||||
unique partant d'une racine[^FHS] et où l'on peut placer au sein de son arborescence
|
||||
des points de montage. Ainsi, l'utilisateur définit généralement deux points de
|
||||
montage :
|
||||
montage :
|
||||
|
||||
[^FHS]: Consultez
|
||||
<https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard> pour
|
||||
@ -26,27 +26,27 @@ et les fichiers des utilisateurs sont sur la troisième partition du premier
|
||||
disque.
|
||||
|
||||
|
||||
## Présentation des pseudos systèmes de fichiers
|
||||
### Présentation des pseudos systèmes de fichiers
|
||||
|
||||
D'autres points de montage sont utilisés par le système : `/dev`, `/proc`,
|
||||
`/tmp`, ... Ces points de montage vont, la plupart du temps, être montés par le
|
||||
D'autres points de montage sont utilisés par le système : `/dev`, `/proc`,
|
||||
`/tmp`, ... Ces points de montage vont, la plupart du temps, être montés par le
|
||||
programme d'initialisation en utilisant des systèmes de fichiers virtuels, mis
|
||||
à disposition par le noyau.
|
||||
|
||||
Ces systèmes sont virtuels, car ils ne correspondent à aucune partition d'aucun
|
||||
disque : l'arborescence est créée de toute pièce par le noyau pour trier les
|
||||
disque : l'arborescence est créée de toute pièce par le noyau pour trier les
|
||||
informations mises à disposition, mais il n'est pas toujours possible d'y
|
||||
apporter des modifications.
|
||||
|
||||
Linux emploie de nombreux systèmes de fichiers virtuels :
|
||||
Linux emploie de nombreux systèmes de fichiers virtuels :
|
||||
|
||||
- `/proc` : contient, principalement, la liste des processus (`top` et ses
|
||||
- `/proc` : contient, principalement, la liste des processus (`top` et ses
|
||||
dérivés se contentent de lire les fichiers de ce point de montage) ;
|
||||
- `/proc/sys` : contient la configuration du noyau ;
|
||||
- `/sys` : contient des informations à propos du matériel (utilisées notamment
|
||||
- `/proc/sys` : contient la configuration du noyau ;
|
||||
- `/sys` : contient des informations à propos du matériel (utilisées notamment
|
||||
par `udev` pour peupler `/dev`) et des périphériques (taille des tampons,
|
||||
clignottement des DELs, ...) ;
|
||||
- `/sys/firmware/efi/efivars` : pour accéder et modifier les variables de
|
||||
clignottement des DELs, ...) ;
|
||||
- `/sys/firmware/efi/efivars` : pour accéder et modifier les variables de
|
||||
l'UEFI ;
|
||||
- ...
|
||||
|
||||
@ -57,9 +57,9 @@ exemple, pour modifier les paramètres du noyau, on passe par le fichier
|
||||
`/etc/sysctl.conf` et du programme `sysctl`.
|
||||
|
||||
|
||||
### Consultation et modification
|
||||
#### Consultation et modification\
|
||||
|
||||
La consultation d'un élément se fait généralement à l'aide d'un simple `cat` :
|
||||
La consultation d'un élément se fait généralement à l'aide d'un simple `cat` :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
@ -68,7 +68,7 @@ freeze mem
|
||||
```
|
||||
</div>
|
||||
|
||||
La modification d'un élément se fait avec `echo`, comme ceci :
|
||||
La modification d'un élément se fait avec `echo`, comme ceci :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
@ -76,15 +76,15 @@ La modification d'un élément se fait avec `echo`, comme ceci :
|
||||
```
|
||||
</div>
|
||||
|
||||
Vous devriez constater l'effet de cette commande sans plus attendre !
|
||||
Vous devriez constater l'effet de cette commande sans plus attendre !
|
||||
|
||||
|
||||
## Exercices
|
||||
### Exercices
|
||||
|
||||
### `procinfo`
|
||||
#### `procinfo`\
|
||||
|
||||
Explorons le pseudo système de fichiers `/proc` pour écrire un script qui va
|
||||
afficher des informations sur un processus donné :
|
||||
afficher des informations sur un processus donné :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
@ -125,17 +125,17 @@ uts:[4026531838]
|
||||
</div>
|
||||
|
||||
|
||||
### `batinfo.sh`, `cpuinfo.sh`
|
||||
#### `batinfo.sh`, `cpuinfo.sh`\
|
||||
|
||||
Explorons le pseudo système de fichiers `/sys` pour écrire un script
|
||||
qui va, en fonction de ce que vous avez de disponible :
|
||||
qui va, en fonction de ce que vous avez de disponible :
|
||||
|
||||
* nous afficher des statistiques sur notre batterie ;
|
||||
* nous afficher des statistiques la fréquence de notre CPU.
|
||||
* afficher des statistiques sur notre batterie ;
|
||||
* afficher des statistiques la fréquence du CPU.
|
||||
|
||||
#### `batinfo.sh`
|
||||
##### `batinfo.sh`\
|
||||
|
||||
Voici un exemple d'utilisation :
|
||||
Voici un exemple d'utilisation :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
@ -158,13 +158,13 @@ Remaining time: N/A
|
||||
```
|
||||
</div>
|
||||
|
||||
Pour les détails sur l'organisation de ce dossier, regardez :
|
||||
Pour les détails sur l'organisation de ce dossier, regardez :
|
||||
<https://www.kernel.org/doc/Documentation/power/power_supply_class.txt>.
|
||||
|
||||
|
||||
#### `cpuinfo.sh`
|
||||
##### `cpuinfo.sh`\
|
||||
|
||||
Voici un exemple d'utilisation :
|
||||
Voici un exemple d'utilisation :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
@ -185,33 +185,33 @@ Thermal throttle count: 0
|
||||
```
|
||||
</div>
|
||||
|
||||
N'hésitez pas à rajouter toute sorte d'information intéressantes !
|
||||
N'hésitez pas à rajouter toute sorte d'information intéressantes !
|
||||
|
||||
|
||||
### `rev_kdb_leds.sh`, `suspend_schedule.sh`
|
||||
#### `rev_kdb_leds.sh`, `suspend_schedule.sh`\
|
||||
|
||||
Maintenant que vous savez lire des informations dans `/sys`, tentons d'aller
|
||||
modifier le comportement de notre système. Au choix, réaliser l'un des scripts
|
||||
suivant, en fonction du matériel dont vous disposez :
|
||||
modifier le comportement de notre système. Au choix, réalisez l'un des scripts
|
||||
suivants, en fonction du matériel dont vous disposez :
|
||||
|
||||
* inverser l'état des diodes de notre clavier ;
|
||||
* mettre en veille votre machine, en ayant programmé une heure de réveil.
|
||||
|
||||
#### `rev_kdb_leds.sh`
|
||||
##### `rev_kdb_leds.sh`\
|
||||
|
||||
Si vous avez :
|
||||
Si vous avez :
|
||||
|
||||
* numlock On,
|
||||
* capslock Off,
|
||||
* scrolllock Off ;
|
||||
|
||||
Après avoir exécuté le script, nous devrions avoir :
|
||||
Après avoir exécuté le script, nous devrions avoir :
|
||||
|
||||
* numlock Off,
|
||||
* capslock On,
|
||||
* scrolllock On.
|
||||
|
||||
Voici un exemple d'utilisation :
|
||||
Voici un exemple d'utilisation :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
@ -222,7 +222,7 @@ Voici un exemple d'utilisation :
|
||||
`input20` correspond à l'identifiant de votre clavier, sous
|
||||
`/sys/class/input/`.
|
||||
|
||||
#### `suspend_schedule.sh`
|
||||
##### `suspend_schedule.sh`\
|
||||
|
||||
Votre script prendra en argument l'heure à laquelle votre machine doit être
|
||||
réveillée, avant de la mettre effectivement en veille.
|
||||
@ -232,7 +232,7 @@ système de fichiers `/sys`. Il n'est pas question de faire appel à un autre
|
||||
programme (vous pourriez cependant avoir besoin de `date(1)` pour faire les
|
||||
calculs horaires).
|
||||
|
||||
Voici un exemple d'utilisation :
|
||||
Voici un exemple d'utilisation :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
@ -242,11 +242,15 @@ Voici un exemple d'utilisation :
|
||||
</div>
|
||||
|
||||
Vous aurez besoin de définir une alarme au niveau de votre RTC, via le
|
||||
fichier : `/sys/class/rtc/rtcX/wakealarm`.
|
||||
fichier : `/sys/class/rtc/rtcX/wakealarm`.
|
||||
|
||||
::::: {.warning}
|
||||
Attention au fuseau horaire utilisé par votre RTC, si votre système principal
|
||||
est Windows, elle utilisera sans doute le fuseau horaire courant. Sinon, ce
|
||||
sera UTC.
|
||||
:::::
|
||||
|
||||
Un article très complet sur le sujet est disponible ici :
|
||||
::::: {.more}
|
||||
Un article très complet sur le sujet est disponible ici :
|
||||
<https://www.linux.com/tutorials/wake-linux-rtc-alarm-clock/>
|
||||
:::::
|
||||
|
@ -12,7 +12,7 @@ particulier peut être renvoyé au programme.
|
||||
Depuis la version 3.17 du noyau, l'appel système `seccomp(2)` permet de faire
|
||||
entrer le processus courant dans ce mode. En effet, c'est le processus lui-même
|
||||
qui déclare au noyau qu'il peut désormais se contenter d'une liste réduite
|
||||
d'appel système ; à l'inverse des politiques de sécurité comme SELinux ou
|
||||
d'appels système ; à l'inverse des politiques de sécurité comme SELinux ou
|
||||
AppArmor, qui encapsulent les programmes pour toute la durée de leur exécution.
|
||||
|
||||
*Seccomp* est particulièrement utile lorsqu'un processus a terminé son
|
||||
@ -61,7 +61,7 @@ exécutée en cas de faute.
|
||||
Notons que les processus fils issus (`fork(2)` ou `clone(2)`) d'un processus
|
||||
auquel est appliqué un filtre `seccomp`, héritent également de ce filtre.
|
||||
|
||||
La construction de ce filtre est faite de manière programatique, via
|
||||
La construction de ce filtre est faite de manière programmatique, via
|
||||
des règles BPF (`Berkeley Packet Filter`). On passe ensuite ce filtre BPF en
|
||||
argument de l'appel système :
|
||||
|
||||
|
@ -12,7 +12,7 @@ abstract: |
|
||||
\vspace{1em}
|
||||
|
||||
Certains éléments de ce TP sont à rendre à <virli@nemunai.re> au
|
||||
plus tard le jeudi 12 novembre 2020 à 12 h 42. Consultez la
|
||||
plus tard le mercredi 6 octobre 2020 à 23 h 42. Consultez la
|
||||
dernière section de chaque partie pour plus d'informations sur les
|
||||
éléments à rendre.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user