128 lines
2.9 KiB
Markdown
128 lines
2.9 KiB
Markdown
#### Exemple C {-}
|
||
\
|
||
Voici un exemple de code C utilisant `setns(2)` :
|
||
|
||
<div lang="en-US">
|
||
```c
|
||
#define _GNU_SOURCE
|
||
#include <fcntl.h>
|
||
#include <sched.h>
|
||
#include <stdlib.h>
|
||
|
||
// ./a.out /proc/PID/ns/FILE cmd args...
|
||
|
||
int
|
||
main(int argc, char *argv[])
|
||
{
|
||
int fd = open(argv[1], O_RDONLY);
|
||
if (fd == -1)
|
||
{
|
||
perror("open");
|
||
return EXIT_FAILURE;
|
||
}
|
||
|
||
if (setns(fd, 0) == -1)
|
||
{
|
||
perror("setns");
|
||
return EXIT_FAILURE;
|
||
}
|
||
|
||
execvp(argv[2], &argv[2]);
|
||
|
||
perror("execve");
|
||
return EXIT_FAILURE;
|
||
}
|
||
```
|
||
</div>
|
||
|
||
Ce programme prend au minimum deux arguments :
|
||
- le chemin d'un fichier d'espace de nom que l'on souhaite rejoindre (le chemin
|
||
vers le lien symbolique donc) ;
|
||
- le programme (et ses arguments) que l'on souhaite souhaite exécuter une fois
|
||
que l'on a rejoint l'espace de noms ciblé.
|
||
|
||
Dans un premier temps, on ouvre le fichier passé en paramètre afin d'obtenir un
|
||
*file descriptor* de la structure du noyau.
|
||
|
||
On passe ensuite ce *file descriptor* en argument de l'appel système
|
||
`setns(2)`. Et enfin on exécute la commande données dans les derniers
|
||
paramètres.
|
||
|
||
::::: {.question}
|
||
|
||
#### Qu'attend le deuxième argument de `setns(2)` ? {-}
|
||
\
|
||
|
||
Il s'agit d'une contrainte sur le type d'espace de nom que l'on souhaite
|
||
rejoindre, dans le cas où on ne souhaite pas rejoindre n'importe quel espace de
|
||
nom.
|
||
|
||
Une fois encore, on utilisera les mêmes options `CLONE_NEW*` lorsque l'on
|
||
attendra un type particulier d'espace de nom, ou 0 pour autoriser tous les
|
||
types.
|
||
|
||
:::::
|
||
|
||
|
||
::::: {.question}
|
||
|
||
#### Peut-on connaître le type de *namespace* à partir du *file descriptor* ? {-}
|
||
\
|
||
|
||
Il est possible de récupérer le type d'espace de nom en passant notre *file
|
||
descriptor* à `ioctl(2)`, avec le *flag* `NS_GET_NSTYPE` :
|
||
|
||
<div lang="en-US">
|
||
```c
|
||
nstype = ioctl(fd, NS_GET_NSTYPE);
|
||
if (nstype & CLONE_NEWUTS != 0) {
|
||
... // This is a file descriptor to an UTS namespace
|
||
}
|
||
```
|
||
</div>
|
||
|
||
:::::
|
||
|
||
|
||
#### Exemple shell {-}
|
||
\
|
||
Dans un shell, nous utiliserons la commande `nsenter(1)` :
|
||
|
||
<div lang="en-US">
|
||
```bash
|
||
42sh# unshare --uts /bin/bash
|
||
inutsns# echo $$
|
||
42
|
||
inutsns# hostname jument
|
||
# Keep this shell active to perform nexts steps, in another shell.
|
||
|
||
42sh# hostname
|
||
chaton
|
||
42sh# nsenter --uts=/proc/42/ns/uts /bin/bash
|
||
inutsns# hostname
|
||
jument
|
||
```
|
||
</div>
|
||
|
||
Avec `nsenter(1)`, il est possible de cibler un processus particulier, sans
|
||
aller nécessairement faire référence aux fichiers de `/proc`, en utilisant
|
||
l'option `--target` :
|
||
|
||
<div lang="en-US">
|
||
```bash
|
||
42sh# unshare --uts /bin/bash
|
||
inutsns# echo $$
|
||
42
|
||
inutsns# hostname jument
|
||
# Keep this shell active to perform nexts steps, in another shell.
|
||
|
||
42sh# hostname
|
||
chaton
|
||
42sh# nsenter --target 42 --uts /bin/bash
|
||
inutsns# hostname
|
||
jument
|
||
```
|
||
</div>
|
||
|
||
Les options supplémentaires `--uts`, `--mount`, `--ipc`, `--pid`, ... ne prennent alors pas d'argument, mais désignent les espaces de noms du processus ciblé que l'on souhaite rejoindre.
|