March 10, 2020·4 min read·engineeringdockersecurityarchives

Docker 19.03.8 removes name lookups from archive creation

The strengthened mitigation for CVE-2019-14271 shows how archive metadata can cause a host process to load code from a container filesystem.

Creating an archive can involve more than reading file contents. Translating a numeric file owner into a name can invoke system services and load libraries. When the archiving process has changed its filesystem root to a container's files, those extra operations become security-relevant. Docker Engine 19.03.8 addresses that problem with an improvement to the mitigation for CVE-2019-14271 under certain nscd configurations, according to today's release notes.

The patch is a useful example of why a container boundary also needs scrutiny during administrative operations. I value Docker's image format and build description for making an environment transferable. Extracting files from that environment should not give those files authority over the host program doing the extraction. That expectation applies even when the operation looks like a routine copy.

A lookup can load code

The CVE record describes code injection in Docker 19.03.x before 19.03.1 when linked against glibc. The problem involves nsswitch dynamically loading a library inside a chroot containing the container's files. That original release-line correction therefore predates today's patch. Docker lists 19.03.1 on 25 July 2019 and describes its correction as fixing the loading of nsswitch-based configuration inside a chroot under glibc.

That mechanism is different from an application deliberately executing a program in its container. Here, a host-side utility is working on container-controlled files and can encounter code through a library operation. The security question concerns what the utility might load after changing its view of the filesystem. An archive can consist of ordinary files while the process creating it performs operations with consequences beyond copying their bytes.

The published original fix concerns that initialization problem. Its intent is also visible in the 19.03.8 chrootarchive source. Package initialization calls a user lookup for the name docker and a host lookup for localhost. The accompanying comment says the purpose is to initialize glibc NSS libraries in the host environment, before entering the untrusted filesystem.

Pre-initialization depends on an ordering assumption. The initialization must perform the work that would otherwise cause a later lookup to load a library. That is a more involved requirement than merely ensuring that a helper process begins execution before changing its root. The library's state and the operations that remain possible afterward also matter.

The copy helper creates a tar stream

The Unix archive helper makes the sequence explicit. Its tar function locks the operating-system thread, reads the source and root arguments, and calls realChroot. It then reads archive options and calls the archive package to create a stream. A separate invocation function starts this work through the docker-tar re-execution entry point and connects its output to a pipe.

This explains why metadata handling belongs in the security analysis of a copy operation. Once execution reaches archive creation, the process has already changed its root. A function called while constructing headers is consequently running in that filesystem context. Reviewing only the explicit chroot call would leave out the behavior of the library code that follows it.

It also explains why an apparently unrelated convenience can matter. A human-readable owner name is additional metadata. Resolving it may seem harmless when writing an archive on a trusted host filesystem. The same operation needs a different assessment when the process is deliberately operating over files supplied by another trust domain. The call's purpose does not determine whether its implementation can load code.

The patch retains numeric ownership

The difference between the 19.03.7 and 19.03.8 tags includes a vendored archive/tar package and a patch that removes population of user and group names. Previously, the code called user.LookupId and user.LookupGroupId. The resulting Unix implementation still copies numeric UID and GID values from file status into the tar header. It does not resolve those values into names.

This is a specific reduction in behavior during archive creation. Numeric ownership and a resolved account name are separate pieces of information. Keeping the former does not require performing the latter operation. The source change therefore supports a more precise description than saying the patch removes ownership metadata or changes all file permissions. It removes the lookup path used to enrich the header with names.

I favor that reduction because it makes the helper's responsibilities easier to reason about. A program creating an archive needs file metadata, but every additional service it consults complicates the account of what it trusts. Avoiding an unnecessary lookup reduces that dependency at the point where the process is handling the container filesystem.

The release notes name certain nscd configurations as the reason for strengthening the mitigation. They do not provide a complete list of those configurations. The code establishes what changed in archive handling, but it does not justify claiming that every use of nscd creates the same exposure. The defensible account combines the published scope with the visible removal of the name-resolution calls.

The helper is part of the isolation design

This patch concerns an administrative path that operates around the application. Its implementation still has to respect the distinction between host code and container-controlled files. The earlier initialization and the new archive change address that distinction at different points in the helper's execution. Reading them together explains why today's release strengthens an existing mitigation rather than introducing the original fix.

For an engineer evaluating this update, the concrete change is the removal of name resolution while constructing tar metadata. The helper still creates an archive and preserves numeric ownership fields. That gives the patch an operational meaning beyond its CVE identifier, and identifies the library behavior that no longer occurs during this part of the copy operation.