Skip to content
/linux-syscalls

Sécurité & Identifiants · Section 2

seccomp(2)

Installe un filtre d'appels système basé sur BPF pour le thread appelant — la colonne vertébrale du sandboxing de conteneurs sous Linux.

Signature

#include <linux/seccomp.h>
#include <sys/syscall.h>

int seccomp(unsigned int operation, unsigned int flags, void * args);
operation
SECCOMP_SET_MODE_STRICT, SECCOMP_SET_MODE_FILTER, SECCOMP_GET_ACTION_AVAIL, ou SECCOMP_GET_NOTIF_SIZES.
flags
Propre à l'opération. Pour SET_MODE_FILTER : TSYNC (appliquer à tous les threads), LOG, SPEC_ALLOW (sauter les atténuations de canal auxiliaire pour filtres de confiance), NEW_LISTENER (retourner le fd de notif), TSYNC_ESRCH.
args
Propre à l'opération. Pour SET_MODE_FILTER, pointeur sur une struct sock_fprog décrivant le programme BPF.

Description

seccomp() configure la fonctionnalité secure-computing du noyau pour le thread appelant (et, avec TSYNC, tous les threads du processus). Deux opérations principales : SECCOMP_SET_MODE_STRICT restreint le thread à read(), write(), _exit() et sigreturn() — un mini bac à sable suffisant pour des sandboxes de type puzzle mais inutilisable pour de vraies charges. SECCOMP_SET_MODE_FILTER installe un programme classic-BPF ; à chaque appel système suivant le programme est exécuté avec seccomp_data (arch, nr, args) en entrée, et sa valeur de retour choisit une action : autoriser, renvoyer un errno, tuer le thread/processus, trap vers SIGSYS, journaliser, ou notifier un superviseur userspace (RET_USER_NOTIF, la primitive de gVisor). Les filtres sont write-once : une fois installés, ils peuvent être durcis (un filtre enfant est ANDé avec le parent) mais jamais relâchés. Avec SECCOMP_FILTER_FLAG_NEW_LISTENER, l'installation retourne un fd d'écoute qu'un processus superviseur peut lire pour les événements de notification.

Numéros par architecture

ArchitectureNuméroABIPoint d'entrée
x86 (i386)354i386sys_seccomp
x64 (x86_64)317commonsys_seccomp
ARM64 (aarch64)277—sys_seccomp

Historique noyau

Introduit dans Linux 3.17.

  1. 2.6.12

    Le mode strict (read/write/exit/sigreturn seulement) est arrivé — le seccomp originel, utile pour de petits bacs à sable type privsep vsftpd mais insuffisant pour les charges générales.

  2. 3.5

    Le mode filtre (piloté par BPF) a été ajouté, permettant le sandbox renderer de Chromium et l'écosystème conteneur moderne. Le noyau exécute le filtre à chaque syscall ; le vérifieur BPF garantit la terminaison.

  3. 3.17

    L'appel système seccomp() a été ajouté (Linux 3.17) pour installer les filtres sans passer par prctl() ; il a aussi introduit SECCOMP_FILTER_FLAG_TSYNC, corrigeant le piège historique « chaque thread doit installer son propre filtre ».

  4. 5.0

    RET_USER_NOTIF et le mécanisme du fd d'écoute ont été ajoutés (Linux 5.0), permettant aux superviseurs userspace d'intercepter et d'émuler des syscalls — fondation de l'implémentation d'appels de gVisor et une primitive majeure de sandboxing.

  5. 5.5

    La notif userspace a gagné SECCOMP_IOCTL_NOTIF_ADDFD pour injecter un descripteur dans le processus cible depuis le handler du superviseur — comblant le dernier gros manque qui empêchait les émulateurs syscall basés seccomp de traiter proprement les appels retournant un fd.

seccomp & conteneurs

Docker default profile

Autorisé

Podman default profile

Autorisé

seccomp() est autorisé par Docker / Podman par défaut car chaque init de conteneur qui installe son propre filtre en a besoin. Le bloquer n'a de sens que pour des charges qui ne devraient pas installer de bac à sable supplémentaire — rarement utile en pratique car un filtre externe ne peut être relâché par un interne. Le filtrage d'arguments sur le code d'opération (n'autoriser que SECCOMP_SET_MODE_FILTER, refuser GET_*) est rarement intéressant.

libseccomp

// Allow seccomp() itself only for SECCOMP_SET_MODE_FILTER
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(seccomp),
    1, SCMP_A0(SCMP_CMP_EQ, SECCOMP_SET_MODE_FILTER));

Exemple strace

$ strace -e seccomp,prctl docker run --rm alpine:3 echo hi 2>&1 | grep -E 'prctl|seccomp' | head -5
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)  = 0
seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_TSYNC, {len=…, filter=0x…}) = 0

seccomp() dans strace apparaît généralement une fois par processus au démarrage, immédiatement après un prctl(PR_SET_NO_NEW_PRIVS). La longueur du programme BPF et son pointeur sont affichés ; -e seccomp filtre. Un seccomp() répété en cours d'exécution est inhabituel — à investiguer.

Sécurité & observabilité

seccomp() est lui-même la primitive principale de sandboxing au niveau appel système sous Linux — colonne vertébrale du profil par défaut Docker, du renderer Chromium, du privsep OpenSSH, du SystemCallFilter= systemd, et de l'interception syscall de gVisor. Les CVE dans l'implémentation seccomp sont rares mais dévastatrices (CVE-2019-5736 est orthogonale mais illustre le rayon de souffle). Pour la chasse, un appel seccomp() inattendu d'une charge qui devrait déjà tourner sous un filtre installé est rare mais mérite attention — la plupart des tentatives par des malwares visent à installer un filtre interceptant les hooks AV/EDR. Le tracepoint eBPF sys_enter_seccomp capture chaque appel. De l'intérieur, /proc/<pid>/status ligne Seccomp: affiche le mode (0=désactivé, 1=strict, 2=filtre).

Erreurs

EACCES
SECCOMP_SET_MODE_FILTER appelé sans PR_SET_NO_NEW_PRIVS et sans CAP_SYS_ADMIN — verrou de sûreté empêchant un appelant non privilégié de contourner la sémantique set-UID en filtrant execve.
EFAULT
—
EINVAL
Mauvaise opération, drapeau inconnu, programme BPF malformé, ou rejeté par le vérifieur (sauts hors plage…).
ENOMEM
Programme trop volumineux ou mémoire noyau épuisée pour le stockage du filtre.
ENOSYS
—
EOPNOTSUPP
—

Drapeaux

SECCOMP_SET_MODE_STRICT
0
—
SECCOMP_SET_MODE_FILTER
1
Installe un programme BPF. Requiert soit CAP_SYS_ADMIN, soit PR_SET_NO_NEW_PRIVS positionné au préalable.
SECCOMP_GET_ACTION_AVAIL
2
—
SECCOMP_GET_NOTIF_SIZES
3
—
SECCOMP_FILTER_FLAG_TSYNC
0x1
Après installation, synchronise le filtre vers tous les autres threads du processus. Sans TSYNC, seul le thread appelant est filtré (bug fréquent des bacs à sable maison).
SECCOMP_FILTER_FLAG_LOG
0x2
—
SECCOMP_FILTER_FLAG_SPEC_ALLOW
0x4
—
SECCOMP_FILTER_FLAG_NEW_LISTENER
0x8
Retourne un fd d'écoute qu'un parent/superviseur peut utiliser pour traiter les syscalls RET_USER_NOTIF — le motif d'interception gVisor / nsjail.
SECCOMP_FILTER_FLAG_TSYNC_ESRCH
0x10
—
SECCOMP_RET_KILL_PROCESS
0x80000000
Tue tout le groupe de threads sur un appel correspondant. Action la plus forte ; préférée en durcissement production.
SECCOMP_RET_KILL_THREAD
0x00000000
—
SECCOMP_RET_TRAP
0x00030000
—
SECCOMP_RET_ERRNO
0x00050000
—
SECCOMP_RET_USER_NOTIF
0x7fc00000
Bloque l'appel et le délivre à un superviseur userspace via le fd d'écoute. Le superviseur inspecte, décide et répond avec une valeur de retour. Utilisé par gVisor.
SECCOMP_RET_TRACE
0x7ff00000
—
SECCOMP_RET_LOG
0x7ffc0000
—
SECCOMP_RET_ALLOW
0x7fff0000
—

Syscalls liés