Skip to content

Commit

Permalink
fuzzing: improve alpine fuzzer
Browse files Browse the repository at this point in the history
Signed-off-by: AdamKorcz <adam@adalogics.com>
  • Loading branch information
AdamKorcz committed Jan 12, 2023
1 parent 70de0c3 commit e055a4e
Showing 1 changed file with 271 additions and 1 deletion.
272 changes: 271 additions & 1 deletion pkg/types/alpine/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,290 @@
package alpine

import (
"archive/tar"
"bytes"
"compress/gzip"
"io"
"strings"
"testing"

fuzz "github.com/AdaLogics/go-fuzz-headers"
)

// Allows the fuzzer to create a .SIGN filename
func getSignFilename(ff *fuzz.ConsumeFuzzer) (string, error) {
keyName, err := ff.GetString()
if err != nil {
return "", err
}
var b strings.Builder
b.WriteString(".SIGN.RSA.")
b.WriteString(keyName)
b.WriteString(".rsa.pub")
return b.String(), nil
}

// createPkgInfoFileContents creates a structured pkginfo file
//
// .PKGINFO files look like this:
//
// # Generated by abuild 3.9.0-r2
// # using fakeroot version 1.25.3
// # Wed Jul 6 19:09:49 UTC 2022
// pkgname = busybox
// pkgver = 1.35.0-r18
// pkgdesc = Size optimized toolbox of many common UNIX utilities
// url = https://busybox.net/
// builddate = 1657134589
// packager = Buildozer <developer@email.org>
// size = 958464
// arch = x86_64
// origin = busybox
// commit = 332d2fff53cd4537d415e15e55e8ceb6fe6eaedb
// maintainer = Sören Tempel <soeren+alpine@soeren-tempel.net>
// provider_priority = 100
// license = GPL-2.0-only
// replaces = busybox-initscripts
// provides = /bin/sh
// triggers = /bin /usr/bin /sbin /usr/sbin /lib/modules/*
// # automatically detected:
// provides = cmd:busybox=1.35.0-r18
// provides = cmd:sh=1.35.0-r18
// depend = so:libc.musl-x86_64.so.1
// datahash = 7d3351ac6c3ebaf18182efb5390061f50d077ce5ade60a15909d91278f70ada7
func createPkgInfoFileContents(ff *fuzz.ConsumeFuzzer) ([]byte, error) {
var b strings.Builder
noOfRows, err := ff.GetInt()
if err != nil {
return []byte(""), err
}

// Comments at the top of the pkginfo file
header, err := ff.GetBytes()
if err != nil {
return []byte(""), err
}
b.Write(header)

for i := 0; i < noOfRows; i++ {
key, err := ff.GetBytes()
if err != nil {
return []byte(""), err
}
value, err := ff.GetBytes()
if err != nil {
return []byte(""), err
}
b.Write(key)
b.Write([]byte(" = "))
b.Write(value)
b.WriteString("\n")
}
return []byte(b.String()), nil
}

// Copies files from structured tarBytes to the tw
// This is used when adding files to tarBytes
func copyTarFiles(tw *tar.Writer, tarBytes []byte) error {
tr := tar.NewReader(bytes.NewReader(tarBytes))
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
fileContents, err := io.ReadAll(tr)
if err != nil {
return err
}
tw.WriteHeader(hdr)
tw.Write(fileContents)
}
return nil
}

// Adds a .SIGN file to tarBytes
func addSignFile(tw *tar.Writer, ff *fuzz.ConsumeFuzzer, tarBytes []byte) error {
err := copyTarFiles(tw, tarBytes)
if err != nil {
return err
}
SIGNFileContents, err := ff.GetBytes()
if err != nil {
return err
}
SIGNFileName, err := getSignFilename(ff)
if err != nil {
return err
}
tw.WriteHeader(&tar.Header{
Name: SIGNFileName,
Mode: 0644,
Size: int64(len(SIGNFileContents)),
Typeflag: tar.TypeReg,
Gid: 0,
Uid: 0,
})
tw.Write(SIGNFileContents)
return nil
}

// Allows the fuzzer to randomize whether a .SIGN file should
// be added to tarBytes
func shouldAddSignFile(ff *fuzz.ConsumeFuzzer, tarBytes []byte) bool {
shouldRequireSIGNFile, err := ff.GetBool()
if err != nil {
return false
}
if shouldRequireSIGNFile {
tr := tar.NewReader(bytes.NewReader(tarBytes))
for {
hdr, err := tr.Next()
if err == io.EOF {
return false
}
if err != nil {
return false
}
if strings.HasPrefix(hdr.Name, ".SIGN") {
return true
}
}
}
return false
}

// Allows the fuzzer to randomize whether a .PKGINFO file should
// be added to tarBytes
func shouldAddPkgInfoFile(ff *fuzz.ConsumeFuzzer, tarBytes []byte) bool {
shouldRequirePKGINFOFile, err := ff.GetBool()
if err != nil {
return false
}
if shouldRequirePKGINFOFile {
tr := tar.NewReader(bytes.NewReader(tarBytes))
for {
hdr, err := tr.Next()
if err == io.EOF {
return false
}
if err != nil {
return false
}
if hdr.Name == ".PKGINFO" {
return true
}
}
}
return false
}

// Adds the .PKGINFO file to tarBytes
func addPkgInfoFile(tw *tar.Writer, ff *fuzz.ConsumeFuzzer, tarBytes []byte) error {
tr := tar.NewReader(bytes.NewReader(tarBytes))
for {
hdr, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
fileContents, err := io.ReadAll(tr)
if err != nil {
return err
}
tw.WriteHeader(hdr)
tw.Write(fileContents)
}
PKGINFOFileContents, err := createPkgInfoFileContents(ff) //nolint:all
if err != nil {
return err
}
tw.WriteHeader(&tar.Header{
Name: ".PKGINFO",
Mode: 0644,
Size: int64(len(PKGINFOFileContents)),
Typeflag: tar.TypeReg,
Gid: 0,
Uid: 0,
})
tw.Write(PKGINFOFileContents)
return nil
}

// FuzzPackageUnmarshal implements the fuzz test
func FuzzPackageUnmarshal(f *testing.F) {
f.Fuzz(func(t *testing.T, data []byte) {
ff := fuzz.NewConsumer(data)

// signature segment
tarBytes, err := ff.TarBytes()
if err != nil {
return
}

if shouldAddSignFile(ff, tarBytes) {
var buf bytes.Buffer
tw := tar.NewWriter(&buf)
err := addSignFile(tw, ff, tarBytes)
if err != nil {
tw.Close()
t.Skip()
}
tw.Close()
tarBytes = buf.Bytes()
}

// control segment
tarBytes2, err := ff.TarBytes()
if err != nil {
t.Skip()
}

if shouldAddPkgInfoFile(ff, tarBytes2) {
var buf bytes.Buffer
tw := tar.NewWriter(&buf)
err := addPkgInfoFile(tw, ff, tarBytes)
if err != nil {
tw.Close()
t.Skip()
}
tw.Close()
tarBytes2 = buf.Bytes()
}

concatenated, err := concatenateTarBytes(tarBytes, tarBytes2)
if err != nil {
t.Skip()
}

p := &Package{}
p.Unmarshal(bytes.NewReader(tarBytes))
p.Unmarshal(bytes.NewReader(concatenated))
})
}

// Concatenates two tar archives.
func concatenateTarBytes(tarBytes []byte, tarBytes2 []byte) ([]byte, error) {
var b1 bytes.Buffer
w1 := gzip.NewWriter(&b1)
defer w1.Close()
_, err := w1.Write(tarBytes)
if err != nil {
return []byte(""), err
}
w1.Close()

var b2 bytes.Buffer
w2 := gzip.NewWriter(&b2)
defer w2.Close()
_, err = w2.Write(tarBytes2)
if err != nil {
return []byte(""), err
}
w2.Close()
concatenated := append(b1.Bytes(), b2.Bytes()...)
return concatenated, nil
}

0 comments on commit e055a4e

Please sign in to comment.