Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions images/oci/boot.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func recoverBootFiles(ctx context.Context, layer v1.Layer, workDir string, idx i
return kp, ip
}

func scanBootFiles(ctx context.Context, r io.Reader, workDir, digestHex string) (kernelPath, initrdPath string, err error) {
func scanBootFiles(ctx context.Context, r io.Reader, workDir, namePrefix string) (kernelPath, initrdPath string, err error) {
logger := log.WithFunc("oci.scanBootFiles")

tr := tar.NewReader(r)
Expand Down Expand Up @@ -121,9 +121,9 @@ func scanBootFiles(ctx context.Context, r io.Reader, workDir, digestHex string)

var dstPath string
if isKernel {
dstPath = filepath.Join(workDir, digestHex+".vmlinuz")
dstPath = filepath.Join(workDir, namePrefix+".vmlinuz")
} else {
dstPath = filepath.Join(workDir, digestHex+".initrd.img")
dstPath = filepath.Join(workDir, namePrefix+".initrd.img")
}

f, createErr := os.Create(dstPath) //nolint:gosec
Expand All @@ -141,7 +141,8 @@ func scanBootFiles(ctx context.Context, r io.Reader, workDir, digestHex string)
} else {
initrdPath = dstPath
}
logger.Debugf(ctx, "Layer %s: extracted %s", digestHex[:12], base)
// namePrefix is a short placeholder on the import path, not always a digest.
logger.Debugf(ctx, "Layer %s: extracted %s", namePrefix[:min(len(namePrefix), 12)], base)
}
return kernelPath, initrdPath, nil
}
74 changes: 74 additions & 0 deletions images/oci/boot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package oci

import (
"archive/tar"
"bytes"
"os"
"path/filepath"
"testing"
)

// Regression for #63: scanBootFiles must not panic on a sub-12-char namePrefix.
func TestScanBootFilesNamePrefixLengths(t *testing.T) {
tests := []struct {
name string
namePrefix string
}{
{"empty prefix", ""},
{"import placeholder under 12 chars", "import-0"},
{"exactly 12 chars", "twelve_chars"},
{"real sha256 hex", "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dir := t.TempDir()
tr := writeBootTar(t, "boot/vmlinuz-6.8.0", "boot/initrd.img-6.8.0")
kernel, initrd, err := scanBootFiles(t.Context(), tr, dir, tt.namePrefix)
if err != nil {
t.Fatalf("scanBootFiles: %v", err)
}
if want := filepath.Join(dir, tt.namePrefix+".vmlinuz"); kernel != want {
t.Errorf("kernel = %q, want %q", kernel, want)
}
if want := filepath.Join(dir, tt.namePrefix+".initrd.img"); initrd != want {
t.Errorf("initrd = %q, want %q", initrd, want)
}
for _, p := range []string{kernel, initrd} {
if _, statErr := os.Stat(p); statErr != nil {
t.Errorf("expected extracted file %s: %v", p, statErr)
}
}
})
}
}

func TestScanBootFilesSkipsNonBoot(t *testing.T) {
dir := t.TempDir()
tr := writeBootTar(t, "usr/bin/vmlinuz-decoy", "boot/vmlinuz-6.8.0.old", "etc/initrd.img")
kernel, initrd, err := scanBootFiles(t.Context(), tr, dir, "import-0")
if err != nil {
t.Fatalf("scanBootFiles: %v", err)
}
if kernel != "" || initrd != "" {
t.Errorf("expected no boot files extracted, got kernel=%q initrd=%q", kernel, initrd)
}
}

func writeBootTar(t *testing.T, paths ...string) *bytes.Reader {
t.Helper()
var buf bytes.Buffer
tw := tar.NewWriter(&buf)
for _, p := range paths {
body := []byte("payload:" + p)
if err := tw.WriteHeader(&tar.Header{Name: p, Typeflag: tar.TypeReg, Mode: 0o644, Size: int64(len(body))}); err != nil {
t.Fatalf("write header %s: %v", p, err)
}
if _, err := tw.Write(body); err != nil {
t.Fatalf("write body %s: %v", p, err)
}
}
if err := tw.Close(); err != nil {
t.Fatalf("close tar: %v", err)
}
return bytes.NewReader(buf.Bytes())
}
Loading