Skip to content

oci/layer: error instead of panic when diff_ids and layer counts differ - #676

Open
arpitjain099 wants to merge 1 commit into
opencontainers:mainfrom
arpitjain099:chore/guard-layers-diffids-mismatch
Open

oci/layer: error instead of panic when diff_ids and layer counts differ#676
arpitjain099 wants to merge 1 commit into
opencontainers:mainfrom
arpitjain099:chore/guard-layers-diffids-mismatch

Conversation

@arpitjain099

Copy link
Copy Markdown

I've been looking at umoci's unpack path from a supply-chain angle, specifically what happens when the image metadata is hostile rather than well-formed.

A manifest's layers list and the config's rootfs.diff_ids are both taken straight from the (untrusted) image, but nothing checks that the two line up. If a crafted image lists more layers than there are diff_ids, UnpackRootfs panics:

  • oci/layer/unpack.go: the extraction loop does layerDiffID := config.RootFS.DiffIDs[idx] where idx ranges over manifest.Layers, so a shorter DiffIDs runs off the end with an index-out-of-range.
  • utils.go (Stat): the history walk indexes config.RootFS.DiffIDs[layerIdx] and manifest.Layers[layerIdx] by a counter that increments per non-empty history entry, again with no bounds check.

This turns a malformed image into a panic instead of a clean error, which isn't great for anything that unpacks or inspects untrusted images.

The change adds a length guard before the unpack loop and a bounds check before the stat indexing, so umoci now returns an error that names the mismatched counts. I added a regression test that builds an image whose config drops one diff_id and asserts UnpackManifest returns an error rather than panicking.

Worth noting the existing fuzzer (layer_fuzzer.go) constructs the config's diff_ids to be exactly as long as the layer list, so it never exercises this mismatch, which is probably why it went unnoticed.

go test ./oci/layer/... for the affected tests passes, and gofmt/go vet are clean. (TestGenerate fails on my macOS box independently of this change, since it exercises Linux-only lstat behaviour.)

…smatch

A manifest's layer list and the config's rootfs.diff_ids both come from
the untrusted image, but nothing checked that they were the same length.
When a crafted image lists more layers than there are diff_ids, the
unpack loop in UnpackRootfs walks off the end of config.RootFS.DiffIDs
and panics with an index-out-of-range. The Stat path in utils.go has the
same problem: it indexes both slices by a counter that increments per
non-empty history entry without any bounds check.

Guard both paths so umoci returns a clear error naming the mismatched
counts rather than panicking. Add a regression test that builds an image
whose config drops one diff_id and asserts UnpackManifest fails cleanly.

Signed-off-by: Arpit Jain <arpitjain099@gmail.com>
@codecov-commenter

codecov-commenter commented Jul 10, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.11%. Comparing base (a058839) to head (3e37658).
⚠️ Report is 72 commits behind head on main.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #676      +/-   ##
==========================================
+ Coverage   72.89%   74.11%   +1.21%     
==========================================
  Files          71       71              
  Lines        6164     4639    -1525     
==========================================
- Hits         4493     3438    -1055     
+ Misses       1213      749     -464     
+ Partials      458      452       -6     
Files with missing lines Coverage Δ
oci/layer/unpack.go 64.60% <100.00%> (+5.44%) ⬆️

... and 58 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants