stacklok / stacklok/go-microvm

Layered extraction fails when layer replaces symlink with real file

Open
#38 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
Dominant language
Go
Stars
25
Forks
5
PR merge metrics
No merged PRs in 30d

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the layered OCI image extraction path and the symlink traversal guard that reports “refusing to write through symlink.” Reproduce the issue with the Alpine 3.21 image described here, then verify that replacing the existing /usr/bin/env symlink with a real file succeeds without falling back to flat extraction and preserves layer caching.

Written by the indexing model from the issue text.

Assessment

Tech stack
docker, go
Domain
infrastructure
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.