Miggo Logo

CVE-2025-52881: runc container escape and denial of service due to arbitrary write gadgets and procfs write redirects

N/A

CVSS Score

Basic Information

EPSS Score
-
Published
11/5/2025
Updated
11/5/2025
KEV Status
No
Technology
TechnologyGo

Technical Details

CVSS Vector
-
Package NameEcosystemVulnerable VersionsFirst Patched Version
github.com/opencontainers/runcgo<= 1.2.71.2.8
github.com/opencontainers/selinuxgo<= 1.12.0
github.com/opencontainers/runcgo>= 1.3.0-rc.1, <= 1.3.21.3.3
github.com/opencontainers/runcgo>= 1.4.0-rc.1, <= 1.4.0-rc.21.4.0-rc.3

Vulnerability Intelligence
Miggo AIMiggo AI

Miggo AIRoot Cause Analysis

The vulnerability is a sophisticated race condition (TOCTOU) that allows an attacker to trick runc into writing to an arbitrary file within the procfs filesystem. This is achieved by manipulating mount points or symbolic links between the time runc checks a path and the time it writes to it.

The analysis of the patches reveals several key areas where runc performed unsafe operations on procfs using string-based paths.

  1. Direct Procfs Writes: Functions like setProcAttr in libcontainer/apparmor/apparmor_linux.go and the now-removed writeSystemProperty in libcontainer/rootfs_linux.go directly constructed paths to files in /proc and wrote to them. An attacker could race these operations to redirect the write to a sensitive file, leading to denial of service (by writing to /proc/sysrq-trigger) or container escape (by writing to /proc/sys/kernel/core_pattern). The same pattern was present in the vendored go-selinux library in functions like SetExecLabel.

  2. Racy Mount Setup: The mountToRootfs function in libcontainer/rootfs_linux.go was responsible for setting up mounts. Its logic was path-based and racy, creating the opportunity for an attacker to replace a directory with a symlink pointing into /proc between the path resolution/creation step and the actual mount operation. This is the foundational part of the exploit that allows the write gadgets to be aimed at sensitive procfs files.

  3. Unsafe Procfs Reads: Functions like Stat in libcontainer/system/proc.go and setupUser in libcontainer/init_linux.go performed reads from procfs using constructed paths. While the immediate impact of redirecting a read is lower than a write, the patches systematically replaced all such unsafe path-based accesses with secure, file-descriptor-based operations to eliminate the entire class of vulnerability.

The patches introduce safe, handle-based APIs (pathrs.ProcSelfOpen, pathrs.Reopen, etc.) and apply them to all identified vulnerable locations, ensuring that once a file handle is opened, subsequent operations are immune to symlink-based redirection attacks.

Vulnerable functions

setProcAttr
libcontainer/apparmor/apparmor_linux.go
The function constructs a path to a procfs attribute file (`/proc/thread-self/attr/...`) and writes to it using `os.OpenFile`. This operation is vulnerable to a race condition where an attacker can replace a component of the path with a symbolic link, redirecting the write to a different, potentially sensitive, file within procfs. This could be used to disable AppArmor protections.
writeSystemProperty
libcontainer/rootfs_linux.go
This function, which was removed by the patch, wrote to sysctl files under `/proc/sys`. The path was constructed from a user-controlled key. This is vulnerable to the same race condition as other functions, allowing an attacker to redirect the write to a sensitive file like `/proc/sysrq-trigger` to crash the system, or `/proc/sys/kernel/core_pattern` to achieve container escape.
mountToRootfs
libcontainer/rootfs_linux.go
The overall logic for setting up mounts was vulnerable to a race condition. It resolved a path, created directories, and then performed a mount, all based on a string path. An attacker could manipulate the path components (e.g., via symlinks) between these steps. This vulnerability is central to the exploit, as it allows an attacker to set up the conditions (e.g., mounting over a procfs directory) to exploit the arbitrary write gadgets in other functions.
SetExecLabel
internal/third_party/selinux/go-selinux/selinux_linux.go
This function, along with other label-setting functions in the vendored `go-selinux` library (`SetTaskLabel`, `SetSocketLabel`, `setFSCreateLabel`, `setKeyLabel`), wrote to various attribute files under `/proc/self/attr/` using string-based paths. This was vulnerable to the same race condition, allowing an attacker to redirect the writes to bypass SELinux protections or cause other damage.
Stat
libcontainer/system/proc.go
This function read from `/proc/<pid>/stat` using a constructed path. While this is a read operation, the series of patches aimed to harden all procfs access. The use of a string-based path for accessing procfs is the pattern this vulnerability's patch set fixes, as it is susceptible to race conditions where the path could be manipulated to point to a different file.

WAF Protection Rules

WAF Rule

### Imp**t ### T*is *tt**k is prim*rily * mor* sop*isti**t** v*rsion o* *V*-****-*****, w*i** w*s * *l*w w*i** *llow** *n *tt**k*r to tri*k run* into writin* t** LSM pro**ss l***ls *or * *ont*in*r pro**ss into * *ummy `tmp*s` *il* *n* t*us not *pply

Reasoning

T** vuln*r**ility is * sop*isti**t** r*** *on*ition (TO*TOU) t**t *llows *n *tt**k*r to tri*k `run*` into writin* to *n *r*itr*ry *il* wit*in t** pro**s *il*syst*m. T*is is ***i*v** *y m*nipul*tin* mount points or sym*oli* links **tw**n t** tim* `run