September 15, 2021·6 min read·engineeringkubernetessecuritystorage

Kubernetes subpath mounts could bypass hostPath restrictions

CVE-2021-25741 lets subpath mounts expose files outside their volume. The advisory identifies kubelet updates and explains why clusters restricting hostPath are particularly affected.

A cluster can prohibit hostPath mounts and still expose host files if another mounting mechanism escapes its intended directory. CVE-2021-25741 describes that failure in Kubernetes subpath volume mounts. A user creating a container with a subpath mount may obtain access to files and directories outside the volume, including on the host.

The 15 September advisory rates the issue High and identifies kubelet as the affected component. It emphasizes environments that restrict hostPath because exploitation can supply hostPath-like access without requesting that feature. The restriction is meaningful only if the kubelet also confines the alternative mount operation.

I regard reconciliation as Kubernetes' strongest design property, but it does not replace the isolation requirements of a node agent. The kubelet performs privileged operations on behalf of workload declarations. A mount must remain confined to the object that validation intended, even when a workload can modify the surrounding filesystem.

The declared volume is only part of the boundary

A subpath mount selects a portion of a volume for use by a container. The security requirement is that resolving and mounting the selection cannot turn it into access outside that volume. A permitted volume does not imply permission to mount an arbitrary host directory.

The advisory describes a symlink-exchange issue. A pathname identifies an object through filesystem lookup, and the object reached through that lookup can change as directories or links change. A security check on a path is therefore insufficient if a later privileged operation resolves it under different conditions.

The consequence is a mismatch between the admitted request and the object the node exposes. Admission can see a request involving a permitted volume and subpath, while an unsafe mount sequence reaches a different filesystem location. Merely rejecting the hostPath volume type does not cover that implementation error.

The relevant trust boundary is between the workload that can influence volume contents and the node agent that performs mounts with greater privileges. A race between them must not expand the accessible filesystem.

This explains the advisory's distinction between configurations. In a cluster that already permits equivalent host access, exploitation can obscure misuse of privileges already granted. In a cluster that intentionally restricts hostPath, it can cross an intended security boundary. The same underlying bug has different consequences depending on the surrounding policy.

That qualification should not be discarded when describing severity. The disclosure gives a high rating and a concrete privilege boundary, while also explaining why default environments and restricted environments are not identical cases.

The implementation has to preserve object identity

The Linux subpath implementation in the fixed 1.22.2 release makes the intended confinement mechanism visible. It first resolves paths, checks that the subpath is within the volume, and opens the selected object through a controlled traversal.

The traversal uses directory file descriptors and openat. Its open flags include O_NOFOLLOW and O_PATH, and the code checks the resulting object with fstat. If it encounters a symbolic link where one is disallowed, it returns an error.

The important distinction is between a string and an open reference. Checking that a string appears beneath a base directory does not hold the object in place. An open file descriptor gives subsequent code a reference to the object it actually opened.

The code then constructs a source under /proc/<kubelet-pid>/fd/<fd> for the bind mount. Its comment explains the purpose of using that source. The user cannot change the kubelet's file descriptor to point to a different place.

This is the confinement design visible in the released implementation, not a claim that every line of it was newly introduced by this patch. Security analysis needs that distinction because existing defensive steps can coexist with a vulnerability elsewhere in the complete mount sequence.

A later lookup can undermine an earlier check

The implementation passes --no-canonicalize when invoking the mount operation. The versioned mount utility shows how mount flags are incorporated into the command arguments separately from filesystem options.

That detail matters to the design because a safe reference must remain the reference the mount consumes. A later pathname transformation can reintroduce a lookup after earlier code has already established what object should be used. The safety property extends across the boundary between kubelet code and the mount utility.

Directory creation has related requirements. The subpath code creates missing directories through directory-relative operations and opens each result without following links. Its comments consider what happens if a user changes the newly created object between those operations.

The intended outcome is constrained. A changed object can cause an error, or it can remain an object the user could already access. The privileged node agent must not convert that race into access to a new location outside the authorized base.

These mechanisms explain why a simple textual prefix check cannot provide the full guarantee. Filesystem names are mutable, and several operations participate in constructing the eventual mount. Confinement requires preserving the relationship between the authorized base, the opened object, and the operation that exposes it to a container.

The affected component is on every relevant node

The public tracking issue lists affected Kubernetes versions. They include 1.22.0 through 1.22.1, 1.21.0 through 1.21.4, and 1.20.0 through 1.20.10. The disclosure also includes versions at or below 1.19.14.

The fixed releases are 1.22.2, 1.21.5, 1.20.11, and 1.19.15. These version boundaries come from the advisory. They identify the remediation without requiring a reader to infer security status from an unrelated maintenance note.

Because kubelet is affected, updating only the API server does not replace the vulnerable node-side implementation. The operation at issue happens where the container's mounts are prepared. That location determines which component needs the corrected code.

The practical unit of remediation is therefore the kubelet population that can prepare these mounts. A cluster-wide version label is less informative than whether the relevant nodes run a fixed implementation. This follows directly from the advisory's component identification.

The vulnerability also illustrates why admitting a Pod and executing it are distinct security responsibilities. Admission evaluates declarations before a node turns them into operating-system actions. A safe declaration still requires an implementation that preserves its constraints during execution.

Mitigation removes the vulnerable capability

For environments that cannot immediately upgrade kubelet, the advisory recommends disabling the VolumeSubpath feature gate on both kubelet and kube-apiserver. It also requires removing existing Pods that use the feature. Those steps should be understood together.

Changing admission behavior alone does not remove an existing workload using the capability. Disabling it on the node alone also leaves the API-facing configuration to consider. The mitigation addresses both components and the current Pods.

This mitigation has an operational cost because legitimate subpath users lose the feature. It is an explicit restriction of functionality, which is different from applying a corrected implementation that preserves the intended confined mount behavior.

The advisory separately recommends admission control preventing less-trusted users from running containers as root to reduce the impact of successful exploitation. It describes that measure as impact reduction. It does not present it as equivalent to fixing the mount implementation.

Security guidance needs to keep those effects separate. A kubelet update repairs the affected component. Disabling subpaths removes access to the vulnerable capability. Restricting root execution changes what an exploit can do with the access it obtains.

Policy depends on the implementation beneath it

My concern with this issue is the gap between a policy name and the access a workload can obtain. A hostPath restriction expresses a useful intention, but the node must enforce equivalent confinement wherever another feature mounts part of a user-controlled volume.

The reported issue does not invalidate admission policy. It identifies a lower-level requirement that policy relies upon. The API can restrict requested volume types while the kubelet must ensure that the resulting mounts remain inside their authorized boundaries.

The fixed-release code shows why that enforcement involves more than checking a path once. Directory-relative opens, stable file descriptors, and the eventual mount invocation all participate in preserving the selected object. The advisory's remediation targets kubelet because that is where these filesystem operations turn an accepted declaration into container access.