Memory · Section 2
mmap(2)
Map files or anonymous memory into a process's address space.
Signature
#include <sys/mman.h>
void * mmap(void * addr, size_t length, int prot, int flags, int fd, off_t offset);- addr
- Hint (or, with MAP_FIXED, requirement) for the address at which to place the mapping. Usually NULL.
- length
- Size of the mapping in bytes. Rounded up to a page-size multiple.
- prot
- Bitwise OR of PROT_READ, PROT_WRITE, PROT_EXEC, or PROT_NONE. Must be compatible with the file's open mode.
- flags
- Sharing flag (MAP_SHARED or MAP_PRIVATE — exactly one) ORed with modifiers (MAP_ANONYMOUS, MAP_FIXED, MAP_HUGETLB, MAP_STACK, etc.).
- fd
- File descriptor of the file to be mapped; ignored when MAP_ANONYMOUS is set (pass -1 by convention).
- offset
- Byte offset into the file; must be a multiple of the page size.
Description
mmap() creates a new mapping in the calling process's virtual address space. The starting address is a hint via addr; with MAP_FIXED it is mandatory. length is rounded up to a multiple of the page size. prot describes the desired memory protection (some combination of PROT_READ, PROT_WRITE, PROT_EXEC, or PROT_NONE) and flags selects sharing semantics (MAP_SHARED vs MAP_PRIVATE) plus modifiers. When fd refers to a file, that file is mapped starting at offset; with MAP_ANONYMOUS the mapping is backed by zero-filled pages and fd is ignored. mmap() returns the address of the new mapping or MAP_FAILED ((void *) -1) on error.
Architecture mapping
| Architecture | Number | ABI | Entry point |
|---|---|---|---|
| x86 (i386) | 90 | i386 | sys_old_mmap |
| x64 (x86_64) | 9 | common | sys_mmap |
| ARM64 (aarch64) | 222 | — | sys_mmap |
Kernel history
Introduced in Linux 1.0.
2.4.0
MAP_ANONYMOUS was clarified and standardised as a portable way to allocate zero-filled memory; it largely replaced the older /dev/zero idiom.
2.6.32
MAP_STACK was introduced as a hint for thread-stack allocations; on some architectures it influences guard-page handling.
3.10
The MAP_HUGE_2MB / MAP_HUGE_1GB encoding was added so callers can request a specific huge-page size via the upper bits of flags.
4.17
MAP_FIXED_NOREPLACE was added so address-space layout pickers can request a fixed location without silently destroying existing mappings — a long-standing footgun of MAP_FIXED.
seccomp & containers
Docker default profile
Allowed
Podman default profile
Allowed
mmap() is on the Docker and Podman default allow-lists and is effectively un-blockable — every dynamic loader, glibc malloc above the brk threshold, and JIT compiler uses it. A useful seccomp hardening pattern is to allow mmap() unless PROT_EXEC is requested on an anonymous mapping (a strong signal of in-process code generation, used by JITs and exploits alike). When enforcing W^X across a container, also constrain mprotect() with the same mask.
libseccomp
// Allow mmap but block PROT_EXEC anonymous mappings (W^X enforcement)
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(mmap),
1, SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC, 0));strace example
$ strace -e mmap cat /etc/hostname
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9b3c4f3000
mmap(NULL, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9b3c4e3000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f9b3c4e2000strace prints mmap arguments expanded — flags become MAP_PRIVATE|MAP_ANONYMOUS|… and prot becomes PROT_READ|PROT_WRITE|… — making it easy to spot suspicious PROT_EXEC|PROT_WRITE allocations at a glance. Filter with -e trace=mmap.
Security & observability
mmap() is the primary vector for in-process code generation: shellcode is typically mapped via mmap(NULL, …, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) before being jumped to. eBPF tracepoint sys_enter_mmap fires for every call; filtering by prot=PROT_EXEC and flags & MAP_ANONYMOUS gives a high-signal feed. Rootkits also use mmap() of /dev/mem or /proc/kcore for kernel-memory inspection on misconfigured systems. Watch for mmap() calls with prot=PROT_EXEC from processes that should never JIT.
Errors
- EACCES
- fd refers to a file that is not open for the requested protection mode, or MAP_SHARED was requested on a read-only fd.
- EAGAIN
- RLIMIT_MEMLOCK would be exceeded (MAP_LOCKED) or temporary resource exhaustion.
- EBADF
- fd is not a valid file descriptor and MAP_ANONYMOUS is not set.
- EEXIST
- —
- EINVAL
- Bad combination of flags, length, offset, or addr (e.g. addr not page-aligned with MAP_FIXED).
- ENFILE
- —
- ENODEV
- —
- ENOMEM
- No memory available, RLIMIT_AS exceeded, or maximum number of mappings (vm.max_map_count) reached.
- EOVERFLOW
- —
- EPERM
- —
- ETXTBSY
- MAP_DENYWRITE on a file that is open for writing.
Flags
- MAP_SHARED
- 0x01
- Modifications are visible to other processes mapping the same file and are persisted to disk on writeback.
- MAP_PRIVATE
- 0x02
- Copy-on-write mapping; changes are not propagated to the file or other mappers.
- MAP_SHARED_VALIDATE
- 0x03
- —
- MAP_FIXED
- 0x10
- Place the mapping at exactly addr, overwriting any existing mapping there. Rarely safe; prefer MAP_FIXED_NOREPLACE.
- MAP_FIXED_NOREPLACE
- 0x100000
- Like MAP_FIXED but fails with EEXIST instead of clobbering an existing mapping (added in 4.17).
- MAP_ANONYMOUS
- 0x20
- The mapping is not backed by any file; pages are zero-initialised. fd is ignored.
- MAP_GROWSDOWN
- 0x0100
- —
- MAP_HUGETLB
- 0x40000
- Allocate the mapping using huge pages. Pair with MAP_HUGE_2MB or MAP_HUGE_1GB encoded in the upper bits of flags.
- MAP_LOCKED
- 0x2000
- —
- MAP_NORESERVE
- 0x4000
- —
- MAP_POPULATE
- 0x8000
- Pre-fault page tables for the entire mapping (useful for reducing later page-fault latency).
- MAP_STACK
- 0x20000
- Hint that the mapping will be used as a thread stack; affects guard-page placement.
- PROT_READ
- 0x1
- —
- PROT_WRITE
- 0x2
- —
- PROT_EXEC
- 0x4
- Pages may be executed as code. Dangerous when combined with PROT_WRITE — see W^X.
- PROT_NONE
- 0x0
- —