Skip to content
/linux-syscalls

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

ArchitectureNumberABIEntry point
x86 (i386)90i386sys_old_mmap
x64 (x86_64)9commonsys_mmap
ARM64 (aarch64)222sys_mmap

Kernel history

Introduced in Linux 1.0.

  1. 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. 2.6.32

    MAP_STACK was introduced as a hint for thread-stack allocations; on some architectures it influences guard-page handling.

  3. 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. 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) = 0x7f9b3c4e2000

strace 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

Related syscalls