virli/tutorial/4/setns-samples.md

2.9 KiB

Exemple C {-}


Voici un exemple de code C utilisant setns(2) :

```c #define _GNU_SOURCE #include #include #include

// ./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
}

:::::

Exemple shell {-}


Dans un shell, nous utiliserons la commande nsenter(1) :

```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

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.