Dirty COW

Dirty COW is a race condition in the kernel's copy-on-write handling of private memory mappings. By racing a write through /proc/self/mem against madvise(MADV_DONTNEED), a process writes to a file it can only open read-only. From a container it overwrites a SUID binary or hijacks the shared vDSO page to run code as root, defeating isolation because the kernel is shared.

2 min di letturaaggiornato il 5 ott 2026florianamette1 contributore
Chiedi al tuo assistente (MCP)Modifica su GitHub

Dirty COW is a race in how the kernel resolves a copy-on-write fault on a private, read-only mapping. When a process maps a read-only file with MAP_PRIVATE and then writes to it, the kernel is supposed to create a private copy so the backing file is never modified. By repeatedly writing through /proc/self/mem while a second thread calls madvise(MADV_DONTNEED) on the same page, an attacker wins a window where the write lands on the original, shared page before the private copy is substituted, so the write reaches the read-only backing file. The result is an arbitrary write to any file the attacker can open for reading, regardless of its permissions.

Because the kernel is shared with the host, this write reaches host-visible files. Confirm the kernel is in the vulnerable range:

bash
uname -r                                   # pre-fix kernels (older 3.x-4.8 line) are affected

Technique#

The exploit opens the target read-only, maps it MAP_PRIVATE, then runs the two racing threads:

c
int f = open(target, O_RDONLY);                 // e.g. a SUID binary readable by all
void *map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, f, 0);
// thread A: discard the private copy so the next write hits the shared page
for(;;) madvise(map, st.st_size, MADV_DONTNEED);
// thread B: write our bytes to the mapping via /proc/self/mem
int m = open("/proc/self/mem", O_RDWR);
for(;;){ lseek(m, (uintptr_t)(map+off), SEEK_SET); write(m, payload, len); }

Winning the race writes payload into the backing file at off.

Escape targets from a container#

  • SUID binary overwrite: overwrite a root-owned SUID executable that is shared read-only between the container and host, replacing its code so the next invocation runs as root on the host.
  • vDSO hijack: patch the shared virtual dynamic shared object page that every process maps, redirecting a frequently-called function to shellcode, which executes in the context of a root process when it next calls that function.

Exploitation notes#

  • The technique is a reliable arbitrary-file-write; the escape depends on choosing a file whose modification yields host root (a shared SUID binary) or on the vDSO code path.
  • The original PoC can crash the target binary; the vDSO variant is favoured for root code execution because it hijacks a live root process rather than waiting for a SUID invocation.
  • Patched kernels close the race; this applies only to hosts running an unpatched kernel in the affected range, so fingerprint uname -r precisely before attempting it.

Tools#

References#