virli/tutorial/3/seccomp.md

94 lines
3.1 KiB
Markdown
Raw Normal View History

2018-10-31 08:41:27 +00:00
Secure Computing Mode
---------------------
2018-10-31 08:41:27 +00:00
Plus connue sous l'acronyme *seccomp*, cette fonctionnalité du noyau Linux
2022-10-18 14:40:31 +00:00
permet de restreindre les appels système qu'un processus est autorisé à
2018-10-31 08:41:27 +00:00
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
2022-02-24 19:43:43 +00:00
d'appels système ; à l'inverse des politiques de sécurité comme SELinux ou
2018-10-31 08:41:27 +00:00
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
2022-02-24 19:43:43 +00:00
de code promptes aux vulnérabilités : c'est notamment le cas des moteurs de
2018-10-31 08:41:27 +00:00
rendus des navigateurs Firefox et Chrome.
### Prérequis
2018-10-31 08:41:27 +00:00
L'utilisation de `seccomp` nécessite d'avoir un noyau compilé avec l'option
`CONFIG_SECCOMP`.
La bibliothèque `libseccomp` est également indispensable car l'appel système
2018-10-31 08:41:27 +00:00
`seccomp(2)` n'a pas de *wrapper* dans la libc, vous devrez donc passer par
cette bibliothèque.
### `MODE_STRICT`
2018-10-31 08:41:27 +00:00
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
2022-02-24 19:43:43 +00:00
ce mode via :
2018-10-31 08:41:27 +00:00
<div lang="en-US">
```c
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
2018-10-31 08:41:27 +00:00
```
</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`
2018-10-31 08:41:27 +00:00
Plus modulable que le mode strict, le mode de filtrage permet une grande
amplitude en permettant au programmeur de définir finement quels appels
2022-10-18 14:40:31 +00:00
système le programme est autorisé à faire ou non, et quelle sentence est
2018-10-31 08:41:27 +00:00
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.
2021-10-05 15:23:09 +00:00
La construction de ce filtre est faite de manière programmatique, via
2018-10-31 08:41:27 +00:00
des règles BPF (`Berkeley Packet Filter`). On passe ensuite ce filtre BPF en
2022-02-24 19:43:43 +00:00
argument de l'appel système :
2018-10-31 08:41:27 +00:00
<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);
2018-10-31 08:41:27 +00:00
```
</div>
::::: {.exercice}
2018-10-31 08:41:27 +00:00
2022-02-24 19:43:43 +00:00
Écrivez un programme filtrant un appel système, à l'aide de `seccomp` :
2018-10-31 08:41:27 +00:00
<div lang="en-US">
```
42sh$ ./syscall_filter sleep 5
sleep: cannot read realtime clock: Operation not permitted
42sh$
2018-10-31 08:41:27 +00:00
```
</div>
2022-10-18 14:40:31 +00:00
Dans cet exemple, l'appel système filtré est `nanosleep(2)` (on
utilise `strace(2)` pour le découvrir).
:::::