Summary
cocoon image import NAME layerA.tar layerB.tar panics on any tar layer that contains /boot/vmlinuz* or /boot/initrd.img* files. Reproduced on cocoon v0.4.2 (release binary), and confirmed still present on master (images/oci/import.go:145 + images/oci/boot.go:144).
Reproduction
ghcr.io/cocoonstack/cocoon/ubuntu:24.04 is a 2-layer OCI image; layer 1 is the rootfs slice that ships /boot/vmlinuz-... and /boot/initrd.img-.... To use it offline I pulled both blobs (b40150c1...f081, 58fb259f...2333), gunzipped them, and ran:
cocoon image import ghcr.io/cocoonstack/cocoon/ubuntu:24.04 layer1.tar layer2.tar
Result:
INF importing tar layers (2 files) ...
INF importing ghcr.io/cocoonstack/cocoon/ubuntu:24.04 (2 layer(s))
panic: runtime error: slice bounds out of range [:12] with length 8
goroutine 19 [running]:
github.com/cocoonstack/cocoon/images/oci.scanBootFiles(...)
images/oci/boot.go:144 +0x856
github.com/cocoonstack/cocoon/images/oci.processTarReader(...)
images/oci/import.go:145 +0x547
github.com/cocoonstack/cocoon/images/oci.processLocalTar(...)
images/oci/import.go:118 +0x192
github.com/cocoonstack/cocoon/images/oci.importTarLayers.func1.1(...)
images/oci/import.go:55 +0x195
Root cause
processTarReader passes a fabricated label as the digestHex argument to scanBootFiles:
// images/oci/import.go:145
kernelPath, initrdPath, scanErr := scanBootFiles(
ctx, teeForErofs, layerDir,
fmt.Sprintf("import-%d", j.idx), // <- 8 chars (e.g. "import-0")
)
But scanBootFiles assumes that argument is a real sha256 hex string and slices [:12] to print a short prefix:
// images/oci/boot.go:144
logger.Debugf(ctx, "Layer %s: extracted %s", digestHex[:12], base)
"import-0" is 8 bytes, so [:12] panics. The crash only fires when the layer actually contains a vmlinuz*/initrd.img* regular file under boot/ (the extracted debug log is the first slice site reached); empty layers happen to skip it.
The pull path is unaffected because it threads the real 64-char sha256 down. Same goes for selfHealBootFiles (boot.go:60) and the cached/log paths in import.go:166/176 and process.go:47/88/94/97 — they all assume a ≥12-char hex digest. Today only processTarReader violates that contract.
Suggested fix
Two options:
- Compute and thread the real sha256 to
scanBootFiles before logging — natural, but requires reordering the streaming pipeline since processTarReader is currently building the hash while scanning.
- Cheaper / minimally invasive: stop assuming the caller-passed string is sha256-shaped. Either:
short := digestHex
if len(short) > 12 { short = short[:12] }
logger.Debugf(ctx, "Layer %s: extracted %s", short, base)
or change the import call site to pass a ≥12-char placeholder (e.g. fmt.Sprintf("import-layer-%02d", j.idx)).
Option 2's call-site fix is one line and avoids the panic everywhere any future caller could pass a short label. Pairing both is safest.
Environment
cocoon v0.4.2 (commit 49818f86, built 2026-05-25, linux/amd64) — official release binary
- Ubuntu 24.04, x86_64, KVM
- Image:
ghcr.io/cocoonstack/cocoon/ubuntu:24.04 (2 OCI tar+gzip layers)
Happy to send a PR if you'd like.
Summary
cocoon image import NAME layerA.tar layerB.tarpanics on any tar layer that contains/boot/vmlinuz*or/boot/initrd.img*files. Reproduced oncocoon v0.4.2(release binary), and confirmed still present onmaster(images/oci/import.go:145+images/oci/boot.go:144).Reproduction
ghcr.io/cocoonstack/cocoon/ubuntu:24.04is a 2-layer OCI image; layer 1 is the rootfs slice that ships/boot/vmlinuz-...and/boot/initrd.img-.... To use it offline I pulled both blobs (b40150c1...f081,58fb259f...2333), gunzipped them, and ran:Result:
Root cause
processTarReaderpasses a fabricated label as thedigestHexargument toscanBootFiles:But
scanBootFilesassumes that argument is a real sha256 hex string and slices[:12]to print a short prefix:"import-0"is 8 bytes, so[:12]panics. The crash only fires when the layer actually contains avmlinuz*/initrd.img*regular file underboot/(theextracteddebug log is the first slice site reached); empty layers happen to skip it.The pull path is unaffected because it threads the real 64-char sha256 down. Same goes for
selfHealBootFiles(boot.go:60) and the cached/log paths inimport.go:166/176andprocess.go:47/88/94/97— they all assume a ≥12-char hex digest. Today onlyprocessTarReaderviolates that contract.Suggested fix
Two options:
scanBootFilesbefore logging — natural, but requires reordering the streaming pipeline sinceprocessTarReaderis currently building the hash while scanning.fmt.Sprintf("import-layer-%02d", j.idx)).Option 2's call-site fix is one line and avoids the panic everywhere any future caller could pass a short label. Pairing both is safest.
Environment
cocoon v0.4.2(commit49818f86, built 2026-05-25, linux/amd64) — official release binaryghcr.io/cocoonstack/cocoon/ubuntu:24.04(2 OCI tar+gzip layers)Happy to send a PR if you'd like.