-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Closed as not planned
Closed as not planned
Copy link
Labels
WaitingForInfoIssue is not actionable because of missing required information, which needs to be provided.Issue is not actionable because of missing required information, which needs to be provided.
Description
Go version
go version go1.24.4 linux/amd64
Output of go env in your module/workspace:
AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/sontapaa_jokulainen/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/sontapaa_jokulainen/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1537132889=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/home/sontapaa_jokulainen/fuzz/archive_fuzzer/go.mod'
GOMODCACHE='/home/sontapaa_jokulainen/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/sontapaa_jokulainen/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/sontapaa_jokulainen/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.4'
GOWORK=''
PKG_CONFIG='pkg-config'What did you do?
Hi!
I am trying to fuzz this program here:
// archive_test.go
package archivedifffuzz
import (
"archive/zip"
"bytes"
"crypto/sha1"
"encoding/hex"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"runtime"
"context"
"time"
"strconv"
)
type FileEntry struct {
Name string
Size int
}
func getLocalUnzipPath() string {
_, filename, _, ok := runtime.Caller(0)
if !ok {
panic("unable to get caller info")
}
dir := filepath.Dir(filename)
return filepath.Join(dir, "unzip")
}
func ExtractWithUnzipAndStatFiles(t *testing.T, zipData []byte) (map[string]int, string, error) {
tmpDir, err := os.MkdirTemp("", "unzipped-*")
if err != nil {
return nil, "", err
}
tmpZip, err := os.CreateTemp("", "fuzz-*.zip")
if err != nil {
os.RemoveAll(tmpDir)
return nil, "", err
}
defer os.Remove(tmpZip.Name())
defer tmpZip.Close()
if _, err := tmpZip.Write(zipData); err != nil {
os.RemoveAll(tmpDir)
return nil, "", err
}
cmd := exec.Command(getLocalUnzipPath(), "-o", tmpZip.Name(), "-d", tmpDir)
var outBuf bytes.Buffer
cmd.Stdout = &outBuf
cmd.Stderr = &outBuf
if err := cmd.Run(); err != nil {
os.RemoveAll(tmpDir)
return nil, "", fmt.Errorf("unzip failed!!!")
}
output := outBuf.String()
if strings.Contains(output, "mismatch") {
os.RemoveAll(tmpDir)
return nil, "", fmt.Errorf("filename mismatch detected")
}
fileMap := make(map[string]int)
err = filepath.Walk(tmpDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
rel, err := filepath.Rel(tmpDir, path)
if err != nil {
return err
}
fileMap[rel] = int(info.Size())
return nil
})
if err != nil {
os.RemoveAll(tmpDir)
return nil, "", err
}
return fileMap, tmpDir, nil
}
func LoadCorpus(f *testing.F) {
files, _ := os.ReadDir("corpus/")
for _, file := range files {
if data, err := os.ReadFile("corpus/" + file.Name()); err == nil {
f.Add(data)
}
}
}
func FuzzZipDifferential(f *testing.F) {
f.Add([]byte("PK\x03\x04..."))
LoadCorpus(f)
f.Fuzz(func(t *testing.T, data []byte) {
if len(data) > 100_000 {
return
}
// runDifferentialTest(t, data)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
done := make(chan struct{})
go func() {
defer func() {
if r := recover(); r != nil {
panic(r)
}
return
}()
runDifferentialTest(t, data)
close(done)
}()
select {
case <-done:
case <-ctx.Done():
return
// panic("timeout")
}
})
}
func mapsEqual(a, b map[string]int) bool {
if len(a) != len(b) {
return false
}
for k, v := range a {
if b[k] != v {
return false
}
}
return true
}
func isValidFilename(s string) bool {
for _, r := range s {
if r < 32 || r > 127 || r == '\n' || r == '\r' {
return false
}
}
return true
}
func findFileInZip(reader *zip.Reader, name string) *zip.File {
for _, f := range reader.File {
if f.Name == name {
return f
}
}
return nil
}
func IncrementCounterInFile(filename string) error {
// Read existing file contents (if any)
data, err := os.ReadFile(filename)
count := 0
if err == nil {
trimmed := strings.TrimSpace(string(data))
if trimmed != "" {
count, err = strconv.Atoi(trimmed)
if err != nil {
return fmt.Errorf("invalid number in file: %v", err)
}
}
} else if !os.IsNotExist(err) {
return err
}
// Increment and write back
count++
return os.WriteFile(filename, []byte(fmt.Sprintf("%d\n", count)), 0644)
}
func runDifferentialTest(t *testing.T, data []byte) {
/*
unzipFiles, unzipDir, err := ExtractWithUnzipAndStatFiles(t, data)
if err != nil || len(unzipFiles) == 0 {
return
}
defer os.RemoveAll(unzipDir)
*/
reader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
if err != nil {
return
}
goFiles := make(map[string]int)
for _, f := range reader.File {
if !isValidFilename(f.Name) {
return
}
rc, err := f.Open()
if err != nil {
return
}
n, err := io.Copy(io.Discard, rc)
rc.Close()
if err != nil {
return
}
goFiles[f.Name] = int(n)
}
// IncrementCounterInFile("/home/YOURHOMEDIRECTORY/integer.txt")
unzipFiles, unzipDir, err := ExtractWithUnzipAndStatFiles(t, data)
if err != nil || len(unzipFiles) == 0 {
// defer os.RemoveAll(unzipDir)
// t.Errorf("Here is the error: %s", err.Error())
// panic("fuck")
return
}
// defer os.RemoveAll(unzipDir)
common := 0
for name, unzipSize := range unzipFiles {
if goSize, ok := goFiles[name]; ok {
common++
if goSize != unzipSize {
sum := sha1.Sum(data)
t.Errorf("Size mismatch for file %s (Go: %d, Unzip: %d)", name, goSize, unzipSize)
t.Errorf("SHA1: %x", sum)
if entry := findFileInZip(reader, name); entry != nil {
rc, err := entry.Open()
if err == nil {
goData, _ := io.ReadAll(rc)
rc.Close()
t.Logf("=== Go version of %s ===\n%s", name, hex.Dump(goData))
}
}
unzipPath := filepath.Join(unzipDir, name)
unzipData, err := os.ReadFile(unzipPath)
if err == nil {
t.Logf("=== unzip version of %s ===\n%s", name, hex.Dump(unzipData))
} else {
t.Logf("Failed to read %s from unzip dir: %v", name, err)
}
panic("size mismatch")
}
}
}
// panic("fuck")
if !mapsEqual(unzipFiles, goFiles) {
sum := sha1.Sum(data)
t.Errorf("File mismatch (common: %d, Go: %d, Unzip: %d)", common, len(goFiles), len(unzipFiles))
t.Errorf("SHA1: %x", sum)
goOnly := []string{}
unzipOnly := []string{}
for name := range goFiles {
if _, ok := unzipFiles[name]; !ok {
goOnly = append(goOnly, name)
}
}
for name := range unzipFiles {
if _, ok := goFiles[name]; !ok {
unzipOnly = append(unzipOnly, name)
}
}
if len(goOnly) > 0 {
t.Errorf("Files only in Go archive:\n%s", strings.Join(goOnly, "\n"))
}
if len(unzipOnly) > 0 {
t.Errorf("Files only in Unzip archive:\n%s", strings.Join(unzipOnly, "\n"))
}
t.Logf("=== RAW FILENAME DUMP (Go) ===")
for name := range goFiles {
t.Logf("%q | bytes: % x", name, []byte(name))
}
t.Logf("=== RAW FILENAME DUMP (Unzip) ===")
for name := range unzipFiles {
t.Logf("%q | bytes: % x", name, []byte(name))
}
panic("filename mismatch")
}
}
I run it with go test -fuzz=FuzzZipDifferential and then after a while I am getting this output here:
fuzz: elapsed: 38m37s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 38m40s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 38m43s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 38m46s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 38m49s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 38m52s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 38m55s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 38m58s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m1s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m4s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m7s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m10s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m13s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m16s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m19s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m22s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m25s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m28s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m31s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m34s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m37s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m40s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m43s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m46s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m49s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m52s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m55s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 39m58s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 40m1s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
fuzz: elapsed: 40m4s, execs: 1548489 (0/sec), new interesting: 4 (total: 577)
in the output log. It claims that no executions are done, even though I added the timeout to the code. This leads me to believe that execution gets stuck somewhere else other than the fuzz target code. I have verified that I have disk space on my machine. I also should have adequate memory and processing power.
What did you see happen?
Fuzzing grinds to a halt for some odd reason.
What did you expect to see?
Fuzzing continues normally.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
WaitingForInfoIssue is not actionable because of missing required information, which needs to be provided.Issue is not actionable because of missing required information, which needs to be provided.