virli/tutorial/3/seccomp.md

3.1 KiB

Secure Computing Mode

Plus connue sous l'acronyme seccomp, cette fonctionnalité du noyau Linux permet de restreindre les appels système qu'un processus est autorisé à 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 d'appels système ; à l'inverse des politiques de sécurité comme SELinux ou 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 de code promptes aux vulnérabilités : c'est notamment le cas des moteurs de rendus des navigateurs Firefox et Chrome.

Prérequis

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 seccomp(2) n'a pas de wrapper dans la libc, vous devrez donc passer par cette bibliothèque.

MODE_STRICT

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 ce mode via :

```c prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT); ```

Une fois passé cet appel système, toute entrée dans un appel système non autorisé conduit à un SIGKILL du processus.

MODE_FILTER

Plus modulable que le mode strict, le mode de filtrage permet une grande amplitude en permettant au programmeur de définir finement quels appels système le programme est autorisé à faire ou non, et quelle sentence est 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.

La construction de ce filtre est faite de manière programmatique, via des règles BPF (Berkeley Packet Filter). On passe ensuite ce filtre BPF en argument de l'appel système :

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

::::: {.exercice}

Écrivez un programme filtrant un appel système, à l'aide de seccomp :

``` 42sh$ ./syscall_filter sleep 5 sleep: cannot read realtime clock: Operation not permitted 42sh$ ```

Dans cet exemple, l'appel système filtré est nanosleep(2) (on utilise strace(2) pour le découvrir).

:::::