seccomp
Table des matières
Retour à l'index
NOM
seccomp - Agir sur l'état de calcul sécurisé (Secure Computing State) du
processus
BIBLIOTHÈQUE
Bibliothèque C standard (libc, -lc)
SYNOPSIS
#include <linux/seccomp.h> /* Définition des constantes SECCOMP_* */
#include <linux/filter.h> /* Définition de struct sock_fprog */
#include <linux/audit.h> /* Définition des constantes AUDIT_* */
#include <linux/signal.h> /* Définition des constantes SIG* */
#include <sys/ptrace.h> /* Définition des constantes PTRACE_* */
#include <sys/syscall.h> /* Définition des constantes SYS_* */
#include <unistd.h>
int syscall(SYS_seccomp, unsigned int opération, unsigned int flags,
void *args);
Remarque : la glibc ne fournit pas d'enveloppe pour seccomp(),
imposant l'utilisation de syscall(2).
DESCRIPTION
L'appel système seccomp() agit sur l'état de calcul sécurisé (seccomp) du
processus appelant.
Actuellement, Linux gère les valeurs d'opération suivantes :
- SECCOMP_SET_MODE_STRICT
-
Les seuls appels système que le thread appelant est autorisé à faire sont
read(2), write(2), _exit(2) (mais pas exit_group(2)) et
sigreturn(2). Les autres appels système aboutissent à la fin du thread
appelant ou à la fin du processus complet avec le signal SIGKILL quand il
n'y a qu'un seul thread. Le mode de calcul sécurisé strict est utile pour
les applications de traitement de nombres qui peuvent avoir besoin
d'exécuter un code à octets non fiable, obtenu peut-être en lisant un tube
ou un socket.
-
Remarquez que si le thread appelant ne peut plus appeler sigprocmask(2),
il peut utiliser sigreturn(2) pour bloquer tous les signaux, sauf ceux
provenant de SIGKILL et de SIGSTOP. Cela veut dire que alarm(2)
(par exemple) n'est pas suffisant pour restreindre la durée d'exécution d'un
processus. Pour terminer de manière fiable un processus, SIGKILL doit
être utilisé. On peut le faire en utilisant timer_create(2) avec
SIGEV_SIGNAL et sigev_signo positionné à SIGKILL ou en utilisant
setrlimit(2) pour positionner la limite ferme de RLIMIT_CPU.
-
Cette fonctionnalité n'est disponible que si le noyau a été construit avec
l'option CONFIG_SECCOMP activée.
-
La valeur de flags doit être de 0 et args doit être NULL.
-
Cette opération est fonctionnellement identique à l'appel :
-
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
- SECCOMP_SET_MODE_FILTER
-
Les appels système autorisés sont définis par un pointeur vers un filtre
Berkeley Packet (BPF) fourni à l'aide de args. Ce paramètre est un
pointeur vers une struct sock_fprog ; il peut être conçu pour filtrer
des appels système de votre choix ainsi que des paramètres d'appel
système. Si le filtre n'est pas valable, seccomp() échoue en renvoyant
EINVAL dans errno.
-
Si fork(2) ou clone(2) est autorisé par le filtre, les processus
enfant seront contraints par les mêmes filtres d'appel système que leur
parent. Si execve(2) est autorisé, les filtres existants seront préservés
lors d'un appel à execve(2).
-
Pour utiliser l'opération SECCOMP_SET_MODE_FILTER, soit le thread
appelant doit avoir la capacité CAP_SYS_ADMIN dans son espace de noms
utilisateur, soit il doit avoir déjà le bit no_new_privs défini. Si ce
bit n'a pas déjà été positionné par un ascendant du thread, le thread doit
effectuer l'appel suivant :
-
prctl(PR_SET_NO_NEW_PRIVS, 1);
-
Sinon, l'opération SECCOMP_SET_MODE_FILTER échoue et renvoie EACCES
dans errno. Cette exigence garantit qu'un processus non privilégié ne
peut pas appliquer un filtre malveillant et appeler un programme set-user-ID
ou avec d'autres privilèges en utilisant execve(2), compromettant ainsi
le programme (un tel filtre malveillant pourrait, par exemple, conduire
setuid(2) à essayer de définir les identifiants utilisateur de l'appelant
à des valeurs non nulles pour renvoyer plutôt 0 sans faire d'appel
système. Ainsi, le programme pourrait être bidouillé pour garder les
privilèges du super-utilisateur à des moments où il est possible de
l'influencer pour faire des choses dangereuses vu qu'il n'a pas abandonné
ses privilèges).
-
Si prctl(2) ou seccomp() est autorisé par le filtre rattaché, d'autres
filtres peuvent être ajoutés. Cela augmentera le temps d'évaluation mais
permet d'autres réductions de la surface d'attaque lors de l'exécution d'un
thread.
-
L'opération SECCOMP_SET_MODE_FILTER n'est disponible que si le noyau a
été configuré avec CONFIG_SECCOMP_FILTER.
-
Quand flags vaut 0, cette opération est fonctionnellement identique à
l'appel :
-
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, args);
-
Les paramètres reconnus de flags sont :
-
- SECCOMP_FILTER_FLAG_LOG (depuis Linux 4.14)
-
Toutes les actions de renvoi des filtres, sauf SECCOMP_RET_ALLOW, doivent
être journalisées. Un administrateur peut outrepasser cet attribut de filtre
en empêchant des actions spécifiques d'être journalisées à l'aide du fichier
/proc/sys/kernel/seccomp/actions_logged.
- SECCOMP_FILTER_FLAG_NEW_LISTENER (depuis Linux 5.0)
-
Après une installation réussie du programme de filtrage, renvoyer un nouveau
descripteur de fichier de notification pour l'espace
utilisateur. (L'attribut close-on-exec est défini pour le descripteur de
fichier.) Quand le filtre renvoie SECCOMP_RET_USER_NOTIF, une
notification sera envoyée à ce descripteur de fichier.
-
Pour un thread, au maximum un seul filtre de seccomp utilisant l'attribut
SECCOMP_FILTER_FLAG_NEW_LISTENER peut être installé.
-
Consultez seccomp_unotify(2) pour plus de détails.
- SECCOMP_FILTER_FLAG_SPEC_ALLOW (depuis Linux 4.17)
-
Désactiver la mitigation Speculative Store Bypass.
- SECCOMP_FILTER_FLAG_TSYNC
-
Lors de l'ajout d'un filtre, synchroniser tous les autres threads du
processus appelant avec la même arborescence de filtres seccomp. Une
« arborescence de filtres » est une liste ordonnée de filtres rattachée à un
thread (le rattachement de filtres identiques dans des appels seccomp()
distincts génère différents filtres depuis cette perspective).
-
Si aucun thread ne peut pas se synchroniser avec l'arborescence de filtres,
l'appel ne rattachera pas le nouveau filtre seccomp et échouera en renvoyant
le premier identifiant de thread qui n'a pas pu se synchroniser. La
synchronisation échouera si un autre thread du même processus est en
SECCOMP_MODE_STRICT ou si des nouveaux filtres seccomp lui sont rattachés
en propre, en décalage par rapport à l'arborescence de filtres du thread
appelant.
- SECCOMP_GET_ACTION_AVAIL (depuis Linux 4.14)
-
Tester pour savoir si une action est prise en charge par le noyau. Cette
opération peut aider à confirmer que le noyau connaît l'action de renvoi
d'un filtre récemment ajouté puisque le noyau traite toutes les actions
inconnues comme des SECCOMP_RET_KILL_PROCESS.
-
La valeur de flags doit être de 0 et args doit être un pointeur
vers une action de renvoi de filtre 32 bits non signé.
- SECCOMP_GET_NOTIF_SIZES (depuis Linux 5.O)
-
Obtenir la taille des structures de notification de l'espace utilisateur de
seccomp. Comme ces structures peuvent évoluer et croître avec le temps,
cette commande peut être utilisée pour déterminer quelle quantité de mémoire
allouer pour envoyer et recevoir des notifications.
-
La valeur de flags doit être de 0 et args doit être un pointeur
vers un struct seccomp_notif_sizes de la forme suivante :
-
struct seccomp_notif_sizes
__u16 seccomp_notif; /* Taille de la structure de notification */
__u16 seccomp_notif_resp; /* Taille de la structure de réponse */
__u16 seccomp_data; /* Taille de 'struct seccomp_data' */
};
-
Consultez seccomp_unotify(2) pour plus de détails.
Filtres
Lors de l'ajout d'un filtre à l'aide de SECCOMP_SET_MODE_FILTER, args
pointe vers un programme de filtrage :
struct sock_fprog {
unsigned short len; /* Nombre d'instructions BPF */
struct sock_filter *filter; /* Pointeur vers le tableau
d'instructions BPF */
};
Chaque programme doit contenir une ou plusieurs instructions BPF :
struct sock_filter { /* Filter block */
__u16 code; /* Code du filtre réel */
__u8 jt; /* Jump true (sauter le vrai) */
__u8 jf; /* Jump false (sauter le faux) */
__u32 k; /* Champ générique multiusages */
};
Lors de l'exécution des instructions, le programme BPF agit sur les
informations de l'appel système qui sont rendues disponibles (c'est-à-dire
qu'il utilise le mode d'adressage BPF_ABS) en tant que tampon (en lecture
seule) ayant la forme suivante :
struct seccomp_data {
int nr; /* Numéro de l'appel système */
__u32 arch; /* Valeur AUDIT_ARCH_*
(voir <linux/audit.h>) */
__u64 instruction_pointer; /* pointeur vers l'instruction du processeur */
__u64 args[6]; /* Jusqu'à 6 paramètres de l'appel système */
};
Comme la numérotation des appels système varie entre les architectures et
comme certaines (comme x86-64) autorisent du code de l'espace utilisateur à
utiliser les conventions de l'appelant d'autres architectures (et comme
cette convention peut varier pendant la vie d'un processus qui utilise
execve(2) pour exécuter des binaires qui utilisent différentes
conventions), il est généralement nécessaire de vérifier la valeur du champ
arch.
Il est fortement recommandé d'utiliser une approche par liste
d'autorisations autant que possible, parce qu'une telle approche est plus
robuste et plus simple. Une liste d'interdictions devra être mise à jour à
chaque fois qu'un appel système dangereux sera ajouté (ou un attribut ou une
option si elles font partie de la liste des interdictions) et il est souvent
possible de modifier la représentation d'une valeur sans changer sa
signification, conduisant à contourner la liste d'interdictions. Voir aussi
Mises en garde ci-dessous.
Le champ arch n'est pas unique pour toutes les conventions
d'appelant. Les ABI x86-64 et x32 utilisent AUDIT_ARCH_X86_64 en tant que
arch et elles fonctionnent sur les mêmes processeurs. Au contraire, le
masque __X32_SYSCALL_BIT est utilisé sur le numéro d'appel système pour
parler indépendamment aux deux ABI.
Cela veut dire qu'une politique peut soit interdire tous les appels système
avec __X32_SYSCALL_BIT, soit elle doit les reconnaître avec le
positionnement ou pas de __X32_SYSCALL_BIT. Une liste des appels système
à interdire qui s'appuie sur nr et qui ne contient pas de valeurs nr
où __X32_SYSCALL_BIT est positionné peut être contournée par un programme
malveillant qui positionne __X32_SYSCALL_BIT.
En outre, les noyaux précédant Linux 5.4 autorisaient à tort nr dans les
intervalles 512–547 ainsi que les appels système non x32 correspondants
reliés (opération OU) avec __X32_SYSCALL_BIT. Par exemple, nr == 521
et nr == (101 | __X32_SYSCALL_BIT) créeraient des appels ptrace(2)
avec une sémantique potentiellement confondue entre x32 et x86_64 dans le
noyau. Les politiques prévues pour fonctionner sur des noyaux antérieurs à
Linux 5.4 doivent garantir qu'elles interdisent ou qu'elles gèrent
correctement ces appels système. Sur Linux 5.4 et plus récents, de tels
appels système échoueront avec une erreur ENOSYS sans rien faire.
Le champ instruction_pointer fournit l'adresse de l'instruction en
langage machine qui a effectué l'appel système. Cela pourrait être utile
avec /proc/pid/maps pour effectuer des vérifications à partir de la
région (projection) du programme qui a fait l'appel système (il est
probablement raisonnable de verrouiller les appels système mmap(2) et
mprotect(2) pour empêcher le programme de contourner de telles
vérifications).
Lors de la vérification des valeurs de args, gardez en tête que les
paramètres sont souvent tronqués silencieusement avant d'être traités mais
après la vérification seccomp. Cela arrive par exemple si l'ABI i386 est
utilisée sur un noyau x86-64 : bien que le noyau n'ira normalement pas
regarder au-delà des 32 bits les plus faibles des paramètres, les valeurs
des registres 64 bits complets seront présentes dans les données de
seccomp. Un exemple moins surprenant est que si l'ABI x86-64 est utilisée
pour effectuer un appel système prenant un paramètre de type int, la
moitié du registre du paramètre la plus significative est ignorée par
l'appel système mais visible dans les données de seccomp.
Un filtre seccomp renvoie une valeur 32 bits en deux parties : la plus
significative, de 16 bits (correspondant au masque défini par la constante
SECCOMP_RET_ACTION_FULL), contient une des valeurs « action » listée
ci-dessous ; la moins significative, de 16 bits (définie par la constante
SECCOMP_RET_DATA), contient des « data » à associer à ce code de retour.
Si plusieurs filtres existent, ils sont tous exécutés dans l'ordre
inverse de leur apparition dans l'arbre des filtres – si bien que le filtre
le plus récemment installé est exécuté en premier) (remarquez que tous les
filtres seront appelés même si l'un des premiers appelés renvoie
SECCOMP_RET_KILL, cela pour simplifier le code du noyau et pour fournir
une petite accélération d’exécution d’ensembles de filtres en évitant la
vérification de ce cas rare). La valeur renvoyée de l'évaluation d'un appel
système donné est la première valeur vue de l'action de plus haute priorité
(ainsi que ses données associées) renvoyée par l'exécution de tous les
filtres.
Dans l'ordre décroissant de priorité, les valeurs d'action qui peuvent être
renvoyées par un filtre seccomp sont :
- SECCOMP_RET_KILL_PROCESS (depuis Linux 4.14)
-
Cette valeur aboutit à la fin immédiate du processus, avec un vidage
mémoire. L'appel système n'est pas exécuté. Contrairement à
SECCOMP_RET_KILL_THREAD ci-dessous, tous les threads du groupe de threads
sont terminés (pour un point sur les groupes de thread, voir la description
de l'attribut CLONE_THREAD de clone(2)).
-
Le processus se termine parce que il a été tué par un signal
SIGSYS. Même si un gestionnaire de signal a été enregistré pour
SIGSYS, le gestionnaire sera ignoré dans ce cas et le processus se
termine toujours. Le processus parent qui attend ce processus (en utilisant
waitpid(2) ou équivalent) reçoit wstatus qui indique que son enfant
s'est terminé suite à un signal SIGSYS.
- SECCOMP_RET_KILL_THREAD (ou SECCOMP_RET_KILL)
-
Cette valeur provoque la fin immédiate du thread qui a effectué l'appel
système. L'appel système n'est pas exécuté. Les autres threads du même
groupe de threads continueront à s'exécuter.
-
Le thread s'est terminé comme tué par un signal SIGSYS. Voir
SECCOMP_RET_KILL_PROCESS ci-dessus.
-
Avant Linux 4.11, tout processus qui se terminait de cette manière ne
générait pas de vidage mémoire (bien que SIGSYS soit documenté dans
signal(7) pour avoir comme action par défaut celle de terminer avec un
vidage mémoire). Depuis Linux 4.11, un processus d'un seul thread créera un
vidage mémoire s'il se termine dans ce cadre.
-
Avec l'apparition de SECCOMP_RET_KILL_PROCESS dans Linux 4.14,
SECCOMP_RET_KILL_THREAD a été ajouté comme synonyme de
SECCOMP_RET_KILL, afin de distinguer plus clairement les deux actions.
-
Remarque : l'utilisation de SECCOMP_RET_KILL_THREAD pour tuer un
thread unique d'un processus de plusieurs threads va probablement mettre le
processus dans un état incohérent et corrompre pour toujours son état.
- SECCOMP_RET_TRAP
-
Cette valeur fait envoyer par le noyau un signal SIGSYS adressé au thread
déclencheur (l'appel système n'est pas exécuté). Divers champs seront
positionnés dans la structure siginfo_t (voir sigaction(2)) associée
au signal :
-
- -
-
si_signo contiendra SIGSYS.
- -
-
si_call_addr affichera l'adresse de l'instruction de l'appel système.
- -
-
si_syscall et si_arch indiqueront l'appel système qui a été tenté.
- -
-
si_code contiendra SYS_SECCOMP.
- -
-
si_errno contiendra la partie SECCOMP_RET_DATA du code de retour du
filtre.
-
Le compteur du programme sera arrêté comme si l'appel système a été fait
(c'est-à-dire que le compteur du programme ne pointera pas vers
l'instruction de l'appel système). Le registre du code de retour contiendra
une valeur dépendante de l'architecture ; en cas de relance de l'exécution,
positionnez-la sur quelque chose adapté à l'appel système (la dépendance de
l'architecture provient du fait que son remplacement par ENOSYS
écraserait des informations utiles).
- SECCOMP_RET_ERRNO
-
Cette valeur fait passer la partie SECCOMP_RET_DATA du code de retour du
filtre à l'espace utilisateur en tant que valeur errno sans exécuter
l'appel système.
- SECCOMP_RET_USER_NOTIF (depuis Linux 5.0)
-
Faire suivre l'appel système à un processus de superviseur attaché de
l'espace utilisateur attaché pour permettre à ce processus de décider quoi
faire de l'appel système. Si il n'y a pas de superviseur attaché (soit parce
que le filtre n'a pas été installé avec l'attribut
SECCOMP_FILTER_FLAG_NEW_LISTENER ou parce que le descripteur de fichier
était fermé), le filtre renvoie ENOSYS (c'est similaire à ce qui se
produit quand un filtre renvoie SECCOMP_RET_TRACE et qu'il n'y a pas
d'observateur). Consultez seccomp_unotify(2) pour plus de détails.
-
Remarquez que le processus de superviseur ne sera pas notifié si un autre
filtre renvoie une valeur d'action ayant une priorité supérieure à
SECCOMP_RET_USER_NOTIF.
- SECCOMP_RET_TRACE
-
Quand cette valeur est renvoyée, le noyau essaiera de notifier à un
observateur basé sur ptrace(2) avant d'exécuter l'appel système. Si aucun
observateur n'est présent, l'appel système n'est pas exécuté et renvoie un
échec en positionnant errno sur ENOSYS.
-
Un observateur sera notifié s'il demande PTRACE_O_TRACESECCOMP en
utilisant ptrace(PTRACE_SETOPTIONS). Il sera notifié d'un
PTRACE_EVENT_SECCOMP et la partie SECCOMP_RET_DATA du code de retour
du filtre sera mise à la disposition de l'observateur à l'aide de
PTRACE_GETEVENTMSG.
-
L'observateur peut ignorer l'appel système en modifiant le numéro de l'appel
système à -1. Autrement, l'observateur peut modifier l'appel système
demandé en le passant à un numéro d'appel système valable. Si l'observateur
demande à ignorer l'appel système, ce dernier renverra la valeur que
l'observateur place dans le registre du code de retour.
-
Avant Linux 4.8, la vérification seccomp ne sera pas refaite après que
l'observateur ait reçu une notification (cela signifie que sur les anciens
noyaux, les conteneurs basés sur seccomp ne doivent pas autoriser
l'utilisation de ptrace(2) – même sur d'autres processus encapsulés –
sans une prudence extrême ; les ptracers peuvent utiliser ce mécanisme pour
sortir d'un conteneur seccomp).
-
Remarquez que le processus d'un observateur ne sera pas notifié si un autre
filtre renvoie une valeur d'action ayant une priorité supérieure à
SECCOMP_RET_TRACE.
- SECCOMP_RET_LOG (depuis Linux 4.14)
-
Cette valeur fait exécuter l'appel système après l'enregistrement de
l'action de retour du filtre. Un administrateur peut supplanter la
journalisation de cette action à l'aide du fichier
/proc/sys/kernel/seccomp/actions_logged.
- SECCOMP_RET_ALLOW
-
Cette valeur provoque l'exécution de l'appel système.
Si on indique un code d'action différent de ceux ci-dessus, l'action de
filtre est traitée soit comme un SECCOMP_RET_KILL_PROCESS (depuis
Linux 4.14), soit comme un SECCOMP_RET_KILL_THREAD (dans Linux 4.13 et
antérieurs).
/proc interfaces
Les fichiers du répertoire /proc/sys/kernel/seccomp offrent des
informations et des configurations seccomp supplémentaires :
- actions_avail (depuis Linux 4.14)
-
Une liste ordonnée en lecture seule d'actions de renvoi de filtre seccomp
sous la forme d'une chaîne. L'ordre, de gauche à droite, est décroissant
pour la priorité. La liste représente l'ensemble des actions de renvoi de
filtre seccomp gérées par le noyau.
- actions_logged (depuis Linux 4.14)
-
Une liste ordonnée en lecture-écriture d'actions de renvoi de filtre seccomp
autorisées pour la journalisation. Les écritures dans le fichier n'ont pas
besoin d'être ordonnées, mais les lectures se feront dans le même ordre que
pour actions_avail.
-
Il est important de remarquer que la valeur de actions_logged n'empêche
pas certaines actions de renvoi de filtre d'être enregistrées quand le
sous-système d'audit est configuré pour auditer une tâche. Si l'action n'est
pas retrouvée dans le fichier actions_logged, la décision finale
d'auditer l'action de cette tâche revient au sous-système d'audit pour
toutes les actions de renvoi de filtre autres que SECCOMP_RET_ALLOW.
-
La chaîne « allow » n'est pas acceptée dans le fichier actions_logged car
il n'est pas possible d'enregistrer les actions
SECCOMP_RET_ALLOW. Essayer d'écrire « allow » dans le fichier échouera
avec l'erreur EINVAL.
Enregistrement d'audit des actions seccomp
Depuis Linux 4.14, le noyau offre la possibilité d'enregistrer les actions
renvoyées par des filtres seccomp dans le compte-rendu d'audit. Le noyau
prend la décision d'enregistrer une action à partir du type d'action, de sa
présence dans le fichier actions_logged et de l'activation de l'audit du
noyau (par exemple avec l'option d'amorçage du noyau audit=1). Les règles
sont les suivantes :
- -
-
Si l'action est SECCOMP_RET_ALLOW, l'action n'est pas enregistrée.
- -
-
Sinon, si l'action est SECCOMP_RET_KILL_PROCESS ou
SECCOMP_RET_KILL_THREAD et si elle apparaît dans le fichier
actions_logged, l'action est enregistrée.
- -
-
Sinon, si le filtre a demandé l'enregistrement (l'attribut
SECCOMP_FILTER_FLAG_LOG) et si elle apparaît dans le fichier
actions_logged, l'action est enregistrée.
- -
-
Sinon, si l'audit du noyau est activé et si le processus doit être audité
(autrace(8)), l'action est enregistrée.
- -
-
Sinon, l'action n'est pas enregistrée.
VALEUR RENVOYÉE
En cas de succès, seccomp() renvoie 0. En cas d'erreur, si
SECCOMP_FILTER_FLAG_TSYNC a été utilisé, le code de retour est
l'identifiant du thread à l'origine de l'échec de la synchronisation (cet
identifiant est un identifiant de thread du noyau du type renvoyé par
clone(2) et gettid(2)). Si une autre erreur arrive, -1 est renvoyé
et errno est positionné pour indiquer l'erreur.
ERREURS
seccomp() peut échouer pour les raisons suivantes :
- EACCES
-
L'appelant n'avait pas la capacité CAP_SYS_ADMIN dans son espace de noms
utilisateur ou n'avait pas positionné no_new_privs avant d'utiliser
SECCOMP_SET_MODE_FILTER.
- EBUSY
-
Pendant l'installation d'un nouveau filtre, l'attribut
SECCOMP_FILTER_FLAG_NEW_LISTENER a été indiqué, mais un filtre précédent
a déjà été installé avec cet attribut.
- EFAULT
-
args n'était pas une adresse valable.
- EINVAL
-
L'opération est inconnue ou n'est pas prise en charge par cette version
ou cette configuration du noyau.
- EINVAL
-
Les flags spécifiés ne sont pas valables pour l'opération donnée.
- EINVAL
-
L'opération comprenait BPF_ABS, mais la position indiquée n'était pas
alignée sur une limite 32 bits ou elle dépassait sizeof(struct seccomp_data).
- EINVAL
-
Un mode de calcul sécurisé a déjà été défini et l'opération diffère du
paramétrage existant.
- EINVAL
-
opération indiquait SECCOMP_SET_MODE_FILTER mais le programme de
filtre vers lequel pointait args n'était pas valable ou sa longueur était
de zéro ou dépassait BPF_MAXINSNS instructions (4096).
- ENOMEM
-
Plus assez de mémoire.
- ENOMEM
-
La taille totale de tous les programmes de filtre rattachés au thread
appelant dépasserait MAX_INSNS_PER_PATH instructions (32768). Remarquez
qu'afin de calculer cette limite, chaque programme de filtre déjà existant
intègre une pénalité de dépassement de 4 instructions.
- EOPNOTSUPP
-
opération indiquait SECCOMP_GET_ACTION_AVAIL mais le noyau ne gère pas
l'action de renvoi de filtre indiquée par args.
- ESRCH
-
Un autre thread a provoqué un échec pendant la synchronisation, mais son
identifiant n'a pas pu être déterminé.
STANDARDS
Linux.
HISTORIQUE
Linux 3.17.
NOTES
Au lieu de coder à la main des filtres seccomp comme démontré dans l'exemple
ci-dessous, vous pourriez préférer utiliser la bibliothèque libseccomp
qui fournit une interface de génération de filtres seccomp.
Le champ Seccomp du fichier /proc/pid/status offre une méthode de
visualisation du mode seccomp du processus ; voir proc(5).
seccomp() fournit un sur-ensemble de fonctionnalités de l'opération
PR_SET_SECCOMP de prctl(2) (qui ne prend pas en charge les flags).
Depuis Linux 4.4, l'opération PTRACE_SECCOMP_GET_FILTER de ptrace(2)
peut être utilisée pour obtenir les filtres seccomp d'un processus.
Gestion d'architecture pour le BPF seccomp
La gestion d'architecture pour le filtrage de BPF seccomp est disponible sur
les architectures suivantes :
- -
-
x86-64, i386, x32 (depuis Linux 3.5)
- -
-
ARM (depuis Linux 3.8)
- -
-
s390 (depuis Linux 3.8)
- -
-
MIPS (depuis Linux 3.16)
- -
-
ARM-64 (depuis Linux 3.19)
- -
-
PowerPC (depuis Linux 4.3)
- -
-
Tile (depuis Linux 4.3)
- -
-
PA-RISC (depuis Linux 4.6)
Mises en garde
Il y a beaucoup de subtilités à prendre en compte lorsqu'on applique des
filtres seccomp à un programme, notamment :
- -
-
Certains appels système traditionnels ont des implémentations dans l'espace
utilisateur dans le vdso(7) de nombreuses architectures. Parmi les
exemples remarquables, se trouvent clock_gettime(2), gettimeofday(2)
et time(2). Sur de telles architectures, le filtrage seccomp de ces
appels système sera sans effet (il y a cependant des cas où les
implémentations vdso(7) se rabattent sur le véritable appel système,
alors les filtres seccomp verraient l'appel système).
- -
-
Le filtrage seccomp s'appuie sur les numéros d'appel système. Cependant, les
applications n'appellent généralement pas directement les appels système,
mais plutôt les fonctions enveloppe de la bibliothèque C qui appellent à
leur tour les appels système. Par conséquent, vous devez garder en tête ce
qui suit :
-
- -
-
Les enveloppes de la glibc pour certains appels système traditionnels
peuvent utiliser des appels système ayant des noms différents dans le
noyau. Par exemple, la fonction enveloppe exit(2) utilise en fait l'appel
système exit_group(2) et la fonction fork(2) utilise en réalité les
appels clone(2).
- -
-
Le comportement des fonctions enveloppe peut changer en fonction des
architectures, selon la plage d'appels système fournie sur ces
architectures. Autrement dit, la même fonction enveloppe peut appeler
différents appels système selon les architectures.
- -
-
Enfin, le comportement des fonctions enveloppe peut changer selon les
versions de la glibc. Par exemple, dans d'anciennes versions, la fonction
enveloppe de la glibc de open(2) appelait l'appel système du même nom,
mais à partir de la 2.26, l'implémentation est passée à l'appel openat(2)
sur toutes les architectures.
La conséquence des points ci-dessus est qu'il pourrait être nécessaire de
filtrer un appel système autre que celui prévu. Plusieurs pages de manuel de
la section 2 donnent des détails utiles sur les différences entre les
fonctions enveloppe et les appels système sous-jacents dans les
sous-sections intitulées Différences entre le noyau et la bibliothèque C.
En outre, remarquez que l'application de filtres seccomp risque même de
provoquer des bogues dans une application, quand les filtres provoquent des
échecs inattendus d'opérations légitimes que l'application a besoin
d'effectuer. De tels bogues pourraient ne pas être facilement identifiés
lors d'un test des filtres seccomp s'ils se produisent à des endroits du
code rarement utilisés.
Détails BPF spécifiques à seccomp
Remarquez que les détails BPF suivants sont spécifiques aux filtres
seccomp :
- -
-
Les modificateurs de taille BPF_H et BPF_B ne sont pas pris en
charge : toutes les opérations doivent charger et stocker des mots
(4 octets) (BPF_W).
- -
-
Pour accéder au contenu du tampon seccomp_data, utilisez le modificateur
du mode d'adressage BPF_ABS.
- -
-
Le modificateur du mode d'adressage BPF_LEN produit un opérande de mode
immédiatement dont la valeur est la taille du tampon seccomp_data.
EXEMPLES
Le programme ci-dessous accepte quatre paramètres ou plus. Les trois
premiers sont un numéro d'appel système, un identifiant numérique
d'architecture et un numéro d'erreur. Le programme utilise ces valeurs pour
construire un filtre BPF utilisé lors de l'exécution pour effectuer les
vérifications suivantes :
- -
-
Si le programme ne tourne pas sur l'architecture indiquée, le filtre BPF
fait échouer les appels système avec l'erreur ENOSYS.
- -
-
Si le programme essaie d'exécuter l'appel système ayant le numéro indiqué,
le filtre BPF fait échouer l'appel système en positionnant errno sur le
numéro d'erreur indiqué.
Les autres paramètres de la ligne de commande indiquent le chemin et les
paramètres supplémentaires d'un programme que notre exemple doit essayer
d'exécuter en utilisant execv(3) (une fonction de bibliothèque qui
utilise l'appel système execve(2)). Certains exemples d’exécution du
programme sont présentés ci-dessous.
Tout d'abord, on affiche l'architecture sur laquelle on est (x86-64) puis on
construit une fonction d’interpréteur qui cherche les numéros d'appels
système sur cette architecture :
$ uname -m
x86_64
$ syscall_nr() { cat /usr/src/linux/arch/x86/syscalls/syscall_64.tbl | \ awk '$2 != "x32" && $3 == "'$1'" { print $1 }' }
Quand le filtre BPF rejette un appel système (cas n° 2 ci-dessus), il fait
échouer l'appel système avec le numéro d'erreur indiqué sur la ligne de
commande. Dans les exemples présentés ici, nous utiliserons le numéro
d'erreur 99 :
$ errno 99
EADDRNOTAVAIL 99 Ne peut pas affecter l'adresse demandée
Dans l'exemple suivant, on essaie d'exécuter la commande whoami(1), mais
le filtre BPF rejette l'appel système execve(2), donc la commande n'est
même pas exécutée :
$ syscall_nr execve
59
$ ./a.out
Utilisation : ./a.out <syscall_nr> <arch> <errno> <prog> [<args>]
Astuce pour <arch> : AUDIT_ARCH_I386: 0x40000003
AUDIT_ARCH_X86_64 : 0xC000003E
$ ./a.out 59 0xC000003E 99 /bin/whoami
execv : Ne peut pas affecter l'adresse demandée
Dans le prochain exemple, le filtre BPF rejette l'appel système write(2)
pour que, même si elle a pu démarrer, la commande whoami(1) ne puisse pas
écrire de sortie :
$ syscall_nr write
1
$ ./a.out 1 0xC000003E 99 /bin/whoami
Dans le dernier exemple, le filtre BPF rejette un appel système qui n'est
pas utilisé par la commande whoami(1), elle peut donc s'exécuter et
produire une sortie :
$ syscall_nr preadv
295
$ ./a.out 295 0xC000003E 99 /bin/whoami
cecilia
Source du programme
#include <linux/audit.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <unistd.h>
#define X32_SYSCALL_BIT 0x40000000
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
static int
install_filter(int syscall_nr, unsigned int t_arch, int f_errno)
{
unsigned int upper_nr_limit = 0xffffffff;
/* On suppose que AUDIT_ARCH_X86_64 renvoie à l'ABI x86-64 normale
(dans l'ABI x32, tous les appels système ont le bit 30 positionné
dans le champ 'nr', donc les numéros sont
>= X32_SYSCALL_BIT). */
if (t_arch == AUDIT_ARCH_X86_64)
upper_nr_limit = X32_SYSCALL_BIT - 1;
struct sock_filter filter[] = {
/* [0] Charger l'architecture depuis le tampon 'seccomp_data'
dans l'accumulateur. */
BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
(offsetof(struct seccomp_data, arch))),
/* [1] Avancer de 5 instructions si l'architecture ne
correspond pas à 't_arch'. */
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, t_arch, 0, 5),
/* [2] Charger le numéro d'appel système depuis le tampon
'seccomp_data' dans l'accumulateur. */
BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
(offsetof(struct seccomp_data, nr))),
/* [3] Vérifier l'ABI - nécessaire seulement pour x86-64 si on
utilise une liste d'interdictions. Utiliser BPF_JGT au lieu de
vérifier par rapport au masque de bits pour ne pas devoir
recharger le numéro d'appel système. */
BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, upper_nr_limit, 3, 0),
/* [4] Avancer d'une instruction si le numéro d'appel système
ne correspond pas à 'syscall_nr'. */
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, syscall_nr, 0, 1),
/* [5] Architecture et appel système correspondants : ne pas
exécuter l'appel système et renvoyer 'f_errno' dans
'errno'. */
BPF_STMT(BPF_RET | BPF_K,
SECCOMP_RET_ERRNO | (f_errno & SECCOMP_RET_DATA)),
/* [6] Cible du numéro d’appel système inadéquate :
autoriser d'autres appels système. */
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
/* [7] Cible de l’architecture inadéquate : tuer le processus. */
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
};
struct sock_fprog prog = {
.len = ARRAY_SIZE(filter),
.filter = filter,
};
if (syscall(SYS_seccomp, SECCOMP_SET_MODE_FILTER, 0, &prog)) {
perror("seccomp");
return 1;
}
return 0;
}
int
main(int argc, char *argv[])
{
if (argc < 5) {
fprintf(stderr, "Utilisation : "
"%s <syscall_nr> <arch> <errno> <prog> [<args>]\n"
"Astuce pour <arch> : AUDIT_ARCH_I386: 0x%X\n"
" AUDIT_ARCH_X86_64: 0x%X\n"
"\n", argv[0], AUDIT_ARCH_I386, AUDIT_ARCH_X86_64);
exit(EXIT_FAILURE);
}
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
perror("prctl");
exit(EXIT_FAILURE);
}
if (install_filter(strtol(argv[1], NULL, 0),
strtoul(argv[2], NULL, 0),
strtol(argv[3], NULL, 0)))
exit(EXIT_FAILURE);
execv(argv[4], &argv[4]);
perror("execv");
exit(EXIT_FAILURE);
}
VOIR AUSSI
bpfc(1), strace(1), bpf(2), prctl(2), ptrace(2),
seccomp_unotify(2), sigaction(2), proc(5), signal(7),
socket(7)
Plusieurs pages de la bibliothèque libseccomp, dont :
scmp_sys_resolver(1), seccomp_export_bpf(3), seccomp_init(3),
seccomp_load(3) et seccomp_rule_add(3).
Les fichiers Documentation/networking/filter.txt et
Documentation/userspace-api/seccomp_filter.rst des sources du noyau (ou
Documentation/prctl/seccomp_filter.txt avant Linux 4.13).
McCanne, S. et Jacobson, V. (1992) The BSD Packet Filter : une nouvelle architecture de captation de paquets au niveau utilisateur,
colloque de la conférence USENIX à l'hiver 1993
TRADUCTION
La traduction française de cette page de manuel a été créée par
Christophe Blaess <https://www.blaess.fr/christophe/>,
Stéphan Rafin <stephan.rafin@laposte.net>,
Thierry Vignaud <tvignaud@mandriva.com>,
François Micaux,
Alain Portal <aportal@univ-montp2.fr>,
Jean-Philippe Guérard <fevrier@tigreraye.org>,
Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>,
Julien Cristau <jcristau@debian.org>,
Thomas Huriaux <thomas.huriaux@gmail.com>,
Nicolas François <nicolas.francois@centraliens.net>,
Florentin Duneau <fduneau@gmail.com>,
Simon Paillard <simon.paillard@resel.enst-bretagne.fr>,
Denis Barbier <barbier@debian.org>,
David Prévot <david@tilapin.org>,
Jean-Philippe MENGUAL <jpmengual@debian.org>
et
Jean-Pierre Giraud <jean-pierregiraud@neuf.fr>
Cette traduction est une documentation libre ; veuillez vous reporter à la
GNU General Public License version 3
concernant les conditions de copie et
de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel,
veuillez envoyer un message à
Index
- NOM
-
- BIBLIOTHÈQUE
-
- SYNOPSIS
-
- DESCRIPTION
-
- Filtres
-
- /proc interfaces
-
- Enregistrement d'audit des actions seccomp
-
- VALEUR RENVOYÉE
-
- ERREURS
-
- STANDARDS
-
- HISTORIQUE
-
- NOTES
-
- Gestion d'architecture pour le BPF seccomp
-
- Mises en garde
-
- Détails BPF spécifiques à seccomp
-
- EXEMPLES
-
- Source du programme
-
- VOIR AUSSI
-
- TRADUCTION
-
This document was created by
man2html,
using the manual pages.
Time: 05:06:05 GMT, September 19, 2025