diff --git a/tutorial/4/cgroupns.md b/tutorial/4/cgroupns.md
new file mode 100644
index 0000000..33567b1
--- /dev/null
+++ b/tutorial/4/cgroupns.md
@@ -0,0 +1,305 @@
+Le *namespace* `cgroup` {#cgroupns}
+-----------------------
+
+### Introduction
+
+L'espace de noms `cgroup`, introduit dans Linux 4.6, permet de virtualiser la
+vue d'un processus sur l'arborescence des *Control Groups*. Au sein d'un
+*namespace* `cgroup`, la racine vue par le processus correspond en fait à un
+sous-groupe de l'arborescence globale.
+
+
+### Pourquoi virtualiser les *cgroups* ?
+
+Sans le *namespace* `cgroup`, un processus dans un conteneur pourrait :
+
+- Voir l'arborescence complète des *cgroups* du système hôte
+- Obtenir des informations sur d'autres conteneurs
+- Comprendre la structure organisationnelle du système
+
+Le *namespace* `cgroup` permet de :
+
+- Masquer l'arborescence globale des *cgroups*
+- Faciliter la migration de conteneurs (l'arborescence reste cohérente)
+- Renforcer l'isolation entre conteneurs
+
+
+### Utilisation pratique
+
+#### Observer les *cgroups* sans isolation\
+
+Commençons par observer notre position dans l'arborescence des *cgroups* :
+
+
+```bash
+42sh$ cat /proc/self/cgroup
+0::/user.slice/user-1000.slice/session-3.scope
+```
+
+
+Cette ligne nous indique que nous nous trouvons dans le *cgroup* unifié
+`/user.slice/user-1000.slice/session-3.scope`.
+
+Nous pouvons également explorer l'arborescence complète :
+
+
+```bash
+42sh$ ls /sys/fs/cgroup/
+cgroup.controllers cpuset.cpus.effective memory.pressure
+cgroup.max.depth cpuset.mems.effective sys-fs-fuse-connections.mount
+cgroup.max.descendants dev-hugepages.mount sys-kernel-config.mount
+cgroup.procs dev-mqueue.mount sys-kernel-debug.mount
+cgroup.stat init.scope sys-kernel-tracing.mount
+cgroup.subtree_control io.pressure system.slice
+cgroup.threads memory.numa_stat user.slice
+cpu.pressure memory.stat
+```
+
+
+
+#### S'isoler dans un nouveau *namespace* `cgroup`\
+
+Créons maintenant un nouveau *namespace* `cgroup` :
+
+
+```bash
+42sh$ unshare --cgroup /bin/bash
+ incgroupns$ cat /proc/self/cgroup
+ 0::/
+```
+
+
+Notre processus se voit maintenant à la racine de l'arborescence des *cgroups* !
+En réalité, il se trouve toujours au même endroit dans l'arborescence globale,
+mais sa vue a été virtualisée.
+
+Si nous regardons le contenu de `/sys/fs/cgroup/` :
+
+
+```bash
+ incgroupns$ ls /sys/fs/cgroup/
+ cgroup.controllers cgroup.threads io.pressure
+ cgroup.events cpu.pressure memory.numa_stat
+ cgroup.freeze cpu.stat memory.pressure
+ cgroup.max.depth cpuset.cpus memory.stat
+ cgroup.max.descendants cpuset.cpus.effective
+ cgroup.procs cpuset.mems
+ cgroup.stat cpuset.mems.effective
+ cgroup.subtree_control io.stat
+```
+
+
+Nous voyons seulement notre sous-arbre, pas l'arborescence complète du système.
+
+
+#### Créer des sous-*cgroups*\
+
+Dans notre nouveau *namespace*, nous pouvons créer des sous-groupes :
+
+
+```bash
+ incgroupns$ mkdir /sys/fs/cgroup/mysubgroup
+ incgroupns$ ls /sys/fs/cgroup/
+ cgroup.controllers cgroup.threads mysubgroup
+ cgroup.events cpu.pressure ...
+ ...
+```
+
+
+Ces sous-groupes sont en réalité créés dans notre branche de l'arborescence
+globale. Depuis l'extérieur du *namespace*, ils apparaîtraient sous un chemin
+différent.
+
+
+### Exemple avec Docker
+
+Docker utilise le *namespace* `cgroup` pour isoler la vue des *cgroups* dans
+les conteneurs. Observons cela :
+
+
+```bash
+42sh$ docker run --rm -it debian /bin/bash
+ indocker# cat /proc/self/cgroup
+ 0::/
+
+ indocker# ls /sys/fs/cgroup/
+ cgroup.controllers cpu.max memory.events
+ cgroup.events cpu.pressure memory.high
+ cgroup.freeze cpu.stat memory.low
+ cgroup.kill cpu.weight memory.max
+ cgroup.max.depth io.max memory.min
+ cgroup.max.descendants io.pressure memory.numa_stat
+ cgroup.procs io.stat memory.oom.group
+ cgroup.stat io.weight memory.pressure
+ cgroup.subtree_control memory.current memory.stat
+ cgroup.threads memory.events.local memory.swap.current
+ cgroup.type ...
+```
+
+
+Le conteneur se voit à la racine, bien qu'il soit en réalité placé dans un
+sous-groupe dédié de l'arborescence globale.
+
+
+### Vérifier la position réelle dans l'arborescence
+
+Depuis l'hôte, nous pouvons voir la véritable position d'un conteneur :
+
+
+```bash
+42sh$ docker inspect mycontainer | grep -A5 CgroupParent
+ "CgroupParent": "",
+ "CgroupDriver": "systemd",
+
+42sh$ ps aux | grep containerd-shim
+root 12345 /usr/bin/containerd-shim-runc-v2 ...
+
+42sh$ cat /proc/12345/cgroup
+0::/system.slice/docker-abc123def456.scope
+```
+
+
+Le processus du conteneur se trouve dans un sous-groupe bien spécifique, mais
+grâce au *namespace* `cgroup`, il se perçoit à la racine.
+
+
+### Combinaison avec le *namespace* `mount`
+
+Pour que l'isolation soit complète, il faut généralement combiner le *namespace*
+`cgroup` avec le *namespace* `mount` afin de remonter `/sys/fs/cgroup` :
+
+
+```bash
+42sh# unshare --cgroup --mount /bin/bash
+ incgroupns# mount -t cgroup2 none /sys/fs/cgroup
+ incgroupns# ls /sys/fs/cgroup/
+ # Vue limitée à notre sous-arbre
+```
+
+
+Sans remonter le *cgroup*, nous verrions toujours l'arborescence complète via
+l'ancien point de montage.
+
+
+### Cas d'usage
+
+#### Migration de conteneurs\
+
+Lors de la migration d'un conteneur avec des outils comme CRIU (Checkpoint/Restore
+In Userspace), le *namespace* `cgroup` garantit que l'arborescence des *cgroups*
+reste cohérente du point de vue du processus, même si la structure de l'hôte
+cible est différente.
+
+
+#### Isolation de sécurité\
+
+Sans *namespace* `cgroup`, un processus malveillant dans un conteneur pourrait :
+
+- Lire `/sys/fs/cgroup/` pour découvrir d'autres conteneurs
+- Analyser les métriques d'autres processus
+- Déduire des informations sur l'architecture du système
+
+
+#### Délégation de contrôle\
+
+Le *namespace* `cgroup` permet de donner à un utilisateur non-privilégié le
+contrôle d'une sous-arborescence de *cgroups*, sans lui donner accès à
+l'arborescence globale.
+
+
+### Exemple en C
+
+Voici un exemple de création d'un *namespace* `cgroup` en C :
+
+
+```c
+#define _GNU_SOURCE
+#include
+#include
+#include
+#include
+#include
+
+static int child_func(void *arg)
+{
+ FILE *fp;
+ char line[256];
+
+ printf("=== Dans le namespace cgroup ===\n");
+
+ fp = fopen("/proc/self/cgroup", "r");
+ if (fp == NULL) {
+ perror("fopen");
+ return EXIT_FAILURE;
+ }
+
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ printf(" %s", line);
+ }
+
+ fclose(fp);
+
+ return 0;
+}
+
+#define STACK_SIZE (1024 * 1024)
+static char child_stack[STACK_SIZE];
+
+int main(void)
+{
+ pid_t pid;
+ FILE *fp;
+ char line[256];
+
+ printf("=== Avant le namespace cgroup ===\n");
+
+ fp = fopen("/proc/self/cgroup", "r");
+ if (fp != NULL) {
+ while (fgets(line, sizeof(line), fp) != NULL) {
+ printf(" %s", line);
+ }
+ fclose(fp);
+ }
+
+ printf("\n");
+
+ pid = clone(child_func, child_stack + STACK_SIZE,
+ CLONE_NEWCGROUP | SIGCHLD, NULL);
+ if (pid == -1) {
+ perror("clone");
+ exit(EXIT_FAILURE);
+ }
+
+ waitpid(pid, NULL, 0);
+
+ return 0;
+}
+```
+
+
+::::: {.code}
+
+Pour compiler et exécuter :
+
+
+```bash
+42sh$ gcc -o cgroup_ns_demo cgroup_ns_demo.c
+42sh$ ./cgroup_ns_demo
+=== Avant le namespace cgroup ===
+ 0::/user.slice/user-1000.slice/session-3.scope
+
+=== Dans le namespace cgroup ===
+ 0::/
+```
+
+
+:::::
+
+
+### Aller plus loin {-}
+
+Pour plus d'informations :
+
+- `cgroup_namespaces(7)` - page de manuel
+- [Cgroup Namespace](https://lwn.net/Articles/621006/) :
+- [Control Group v2](https://www.kernel.org/doc/html/latest/admin-guide/cgroup-v2.html) : Documentation du noyau sur cgroup v2
diff --git a/tutorial/4/howto.md b/tutorial/4/howto.md
index f4e5dbf..2f6eb9b 100644
--- a/tutorial/4/howto.md
+++ b/tutorial/4/howto.md
@@ -121,6 +121,34 @@ pid_t pid = clone(do_execvp, // First function executed by child
Dans cet exemple, le processus fils créé disposera d'un nouvel espace de noms
pour les *CGroups* et disposera d'une nouvelle pile réseau.
+::::: {.more}
+
+#### Compilation des exemples C {-}
+\
+
+Pour compiler les programmes C utilisant les namespaces, aucune bibliothèque
+spéciale n'est requise au-delà de la bibliothèque C standard :
+
+
+```bash
+42sh$ gcc -o mon_programme mon_programme.c
+```
+
+
+Notez que certains appels système utilisés avec les namespaces nécessitent la
+définition de `_GNU_SOURCE` au début du fichier source pour accéder aux
+extensions GNU :
+
+
+```c
+#define _GNU_SOURCE
+#include
+// ...
+```
+
+
+:::::
+
::::: {.question}
#### Quel est le rôle du *flag* `SIGCHLD` ? {-}
diff --git a/tutorial/4/ipcns.md b/tutorial/4/ipcns.md
new file mode 100644
index 0000000..d5d8a62
--- /dev/null
+++ b/tutorial/4/ipcns.md
@@ -0,0 +1,514 @@
+Le *namespace* `IPC` {#ipc-ns}
+-------------------
+
+### Introduction
+
+L'espace de noms `IPC`, introduit dans Linux 2.6.19, isole les objets de
+communication inter-processus (IPC) System V et les files de messages POSIX.
+
+Les objets isolés incluent :
+
+- Les files de messages System V (`msgget`, `msgsnd`, `msgrcv`)
+- Les sémaphores System V (`semget`, `semop`)
+- Les segments de mémoire partagée System V (`shmget`, `shmat`)
+- Les files de messages POSIX (`mq_open`, `mq_send`, `mq_receive`)
+
+Une fois dans un *namespace* IPC différent, un processus ne peut communiquer
+qu'avec les processus du même *namespace* via ces mécanismes IPC.
+
+
+### Pourquoi isoler les IPC ?
+
+Sans isolation IPC, des processus dans différents conteneurs pourraient :
+
+- Communiquer entre eux via des files de messages partagées
+- Accéder à la mémoire partagée d'autres conteneurs
+- Interférer avec les sémaphores d'autres applications
+
+L'isolation IPC garantit que chaque conteneur dispose de son propre ensemble
+d'objets IPC, renforçant ainsi la sécurité et l'isolation.
+
+
+### Utilisation pratique
+
+#### Observer les objets IPC du système\
+
+La commande `ipcs` permet de lister tous les objets IPC du système :
+
+
+```bash
+42sh$ ipcs
+
+------ Message Queues --------
+key msqid owner perms used-bytes messages
+
+------ Shared Memory Segments --------
+key shmid owner perms bytes nattch status
+0x00000000 32768 alice 600 524288 2 dest
+
+------ Semaphore Arrays --------
+key semid owner perms nsems
+0x12345678 0 bob 666 1
+```
+
+
+Cette commande nous montre tous les objets IPC visibles dans notre *namespace*
+actuel.
+
+
+#### Créer une file de messages System V\
+
+Créons d'abord une file de messages dans notre *namespace* initial :
+
+
+```c
+// ipc_create.c
+#include
+#include
+#include
+#include
+
+int main(void)
+{
+ key_t key;
+ int msgid;
+
+ // Créer une clé unique
+ key = ftok("/tmp", 'A');
+ if (key == -1) {
+ perror("ftok");
+ exit(EXIT_FAILURE);
+ }
+
+ // Créer une file de messages
+ msgid = msgget(key, 0666 | IPC_CREAT);
+ if (msgid == -1) {
+ perror("msgget");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("File de messages créée avec l'ID : %d\n", msgid);
+ printf("Clé : 0x%08x\n", key);
+
+ return 0;
+}
+```
+
+
+::::: {.code}
+
+Compilation et exécution :
+
+
+```bash
+42sh$ gcc -o ipc_create ipc_create.c
+42sh$ touch /tmp/ipc_key_file
+42sh$ ./ipc_create
+File de messages créée avec l'ID : 0
+Clé : 0x41000001
+
+42sh$ ipcs -q
+------ Message Queues --------
+key msqid owner perms used-bytes messages
+0x41000001 0 alice 666 0 0
+```
+
+
+:::::
+
+
+#### S'isoler dans un nouveau *namespace* IPC\
+
+Maintenant, créons un nouveau *namespace* IPC :
+
+
+```bash
+42sh$ unshare --ipc /bin/bash
+ inipcns$ ipcs -q
+ ------ Message Queues --------
+ key msqid owner perms used-bytes messages
+```
+
+
+Notre nouveau *namespace* ne contient aucun objet IPC ! La file de messages
+créée précédemment n'est pas visible ici.
+
+Si nous créons une nouvelle file de messages dans ce *namespace* :
+
+
+```bash
+ inipcns$ ./ipc_create
+ File de messages créée avec l'ID : 0
+ Clé : 0x41000001
+
+ inipcns$ ipcs -q
+ ------ Message Queues --------
+ key msqid owner perms used-bytes messages
+ 0x41000001 0 alice 666 0 0
+```
+
+
+Cette nouvelle file a le même ID (0) et la même clé que celle créée dans le
+*namespace* initial, mais il s'agit d'un objet complètement distinct.
+
+
+#### Communication entre processus dans le même *namespace*\
+
+Créons un exemple de communication par file de messages :
+
+
+```c
+// ipc_send.c
+#include
+#include
+#include
+#include
+#include
+
+struct message {
+ long mtype;
+ char mtext[100];
+};
+
+int main(void)
+{
+ key_t key;
+ int msgid;
+ struct message msg;
+
+ key = ftok("/tmp", 'A');
+ msgid = msgget(key, 0666 | IPC_CREAT);
+
+ msg.mtype = 1;
+ snprintf(msg.mtext, sizeof(msg.mtext), "Hello from PID %d", getpid());
+
+ if (msgsnd(msgid, &msg, sizeof(msg.mtext), 0) == -1) {
+ perror("msgsnd");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Message envoyé : %s\n", msg.mtext);
+
+ return 0;
+}
+```
+
+
+
+```c
+// ipc_receive.c
+#include
+#include
+#include
+#include
+
+struct message {
+ long mtype;
+ char mtext[100];
+};
+
+int main(void)
+{
+ key_t key;
+ int msgid;
+ struct message msg;
+
+ key = ftok("/tmp", 'A');
+ msgid = msgget(key, 0666 | IPC_CREAT);
+
+ if (msgrcv(msgid, &msg, sizeof(msg.mtext), 1, 0) == -1) {
+ perror("msgrcv");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Message reçu : %s\n", msg.mtext);
+
+ return 0;
+}
+```
+
+
+::::: {.code}
+
+Compilation :
+
+
+```bash
+42sh$ gcc -o ipc_send ipc_send.c
+42sh$ gcc -o ipc_receive ipc_receive.c
+```
+
+
+Test dans le même *namespace* :
+
+
+```bash
+# Terminal 1
+42sh$ ./ipc_receive
+# Attend un message...
+
+# Terminal 2
+42sh$ ./ipc_send
+Message envoyé : Hello from PID 12345
+
+# Terminal 1 reçoit :
+Message reçu : Hello from PID 12345
+```
+
+
+:::::
+
+
+#### Isolation entre *namespaces*\
+
+Maintenant, testons avec deux *namespaces* IPC différents :
+
+
+```bash
+# Terminal 1 - namespace IPC A
+42sh$ unshare --ipc /bin/bash
+ ipcns-A$ ./ipc_receive
+ # Attend un message...
+
+# Terminal 2 - namespace IPC B (différent)
+42sh$ unshare --ipc /bin/bash
+ ipcns-B$ ./ipc_send
+ Message envoyé : Hello from PID 23456
+
+# Terminal 1 ne reçoit RIEN car les namespaces sont différents
+```
+
+
+Les deux processus utilisent la même clé IPC, mais comme ils sont dans des
+*namespaces* différents, ils ne peuvent pas communiquer.
+
+
+### Exemple avec la mémoire partagée
+
+Voici un exemple utilisant la mémoire partagée System V :
+
+
+```c
+// shm_demo.c
+#include
+#include
+#include
+#include
+#include
+#include
+
+int main(void)
+{
+ key_t key;
+ int shmid;
+ char *data;
+
+ // Créer une clé
+ key = ftok("/tmp", 'S');
+
+ // Créer un segment de mémoire partagée de 1024 octets
+ shmid = shmget(key, 1024, 0644 | IPC_CREAT);
+ if (shmid == -1) {
+ perror("shmget");
+ exit(EXIT_FAILURE);
+ }
+
+ // Attacher le segment
+ data = shmat(shmid, NULL, 0);
+ if (data == (char *)(-1)) {
+ perror("shmat");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Segment de mémoire partagée attaché\n");
+ printf("Écriture dans la mémoire partagée...\n");
+
+ sprintf(data, "Hello from PID %d in namespace", getpid());
+
+ printf("Contenu : %s\n", data);
+ printf("Appuyez sur Entrée pour détacher...\n");
+ getchar();
+
+ // Détacher
+ shmdt(data);
+
+ printf("Voulez-vous supprimer le segment ? (o/n) : ");
+ char choice = getchar();
+ if (choice == 'o' || choice == 'O') {
+ shmctl(shmid, IPC_RMID, NULL);
+ printf("Segment supprimé\n");
+ }
+
+ return 0;
+}
+```
+
+
+::::: {.code}
+
+Compilation et test :
+
+
+```bash
+42sh$ gcc -o shm_demo shm_demo.c
+
+# Dans le namespace initial
+42sh$ ./shm_demo &
+Segment de mémoire partagée attaché
+Écriture dans la mémoire partagée...
+Contenu : Hello from PID 12345 in namespace
+
+42sh$ ipcs -m
+------ Shared Memory Segments --------
+key shmid owner perms bytes nattch status
+0x53000001 0 alice 644 1024 1
+
+# Dans un nouveau namespace IPC
+42sh$ unshare --ipc /bin/bash
+ inipcns$ ipcs -m
+ ------ Shared Memory Segments --------
+ key shmid owner perms bytes nattch status
+
+ # Aucun segment visible !
+```
+
+
+:::::
+
+
+### Files de messages POSIX
+
+Le *namespace* IPC isole également les files de messages POSIX (qui sont
+différentes des files System V) :
+
+
+```c
+// mqueue_demo.c
+#include
+#include
+#include
+#include
+#include
+
+int main(void)
+{
+ mqd_t mq;
+ struct mq_attr attr;
+ char buffer[1024];
+
+ // Configurer les attributs de la file
+ attr.mq_flags = 0;
+ attr.mq_maxmsg = 10;
+ attr.mq_msgsize = 1024;
+ attr.mq_curmsgs = 0;
+
+ // Créer ou ouvrir une file de messages POSIX
+ mq = mq_open("/myqueue", O_CREAT | O_RDWR, 0644, &attr);
+ if (mq == (mqd_t)-1) {
+ perror("mq_open");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("File de messages POSIX créée : /myqueue\n");
+
+ // Envoyer un message
+ sprintf(buffer, "Hello from PID %d", getpid());
+ if (mq_send(mq, buffer, strlen(buffer) + 1, 0) == -1) {
+ perror("mq_send");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Message envoyé : %s\n", buffer);
+
+ // Recevoir le message
+ if (mq_receive(mq, buffer, 1024, NULL) == -1) {
+ perror("mq_receive");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Message reçu : %s\n", buffer);
+
+ mq_close(mq);
+ mq_unlink("/myqueue");
+
+ return 0;
+}
+```
+
+
+::::: {.code}
+
+Pour compiler (nécessite la bibliothèque `librt`) :
+
+
+```bash
+42sh$ gcc -o mqueue_demo mqueue_demo.c -lrt
+42sh$ ./mqueue_demo
+File de messages POSIX créée : /myqueue
+Message envoyé : Hello from PID 12345
+Message reçu : Hello from PID 12345
+```
+
+
+Les files de messages POSIX peuvent être listées dans `/dev/mqueue/` :
+
+
+```bash
+42sh$ ls -l /dev/mqueue/
+total 0
+-rw-r--r-- 1 alice alice 80 Nov 15 10:30 myqueue
+```
+
+
+Dans un nouveau *namespace* IPC, ce répertoire sera vide.
+
+:::::
+
+
+### Combinaison avec d'autres *namespaces*
+
+En pratique, le *namespace* IPC est souvent combiné avec d'autres *namespaces*
+pour une isolation complète :
+
+
+```bash
+42sh# unshare --ipc --pid --mount --fork --mount-proc /bin/bash
+ incontainer# # Conteneur isolé avec IPC, PID et mount namespaces
+```
+
+
+
+### Nettoyage des objets IPC
+
+Les objets IPC persistent généralement après la terminaison des processus qui
+les ont créés. Pour les nettoyer :
+
+
+```bash
+# Supprimer une file de messages
+42sh$ ipcrm -q
+
+# Supprimer un segment de mémoire partagée
+42sh$ ipcrm -m
+
+# Supprimer un sémaphore
+42sh$ ipcrm -s
+
+# Ou supprimer par clé
+42sh$ ipcrm -Q 0x41000001
+```
+
+
+Lorsqu'un *namespace* IPC est détruit (tous les processus terminés), tous ses
+objets IPC sont automatiquement nettoyés.
+
+
+### Aller plus loin {-}
+
+Pour plus d'informations :
+
+- `ipc_namespaces(7)` - page de manuel
+- `ipcs(1)` - lister les objets IPC
+- `ipcrm(1)` - supprimer les objets IPC
+- `svipc(7)` - aperçu de System V IPC
+- `mq_overview(7)` - aperçu des files de messages POSIX
diff --git a/tutorial/4/mountns.md b/tutorial/4/mountns.md
index 4fa7f09..acf7816 100644
--- a/tutorial/4/mountns.md
+++ b/tutorial/4/mountns.md
@@ -189,7 +189,7 @@ On considère préalablement que l'environnement est propice à la réalisation
```
42sh# mkdir -p /mnt/newroot
42sh# mount -t tmpfs none /mnt/newroot
-42sh# wget https://dl-cdn.alpinelinux.org/alpine/v3.14/releases/x86_64/alpine-minirootfs-3.14.8-x86_64.tar.gz
+42sh# wget https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/x86_64/alpine-minirootfs-3.20.3-x86_64.tar.gz
42sh# tar xpf alpine-minirootfs-*.tar.gz -C /mnt/newroot
42sh# cd /
```
diff --git a/tutorial/4/namespaces-recap.md b/tutorial/4/namespaces-recap.md
new file mode 100644
index 0000000..6267dbb
--- /dev/null
+++ b/tutorial/4/namespaces-recap.md
@@ -0,0 +1,532 @@
+\newpage
+
+Récapitulatif des *namespaces*
+===============================
+
+Nous venons d'explorer en détail les huit types d'espaces de noms disponibles
+dans le noyau Linux. Avant de conclure cette partie, récapitulons les concepts
+clés et les meilleures pratiques pour utiliser efficacement ces mécanismes
+d'isolation.
+
+
+## Tableau comparatif des *namespaces*
+
+Le tableau suivant résume les caractéristiques principales de chaque type
+d'espace de noms :
+
+| *Namespace* | Flag `clone()` | Depuis | Isole | Privilèges requis* |
+|-------------|----------------|--------|-------|-------------------|
+| **mount** | `CLONE_NEWNS` | 2.4.19 | Points de montage | Oui |
+| **UTS** | `CLONE_NEWUTS` | 2.6.19 | Hostname, domaine NIS | Oui |
+| **IPC** | `CLONE_NEWIPC` | 2.6.19 | Objets IPC System V et POSIX | Oui |
+| **PID** | `CLONE_NEWPID` | 2.6.24 | Arbre de processus | Oui |
+| **network** | `CLONE_NEWNET` | 2.6.29 | Interfaces, routes, ports | Oui |
+| **user** | `CLONE_NEWUSER` | 3.8 | UIDs, GIDs, capabilities | **Non** |
+| **cgroup** | `CLONE_NEWCGROUP` | 4.6 | Vue arborescence cgroup | Oui |
+| **time** | `CLONE_NEWTIME` | 5.6 | Horloges monotones | Oui |
+
+*\* Sauf si combiné avec un *namespace* `user`*
+
+
+## Ce que chaque *namespace* vous permet de faire
+
+### `mount` -- Systèmes de fichiers isolés
+
+**Fonctionnalité :** Isole l'arborescence des points de montage.
+
+**Permet de :**
+- Créer un système de fichiers racine différent (`pivot_root`, `switch_root`)
+- Monter/démonter des partitions sans affecter l'hôte
+- Implémenter un `chroot` sécurisé (impossible de s'échapper)
+- Utiliser des systèmes de fichiers en couches (OverlayFS)
+
+**Cas d'usage typiques :**
+- Conteneurs avec leur propre filesystem
+- Environnements de build isolés
+- Systèmes d'installation et de récupération
+
+
+### `UTS` -- Identité système
+
+**Fonctionnalité :** Isole le nom d'hôte et le domaine NIS.
+
+**Permet de :**
+- Donner un nom unique à chaque conteneur
+- Éviter les conflits de nommage
+- Faciliter l'identification des conteneurs
+
+**Cas d'usage typiques :**
+- Conteneurs avec des noms de machine distincts
+- Environnements multi-tenants
+- Tests de configurations réseau
+
+
+### `IPC` -- Communication inter-processus
+
+**Fonctionnalité :** Isole les objets IPC (files de messages, sémaphores,
+mémoire partagée).
+
+**Permet de :**
+- Empêcher la communication IPC entre conteneurs
+- Isoler les applications utilisant IPC System V ou POSIX
+- Protéger contre les fuites d'informations via IPC
+
+**Cas d'usage typiques :**
+- Isolation de sécurité entre conteneurs
+- Applications legacy utilisant IPC System V
+- Environnements de test pour applications IPC
+
+
+### `PID` -- Arbre de processus virtualisé
+
+**Fonctionnalité :** Isole l'arbre des processus avec renumérotation.
+
+**Permet de :**
+- Avoir un processus `init` (PID 1) par conteneur
+- Masquer les processus de l'hôte et des autres conteneurs
+- Gérer le cycle de vie des processus indépendamment
+- Récolter les processus orphelins proprement
+
+**Cas d'usage typiques :**
+- Conteneurs avec gestion complète du cycle de vie
+- Isolation de sécurité (masquage des processus)
+- Environnements avec plusieurs niveaux d'`init`
+
+**Particularité :** Le processus doit forker après `unshare(CLONE_NEWPID)`
+pour que l'isolation soit effective.
+
+
+### `network` -- Pile réseau dédiée
+
+**Fonctionnalité :** Isole les interfaces réseau, routes, règles de pare-feu et
+ports.
+
+**Permet de :**
+- Donner une pile réseau complète à chaque conteneur
+- Réutiliser les mêmes ports dans différents conteneurs
+- Configurer des routes et pare-feu indépendants
+- Créer des topologies réseau complexes (bridges, VLAN, MACVLAN)
+
+**Cas d'usage typiques :**
+- Conteneurs avec leur propre IP
+- Tests réseau isolés
+- Micro-services avec ports identiques
+- Simulations de topologies réseau
+
+**Note :** Nécessite généralement des interfaces virtuelles (`veth`, `macvlan`,
+etc.) pour connecter les conteneurs.
+
+
+### `user` -- Privilèges virtualisés
+
+**Fonctionnalité :** Isole les UIDs, GIDs et les capabilities.
+
+**Permet de :**
+- Être root dans le conteneur sans être root sur l'hôte
+- Lancer des conteneurs sans privilèges (rootless containers)
+- Mapper des plages d'UIDs entre conteneur et hôte
+- Déléguer des capacités limitées
+
+**Cas d'usage typiques :**
+- Conteneurs rootless (podman, systemd-nspawn)
+- Environnements multi-utilisateurs sécurisés
+- Délégation contrôlée de privilèges
+
+**Particularité :** Seul *namespace* créable sans privilèges. Permet ensuite de
+créer tous les autres types de *namespaces*.
+
+**Attention :** Historiquement source de vulnérabilités ; à utiliser avec
+précaution.
+
+
+### `cgroup` -- Vue filtrée des control groups
+
+**Fonctionnalité :** Virtualise la vue de l'arborescence des cgroups.
+
+**Permet de :**
+- Masquer l'organisation des cgroups de l'hôte
+- Faciliter la migration de conteneurs
+- Empêcher la fuite d'informations système via `/sys/fs/cgroup`
+- Déléguer la gestion de sous-arbres de cgroups
+
+**Cas d'usage typiques :**
+- Renforcement de l'isolation de sécurité
+- Migration de conteneurs (CRIU)
+- Systèmes multi-tenants
+
+**Note :** Souvent combiné avec un *namespace* `mount` pour remonter
+`/sys/fs/cgroup`.
+
+
+### `time` -- Horloges virtualisées
+
+**Fonctionnalité :** Virtualise `CLOCK_MONOTONIC` et `CLOCK_BOOTTIME`.
+
+**Permet de :**
+- Décaler les horloges monotones pour un conteneur
+- Préserver l'état temporel lors de migrations
+- Accélérer le temps pour les tests
+
+**Cas d'usage typiques :**
+- Migration de conteneurs avec CRIU
+- Tests d'applications sensibles au temps
+- Simulations temporelles
+
+**Limitation :** Ne virtualise **pas** l'heure système (CLOCK_REALTIME).
+
+**Particularité :** Les offsets doivent être configurés avant de créer le
+premier processus enfant.
+
+
+## Combinaisons recommandées
+
+Les *namespaces* sont rarement utilisés seuls. Voici les combinaisons courantes
+selon les besoins d'isolation :
+
+
+### Isolation minimale (développement)
+
+Pour un environnement de développement simple avec un filesystem isolé :
+
+
+```bash
+unshare --mount --pid --fork --mount-proc /bin/bash
+```
+
+
+**Isolation :** Filesystem et processus
+**Avantages :** Rapide, simple, suffisant pour tester des installations
+**Limitations :** Partage le réseau, les utilisateurs, IPC avec l'hôte
+
+
+### Conteneur standard (production light)
+
+Pour une isolation raisonnable sans réseau séparé :
+
+
+```bash
+unshare --mount --uts --ipc --pid --fork --mount-proc /bin/bash
+```
+
+
+**Isolation :** Filesystem, processus, IPC, hostname
+**Avantages :** Bonne isolation, partage le réseau de l'hôte
+**Cas d'usage :** Services système, environnements de build
+
+
+### Conteneur avec réseau isolé
+
+Pour une isolation complète incluant le réseau :
+
+
+```bash
+unshare --mount --uts --ipc --net --pid --fork --mount-proc /bin/bash
+```
+
+
+**Isolation :** Filesystem, processus, IPC, hostname, réseau
+**Avantages :** Isolation réseau complète
+**Note :** Nécessite configuration réseau supplémentaire (veth, bridge, etc.)
+
+
+### Conteneur rootless (sans privilèges)
+
+Pour lancer un conteneur en tant qu'utilisateur normal :
+
+
+```bash
+unshare --user --map-root-user \
+ --mount --uts --ipc --net --pid \
+ --fork --mount-proc /bin/bash
+```
+
+
+**Isolation :** Complète + virtualisation des privilèges
+**Avantages :** Aucun privilège requis, sécurité renforcée
+**Cas d'usage :** Environnements multi-utilisateurs, CI/CD non-privilégiée
+
+
+### Conteneur type Docker (isolation maximale)
+
+Pour une isolation complète similaire à Docker :
+
+
+```bash
+unshare --user --map-root-user \
+ --mount --uts --ipc --net --pid --cgroup \
+ --fork --mount-proc /bin/bash
+```
+
+
+**Isolation :** Tous les namespaces (sauf `time`)
+**Avantages :** Isolation maximale
+**Note :** Équivalent approximatif de `docker run --rm -it`
+
+
+## Ordre de création des *namespaces*
+
+L'ordre dans lequel les *namespaces* sont créés peut être important :
+
+1. **`user` en premier** : Si vous voulez créer des *namespaces* sans
+ privilèges, commencez toujours par le *namespace* `user`.
+
+2. **`mount` avant `pid`** : Pour pouvoir remonter `/proc` correctement avec
+ l'option `--mount-proc`.
+
+3. **`pid` avec `--fork`** : N'oubliez jamais l'option `--fork` avec le
+ *namespace* `pid`, sinon le processus actuel ne sera pas réellement isolé.
+
+4. **`time` et `cgroup` avant le fork** : Ces deux namespaces nécessitent des
+ configurations avant la création du premier processus enfant.
+
+
+## Commandes essentielles
+
+Voici un récapitulatif des commandes les plus utiles pour travailler avec les
+*namespaces* :
+
+### Création et entrée dans des *namespaces*
+
+
+```bash
+# Créer de nouveaux namespaces et exécuter une commande
+unshare [options] [commande]
+
+# Principales options :
+# -m, --mount Namespace mount
+# -u, --uts Namespace UTS
+# -i, --ipc Namespace IPC
+# -n, --net Namespace network
+# -p, --pid Namespace PID
+# -U, --user Namespace user
+# -C, --cgroup Namespace cgroup
+# -T, --time Namespace time
+# -f, --fork Fork avant d'exécuter la commande (requis avec --pid)
+# --mount-proc Monter /proc après création du namespace
+
+# Entrer dans les namespaces d'un processus existant
+nsenter [options] [commande]
+nsenter --target
--all [commande]
+```
+
+
+### Inspection des *namespaces*
+
+
+```bash
+# Lister tous les namespaces du système
+lsns
+
+# Lister les namespaces d'un processus spécifique
+lsns -p
+
+# Voir les namespaces d'un processus
+ls -l /proc//ns/
+
+# Comparer les namespaces de deux processus
+readlink /proc//ns/net
+readlink /proc//ns/net
+```
+
+
+### Gestion réseau (namespace network)
+
+
+```bash
+# Créer un namespace network nommé
+ip netns add
+
+# Lister les namespaces network
+ip netns list
+
+# Exécuter une commande dans un namespace network
+ip netns exec
+
+# Créer une paire veth
+ip link add veth0 type veth peer name veth1
+
+# Déplacer une interface dans un namespace
+ip link set veth1 netns
+```
+
+
+
+## Appels système
+
+Pour les développeurs, voici les appels système principaux :
+
+
+```c
+// Créer un nouveau processus dans de nouveaux namespaces
+pid_t clone(int (*fn)(void *), void *stack, int flags, void *arg);
+// flags: CLONE_NEWNS, CLONE_NEWUTS, CLONE_NEWIPC, CLONE_NEWPID,
+// CLONE_NEWNET, CLONE_NEWUSER, CLONE_NEWCGROUP, CLONE_NEWTIME
+
+// Se dissocier de namespaces actuels
+int unshare(int flags);
+
+// Rejoindre les namespaces d'un autre processus
+int setns(int fd, int nstype);
+// fd: file descriptor de /proc/
/ns/
+// nstype: 0 ou CLONE_NEW* pour vérification de type
+
+// Obtenir un file descriptor vers un processus (pour setns)
+int pidfd_open(pid_t pid, unsigned int flags);
+```
+
+
+
+## Bonnes pratiques
+
+### Sécurité
+
+1. **Privilèges minimaux** : Utilisez le *namespace* `user` quand possible pour
+ éviter d'exécuter des conteneurs en tant que root.
+
+2. **Combinaison d'isolations** : Un seul namespace ne suffit généralement pas
+ pour une isolation sécurisée. Combinez plusieurs namespaces.
+
+3. **User namespace avec précaution** : Bien que pratique, le *namespace*
+ `user` a été source de nombreuses vulnérabilités. Assurez-vous d'utiliser un
+ noyau récent et correctement patché.
+
+4. **Nettoyage des ressources** : Les namespaces persistent tant qu'ils sont
+ référencés. Utilisez `umount` pour les bind mounts qui maintiennent des
+ namespaces actifs.
+
+5. **Capabilities** : Même dans un *namespace* `user`, les capabilities sont
+ limitées à l'intérieur du namespace. Ne comptez pas sur elles pour des
+ actions hors namespace.
+
+
+### Performance
+
+1. **Coût minimal** : La création de namespaces a un coût négligeable en termes
+ de performance. N'hésitez pas à les utiliser.
+
+2. **Réseau** : Le type d'interface virtuelle utilisé (`veth`, `macvlan`,
+ `ipvlan`) peut avoir un impact significatif sur les performances réseau.
+
+3. **OverlayFS vs device-mapper** : Pour le stockage, OverlayFS est
+ généralement plus performant que les snapshots LVM (device-mapper).
+
+
+### Débogage
+
+1. **`lsns` est votre ami** : Utilisez `lsns` pour comprendre rapidement
+ l'organisation des namespaces sur votre système.
+
+2. **Inspecter /proc** : Les fichiers dans `/proc//ns/` sont essentiels
+ pour comprendre dans quels namespaces se trouve un processus.
+
+3. **Bind mounts pour persistence** : Utilisez `mount --bind` sur les fichiers
+ de `/proc//ns/` pour maintenir un namespace actif même après la
+ terminaison du processus.
+
+4. **Logs et `strace`** : En cas de problème, `strace` peut vous montrer
+ exactement quels appels système échouent et pourquoi.
+
+
+## Limitations et pièges courants
+
+### Namespace `PID`
+
+- **Oubli du `--fork`** : Sans fork, le processus actuel reste dans l'ancien
+ namespace PID.
+- **Bash et PID 1** : Bash peut avoir des comportements inattendus en tant que
+ PID 1 (voir pidns.md pour les détails).
+- **`/proc` doit être remonté** : Sinon `ps`, `top` montrent tous les processus
+ du système.
+
+
+### Namespace `mount`
+
+- **Propagation des montages** : Attention aux politiques `shared`, `slave`,
+ `private`. Par défaut, utilisez `mount --make-rslave /` pour éviter les
+ fuites.
+- **`pivot_root` vs `chroot`** : `pivot_root` est plus sûr mais plus complexe à
+ mettre en œuvre.
+
+
+### Namespace `network`
+
+- **Pas d'interface par défaut** : Un nouveau namespace network ne contient
+ qu'une interface loopback désactivée. Il faut configurer le réseau
+ manuellement.
+- **Complexité de la configuration** : Bridges, veth, routes, NAT... la
+ configuration réseau peut devenir complexe rapidement.
+
+
+### Namespace `user`
+
+- **MappingUID/GID limité** : Sans privilèges, vous ne pouvez mapper qu'un
+ seul UID (le vôtre vers root).
+- **Fichiers setuid** : Ne fonctionnent pas correctement dans un namespace
+ user.
+- **Restrictions par distribution** : Certaines distributions désactivent le
+ namespace user par défaut (voir setup.md).
+
+
+### Namespace `time`
+
+- **Configuration unique** : Les offsets ne peuvent être configurés qu'une fois,
+ avant le premier fork.
+- **Pas d'heure réelle** : Ne virtualise pas `CLOCK_REALTIME`, seulement les
+ horloges monotones.
+
+
+## Pour aller plus loin
+
+### Documentation officielle
+
+- Pages de manuel : `namespaces(7)`, `pid_namespaces(7)`, `user_namespaces(7)`,
+ `mount_namespaces(7)`, `network_namespaces(7)`, `ipc_namespaces(7)`,
+ `uts_namespaces(7)`, `cgroup_namespaces(7)`, `time_namespaces(7)`
+
+- Documentation du noyau :
+
+
+
+### Articles de référence
+
+- [Namespaces in operation (série LWN)](https://lwn.net/Articles/531114/) :
+ série d'articles exhaustive par Michael Kerrisk
+
+
+- [Anatomy of a user namespaces vulnerability](https://lwn.net/Articles/543273/) :
+ pour comprendre les enjeux de sécurité
+
+
+
+### Projets utilisant les namespaces
+
+- **Docker/Podman/containerd** : Containerisation d'applications
+- **systemd-nspawn** : Conteneurs légers pour systemd
+- **LXC/LXD** : Conteneurs système complets
+- **Flatpak/Snap** : Sandboxing d'applications
+- **Chrome/Firefox** : Sandboxing de processus de rendu
+- **bubblewrap** : Outil de sandboxing générique
+
+
+## Conclusion
+
+Les *namespaces* Linux constituent une brique fondamentale de la virtualisation
+légère moderne. Leur conception modulaire permet de créer des niveaux
+d'isolation sur mesure, depuis un simple environnement de développement isolé
+jusqu'à des conteneurs de production complets.
+
+La maîtrise des *namespaces* nécessite de comprendre :
+
+1. **Ce que chaque type isole** et dans quel contexte l'utiliser
+2. **Comment les combiner** pour atteindre le niveau d'isolation souhaité
+3. **Leurs interactions** et dépendances mutuelles
+4. **Leurs limitations** et les cas particuliers à gérer
+
+Combinés avec les *cgroups* (pour la limitation de ressources) et les *security
+modules* (AppArmor, SELinux pour les politiques de sécurité), les *namespaces*
+permettent de construire des environnements d'exécution sûrs, isolés et
+performants.
+
+Que vous développiez des outils de containerisation, construisiez des
+plateformes cloud, ou cherchiez simplement à mieux isoler vos applications, les
+*namespaces* sont un outil incontournable de l'écosystème Linux moderne.
diff --git a/tutorial/4/networkns.md b/tutorial/4/networkns.md
index 8fe702d..62065dd 100644
--- a/tutorial/4/networkns.md
+++ b/tutorial/4/networkns.md
@@ -82,7 +82,7 @@ virli
42sh# ip netns
foo virli
42sh# ip netns exec foo ip link
-1: lo: mut 65536 qdisc noop state DOWN mode DEFAULT group default
+1: lo: mtu 65536 qdisc noop state DOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
```
@@ -99,7 +99,7 @@ des interfaces :
```
42sh# ip netns exec virli ip link
-1: lo: mut 65536 qdisc noop state DOWN mode DEFAULT group default
+1: lo: mtu 65536 qdisc noop state DOWN mode DEFAULT group default
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
```
@@ -175,11 +175,13 @@ struct nlmsghdr {
```
-Parmi les fonctionnalités de Netlink, nous allons utiliser le module NIS
-(Network Interface Service)[^RFC3549NIS]. Il spécifie le format par lequel
+Parmi les fonctionnalités de Netlink, nous allons utiliser RTNetlink
+(Routing Netlink)[^RFC3549RTNETLINK]. Il spécifie le format par lequel
doivent commencer les données liées à l'administration d'interfaces réseau.
+Le module RTNetlink utilise la famille `NETLINK_ROUTE` pour communiquer avec
+le noyau concernant les interfaces, routes et règles de routage.
-[^RFC3549NIS]: Network Interface Service Module
+[^RFC3549RTNETLINK]: RTNetlink - Linux Routing Socket
```c
diff --git a/tutorial/4/timens.md b/tutorial/4/timens.md
new file mode 100644
index 0000000..acf4167
--- /dev/null
+++ b/tutorial/4/timens.md
@@ -0,0 +1,263 @@
+Le *namespace* `time` {#time-ns}
+---------------------
+
+### Introduction
+
+L'espace de noms `time`, introduit dans Linux 5.6, permet de virtualiser les
+horloges `CLOCK_MONOTONIC` et `CLOCK_BOOTTIME` pour des processus. Cela est
+particulièrement utile pour la migration de conteneurs ou pour tester des
+applications sensibles au temps.
+
+::::: {.warning}
+
+Contrairement à ce que son nom pourrait suggérer, le *namespace* `time` ne
+permet **pas** de virtualiser l'heure système (l'horloge temps réel). Il ne
+virtualise que les compteurs monotones.
+
+:::::
+
+
+### Utilisation pratique
+
+Voyons comment utiliser le *namespace* `time` pour modifier le temps
+d'exécution perçu par un processus.
+
+
+#### Lire les horloges monotones\
+
+Commençons par observer les valeurs actuelles de nos horloges :
+
+
+```bash
+42sh$ cat /proc/uptime
+123456.78 987654.32
+```
+
+
+Le premier nombre représente le temps depuis le démarrage du système (équivalent
+à `CLOCK_BOOTTIME`), et le second le temps CPU cumulé en mode idle.
+
+On peut également utiliser un petit programme C pour afficher les horloges :
+
+
+```c
+#include
+#include
+
+int main(void)
+{
+ struct timespec ts;
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ printf("CLOCK_MONOTONIC: %ld.%09ld\n", ts.tv_sec, ts.tv_nsec);
+
+ clock_gettime(CLOCK_BOOTTIME, &ts);
+ printf("CLOCK_BOOTTIME: %ld.%09ld\n", ts.tv_sec, ts.tv_nsec);
+
+ return 0;
+}
+```
+
+
+::::: {.code}
+
+Pour compiler ce programme :
+
+
+```bash
+42sh$ gcc -o show_clocks show_clocks.c
+```
+
+
+:::::
+
+
+#### Créer un *namespace* `time` avec décalage\
+
+Pour créer un nouveau *namespace* `time`, il faut d'abord le dissocier puis
+configurer les décalages (offsets) avant de lancer un processus enfant.
+
+Le fichier `/proc/
/timens_offsets` permet de configurer les décalages pour
+les horloges. Le format est le suivant :
+
+
+```
+
+```
+
+
+Où `` peut être :
+- `monotonic` pour `CLOCK_MONOTONIC`
+- `boottime` pour `CLOCK_BOOTTIME`
+
+Voici un script shell pour créer un conteneur avec un temps décalé de 10 jours
+dans le futur :
+
+
+```bash
+42sh# unshare --time /bin/bash
+ intimens# echo "monotonic 864000 0" > /proc/self/timens_offsets
+ intimens# echo "boottime 864000 0" > /proc/self/timens_offsets
+ intimens# exec /bin/bash
+ intimens-child# ./show_clocks
+ CLOCK_MONOTONIC: 987654.123456789
+ CLOCK_BOOTTIME: 987654.123456789
+```
+
+
+::::: {.warning}
+
+**Important :** Les décalages doivent être configurés **avant** de créer le
+premier processus enfant. Une fois qu'un processus enfant existe dans le
+*namespace*, les offsets ne peuvent plus être modifiés. C'est pourquoi nous
+utilisons `exec` pour remplacer le shell actuel.
+
+:::::
+
+
+#### Exemple en C\
+
+Voici un exemple complet en C pour créer un *namespace* `time` avec un décalage :
+
+
+```c
+#define _GNU_SOURCE
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static int child_func(void *arg)
+{
+ struct timespec ts;
+
+ // Attendre que le parent configure les offsets
+ sleep(1);
+
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ printf("Child - CLOCK_MONOTONIC: %ld.%09ld\n",
+ ts.tv_sec, ts.tv_nsec);
+
+ clock_gettime(CLOCK_BOOTTIME, &ts);
+ printf("Child - CLOCK_BOOTTIME: %ld.%09ld\n",
+ ts.tv_sec, ts.tv_nsec);
+
+ return 0;
+}
+
+#define STACK_SIZE (1024 * 1024)
+static char child_stack[STACK_SIZE];
+
+int main(void)
+{
+ pid_t pid;
+ int fd;
+ char path[256];
+ struct timespec ts;
+
+ // Afficher les horloges du parent
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ printf("Parent - CLOCK_MONOTONIC: %ld.%09ld\n",
+ ts.tv_sec, ts.tv_nsec);
+
+ // Se dissocier du namespace time
+ if (unshare(CLONE_NEWTIME) == -1) {
+ perror("unshare");
+ exit(EXIT_FAILURE);
+ }
+
+ // Configurer les offsets (décalage de 1000 secondes)
+ fd = open("/proc/self/timens_offsets", O_WRONLY);
+ if (fd == -1) {
+ perror("open timens_offsets");
+ exit(EXIT_FAILURE);
+ }
+
+ if (write(fd, "monotonic 1000 0\n", 17) != 17) {
+ perror("write monotonic offset");
+ exit(EXIT_FAILURE);
+ }
+
+ if (write(fd, "boottime 1000 0\n", 16) != 16) {
+ perror("write boottime offset");
+ exit(EXIT_FAILURE);
+ }
+
+ close(fd);
+
+ // Créer un processus enfant qui verra les nouvelles horloges
+ pid = clone(child_func, child_stack + STACK_SIZE,
+ SIGCHLD, NULL);
+ if (pid == -1) {
+ perror("clone");
+ exit(EXIT_FAILURE);
+ }
+
+ waitpid(pid, NULL, 0);
+
+ return 0;
+}
+```
+
+
+::::: {.code}
+
+Pour compiler :
+
+
+```bash
+42sh$ gcc -o time_ns_demo time_ns_demo.c
+42sh$ ./time_ns_demo
+Parent - CLOCK_MONOTONIC: 123456.789012345
+Child - CLOCK_MONOTONIC: 124456.789012345
+Child - CLOCK_BOOTTIME: 124456.789012345
+```
+
+
+On voit bien le décalage de 1000 secondes entre le parent et l'enfant.
+
+:::::
+
+
+### Cas d'usage pratiques
+
+#### Migration de conteneurs\
+
+Lors de la migration d'un conteneur d'une machine à une autre, les processus
+peuvent avoir des timers ou des alarmes basées sur `CLOCK_MONOTONIC`. Si on ne
+virtualise pas ces horloges, tous ces timers seraient incorrects après la
+migration.
+
+Le *namespace* `time` permet de restaurer l'état des horloges monotones lors
+de la restauration d'un conteneur.
+
+
+#### Tests et simulation\
+
+Pour tester des applications qui utilisent des timeouts ou des mécanismes de
+retry avec backoff exponentiel, il peut être utile de virtualiser le temps pour
+accélérer les tests sans modifier le code de l'application.
+
+
+### Limitations
+
+- Seules les horloges `CLOCK_MONOTONIC` et `CLOCK_BOOTTIME` peuvent être
+ virtualisées
+- L'heure système (`CLOCK_REALTIME`) reste identique pour tous les processus
+- Les offsets ne peuvent être configurés qu'une seule fois, avant la création
+ du premier processus enfant
+- Les décalages ne peuvent pas être négatifs (on ne peut pas remonter dans le
+ temps)
+
+
+### Aller plus loin {-}
+
+Pour plus d'informations sur le *namespace* `time`, consultez :
+
+- `time_namespaces(7)` - page de manuel
+- [Time Namespace support](https://lwn.net/Articles/766089/) :
+- [Checkpoint/Restore and Time Namespace](https://lwn.net/Articles/801652/) :