Files
goget/internal/archive/fuzz_test.go
T

81 lines
2.0 KiB
Go

//go:build linux || freebsd
// +build linux freebsd
package archive
import (
"bytes"
"testing"
)
// FuzzTarExtract tests tar extraction with fuzzed input to catch path traversal
// and other security issues in header parsing.
func FuzzTarExtract(f *testing.F) {
// Seed corpus with valid tar data
f.Add([]byte{})
// Minimal valid tar header (512 bytes of zeros)
emptyHeader := make([]byte, 512)
f.Add(emptyHeader)
// Tar file with a ".." path traversal attempt
traversalTar := makeTarWithName("../../../etc/passwd")
f.Add(traversalTar)
// Tar file with absolute path
absTar := makeTarWithName("/etc/passwd")
f.Add(absTar)
// Tar file with symlink pointing outside
symlinkTar := makeSymlinkTar("link", "../../../etc/passwd")
f.Add(symlinkTar)
f.Fuzz(func(t *testing.T, data []byte) {
// Fuzz the tar extraction — it must never panic or escape the temp dir
dir := t.TempDir()
ext := NewTarExtractor()
reader := bytes.NewReader(data)
// Ignore errors — we only care about panics and path escapes
_ = ext.Extract(reader, dir)
})
}
func makeTarWithName(name string) []byte {
// Create a minimal tar file with a regular file at the given path
var buf bytes.Buffer
nameBytes := []byte(name)
if len(nameBytes) > 99 {
nameBytes = nameBytes[:99]
}
header := make([]byte, 512)
copy(header[0:99], nameBytes)
// Set type flag to regular file
header[156] = '0'
// Set size to zero
buf.Write(header)
// Two zero blocks to mark end of archive
buf.Write(make([]byte, 1024))
return buf.Bytes()
}
func makeSymlinkTar(name, target string) []byte {
var buf bytes.Buffer
nameBytes := []byte(name)
if len(nameBytes) > 99 {
nameBytes = nameBytes[:99]
}
header := make([]byte, 512)
copy(header[0:99], nameBytes)
// Set type flag to symlink
header[156] = '2'
// Write link target
targetBytes := []byte(target)
if len(targetBytes) > 99 {
targetBytes = targetBytes[:99]
}
copy(header[157:256], targetBytes)
buf.Write(header)
buf.Write(make([]byte, 1024))
return buf.Bytes()
}