DEV Community

StarkMan
StarkMan

Posted on

Writable core_pattern Is a Host Takeover: Why Container Isolation Fails at /proc/sys/kernel/core_pattern

Writable core_pattern Is a Host Takeover: Why Container Isolation Fails at /proc/sys/kernel/core_pattern

A container escape does not always need a kernel bug. Sometimes it needs one writable file in a namespace that was supposed to be read-only. The core_pattern interface is a common example, and it is worth understanding before the next incident report arrives.

Why the reader needs this

Container isolation is usually described in terms of namespaces, cgroups and seccomp profiles. Those controls matter, but they do not cover every kernel interface that a process can reach. When /proc/sys/kernel/core_pattern is writable from inside a container, a crash in any process can be turned into execution of an attacker-chosen program on the host.

This is not a theoretical curiosity. It appears in real deployments whenever a container runs with --privileged, with a broad --cap-add, or with a bind mount that exposes /proc/sys from the host. The result is a path from a compromised workload to host code execution that never touches a memory-corruption bug.

Technical context: what core_pattern actually does

The kernel writes core dumps according to /proc/sys/kernel/core_pattern. The value can be a filename template, or it can begin with a pipe character. When it begins with |, the kernel treats the remainder as a program to execute and pipes the core dump to that program's standard input.

That design is intentional. It lets an administrator route core dumps to a crash-reporting daemon such as systemd-coredump or apport rather than writing large files to disk. The security consequence follows directly from the same design: whoever controls the value controls which program the kernel runs, and the kernel runs it as root.

Two details make the primitive practical for an attacker. First, the program is executed by the kernel in the initial namespace, outside the container's namespace restrictions. Second, the trigger is a crash, which an attacker can cause deliberately in a process they already control.

Walkthrough: from writable sysctl to host execution

The sequence has four steps.

  1. The attacker gains code execution inside a container that can write to /proc/sys/kernel/core_pattern.
  2. The attacker writes a pipe pattern pointing at a program they control, for example a script on a path that is visible to the host, or a shell command with an absolute path.
  3. The attacker causes a process in the container to crash, producing a core dump.
  4. The kernel executes the configured program as root in the host namespace, and the attacker's code runs outside the container.

Whether step 2 succeeds depends on what the container can actually write. A container started with --privileged has the capability to modify this sysctl. A container with CAP_SYS_ADMIN may also be able to do so depending on the runtime and kernel version. A container that bind-mounts the host's /proc/sys read-write exposes the same interface directly.

The important point for defenders is that none of these are exotic misconfigurations. --privileged is common in CI runners, development environments and monitoring agents that were given broad access to make them work.

Defensive implications

Treat this as a configuration problem with a small number of concrete checks.

  • Audit for --privileged and for containers with CAP_SYS_ADMIN. Both should be rare and justified in writing.
  • Check whether any container mounts /proc/sys or /proc from the host with write access. Read-only mounts close this path.
  • Apply a seccomp profile that blocks the mount and unshare syscalls where they are not needed, and use the runtime's default profile rather than unconfined.
  • Enable user namespaces so that root inside the container is not root on the host. This does not remove the primitive on its own, but it removes the privilege escalation that makes it valuable.
  • Monitor writes to /proc/sys/kernel/core_pattern on hosts that run containers. A change to a pipe pattern outside a known maintenance window is a high-signal event.

There are limits to this advice. Some workloads genuinely need broad privileges, and user namespaces interact badly with certain storage drivers. The goal is not to eliminate every privileged container but to know which ones exist and to make the writable-core-pattern case impossible where it is not required.

References

  • Linux kernel documentation, /proc/sys/kernel sysctl interface.
  • core(5) manual page, core dump file naming and pipe patterns.
  • Docker documentation, runtime privilege and Linux capabilities.
  • Kubernetes documentation, Pod Security Standards and the privileged policy.

Top comments (0)