340 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			340 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package gofuzzheaders
 | |
| 
 | |
| import (
 | |
| 	"archive/tar"
 | |
| 	"bytes"
 | |
| 	"errors"
 | |
| 	//"fmt"
 | |
| 	"reflect"
 | |
| 	"unsafe"
 | |
| )
 | |
| 
 | |
| type ConsumeFuzzer struct {
 | |
| 	data                 []byte
 | |
| 	CommandPart          []byte
 | |
| 	RestOfArray          []byte
 | |
| 	NumberOfCalls        int
 | |
| 	position             int
 | |
| 	fuzzUnexportedFields bool
 | |
| }
 | |
| 
 | |
| func IsDivisibleBy(n int, divisibleby int) bool {
 | |
| 	return (n % divisibleby) == 0
 | |
| }
 | |
| 
 | |
| func NewConsumer(fuzzData []byte) *ConsumeFuzzer {
 | |
| 	f := &ConsumeFuzzer{data: fuzzData, position: 0}
 | |
| 	return f
 | |
| }
 | |
| 
 | |
| func (f *ConsumeFuzzer) Split(minCalls, maxCalls int) error {
 | |
| 	if len(f.data) == 0 {
 | |
| 		return errors.New("Could not split")
 | |
| 	}
 | |
| 	numberOfCalls := int(f.data[0])
 | |
| 	if numberOfCalls < minCalls || numberOfCalls > maxCalls {
 | |
| 		return errors.New("Bad number of calls")
 | |
| 
 | |
| 	}
 | |
| 	if len(f.data) < numberOfCalls+numberOfCalls+1 {
 | |
| 		return errors.New("Length of data does not match required parameters")
 | |
| 	}
 | |
| 
 | |
| 	// Define part 2 and 3 of the data array
 | |
| 	commandPart := f.data[1 : numberOfCalls+1]
 | |
| 	restOfArray := f.data[numberOfCalls+1:]
 | |
| 
 | |
| 	// Just a small check. It is necessary
 | |
| 	if len(commandPart) != numberOfCalls {
 | |
| 		return errors.New("Length of commandPart does not match number of calls")
 | |
| 	}
 | |
| 
 | |
| 	// Check if restOfArray is divisible by numberOfCalls
 | |
| 	if !IsDivisibleBy(len(restOfArray), numberOfCalls) {
 | |
| 		return errors.New("Length of commandPart does not match number of calls")
 | |
| 	}
 | |
| 	f.CommandPart = commandPart
 | |
| 	f.RestOfArray = restOfArray
 | |
| 	f.NumberOfCalls = numberOfCalls
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (f *ConsumeFuzzer) AllowUnexportedFields() {
 | |
| 	f.fuzzUnexportedFields = true
 | |
| }
 | |
| 
 | |
| func (f *ConsumeFuzzer) DisallowUnexportedFields() {
 | |
| 	f.fuzzUnexportedFields = false
 | |
| }
 | |
| 
 | |
| func (f *ConsumeFuzzer) GenerateStruct(targetStruct interface{}) error {
 | |
| 	v := reflect.ValueOf(targetStruct)
 | |
| 	/*if !v.CanSet() {
 | |
| 		return errors.New("This interface cannot be set")
 | |
| 	}*/
 | |
| 	e := v.Elem()
 | |
| 	err := f.fuzzStruct(e)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (f *ConsumeFuzzer) fuzzStruct(e reflect.Value) error {
 | |
| 	switch e.Kind() {
 | |
| 	case reflect.Struct:
 | |
| 		for i := 0; i < e.NumField(); i++ {
 | |
| 			// Useful for debugging, so we leave it for now:
 | |
| 			//vt := e.Type().Field(i).Name
 | |
| 			//fmt.Println("vt:::::::::::::::::::::: ", vt)
 | |
| 			var v reflect.Value
 | |
| 			if !e.Field(i).CanSet() {
 | |
| 				if f.fuzzUnexportedFields {
 | |
| 					v = reflect.NewAt(e.Field(i).Type(), unsafe.Pointer(e.Field(i).UnsafeAddr())).Elem()
 | |
| 				}
 | |
| 			} else {
 | |
| 				v = e.Field(i)
 | |
| 			}
 | |
| 			err := f.fuzzStruct(v)
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		}
 | |
| 	case reflect.String:
 | |
| 		str, err := f.GetString()
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if e.CanSet() {
 | |
| 			e.SetString(str)
 | |
| 		}
 | |
| 	case reflect.Slice:
 | |
| 		maxElements := 50
 | |
| 		randQty, err := f.GetInt()
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		numOfElements := randQty % maxElements
 | |
| 
 | |
| 		uu := reflect.MakeSlice(e.Type(), numOfElements, numOfElements)
 | |
| 
 | |
| 		for i := 0; i < numOfElements; i++ {
 | |
| 			err := f.fuzzStruct(uu.Index(i))
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		}
 | |
| 		if e.CanSet() {
 | |
| 			e.Set(uu)
 | |
| 		}
 | |
| 	case reflect.Uint64:
 | |
| 		newInt, err := f.GetInt()
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if e.CanSet() {
 | |
| 			e.SetUint(uint64(newInt))
 | |
| 		}
 | |
| 	case reflect.Int:
 | |
| 		newInt, err := f.GetInt()
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if e.CanSet() {
 | |
| 			e.SetInt(int64(newInt))
 | |
| 		}
 | |
| 	case reflect.Map:
 | |
| 		if e.CanSet() {
 | |
| 			e.Set(reflect.MakeMap(e.Type()))
 | |
| 			maxElements := 50
 | |
| 			randQty, err := f.GetInt()
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			numOfElements := randQty % maxElements
 | |
| 			for i := 0; i < numOfElements; i++ {
 | |
| 				key := reflect.New(e.Type().Key()).Elem()
 | |
| 				err := f.fuzzStruct(key)
 | |
| 				if err != nil {
 | |
| 					return err
 | |
| 				}
 | |
| 				val := reflect.New(e.Type().Elem()).Elem()
 | |
| 				err = f.fuzzStruct(val)
 | |
| 				if err != nil {
 | |
| 					return err
 | |
| 				}
 | |
| 				e.SetMapIndex(key, val)
 | |
| 			}
 | |
| 		}
 | |
| 	case reflect.Ptr:
 | |
| 		if e.CanSet() {
 | |
| 			e.Set(reflect.New(e.Type().Elem()))
 | |
| 			err := f.fuzzStruct(e.Elem())
 | |
| 			if err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 			return nil
 | |
| 		}
 | |
| 	case reflect.Uint8:
 | |
| 		b, err := f.GetByte()
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if e.CanSet() {
 | |
| 			e.SetUint(uint64(b))
 | |
| 		}
 | |
| 	default:
 | |
| 		return nil
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (f *ConsumeFuzzer) GetStringArray() (reflect.Value, error) {
 | |
| 	// The max size of the array:
 | |
| 	max := 20
 | |
| 
 | |
| 	arraySize := f.position
 | |
| 	if arraySize > max {
 | |
| 		arraySize = max
 | |
| 	}
 | |
| 	elemType := reflect.TypeOf("string")
 | |
| 	stringArray := reflect.MakeSlice(reflect.SliceOf(elemType), arraySize, arraySize)
 | |
| 	if f.position+arraySize >= len(f.data) {
 | |
| 		return stringArray, errors.New("Could not make string array")
 | |
| 	}
 | |
| 
 | |
| 	for i := 0; i < arraySize; i++ {
 | |
| 		stringSize := int(f.data[f.position])
 | |
| 
 | |
| 		if f.position+stringSize >= len(f.data) {
 | |
| 			return stringArray, nil
 | |
| 		}
 | |
| 		stringToAppend := string(f.data[f.position : f.position+stringSize])
 | |
| 		strVal := reflect.ValueOf(stringToAppend)
 | |
| 		stringArray = reflect.Append(stringArray, strVal)
 | |
| 		f.position = f.position + stringSize
 | |
| 	}
 | |
| 	return stringArray, nil
 | |
| }
 | |
| 
 | |
| func (f *ConsumeFuzzer) GetInt() (int, error) {
 | |
| 	if f.position >= len(f.data) {
 | |
| 		return 0, errors.New("Not enough bytes to create int")
 | |
| 	}
 | |
| 	returnInt := int(f.data[f.position])
 | |
| 	f.position++
 | |
| 	return returnInt, nil
 | |
| }
 | |
| 
 | |
| func (f *ConsumeFuzzer) GetByte() (byte, error) {
 | |
| 	if len(f.data) == 0 {
 | |
| 		return 0x00, errors.New("Not enough bytes to get byte")
 | |
| 	}
 | |
| 	if f.position >= len(f.data) {
 | |
| 		return 0x00, errors.New("Not enough bytes to get byte")
 | |
| 	}
 | |
| 	returnByte := f.data[f.position]
 | |
| 	f.position += 1
 | |
| 	return returnByte, nil
 | |
| }
 | |
| 
 | |
| func (f *ConsumeFuzzer) GetBytes() ([]byte, error) {
 | |
| 	if len(f.data) == 0 || f.position >= len(f.data) {
 | |
| 		return nil, errors.New("Not enough bytes to create byte array")
 | |
| 	}
 | |
| 	length := int(f.data[f.position])
 | |
| 	byteBegin := f.position + 1
 | |
| 	if byteBegin >= len(f.data) {
 | |
| 		return nil, errors.New("Not enough bytes to create byte array")
 | |
| 	}
 | |
| 	if length == 0 {
 | |
| 		return nil, errors.New("Zero-length is not supported")
 | |
| 	}
 | |
| 	if byteBegin+length >= len(f.data) {
 | |
| 		return nil, errors.New("Not enough bytes to create byte array")
 | |
| 	}
 | |
| 	b := f.data[byteBegin : byteBegin+length]
 | |
| 	f.position = byteBegin + length
 | |
| 	return b, nil
 | |
| }
 | |
| 
 | |
| func (f *ConsumeFuzzer) GetString() (string, error) {
 | |
| 	if f.position >= len(f.data) {
 | |
| 		return "nil", errors.New("Not enough bytes to create string")
 | |
| 	}
 | |
| 	length := int(f.data[f.position])
 | |
| 	byteBegin := f.position + 1
 | |
| 	if byteBegin >= len(f.data) {
 | |
| 		return "nil", errors.New("Not enough bytes to create string")
 | |
| 	}
 | |
| 	if byteBegin+length > len(f.data) {
 | |
| 		return "nil", errors.New("Not enough bytes to create string")
 | |
| 	}
 | |
| 	str := string(f.data[byteBegin : byteBegin+length])
 | |
| 	f.position = byteBegin + length
 | |
| 	return str, nil
 | |
| }
 | |
| 
 | |
| func (f *ConsumeFuzzer) GetBool() (bool, error) {
 | |
| 	if f.position >= len(f.data) {
 | |
| 		return false, errors.New("Not enough bytes to create bool")
 | |
| 	}
 | |
| 	if IsDivisibleBy(int(f.data[f.position]), 2) {
 | |
| 		f.position++
 | |
| 		return true, nil
 | |
| 	} else {
 | |
| 		f.position++
 | |
| 		return false, nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func (f *ConsumeFuzzer) FuzzMap(m interface{}) error {
 | |
| 	err := f.GenerateStruct(m)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| // TarBytes returns valid tar bytes for a tar archive
 | |
| func (f *ConsumeFuzzer) TarBytes() ([]byte, error) {
 | |
| 	var buf bytes.Buffer
 | |
| 	tw := tar.NewWriter(&buf)
 | |
| 
 | |
| 	numberOfFiles, err := f.GetInt()
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	maxNoOfFiles := 100000
 | |
| 	for i := 0; i < numberOfFiles%maxNoOfFiles; i++ {
 | |
| 		filename, err := f.GetString()
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		filebody, err := f.GetBytes()
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		hdr := &tar.Header{}
 | |
| 		err = f.GenerateStruct(hdr)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		hdr.Name = filename
 | |
| 		hdr.Size = int64(len(filebody))
 | |
| 		hdr.Mode = 0600
 | |
| 
 | |
| 		if err := tw.WriteHeader(hdr); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		if _, err := tw.Write(filebody); err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 	}
 | |
| 	if err := tw.Close(); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	//fmt.Println(string(buf.Bytes()))
 | |
| 	return buf.Bytes(), nil
 | |
| }
 | 
