81 lines
2.0 KiB
Go
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()
|
|
}
|