tuto: Prepare for 2022
This commit is contained in:
parent
37f0ba4b3d
commit
af860b40a0
40 changed files with 246 additions and 1974 deletions
|
@ -1,14 +1,6 @@
|
|||
include ../pandoc-opts.mk
|
||||
|
||||
SOURCES = tutorial.md \
|
||||
../devops/devops.md \
|
||||
../devops/what.md \
|
||||
../devops/tools.md \
|
||||
../devops/ci.md \
|
||||
../devops/publish-docker.md \
|
||||
../docker-internals/oci.md \
|
||||
../docker-internals/registry.md \
|
||||
rendu.md
|
||||
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
|
||||
|
||||
|
||||
all: tutorial.pdf
|
||||
|
|
202
tutorial/3/capabilities.md
Normal file
202
tutorial/3/capabilities.md
Normal file
|
@ -0,0 +1,202 @@
|
|||
\newpage
|
||||
|
||||
Les *capabilities*
|
||||
==================
|
||||
|
||||
## Présentation
|
||||
|
||||
Historiquement, dans la tradition UNIX, on distinguait deux catégories de
|
||||
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
|
||||
utilisateur n'est pas 0.
|
||||
|
||||
Lors des différents tests de permission fait par le noyau, les processus
|
||||
privilégiés outrepassaient ces tests, tandis que les autres devaient passer les
|
||||
tests de l'effective UID, effective GID, et autres groupes supplémentaires...
|
||||
|
||||
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 :
|
||||
|
||||
* `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) !
|
||||
|
||||
|
||||
### `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.
|
||||
|
||||
Pour permettre à tous les utilisateurs de pouvoir envoyer des ping, le
|
||||
programme est donc généralement *Setuid root*. Cela permet à n'importe quel
|
||||
utilisateur de prendre les droits du super-utilisateur, le temps de l'exécution
|
||||
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 à
|
||||
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
|
||||
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`.
|
||||
|
||||
|
||||
## 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 :
|
||||
|
||||
* *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
|
||||
propriétaire du fichier.
|
||||
|
||||
Par exemple, on peut définir un attribut sur un fichier comme cela :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh$ echo 'Hello World!' > toto
|
||||
42sh$ setfattr -n user.foo -v bar toto
|
||||
42sh$ getfattr -d toto
|
||||
# file: toto
|
||||
user.foo="bar"
|
||||
```
|
||||
</div>
|
||||
|
||||
Encore plus fort, vous pouvez utiliser 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$ cat toto
|
||||
Hello World!
|
||||
```
|
||||
</div>
|
||||
|
||||
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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh$ getfattr -d -m "^system" toto
|
||||
# file: toto
|
||||
system.posix_acl_access=0sgAAEAD/////AgAEOgDAEAA/////xAABAD////8=
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
### `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*.
|
||||
|
||||
Si votre distribution profite de ces attributs étendus, vous devriez obtenir :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh$ getfattr -d -m "^security" $(which ping)
|
||||
# file: bin/ping
|
||||
security.capability=0sAQAAAgAgAAAAAAAAAAAAAAAAAAA=
|
||||
```
|
||||
</div>
|
||||
|
||||
Ou, dans sa version plus lisible :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh$ getcap $(which ping)
|
||||
/bin/ping = cap_net_raw+ep
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
## Exercice : visualisateur de capabilities d'un processus {-}
|
||||
|
||||
Écrivons maintenant un programme permettant de voir les *capabilities*
|
||||
d'un processus :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ ./view_caps 1
|
||||
cap_user_header_t
|
||||
-----------------
|
||||
Version: 20080522
|
||||
PID: 1
|
||||
|
||||
cap_user_data_t
|
||||
---------------
|
||||
effective: 0x3fffffffff
|
||||
CAP_AUDIT_CONTROL
|
||||
CAP_AUDIT_READ
|
||||
[...]
|
||||
CAP_SYS_TIME
|
||||
CAP_SYS_TTY_CONFIG
|
||||
CAP_SYSLOG
|
||||
CAP_WAKE_ALARM
|
||||
permitted: 0x3fffffffff
|
||||
CAP_AUDIT_CONTROL
|
||||
CAP_AUDIT_READ
|
||||
[...]
|
||||
CAP_SYS_TIME
|
||||
CAP_SYS_TTY_CONFIG
|
||||
CAP_SYSLOG
|
||||
CAP_WAKE_ALARM
|
||||
inheritable: 0x0
|
||||
```
|
||||
</div>
|
||||
|
||||
Astuces : `capget(2)`, X-macros, ...
|
||||
|
||||
|
||||
## Pour aller plus loin {-}
|
||||
|
||||
Je vous recommande la lecture des *man* suivants :
|
||||
|
||||
* `capabilities(7)` : énumérant tous les capabilities, leur utilisation, etc. ;
|
||||
* `xattrs(7)` : à propos des attributs étendus.
|
||||
|
||||
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)
|
||||
* [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`.
|
287
tutorial/3/cgroups.md
Normal file
287
tutorial/3/cgroups.md
Normal file
|
@ -0,0 +1,287 @@
|
|||
\newpage
|
||||
|
||||
Utiliser 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.
|
||||
|
||||
|
||||
## Premiers tests
|
||||
|
||||
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.
|
||||
|
||||
|
||||
### Montage du *cgroup*
|
||||
|
||||
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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
mkdir /sys/fs/cgroup/freezer/
|
||||
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.
|
||||
|
||||
|
||||
### Création d'un nouveau groupe
|
||||
|
||||
La première étape dans l'utilisation d'un *cgroup* est de créer un groupe.
|
||||
|
||||
Pour ce faire, il suffit de créer un nouveau dossier dans un groupe existant,
|
||||
par exemple la racine :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
mkdir /sys/fs/cgroup/freezer/virli/
|
||||
ls /sys/fs/cgroup/freezer/virli/
|
||||
```
|
||||
</div>
|
||||
|
||||
Nous avons maintenant un nouveau groupe de processus `virli` dans le *cgroup*
|
||||
*Freezer*. Comme il s'agit d'une hiérarchie, le groupe `virli` hérite des
|
||||
propriétés de son (ses) père(s).
|
||||
|
||||
|
||||
### Rattachement de processus
|
||||
|
||||
Pour le moment, ce nouveau groupe ne contient aucune tâche.
|
||||
|
||||
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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
echo $PID > /sys/fs/cgroup/freezer/virli/tasks
|
||||
```
|
||||
</div>
|
||||
|
||||
Il faut ici remplacer `$PID` par le PID du shell que l'on a relevé juste avant.
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
|
||||
### 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.
|
||||
|
||||
Nous pouvons consulter l'état de gel du groupe en affichant le contenu du
|
||||
fichier\newline `/sys/fs/cgroup/freezer/virli/freezer.state`.
|
||||
|
||||
Pour plus d'information 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).
|
||||
|
||||
|
||||
### Changement d'état
|
||||
|
||||
Faisons exécuter à notre interpréteur une commande pour voir effectivement
|
||||
l'exécution s'arrêter. Si vous manquez d'inspiration, utilisez :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
for i in $(seq 9999); do echo -n $i; sleep .1; echo -n " - "; sleep .1; done
|
||||
```
|
||||
</div>
|
||||
|
||||
Maintenant, nous avons donné l'ordre au noyau de ne plus allouer de temps de
|
||||
calcul à notre shell et ses fils :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
echo FROZEN > /sys/fs/cgroup/freezer/virli/freezer.state
|
||||
```
|
||||
</div>
|
||||
|
||||
À cet instant, vous devriez voir votre compteur s'arrêter. Pour reprendre
|
||||
l'exécution :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
echo THAWED > /sys/fs/cgroup/freezer/virli/freezer.state
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
## Exercice : script de 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
|
||||
|
||||
Dans un premier temps, commençons par afficher dans la console, la quantité de
|
||||
mémoire utilisée par le groupe monitoré.
|
||||
|
||||
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# ./monitor group_name memhog 500
|
||||
~~~ 13595 ~~~ Current memory usage: 75194368/550502400 (13%)
|
||||
~~~ 13595 ~~~ Current memory usage: 150290432/550502400 (27%)
|
||||
~~~ 13595 ~~~ Current memory usage: 223690752/550502400 (40%)
|
||||
~~~ 13595 ~~~ Current memory usage: 296828928/550502400 (53%)
|
||||
~~~ 13595 ~~~ Current memory usage: 368001024/550502400 (66%)
|
||||
~~~ 13595 ~~~ Current memory usage: 438517760/550502400 (79%)
|
||||
~~~ 13595 ~~~ Current memory usage: 480329728/550502400 (87%)
|
||||
~~~ 13595 ~~~ Current memory usage: 155648/550502400 (0%)
|
||||
```
|
||||
</div>
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ cat /sys/fs/cgroup/memory/virli/memory.max_usage_in_bytes
|
||||
0
|
||||
# 0 = Aucune limite
|
||||
42sh$ echo 4M > /sys/fs/cgroup/memory/virli/memory.max_usage_in_bytes
|
||||
# Maintenant, la limite est à 4MB, vérifions...
|
||||
42sh$ cat /sys/fs/cgroup/memory/virli/memory.max_usage_in_bytes
|
||||
4194304
|
||||
```
|
||||
</div>
|
||||
|
||||
Chaque *cgroup*s défini 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 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).
|
46
tutorial/3/check.sh
Executable file
46
tutorial/3/check.sh
Executable file
|
@ -0,0 +1,46 @@
|
|||
#!/bin/sh
|
||||
|
||||
note_init() {
|
||||
NOTE=0
|
||||
echo -n $@
|
||||
}
|
||||
|
||||
note() {
|
||||
NOTE=$(($NOTE + $1))
|
||||
echo -n ,$@
|
||||
}
|
||||
|
||||
for LOGIN in $@
|
||||
do
|
||||
note_init $LOGIN
|
||||
|
||||
if [ -f "$LOGIN" ]; then
|
||||
QUESTIONSF="$LOGIN"
|
||||
else
|
||||
QUESTIONSF="$LOGIN/questions.txt"
|
||||
fi
|
||||
|
||||
# Questions
|
||||
|
||||
if grep -E -i "(grsec)" "${QUESTIONSF}" 2> /dev/null > /dev/null; then
|
||||
note 1
|
||||
else
|
||||
note 0
|
||||
fi
|
||||
|
||||
|
||||
if grep -E -i "(/proc/.*/oom_|score)" "${QUESTIONSF}" 2> /dev/null > /dev/null; then
|
||||
note 1
|
||||
else
|
||||
note 0
|
||||
fi
|
||||
|
||||
if grep -E -i "root" "${QUESTIONSF}" 2> /dev/null > /dev/null; then
|
||||
note 1
|
||||
else
|
||||
note 0
|
||||
fi
|
||||
|
||||
|
||||
echo #" = $NOTE"
|
||||
done
|
111
tutorial/3/chroot.md
Normal file
111
tutorial/3/chroot.md
Normal file
|
@ -0,0 +1,111 @@
|
|||
\newpage
|
||||
|
||||
L'isolation ... du pauvre
|
||||
=========================
|
||||
|
||||
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.
|
||||
|
||||
|
||||
## 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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
mkdir newroot
|
||||
```
|
||||
</div>
|
||||
|
||||
### `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\ :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
cp $(which busybox) newroot/
|
||||
chroot newroot /busybox ash
|
||||
```
|
||||
</div>
|
||||
|
||||
Jusque là ... ça fonctionne, rien de surprenant ! Mais qu'en est-il pour
|
||||
`bash` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
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`
|
||||
|
||||
`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
|
||||
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 buster 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\ :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
wget http://gentoo.mirrors.ovh.net/gentoo-distfiles/releases/amd64/autobuilds/current-stage3-amd64/stage3-amd64-20201104T214503Z.tar.xz
|
||||
tar xpf stage3-amd64-*.tar.xz -C newroot/
|
||||
```
|
||||
</div>
|
||||
|
||||
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.
|
||||
|
||||
|
||||
## Exercice {-}
|
||||
|
||||
É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>
|
102
tutorial/3/installation.md
Normal file
102
tutorial/3/installation.md
Normal file
|
@ -0,0 +1,102 @@
|
|||
\newpage
|
||||
|
||||
Prérequis
|
||||
=========
|
||||
|
||||
## 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) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
General setup --->
|
||||
[*] Control Group support --->
|
||||
[*] Freezer cgroup subsystem
|
||||
[*] PIDs cgroup subsystem
|
||||
[*] Device controller for cgroups
|
||||
[*] Cpuset support
|
||||
[*] Simple CPU accounting cgroup subsystem
|
||||
[*] Memory Resource Controller for Control Groups
|
||||
[*] Group CPU scheduler --->
|
||||
[*] Group scheduling for SCHED_OTHER
|
||||
[*] Group scheduling for SCHED_RR/FIFO
|
||||
<*> Block IO controller
|
||||
[*] Networking support --->
|
||||
Networking options --->
|
||||
[*] Network priority cgroup
|
||||
[*] Network classid cgroup
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
### 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,
|
||||
chaque noyau Linux peut être entièrement personnalisé en fonction des options
|
||||
et des pilotes que l'on voudra utiliser.
|
||||
|
||||
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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
make menuconfig
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
### 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
|
||||
`/boot`, aux côtés de l'image du noyau `vmlinuz-xxx`, de l'éventuel système de
|
||||
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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_CGROUP_FREEZER=y
|
||||
CONFIG_CGROUP_PIDS=y
|
||||
CONFIG_CGROUP_DEVICE=y
|
||||
CONFIG_CPUSETS=y
|
||||
CONFIG_CGROUP_CPUACCT=y
|
||||
CONFIG_CGROUP_MEMCG=y
|
||||
CONFIG_CGROUP_SCHED=y
|
||||
CONFIG_BLK_CGROUP=y
|
||||
|
||||
CONFIG_NET=y
|
||||
CONFIG_CGROUP_NET_PRIO=y
|
||||
CONFIG_CGROUP_NET_CLASSID=y
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
### 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
|
||||
`/proc` pour décompresser le fichier, utilisez les outils `zcat`, `zgrep`, ...
|
||||
|
||||
Vous devez retrouver les mêmes options que celles de la section précédente.
|
||||
|
||||
|
||||
|
||||
## 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.
|
||||
|
||||
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.
|
52
tutorial/3/oom.md
Normal file
52
tutorial/3/oom.md
Normal file
|
@ -0,0 +1,52 @@
|
|||
\newpage
|
||||
|
||||
Gestion de la mémoire
|
||||
=====================
|
||||
|
||||
Linux a une gestion de la mémoire bien particulière[^vm-overcommit] : par
|
||||
défaut, `malloc(3)` ne retournera jamais `NULL`. En se basant sur l'euristique
|
||||
qu'un bloc mémoire demandé ne sera pas utilisé directement et que de nombreux
|
||||
process ne feront pas un usage total des blocks qu'ils ont alloués, le noyau
|
||||
permet d'allouer plus de mémoire qu'il n'y en a réellement disponible. La
|
||||
mémoire est donc utilisée de manière plus efficace.
|
||||
|
||||
[^vm-overcommit]: Dépendant de la valeur de `/proc/sys/vm/overcommit_memory`,
|
||||
généralement 0. Voir
|
||||
<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
|
||||
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
|
||||
dit alors que le noyau est *Out-Of-Memory*.
|
||||
|
||||
Pour se sortir d'une telle situation, et après avoir tenté de vider les caches,
|
||||
il lance son arme ultime, pour retrouver au plus vite de la mémoire :
|
||||
l'*Out-Of-Memory killer*.
|
||||
|
||||
|
||||
## OOM 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
|
||||
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.
|
||||
|
||||
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
|
||||
killer ne passe.
|
||||
|
||||
Jetez un œil à [cet article parru sur LWN](https://lwn.net/Articles/590960/) à
|
||||
ce sujet.
|
1
tutorial/3/project-body.md
Symbolic link
1
tutorial/3/project-body.md
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../subject/2/project-part1.md
|
24
tutorial/3/project-intro.md
Normal file
24
tutorial/3/project-intro.md
Normal file
|
@ -0,0 +1,24 @@
|
|||
\newpage
|
||||
|
||||
Projet et rendu
|
||||
===============
|
||||
|
||||
## Sujet
|
||||
|
||||
Vous allez commencer aujourd'hui un projet qui s'étendra au prochain TP et qui
|
||||
consistera à réaliser la partie d'isolation de la moulinette des ACUs !
|
||||
|
||||
Cette semaine, il faudra faire en sorte de restreindre un groupe de processus
|
||||
pour qu'il ne puisse pas faire de déni de service sur notre machine.
|
||||
|
||||
Il n'y a pas de restriction sur le langage utilisé, vous pouvez tout aussi bien
|
||||
utiliser du C, du C++, du Python, etc.
|
||||
|
||||
L'usage de bibliothèques **non relatives** au projet est autorisé : le but de
|
||||
ce sujet est d'évaluer votre compréhension et votre utilisation de la
|
||||
tuyauterie bas-niveau du noyau liée à la virtualisation légère. À partir du
|
||||
moment où vous n'utilisez pas une bibliothèque qui abstrait complètement cette
|
||||
plomberie, n'hésitez pas à l'utiliser !
|
||||
|
||||
Gardez en tête que ce projet sera à continuer au prochain TP, où il sera
|
||||
principalement question de faire des appels systèmes.
|
39
tutorial/3/project-rendu.md
Normal file
39
tutorial/3/project-rendu.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
## 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
|
||||
rejet).
|
||||
|
||||
Ce service écoute sur l'adresse <virli@nemunai.re>, c'est donc à cette adresse
|
||||
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).
|
||||
|
||||
|
||||
## Tarball
|
||||
|
||||
Tous les fichiers identifiés comme étant à rendre pour ce TP sont à
|
||||
placer dans une tarball (pas d'archive ZIP, RAR, ...).
|
||||
|
||||
Voici une arborescence type (adaptez les extensions et les éventuels
|
||||
fichiers supplémentaires associés au langage que vous aurez choisi
|
||||
pour chaque exercice) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
login_x-TP3/
|
||||
login_x-TP3/escape.c
|
||||
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/syscall_filter.c
|
||||
```
|
||||
</div>
|
||||
|
||||
Les premières étapes du projet ne sont pas à rendre et feront l'objet
|
||||
d'un rendu à part.
|
252
tutorial/3/pseudofs.md
Normal file
252
tutorial/3/pseudofs.md
Normal file
|
@ -0,0 +1,252 @@
|
|||
\newpage
|
||||
|
||||
Pseudos systèmes de fichiers
|
||||
============================
|
||||
|
||||
## 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 :
|
||||
|
||||
[^FHS]: Consultez
|
||||
<https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard> pour
|
||||
plus de détails sur l'arboresence.
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
/dev/sda1 on / type ext4 (rw,relatime,data=ordered)
|
||||
/dev/sda3 on /home type ext4 (rw,relatime,data=ordered)
|
||||
```
|
||||
</div>
|
||||
|
||||
Dans ce schéma, la racine correspond à la première partition du premier disque,
|
||||
et les fichiers des utilisateurs sont sur la troisième partition du premier
|
||||
disque.
|
||||
|
||||
|
||||
## 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
|
||||
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
|
||||
informations mises à disposition, mais il n'est pas toujours possible d'y
|
||||
apporter des modifications.
|
||||
|
||||
Linux emploie de nombreux systèmes de fichiers virtuels :
|
||||
|
||||
- `/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
|
||||
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
|
||||
l'UEFI ;
|
||||
- ...
|
||||
|
||||
Tous ces systèmes de fichiers sont généralement exclusivement stockés en
|
||||
RAM. Pour rendre une modification persistante, il est nécessaire de modifier un
|
||||
fichier de configuration qui sera chargé par le programme d'initialisation. Par
|
||||
exemple, pour modifier les paramètres du noyau, on passe par le fichier
|
||||
`/etc/sysctl.conf` et du programme `sysctl`.
|
||||
|
||||
|
||||
### Consultation et modification
|
||||
|
||||
La consultation d'un élément se fait généralement à l'aide d'un simple `cat` :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ cat /sys/power/state
|
||||
freeze mem
|
||||
```
|
||||
</div>
|
||||
|
||||
La modification d'un élément se fait avec `echo`, comme ceci :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh# echo mem > /sys/power/state
|
||||
```
|
||||
</div>
|
||||
|
||||
Vous devriez constater l'effet de cette commande sans plus attendre !
|
||||
|
||||
|
||||
## Exercices
|
||||
|
||||
### `procinfo`
|
||||
|
||||
Explorons le pseudo système de fichiers `/proc` pour écrire un script qui va
|
||||
afficher des informations sur un processus donné :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ ./procinfo $$
|
||||
PID: 4242
|
||||
Path: /bin/bash
|
||||
Command line: bash
|
||||
Working directory: /home/nemunaire/virli/
|
||||
Root: /
|
||||
State: S (sleeping)
|
||||
Threads: 1
|
||||
|
||||
CGroups
|
||||
=======
|
||||
12:pids:/
|
||||
11:net_prio:/
|
||||
10:perf_event:/
|
||||
9:net_cls:/
|
||||
8:freezer:/
|
||||
7:devices:/
|
||||
6:memory:/
|
||||
5:blkio:/
|
||||
4:cpuacct:/
|
||||
3:cpu:/
|
||||
2:cpuset:/
|
||||
1:name=openrc:/
|
||||
|
||||
Namespaces
|
||||
==========
|
||||
cgroup:[4026531835]
|
||||
ipc:[4026531839]
|
||||
mnt:[4026531840]
|
||||
net:[4026531969]
|
||||
pid:[4026531836]
|
||||
user:[4026531837]
|
||||
uts:[4026531838]
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
### `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 :
|
||||
|
||||
* nous afficher des statistiques sur notre batterie ;
|
||||
* nous afficher des statistiques la fréquence de notre CPU.
|
||||
|
||||
#### `batinfo.sh`
|
||||
|
||||
Voici un exemple d'utilisation :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ ./batinfo.sh
|
||||
BAT0 Discharging
|
||||
====
|
||||
Capacity: 83% (Normal)
|
||||
Voltage: 11.972000 V (minimal: 11.400000 V)
|
||||
Energy: 18.290000/21.830000 Wh
|
||||
Power: 7.937000 W
|
||||
Remaining time: 2.304 h
|
||||
|
||||
BAT1 Unknown
|
||||
====
|
||||
Capacity: 83% (Normal)
|
||||
Voltage: 11.972000 V (minimal: 11.400000 V)
|
||||
Energy: 18.290000/21.830000 Wh
|
||||
Power: 0.0 W
|
||||
Remaining time: N/A
|
||||
```
|
||||
</div>
|
||||
|
||||
Pour les détails sur l'organisation de ce dossier, regardez :
|
||||
<https://www.kernel.org/doc/Documentation/power/power_supply_class.txt>.
|
||||
|
||||
|
||||
#### `cpuinfo.sh`
|
||||
|
||||
Voici un exemple d'utilisation :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ ./cpuinfo.sh
|
||||
cpu0
|
||||
====
|
||||
Current frequency: 2100384 Hz
|
||||
Current governor: powersave
|
||||
Allowed frequencies: between 500000 - 2100000 Hz
|
||||
Thermal throttle count: 0
|
||||
|
||||
cpu1
|
||||
====
|
||||
Current frequency: 2099871 Hz
|
||||
Current governor: powersave
|
||||
Allowed frequencies: between 500000 - 2100000 Hz
|
||||
Thermal throttle count: 0
|
||||
```
|
||||
</div>
|
||||
|
||||
N'hésitez pas à rajouter toute sorte d'information intéressantes !
|
||||
|
||||
|
||||
### `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 :
|
||||
|
||||
* 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`
|
||||
|
||||
Si vous avez :
|
||||
|
||||
* numlock On,
|
||||
* capslock Off,
|
||||
* scrolllock Off ;
|
||||
|
||||
Après avoir exécuté le script, nous devrions avoir :
|
||||
|
||||
* numlock Off,
|
||||
* capslock On,
|
||||
* scrolllock On.
|
||||
|
||||
Voici un exemple d'utilisation :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh# ./rev_kdb_leds.sh input20
|
||||
```
|
||||
</div>
|
||||
|
||||
`input20` correspond à l'identifiant de votre clavier, sous
|
||||
`/sys/class/input/`.
|
||||
|
||||
#### `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.
|
||||
|
||||
Bien sûr, vous ne devez utiliser que des écritures (et des lectures) dans le
|
||||
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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh# ./suspend_schedule.sh 15:42
|
||||
|
||||
```
|
||||
</div>
|
||||
|
||||
Vous aurez besoin de définir une alarme au niveau de votre RTC, via le
|
||||
fichier : `/sys/class/rtc/rtcX/wakealarm`.
|
||||
|
||||
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 :
|
||||
<https://www.linux.com/tutorials/wake-linux-rtc-alarm-clock/>
|
|
@ -1,49 +0,0 @@
|
|||
\newpage
|
||||
|
||||
Rendu
|
||||
=====
|
||||
|
||||
Modalités de rendu
|
||||
------------------
|
||||
|
||||
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
|
||||
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/5).
|
||||
|
||||
|
||||
Tarball
|
||||
-------
|
||||
|
||||
Tous les fichiers identifiés comme étant à rendre pour ce TP sont à
|
||||
placer dans une tarball (pas d'archive ZIP, RAR, ...).
|
||||
|
||||
Voici une arborescence type (vous pourriez avoir des fichiers
|
||||
supplémentaires) :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
login_x-TP3/
|
||||
login_x-TP3/cicd-playbook/
|
||||
login_x-TP3/cicd-playbook/cicd-setup.yml
|
||||
login_x-TP3/cicd-playbook/roles/...
|
||||
login_x-TP3/youp0m/
|
||||
login_x-TP3/youp0m/.drone.yml
|
||||
login_x-TP3/youp0m/.ansible/... # Pour ceux qui auraient fait le 5.4 optionnel
|
||||
login_x-TP3/youp0m/Dockerfile
|
||||
login_x-TP3/youp0m/entrypoint.sh
|
||||
login_x-TP3/youp0m/.dockerignore
|
||||
login_x-TP3/youp0m/...
|
||||
login_x-TP3/registry_play.sh
|
||||
```
|
||||
</div>
|
92
tutorial/3/seccomp.md
Normal file
92
tutorial/3/seccomp.md
Normal file
|
@ -0,0 +1,92 @@
|
|||
\newpage
|
||||
|
||||
Secure Computing Mode
|
||||
=====================
|
||||
|
||||
Plus connue sous l'acronyme *seccomp*, cette fonctionnalité du noyau Linux
|
||||
permet de restreindre les appels systèmes qu'un processus est autorisé à
|
||||
utiliser. En cas d'appel non autorisé, le processus fautif est directement tué
|
||||
(`SIGKILL`) par le noyau, ou, lorsque c'est précisé, un code `errno`
|
||||
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
|
||||
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
|
||||
initialisation (ne dépendant en général pas de données sujettes à
|
||||
l'exploitation de vulnérabilité) et doit commencer à entrer dans des portions
|
||||
de code promptes aux vulnérabilités : c'est notamment le cas des moteurs de
|
||||
rendus des navigateurs Firefox et Chrome.
|
||||
|
||||
|
||||
## Prérequis
|
||||
|
||||
L'utilisation de `seccomp` nécessite d'avoir un noyau compilé avec l'option
|
||||
`CONFIG_SECCOMP`.
|
||||
|
||||
Vous aurez également besoin de la bibliothèque `libseccomp` car l'appel système
|
||||
`seccomp(2)` n'a pas de *wrapper* dans la libc, vous devrez donc passer par
|
||||
cette bibliothèque.
|
||||
|
||||
|
||||
## `MODE_STRICT`
|
||||
|
||||
Le mode traditionnel de *seccomp* est de ne permettre uniquement l'utilisation
|
||||
des appels système `read(2)`, `write(2)` (sur les descripteurs de fichier déjà
|
||||
ouvert), `_exit(2)` et `sigreturn(2)`.
|
||||
|
||||
Historiquement, avant la création de l'appel système `seccomp(2)`, on activait
|
||||
ce mode via :
|
||||
|
||||
<div lang="en-US">
|
||||
```c
|
||||
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
|
||||
```
|
||||
</div>
|
||||
|
||||
Une fois passé cet appel système, toute entrée dans un appel système non
|
||||
autorisé conduit à un `SIGKILL` du processus.
|
||||
|
||||
|
||||
## `MODE_FILTER`
|
||||
|
||||
Plus modulable que le mode strict, le mode de filtrage permet une grande
|
||||
amplitude en permettant au programmeur de définir finement quels appels
|
||||
systèmes le programme est autorisé à faire ou non, et quel sentence est
|
||||
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
|
||||
des règles BPF (`Berkeley Packet Filter`). On passe ensuite ce filtre BPF en
|
||||
argument de l'appel système :
|
||||
|
||||
<div lang="en-US">
|
||||
```c
|
||||
struct sock_filter filter[];
|
||||
struct sock_fprog prog = {
|
||||
.len = (unsigned short) (sizeof(filter) / sizeof(filter[0])),
|
||||
.filter = filter,
|
||||
};
|
||||
seccomp(SECCOMP_SET_MODE_FILTER, 0, &prog);
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
### Exercice {-}
|
||||
|
||||
Écrivez un programme filtrant un appel système, à l'aide de `seccomp` :
|
||||
|
||||
<div lang="en-US">
|
||||
```
|
||||
42sh$ ./syscall_filter sleep 5
|
||||
sleep: cannot read realtime clock: Operation not permitted
|
||||
42sh$
|
||||
```
|
||||
</div>
|
||||
|
||||
Dans cet exemple, l'appel système filtré est `nanosleep(2)`.
|
|
@ -1,20 +1,20 @@
|
|||
---
|
||||
title: Virtualisation légère -- TP n^o^ 3
|
||||
subtitle: DevOps, intégration et déploiement continu
|
||||
subtitle: Linux Internals partie 1
|
||||
author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps}
|
||||
institute: EPITA
|
||||
date: Mercredi 28 octobre 2020
|
||||
date: Jeudi 30 septembre 2021
|
||||
abstract: |
|
||||
Durant ce troisième TP, nous allons jouer les DevOps et déployer
|
||||
automatiquement des services !
|
||||
Ce premier TP consacré aux Linux Internals va nous permettre
|
||||
d'appréhender les notions de pseudos systèmes de fichiers, de
|
||||
cgroups ainsi que de capabilities.
|
||||
|
||||
\vspace{1em}
|
||||
|
||||
Tous les éléments de ce TP (exercices et projet) sont à rendre à
|
||||
<virli@nemunai.re> au plus tard le **mercredi 4 novembre 2020 à 12 h
|
||||
42**. Consultez la dernière section de chaque partie pour plus d'information
|
||||
sur les éléments à rendre. Et n'oubliez pas de répondre aux [questions de
|
||||
cours](https://virli.nemunai.re/quiz/5).
|
||||
Certains éléments de ce TP sont à rendre à <virli@nemunai.re> au
|
||||
plus tard le jeudi 12 novembre 2020 à 12 h 42. Consultez la
|
||||
dernière section de chaque partie pour plus d'information sur les
|
||||
éléments à rendre.
|
||||
|
||||
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 à
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue