Man page - seccomp(2)

Packages contains this manual

Available languages:

en fr ru

Manual

seccomp

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
Avertissements
Détails BPF spécifiques à seccomp
EXEMPLES
Source du programme
VOIR AUSSI
TRADUCTION

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)

Avertissements

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 http://www.tcpdump.org/papers/bpf-usenix93.pdf

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 à debian-l10n-french@lists.debian.org .