Skip to content
/linux-syscalls

Sécurité & Identifiants · Section 2

prctl(2)

Multiplexeur de contrôle de processus : configure une centaine de leviers par processus — nom, capacités, no-new-privs, installation seccomp, dumpable, et plus.

Signature

#include <sys/prctl.h>

int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
option
Opération à effectuer. Voir <sys/prctl.h> pour les constantes PR_* (>60 options).
arg2
Propre à l'opération. Souvent une valeur à positionner ou un pointeur de réception.
arg3
Propre à l'opération. Souvent une longueur de tampon ou un paramètre secondaire.
arg4
Propre à l'opération. La plupart des options ignorent arg4 et arg5 — doivent alors valoir 0.
arg5
Propre à l'opération. Idem arg4.

Description

prctl() est un appel système multiplexeur qui expose des opérations de contrôle par processus sous un même numéro. Le premier argument, option, choisit l'opération ; les autres sont propres à l'opération. Options importantes : PR_SET_NAME (positionne le nom 16 octets du processus, visible dans /proc/<pid>/comm et ps), PR_SET_DUMPABLE (contrôle si le processus peut être ptracé et s'il dump un core), PR_SET_NO_NEW_PRIVS (désactive irrévocablement l'élévation de privilèges via execve — prérequis pour installer un filtre seccomp non privilégié), PR_SET_SECCOMP (installe un filtre seccomp), PR_CAPBSET_READ / PR_CAPBSET_DROP (ensemble borne de capacités), PR_SET_PDEATHSIG (envoie un signal à ce processus quand son parent meurt). Beaucoup d'options spécifiques d'architecture existent (PR_PAC_*, PR_SVE_*, PR_SET_TAGGED_ADDR_CTRL sur aarch64 ; PR_MPX_* sur x86, retiré). Chaque option a sa propre sémantique de retour ; voir prctl(2).

Numéros par architecture

ArchitectureNuméroABIPoint d'entrée
x86 (i386)172i386sys_prctl
x64 (x86_64)157commonsys_prctl
ARM64 (aarch64)167—sys_prctl

Historique noyau

Introduit dans Linux 2.1.57.

  1. 2.1.57

    prctl() a été ajouté en 2.1.57 pour multiplexer de nombreuses petites opérations par processus derrière un seul numéro d'appel, évitant l'ajout de nouveaux syscalls pour chaque réglage.

  2. 3.5

    PR_SET_NO_NEW_PRIVS a été introduit comme pierre angulaire du sandboxing non privilégié. Avec no_new_privs, execve() ne peut élever les privilèges — sécurisant l'installation par un processus non privilégié de filtres seccomp sur ses propres enfants, sans root.

  3. 3.17

    PR_SET_MM a été étendu avec des options comme PR_SET_MM_ARG_START pour permettre à l'espace utilisateur de réécrire les pointeurs argv/envv d'un processus — utilisé par setproctitle() et certains frameworks de live-patching.

  4. 5.6

    PR_SET_TAGGED_ADDR_CTRL a été ajouté sur aarch64 pour activer Top Byte Ignore — l'espace utilisateur range alors 8 bits de métadonnées dans l'octet haut des pointeurs (utilisé par HWASan, MTE).

seccomp & conteneurs

Docker default profile

Autorisé

Podman default profile

Autorisé

prctl() est autorisé par défaut dans Docker / Podman. C'est aussi l'appel que tout bac à sable seccomp utilise pour s'installer lui-même (PR_SET_NO_NEW_PRIVS + PR_SET_SECCOMP), donc le bloquer entièrement se sabote soi-même. Le levier de durcissement est le filtrage d'arguments : autoriser uniquement les options PR_* dont la charge a réellement besoin (typiquement PR_SET_NAME et le duo seccomp / no-new-privs si elle se sandboxe). PR_SET_MM en particulier mérite d'être bloqué hors builds de debug — c'est un vecteur d'usurpation d'argv.

libseccomp

// Allow only the prctl options the workload actually needs.
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl),
    1, SCMP_A0(SCMP_CMP_EQ, PR_SET_NAME));
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl),
    1, SCMP_A0(SCMP_CMP_EQ, PR_SET_NO_NEW_PRIVS));
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl),
    1, SCMP_A0(SCMP_CMP_EQ, PR_SET_SECCOMP));

Exemple strace

$ strace -e prctl bash -c 'true'
prctl(PR_SET_NAME, "bash")              = 0
prctl(PR_SET_DUMPABLE, SUID_DUMP_USER)  = 0
prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0)  = 0

strace décode les noms d'options PR_* et déballe leurs structures argument (par ex. PR_SET_NAME affiche le nouveau nom en chaîne). Utiliser -e prctl pour enquêter sur un binaire suspect. Le premier appel prctl(PR_SET_NAME, …) d'un processus est souvent une empreinte fiable de l'identité réelle du programme même quand le chemin du binaire a été masqué.

Sécurité & observabilité

prctl() est intéressant dans deux directions sécurité. (1) Resserrement de capacités : un init privilégié peut utiliser PR_CAPBSET_DROP pour retirer définitivement les capacités inutiles avant de forker des workers, réduisant la surface post-exploitation. PR_SET_NO_NEW_PRIVS empêche les enfants de regagner du privilège via des binaires set-UID. PR_SET_DUMPABLE(0) empêche les secrets de fuir dans les core dumps. (2) Anti-forensique : des malwares utilisent PR_SET_NAME pour se renommer en quelque chose d'inoffensif (kthread, systemd-…) dans /proc/<pid>/comm, et PR_SET_MM pour réécrire /proc/<pid>/cmdline ; ces réécritures se comparent aisément à /proc/<pid>/exe (le binaire réel, que prctl() ne peut pas réécrire). Le tracepoint eBPF sys_enter_prctl capture l'option, rendant l'activité PR_SET_NAME / PR_SET_MM très observable.

Erreurs

EACCES
Permission refusée — propre à l'opération, souvent lié aux champs mm (PR_SET_MM).
EBADF
—
EBUSY
—
EFAULT
—
EINVAL
option non reconnue par ce noyau, ou arg2..arg5 invalides pour l'option choisie.
ENXIO
—
EPERM
L'option requiert une capacité que l'appelant n'a pas (par ex. PR_SET_KEEPCAPS sans CAP_SETPCAP, ou PR_SET_SECUREBITS sans CAP_SETPCAP).

Drapeaux

PR_SET_PDEATHSIG
1
Délivre le signal indiqué au processus appelant lorsque son parent se termine. Utile pour le nettoyage de sous-processus détachés ; attention au recyclage de PID.
PR_GET_DUMPABLE
3
—
PR_SET_DUMPABLE
4
0 = pas de core dump et non ptraçable ; 1 = normal ; 2 = ptraçable uniquement par root. Les binaires set-UID sont remis à 0 à l'exec — la plupart des démons en production devraient explicitement positionner 0 pour empêcher les core dumps contenant des secrets.
PR_SET_KEEPCAPS
8
—
PR_SET_NAME
15
Positionne le nom 16 octets du processus (visible dans /proc/<pid>/comm et ps). Tronqué silencieusement à 15 caractères + NUL.
PR_GET_NAME
16
—
PR_SET_SECCOMP
22
Installe un filtre seccomp. SECCOMP_MODE_FILTER attache un programme BPF ; SECCOMP_MODE_STRICT restreint à read/write/exit/sigreturn.
PR_CAPBSET_READ
23
—
PR_CAPBSET_DROP
24
Retire irrévocablement une capacité de l'ensemble borne pour ce processus et ses enfants. Essentiel pour construire un sous-processus à privilèges réduits.
PR_GET_SECUREBITS
27
—
PR_SET_SECUREBITS
28
—
PR_SET_NO_NEW_PRIVS
38
Positionne irrévocablement le bit no_new_privs. Après cela, execve() ignore set-UID, set-GID, capabilities de fichier, et AT_SECURE — prérequis dur pour les filtres seccomp non privilégiés.
PR_GET_NO_NEW_PRIVS
39
—
PR_SET_THP_DISABLE
41
—
PR_CAP_AMBIENT
47
—
PR_SVE_SET_VL
50
—
PR_PAC_RESET_KEYS
54
—
PR_SET_TAGGED_ADDR_CTRL
55
—
PR_SET_VMA
0x53564d41
—

Syscalls liés