Skip to content

Layered extraction fails when layer replaces symlink with real file #38

@JAORMX

Description

@JAORMX

Summary

Layered OCI image extraction fails with refusing to write through symlink when a higher layer legitimately replaces a symlink (created by a lower layer) with a real file. Extraction falls back to flat mode, losing the layer caching benefit.

Reproduction

Build a layered Alpine image where the base layer has busybox (which creates /usr/bin/env as a symlink) and a subsequent layer installs coreutils (which replaces /usr/bin/env with a real binary):

# base image
FROM alpine:3.21
RUN apk add --no-cache coreutils findutils

When propolis extracts this image with layered extraction enabled, layer 1 (the apk add layer) tries to write the real coreutils /usr/bin/env over the busybox symlink from layer 0 and hits the symlink traversal guard:

level=WARN msg="layered extraction failed, falling back to flat extraction"
  err="apply layer 1 (sha256:6a4114a...): copy file usr/bin/env: refusing to write through symlink: /path/to/cache/tmp-rootfs-.../usr/bin/env"

Expected behavior

Layered extraction should handle the case where a layer replaces an existing symlink with a real file. The symlink traversal protection should detect that the target path is the symlink itself (not traversing through one to reach a different location) and allow the replacement.

Context

This was discovered in waggle after upgrading to propolis v0.0.15 and introducing a shared base image with coreutils. The flat extraction fallback works correctly — VMs boot and run fine — but layer-level caching is not effective since every extraction falls back to flat mode.

Environment

  • propolis v0.0.15
  • Alpine 3.21 base images
  • coreutils package triggers the symlink replacement

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions