Mémoire · Section 2
brk(2)
Positionne la fin du segment de données (program break) — la primitive historique de croissance du tas.
Signature
#include <unistd.h>
int brk(void * addr);- addr
- Nouveau program break souhaité. NULL interroge le break courant sans le modifier ; non-NULL est l'adresse cible. Le noyau peut arrondir aux frontières de page.
Description
brk() positionne le program break — l'adresse marquant la fin du segment de données du processus (informellement, le sommet du tas). Appelé avec addr == NULL, il retourne le break courant ; avec une adresse supérieure, il fait croître le tas ; avec une adresse inférieure, il le rétrécit. Le noyau est invoqué via brk() dans le cadre de la gestion d'arène malloc de la glibc pour les petites allocations (sous MMAP_THRESHOLD, défaut 128 KiB) ; les grosses allocations contournent brk() et utilisent mmap() directement. brk() est l'un des plus vieux syscalls (V7 Unix) ; le code moderne l'appelle rarement directement — sbrk() de la glibc et l'appel système sous-jacent sont un détail interne. Le motif à deux appels (brk(NULL) pour lire le break courant, brk(new) pour le positionner) est universel.
Numéros par architecture
| Architecture | Numéro | ABI | Point d'entrée |
|---|---|---|---|
| x86 (i386) | 45 | i386 | sys_brk |
| x64 (x86_64) | 12 | common | sys_brk |
| ARM64 (aarch64) | 214 | — | sys_brk |
Historique noyau
Introduit dans Linux 1.0.
1.0
brk() est présent dans Linux depuis 1.0 — directement hérité de V7 Unix où c'était le seul mécanisme de croissance du tas. Les allocateurs modernes utilisent mmap() pour les grosses allocations et réservent brk() à l'arène des petits blocs.
seccomp & conteneurs
Docker default profile
Autorisé
Podman default profile
Autorisé
brk() est autorisé par tout profil par défaut et impossible à bloquer utilement — la malloc de la glibc ne peut pas fonctionner sans. Pas de filtrage d'arguments utile.
libseccomp
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0);Exemple strace
$ strace -e brk /bin/true 2>&1 | head -3
brk(NULL) = 0x5650c4a6a000
brk(0x5650c4a8b000) = 0x5650c4a8b000brk() apparaît au démarrage de tout programme — typiquement deux appels successifs : brk(NULL) pour lire, brk(new) pour positionner. Le premier set est la glibc réservant son arène initiale. Une séquence de brk() croissants révèle la croissance du tas dans la vie du programme ; le résumé strace -c affiche le temps brk total en proxy du churn malloc.
Sécurité & observabilité
brk() est rarement pertinent en soi côté sécurité. Le motif historique : dans les systèmes pré-ASLR (ou partiellement ASLR), la position du tas était prévisible, ce qui facilitait grandement les exploits par débordement de tas. L'ASLR moderne randomise la base brk(), rendant les adresses du tas imprévisibles. Le tracepoint eBPF sys_enter_brk est extrêmement bruyant et jamais utile en production. À noter : un processus qui fait soudainement beaucoup d'appels brk() agrandissant rapidement le tas fuit généralement de la mémoire ou subit un DoS par épuisement — mais la détection par rss dans les cgroups attrape ça plus tôt.
Erreurs
- ENOMEM
- Mémoire insuffisante pour satisfaire la demande, ou l'adresse demandée entrerait en collision avec une autre projection (le tas ne peut pas croître dans des régions mmap).