Add content for missing namespaces
This commit is contained in:
parent
ab3341bc54
commit
822dc619b8
7 changed files with 1650 additions and 6 deletions
514
tutorial/4/ipcns.md
Normal file
514
tutorial/4/ipcns.md
Normal file
|
|
@ -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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```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
|
||||
```
|
||||
</div>
|
||||
|
||||
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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```c
|
||||
// ipc_create.c
|
||||
#include <stdio.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
||||
```
|
||||
</div>
|
||||
|
||||
::::: {.code}
|
||||
|
||||
Compilation et exécution :
|
||||
|
||||
<div lang="en-US">
|
||||
```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
|
||||
```
|
||||
</div>
|
||||
|
||||
:::::
|
||||
|
||||
|
||||
#### S'isoler dans un nouveau *namespace* IPC\
|
||||
|
||||
Maintenant, créons un nouveau *namespace* IPC :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh$ unshare --ipc /bin/bash
|
||||
inipcns$ ipcs -q
|
||||
------ Message Queues --------
|
||||
key msqid owner perms used-bytes messages
|
||||
```
|
||||
</div>
|
||||
|
||||
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* :
|
||||
|
||||
<div lang="en-US">
|
||||
```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
|
||||
```
|
||||
</div>
|
||||
|
||||
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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```c
|
||||
// ipc_send.c
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
||||
```
|
||||
</div>
|
||||
|
||||
<div lang="en-US">
|
||||
```c
|
||||
// ipc_receive.c
|
||||
#include <stdio.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/msg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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;
|
||||
}
|
||||
```
|
||||
</div>
|
||||
|
||||
::::: {.code}
|
||||
|
||||
Compilation :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh$ gcc -o ipc_send ipc_send.c
|
||||
42sh$ gcc -o ipc_receive ipc_receive.c
|
||||
```
|
||||
</div>
|
||||
|
||||
Test dans le même *namespace* :
|
||||
|
||||
<div lang="en-US">
|
||||
```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
|
||||
```
|
||||
</div>
|
||||
|
||||
:::::
|
||||
|
||||
|
||||
#### Isolation entre *namespaces*\
|
||||
|
||||
Maintenant, testons avec deux *namespaces* IPC différents :
|
||||
|
||||
<div lang="en-US">
|
||||
```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
|
||||
```
|
||||
</div>
|
||||
|
||||
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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```c
|
||||
// shm_demo.c
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
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;
|
||||
}
|
||||
```
|
||||
</div>
|
||||
|
||||
::::: {.code}
|
||||
|
||||
Compilation et test :
|
||||
|
||||
<div lang="en-US">
|
||||
```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 !
|
||||
```
|
||||
</div>
|
||||
|
||||
:::::
|
||||
|
||||
|
||||
### Files de messages POSIX
|
||||
|
||||
Le *namespace* IPC isole également les files de messages POSIX (qui sont
|
||||
différentes des files System V) :
|
||||
|
||||
<div lang="en-US">
|
||||
```c
|
||||
// mqueue_demo.c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <mqueue.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
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;
|
||||
}
|
||||
```
|
||||
</div>
|
||||
|
||||
::::: {.code}
|
||||
|
||||
Pour compiler (nécessite la bibliothèque `librt`) :
|
||||
|
||||
<div lang="en-US">
|
||||
```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
|
||||
```
|
||||
</div>
|
||||
|
||||
Les files de messages POSIX peuvent être listées dans `/dev/mqueue/` :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh$ ls -l /dev/mqueue/
|
||||
total 0
|
||||
-rw-r--r-- 1 alice alice 80 Nov 15 10:30 myqueue
|
||||
```
|
||||
</div>
|
||||
|
||||
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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
42sh# unshare --ipc --pid --mount --fork --mount-proc /bin/bash
|
||||
incontainer# # Conteneur isolé avec IPC, PID et mount namespaces
|
||||
```
|
||||
</div>
|
||||
|
||||
|
||||
### 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 :
|
||||
|
||||
<div lang="en-US">
|
||||
```bash
|
||||
# Supprimer une file de messages
|
||||
42sh$ ipcrm -q <msqid>
|
||||
|
||||
# Supprimer un segment de mémoire partagée
|
||||
42sh$ ipcrm -m <shmid>
|
||||
|
||||
# Supprimer un sémaphore
|
||||
42sh$ ipcrm -s <semid>
|
||||
|
||||
# Ou supprimer par clé
|
||||
42sh$ ipcrm -Q 0x41000001
|
||||
```
|
||||
</div>
|
||||
|
||||
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
|
||||
Loading…
Add table
Add a link
Reference in a new issue