Memory · Section 2
brk(2)
Set the end of the data segment (program break) — the legacy heap-growth primitive.
Signature
#include <unistd.h>
int brk(void * addr);- addr
- Desired new program break. NULL queries the current break without changing it; non-NULL is the target address. The kernel may round to page boundaries.
Description
brk() sets the program break — the address marking the end of the process's data segment (informally, the top of the heap). Called with addr == NULL, it returns the current break; called with a higher address, it grows the heap; called with a lower address, it shrinks it. The kernel actually invokes brk() as part of glibc's malloc() arena management for small allocations (below the MMAP_THRESHOLD, default 128 KiB); larger allocations bypass brk() and use mmap() directly. brk() is one of the oldest syscalls (V7 Unix); modern code rarely calls it directly — glibc's sbrk() and the underlying syscall are an internal detail. The two-call pattern (brk(NULL) to learn the current break, brk(new) to set) is universal.
Architecture mapping
| Architecture | Number | ABI | Entry point |
|---|---|---|---|
| x86 (i386) | 45 | i386 | sys_brk |
| x64 (x86_64) | 12 | common | sys_brk |
| ARM64 (aarch64) | 214 | — | sys_brk |
Kernel history
Introduced in Linux 1.0.
1.0
brk() has been part of Linux since 1.0 — directly inherited from V7 Unix where it was the only heap-growth mechanism. Modern allocators use mmap() for large allocations and reserve brk() for the small-block arena.
seccomp & containers
Docker default profile
Allowed
Podman default profile
Allowed
brk() is allowed by every default profile and is impossible to block usefully — glibc's malloc cannot function without it. No useful argument-level filtering.
libseccomp
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(brk), 0);strace example
$ strace -e brk /bin/true 2>&1 | head -3
brk(NULL) = 0x5650c4a6a000
brk(0x5650c4a8b000) = 0x5650c4a8b000brk() appears in any program start-up — typically two calls back-to-back: brk(NULL) to read, brk(new) to set. The first set is glibc reserving its initial small-allocation arena. A sequence of growing brk() targets reveals heap growth over the program's lifetime; strace -c summary shows the total brk-time as a proxy for malloc churn.
Security & observability
brk() is rarely security-relevant on its own. The historical pattern that matters: in pre-ASLR (or partial-ASLR) systems, the heap location was predictable, which made heap-overflow exploits much easier. Modern ASLR randomises the brk() base, so heap addresses are unpredictable. eBPF tracepoint sys_enter_brk is extremely noisy and never useful in production monitoring. The one specific thing worth noting: a process that suddenly does many brk() calls expanding the heap rapidly is usually leaking memory or being abused for memory-exhaustion DoS — but rss-based detection in cgroups catches this earlier.
Errors
- ENOMEM
- Insufficient memory to satisfy the request, or the requested address would collide with another mapping (the heap cannot grow into mmap regions).