...

Source file src/github.com/AdaLogics/go-fuzz-headers/consumer.go

Documentation: github.com/AdaLogics/go-fuzz-headers

     1  // Copyright 2023 The go-fuzz-headers Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package gofuzzheaders
    16  
    17  import (
    18  	"archive/tar"
    19  	"bytes"
    20  	"encoding/binary"
    21  	"errors"
    22  	"fmt"
    23  	"io"
    24  	"math"
    25  	"os"
    26  	"path/filepath"
    27  	"reflect"
    28  	"strconv"
    29  	"strings"
    30  	"time"
    31  	"unsafe"
    32  )
    33  
    34  var (
    35  	MaxTotalLen uint32 = 2000000
    36  	maxDepth           = 100
    37  )
    38  
    39  func SetMaxTotalLen(newLen uint32) {
    40  	MaxTotalLen = newLen
    41  }
    42  
    43  type ConsumeFuzzer struct {
    44  	data                 []byte
    45  	dataTotal            uint32
    46  	CommandPart          []byte
    47  	RestOfArray          []byte
    48  	NumberOfCalls        int
    49  	position             uint32
    50  	fuzzUnexportedFields bool
    51  	curDepth             int
    52  	Funcs                map[reflect.Type]reflect.Value
    53  }
    54  
    55  func IsDivisibleBy(n int, divisibleby int) bool {
    56  	return (n % divisibleby) == 0
    57  }
    58  
    59  func NewConsumer(fuzzData []byte) *ConsumeFuzzer {
    60  	return &ConsumeFuzzer{
    61  		data:      fuzzData,
    62  		dataTotal: uint32(len(fuzzData)),
    63  		Funcs:     make(map[reflect.Type]reflect.Value),
    64  		curDepth:  0,
    65  	}
    66  }
    67  
    68  func (f *ConsumeFuzzer) Split(minCalls, maxCalls int) error {
    69  	if f.dataTotal == 0 {
    70  		return errors.New("could not split")
    71  	}
    72  	numberOfCalls := int(f.data[0])
    73  	if numberOfCalls < minCalls || numberOfCalls > maxCalls {
    74  		return errors.New("bad number of calls")
    75  	}
    76  	if int(f.dataTotal) < numberOfCalls+numberOfCalls+1 {
    77  		return errors.New("length of data does not match required parameters")
    78  	}
    79  
    80  	// Define part 2 and 3 of the data array
    81  	commandPart := f.data[1 : numberOfCalls+1]
    82  	restOfArray := f.data[numberOfCalls+1:]
    83  
    84  	// Just a small check. It is necessary
    85  	if len(commandPart) != numberOfCalls {
    86  		return errors.New("length of commandPart does not match number of calls")
    87  	}
    88  
    89  	// Check if restOfArray is divisible by numberOfCalls
    90  	if !IsDivisibleBy(len(restOfArray), numberOfCalls) {
    91  		return errors.New("length of commandPart does not match number of calls")
    92  	}
    93  	f.CommandPart = commandPart
    94  	f.RestOfArray = restOfArray
    95  	f.NumberOfCalls = numberOfCalls
    96  	return nil
    97  }
    98  
    99  func (f *ConsumeFuzzer) AllowUnexportedFields() {
   100  	f.fuzzUnexportedFields = true
   101  }
   102  
   103  func (f *ConsumeFuzzer) DisallowUnexportedFields() {
   104  	f.fuzzUnexportedFields = false
   105  }
   106  
   107  func (f *ConsumeFuzzer) GenerateStruct(targetStruct interface{}) error {
   108  	e := reflect.ValueOf(targetStruct).Elem()
   109  	return f.fuzzStruct(e, false)
   110  }
   111  
   112  func (f *ConsumeFuzzer) setCustom(v reflect.Value) error {
   113  	// First: see if we have a fuzz function for it.
   114  	doCustom, ok := f.Funcs[v.Type()]
   115  	if !ok {
   116  		return fmt.Errorf("could not find a custom function")
   117  	}
   118  
   119  	switch v.Kind() {
   120  	case reflect.Ptr:
   121  		if v.IsNil() {
   122  			if !v.CanSet() {
   123  				return fmt.Errorf("could not use a custom function")
   124  			}
   125  			v.Set(reflect.New(v.Type().Elem()))
   126  		}
   127  	case reflect.Map:
   128  		if v.IsNil() {
   129  			if !v.CanSet() {
   130  				return fmt.Errorf("could not use a custom function")
   131  			}
   132  			v.Set(reflect.MakeMap(v.Type()))
   133  		}
   134  	default:
   135  		return fmt.Errorf("could not use a custom function")
   136  	}
   137  
   138  	verr := doCustom.Call([]reflect.Value{v, reflect.ValueOf(Continue{
   139  		F: f,
   140  	})})
   141  
   142  	// check if we return an error
   143  	if verr[0].IsNil() {
   144  		return nil
   145  	}
   146  	return fmt.Errorf("could not use a custom function")
   147  }
   148  
   149  func (f *ConsumeFuzzer) fuzzStruct(e reflect.Value, customFunctions bool) error {
   150  	if f.curDepth >= maxDepth {
   151  		// return err or nil here?
   152  		return nil
   153  	}
   154  	f.curDepth++
   155  	defer func() { f.curDepth-- }()
   156  
   157  	// We check if we should check for custom functions
   158  	if customFunctions && e.IsValid() && e.CanAddr() {
   159  		err := f.setCustom(e.Addr())
   160  		if err != nil {
   161  			return err
   162  		}
   163  	}
   164  
   165  	switch e.Kind() {
   166  	case reflect.Struct:
   167  		for i := 0; i < e.NumField(); i++ {
   168  			var v reflect.Value
   169  			if !e.Field(i).CanSet() {
   170  				if f.fuzzUnexportedFields {
   171  					v = reflect.NewAt(e.Field(i).Type(), unsafe.Pointer(e.Field(i).UnsafeAddr())).Elem()
   172  				}
   173  				if err := f.fuzzStruct(v, customFunctions); err != nil {
   174  					return err
   175  				}
   176  			} else {
   177  				v = e.Field(i)
   178  				if err := f.fuzzStruct(v, customFunctions); err != nil {
   179  					return err
   180  				}
   181  			}
   182  		}
   183  	case reflect.String:
   184  		str, err := f.GetString()
   185  		if err != nil {
   186  			return err
   187  		}
   188  		if e.CanSet() {
   189  			e.SetString(str)
   190  		}
   191  	case reflect.Slice:
   192  		var maxElements uint32
   193  		// Byte slices should not be restricted
   194  		if e.Type().String() == "[]uint8" {
   195  			maxElements = 10000000
   196  		} else {
   197  			maxElements = 50
   198  		}
   199  
   200  		randQty, err := f.GetUint32()
   201  		if err != nil {
   202  			return err
   203  		}
   204  		numOfElements := randQty % maxElements
   205  		if (f.dataTotal - f.position) < numOfElements {
   206  			numOfElements = f.dataTotal - f.position
   207  		}
   208  
   209  		uu := reflect.MakeSlice(e.Type(), int(numOfElements), int(numOfElements))
   210  
   211  		for i := 0; i < int(numOfElements); i++ {
   212  			// If we have more than 10, then we can proceed with that.
   213  			if err := f.fuzzStruct(uu.Index(i), customFunctions); err != nil {
   214  				if i >= 10 {
   215  					if e.CanSet() {
   216  						e.Set(uu)
   217  					}
   218  					return nil
   219  				} else {
   220  					return err
   221  				}
   222  			}
   223  		}
   224  		if e.CanSet() {
   225  			e.Set(uu)
   226  		}
   227  	case reflect.Uint16:
   228  		newInt, err := f.GetUint16()
   229  		if err != nil {
   230  			return err
   231  		}
   232  		if e.CanSet() {
   233  			e.SetUint(uint64(newInt))
   234  		}
   235  	case reflect.Uint32:
   236  		newInt, err := f.GetUint32()
   237  		if err != nil {
   238  			return err
   239  		}
   240  		if e.CanSet() {
   241  			e.SetUint(uint64(newInt))
   242  		}
   243  	case reflect.Uint64:
   244  		newInt, err := f.GetInt()
   245  		if err != nil {
   246  			return err
   247  		}
   248  		if e.CanSet() {
   249  			e.SetUint(uint64(newInt))
   250  		}
   251  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   252  		newInt, err := f.GetInt()
   253  		if err != nil {
   254  			return err
   255  		}
   256  		if e.CanSet() {
   257  			e.SetInt(int64(newInt))
   258  		}
   259  	case reflect.Float32:
   260  		newFloat, err := f.GetFloat32()
   261  		if err != nil {
   262  			return err
   263  		}
   264  		if e.CanSet() {
   265  			e.SetFloat(float64(newFloat))
   266  		}
   267  	case reflect.Float64:
   268  		newFloat, err := f.GetFloat64()
   269  		if err != nil {
   270  			return err
   271  		}
   272  		if e.CanSet() {
   273  			e.SetFloat(float64(newFloat))
   274  		}
   275  	case reflect.Map:
   276  		if e.CanSet() {
   277  			e.Set(reflect.MakeMap(e.Type()))
   278  			const maxElements = 50
   279  			randQty, err := f.GetInt()
   280  			if err != nil {
   281  				return err
   282  			}
   283  			numOfElements := randQty % maxElements
   284  			for i := 0; i < numOfElements; i++ {
   285  				key := reflect.New(e.Type().Key()).Elem()
   286  				if err := f.fuzzStruct(key, customFunctions); err != nil {
   287  					return err
   288  				}
   289  				val := reflect.New(e.Type().Elem()).Elem()
   290  				if err = f.fuzzStruct(val, customFunctions); err != nil {
   291  					return err
   292  				}
   293  				e.SetMapIndex(key, val)
   294  			}
   295  		}
   296  	case reflect.Ptr:
   297  		if e.CanSet() {
   298  			e.Set(reflect.New(e.Type().Elem()))
   299  			if err := f.fuzzStruct(e.Elem(), customFunctions); err != nil {
   300  				return err
   301  			}
   302  			return nil
   303  		}
   304  	case reflect.Uint8:
   305  		b, err := f.GetByte()
   306  		if err != nil {
   307  			return err
   308  		}
   309  		if e.CanSet() {
   310  			e.SetUint(uint64(b))
   311  		}
   312  	}
   313  	return nil
   314  }
   315  
   316  func (f *ConsumeFuzzer) GetStringArray() (reflect.Value, error) {
   317  	// The max size of the array:
   318  	const max uint32 = 20
   319  
   320  	arraySize := f.position
   321  	if arraySize > max {
   322  		arraySize = max
   323  	}
   324  	stringArray := reflect.MakeSlice(reflect.SliceOf(reflect.TypeOf("string")), int(arraySize), int(arraySize))
   325  	if f.position+arraySize >= f.dataTotal {
   326  		return stringArray, errors.New("could not make string array")
   327  	}
   328  
   329  	for i := 0; i < int(arraySize); i++ {
   330  		stringSize := uint32(f.data[f.position])
   331  		if f.position+stringSize >= f.dataTotal {
   332  			return stringArray, nil
   333  		}
   334  		stringToAppend := string(f.data[f.position : f.position+stringSize])
   335  		strVal := reflect.ValueOf(stringToAppend)
   336  		stringArray = reflect.Append(stringArray, strVal)
   337  		f.position += stringSize
   338  	}
   339  	return stringArray, nil
   340  }
   341  
   342  func (f *ConsumeFuzzer) GetInt() (int, error) {
   343  	if f.position >= f.dataTotal {
   344  		return 0, errors.New("not enough bytes to create int")
   345  	}
   346  	returnInt := int(f.data[f.position])
   347  	f.position++
   348  	return returnInt, nil
   349  }
   350  
   351  func (f *ConsumeFuzzer) GetByte() (byte, error) {
   352  	if f.position >= f.dataTotal {
   353  		return 0x00, errors.New("not enough bytes to get byte")
   354  	}
   355  	returnByte := f.data[f.position]
   356  	f.position++
   357  	return returnByte, nil
   358  }
   359  
   360  func (f *ConsumeFuzzer) GetNBytes(numberOfBytes int) ([]byte, error) {
   361  	if f.position >= f.dataTotal {
   362  		return nil, errors.New("not enough bytes to get byte")
   363  	}
   364  	returnBytes := make([]byte, 0, numberOfBytes)
   365  	for i := 0; i < numberOfBytes; i++ {
   366  		newByte, err := f.GetByte()
   367  		if err != nil {
   368  			return nil, err
   369  		}
   370  		returnBytes = append(returnBytes, newByte)
   371  	}
   372  	return returnBytes, nil
   373  }
   374  
   375  func (f *ConsumeFuzzer) GetUint16() (uint16, error) {
   376  	u16, err := f.GetNBytes(2)
   377  	if err != nil {
   378  		return 0, err
   379  	}
   380  	littleEndian, err := f.GetBool()
   381  	if err != nil {
   382  		return 0, err
   383  	}
   384  	if littleEndian {
   385  		return binary.LittleEndian.Uint16(u16), nil
   386  	}
   387  	return binary.BigEndian.Uint16(u16), nil
   388  }
   389  
   390  func (f *ConsumeFuzzer) GetUint32() (uint32, error) {
   391  	u32, err := f.GetNBytes(4)
   392  	if err != nil {
   393  		return 0, err
   394  	}
   395  	return binary.BigEndian.Uint32(u32), nil
   396  }
   397  
   398  func (f *ConsumeFuzzer) GetUint64() (uint64, error) {
   399  	u64, err := f.GetNBytes(8)
   400  	if err != nil {
   401  		return 0, err
   402  	}
   403  	littleEndian, err := f.GetBool()
   404  	if err != nil {
   405  		return 0, err
   406  	}
   407  	if littleEndian {
   408  		return binary.LittleEndian.Uint64(u64), nil
   409  	}
   410  	return binary.BigEndian.Uint64(u64), nil
   411  }
   412  
   413  func (f *ConsumeFuzzer) GetBytes() ([]byte, error) {
   414  	var length uint32
   415  	var err error
   416  	length, err = f.GetUint32()
   417  	if err != nil {
   418  		return nil, errors.New("not enough bytes to create byte array")
   419  	}
   420  
   421  	if length == 0 {
   422  		length = 30
   423  	}
   424  	bytesLeft := f.dataTotal - f.position
   425  	if bytesLeft <= 0 {
   426  		return nil, errors.New("not enough bytes to create byte array")
   427  	}
   428  
   429  	// If the length is the same as bytes left, we will not overflow
   430  	// the remaining bytes.
   431  	if length != bytesLeft {
   432  		length = length % bytesLeft
   433  	}
   434  	byteBegin := f.position
   435  	if byteBegin+length < byteBegin {
   436  		return nil, errors.New("numbers overflow")
   437  	}
   438  	f.position = byteBegin + length
   439  	return f.data[byteBegin:f.position], nil
   440  }
   441  
   442  func (f *ConsumeFuzzer) GetString() (string, error) {
   443  	if f.position >= f.dataTotal {
   444  		return "nil", errors.New("not enough bytes to create string")
   445  	}
   446  	length, err := f.GetUint32()
   447  	if err != nil {
   448  		return "nil", errors.New("not enough bytes to create string")
   449  	}
   450  	if f.position > MaxTotalLen {
   451  		return "nil", errors.New("created too large a string")
   452  	}
   453  	byteBegin := f.position
   454  	if byteBegin >= f.dataTotal {
   455  		return "nil", errors.New("not enough bytes to create string")
   456  	}
   457  	if byteBegin+length > f.dataTotal {
   458  		return "nil", errors.New("not enough bytes to create string")
   459  	}
   460  	if byteBegin > byteBegin+length {
   461  		return "nil", errors.New("numbers overflow")
   462  	}
   463  	f.position = byteBegin + length
   464  	return string(f.data[byteBegin:f.position]), nil
   465  }
   466  
   467  func (f *ConsumeFuzzer) GetBool() (bool, error) {
   468  	if f.position >= f.dataTotal {
   469  		return false, errors.New("not enough bytes to create bool")
   470  	}
   471  	if IsDivisibleBy(int(f.data[f.position]), 2) {
   472  		f.position++
   473  		return true, nil
   474  	} else {
   475  		f.position++
   476  		return false, nil
   477  	}
   478  }
   479  
   480  func (f *ConsumeFuzzer) FuzzMap(m interface{}) error {
   481  	return f.GenerateStruct(m)
   482  }
   483  
   484  func returnTarBytes(buf []byte) ([]byte, error) {
   485  	return buf, nil
   486  	// Count files
   487  	var fileCounter int
   488  	tr := tar.NewReader(bytes.NewReader(buf))
   489  	for {
   490  		_, err := tr.Next()
   491  		if err == io.EOF {
   492  			break
   493  		}
   494  		if err != nil {
   495  			return nil, err
   496  		}
   497  		fileCounter++
   498  	}
   499  	if fileCounter >= 1 {
   500  		return buf, nil
   501  	}
   502  	return nil, fmt.Errorf("not enough files were created\n")
   503  }
   504  
   505  func setTarHeaderFormat(hdr *tar.Header, f *ConsumeFuzzer) error {
   506  	ind, err := f.GetInt()
   507  	if err != nil {
   508  		hdr.Format = tar.FormatGNU
   509  		//return nil
   510  	}
   511  	switch ind % 4 {
   512  	case 0:
   513  		hdr.Format = tar.FormatUnknown
   514  	case 1:
   515  		hdr.Format = tar.FormatUSTAR
   516  	case 2:
   517  		hdr.Format = tar.FormatPAX
   518  	case 3:
   519  		hdr.Format = tar.FormatGNU
   520  	}
   521  	return nil
   522  }
   523  
   524  func setTarHeaderTypeflag(hdr *tar.Header, f *ConsumeFuzzer) error {
   525  	ind, err := f.GetInt()
   526  	if err != nil {
   527  		return err
   528  	}
   529  	switch ind % 13 {
   530  	case 0:
   531  		hdr.Typeflag = tar.TypeReg
   532  	case 1:
   533  		hdr.Typeflag = tar.TypeLink
   534  		linkname, err := f.GetString()
   535  		if err != nil {
   536  			return err
   537  		}
   538  		hdr.Linkname = linkname
   539  	case 2:
   540  		hdr.Typeflag = tar.TypeSymlink
   541  		linkname, err := f.GetString()
   542  		if err != nil {
   543  			return err
   544  		}
   545  		hdr.Linkname = linkname
   546  	case 3:
   547  		hdr.Typeflag = tar.TypeChar
   548  	case 4:
   549  		hdr.Typeflag = tar.TypeBlock
   550  	case 5:
   551  		hdr.Typeflag = tar.TypeDir
   552  	case 6:
   553  		hdr.Typeflag = tar.TypeFifo
   554  	case 7:
   555  		hdr.Typeflag = tar.TypeCont
   556  	case 8:
   557  		hdr.Typeflag = tar.TypeXHeader
   558  	case 9:
   559  		hdr.Typeflag = tar.TypeXGlobalHeader
   560  	case 10:
   561  		hdr.Typeflag = tar.TypeGNUSparse
   562  	case 11:
   563  		hdr.Typeflag = tar.TypeGNULongName
   564  	case 12:
   565  		hdr.Typeflag = tar.TypeGNULongLink
   566  	}
   567  	return nil
   568  }
   569  
   570  func (f *ConsumeFuzzer) createTarFileBody() ([]byte, error) {
   571  	return f.GetBytes()
   572  	/*length, err := f.GetUint32()
   573  	if err != nil {
   574  		return nil, errors.New("not enough bytes to create byte array")
   575  	}
   576  
   577  	// A bit of optimization to attempt to create a file body
   578  	// when we don't have as many bytes left as "length"
   579  	remainingBytes := f.dataTotal - f.position
   580  	if remainingBytes <= 0 {
   581  		return nil, errors.New("created too large a string")
   582  	}
   583  	if f.position+length > MaxTotalLen {
   584  		return nil, errors.New("created too large a string")
   585  	}
   586  	byteBegin := f.position
   587  	if byteBegin >= f.dataTotal {
   588  		return nil, errors.New("not enough bytes to create byte array")
   589  	}
   590  	if length == 0 {
   591  		return nil, errors.New("zero-length is not supported")
   592  	}
   593  	if byteBegin+length >= f.dataTotal {
   594  		return nil, errors.New("not enough bytes to create byte array")
   595  	}
   596  	if byteBegin+length < byteBegin {
   597  		return nil, errors.New("numbers overflow")
   598  	}
   599  	f.position = byteBegin + length
   600  	return f.data[byteBegin:f.position], nil*/
   601  }
   602  
   603  // getTarFileName is similar to GetString(), but creates string based
   604  // on the length of f.data to reduce the likelihood of overflowing
   605  // f.data.
   606  func (f *ConsumeFuzzer) getTarFilename() (string, error) {
   607  	return f.GetString()
   608  	/*length, err := f.GetUint32()
   609  	if err != nil {
   610  		return "nil", errors.New("not enough bytes to create string")
   611  	}
   612  
   613  	// A bit of optimization to attempt to create a file name
   614  	// when we don't have as many bytes left as "length"
   615  	remainingBytes := f.dataTotal - f.position
   616  	if remainingBytes <= 0 {
   617  		return "nil", errors.New("created too large a string")
   618  	}
   619  	if f.position > MaxTotalLen {
   620  		return "nil", errors.New("created too large a string")
   621  	}
   622  	byteBegin := f.position
   623  	if byteBegin >= f.dataTotal {
   624  		return "nil", errors.New("not enough bytes to create string")
   625  	}
   626  	if byteBegin+length > f.dataTotal {
   627  		return "nil", errors.New("not enough bytes to create string")
   628  	}
   629  	if byteBegin > byteBegin+length {
   630  		return "nil", errors.New("numbers overflow")
   631  	}
   632  	f.position = byteBegin + length
   633  	return string(f.data[byteBegin:f.position]), nil*/
   634  }
   635  
   636  type TarFile struct {
   637  	Hdr  *tar.Header
   638  	Body []byte
   639  }
   640  
   641  // TarBytes returns valid bytes for a tar archive
   642  func (f *ConsumeFuzzer) TarBytes() ([]byte, error) {
   643  	numberOfFiles, err := f.GetInt()
   644  	if err != nil {
   645  		return nil, err
   646  	}
   647  	var tarFiles []*TarFile
   648  	tarFiles = make([]*TarFile, 0)
   649  
   650  	const maxNoOfFiles = 100
   651  	for i := 0; i < numberOfFiles%maxNoOfFiles; i++ {
   652  		var filename string
   653  		var filebody []byte
   654  		var sec, nsec int
   655  		var err error
   656  
   657  		filename, err = f.getTarFilename()
   658  		if err != nil {
   659  			var sb strings.Builder
   660  			sb.WriteString("file-")
   661  			sb.WriteString(strconv.Itoa(i))
   662  			filename = sb.String()
   663  		}
   664  		filebody, err = f.createTarFileBody()
   665  		if err != nil {
   666  			var sb strings.Builder
   667  			sb.WriteString("filebody-")
   668  			sb.WriteString(strconv.Itoa(i))
   669  			filebody = []byte(sb.String())
   670  		}
   671  
   672  		sec, err = f.GetInt()
   673  		if err != nil {
   674  			sec = 1672531200 // beginning of 2023
   675  		}
   676  		nsec, err = f.GetInt()
   677  		if err != nil {
   678  			nsec = 1703980800 // end of 2023
   679  		}
   680  
   681  		hdr := &tar.Header{
   682  			Name:    filename,
   683  			Size:    int64(len(filebody)),
   684  			Mode:    0o600,
   685  			ModTime: time.Unix(int64(sec), int64(nsec)),
   686  		}
   687  		if err := setTarHeaderTypeflag(hdr, f); err != nil {
   688  			return []byte(""), err
   689  		}
   690  		if err := setTarHeaderFormat(hdr, f); err != nil {
   691  			return []byte(""), err
   692  		}
   693  		tf := &TarFile{
   694  			Hdr:  hdr,
   695  			Body: filebody,
   696  		}
   697  		tarFiles = append(tarFiles, tf)
   698  	}
   699  
   700  	var buf bytes.Buffer
   701  	tw := tar.NewWriter(&buf)
   702  	defer tw.Close()
   703  
   704  	for _, tf := range tarFiles {
   705  		tw.WriteHeader(tf.Hdr)
   706  		tw.Write(tf.Body)
   707  	}
   708  	return buf.Bytes(), nil
   709  }
   710  
   711  // This is similar to TarBytes, but it returns a series of
   712  // files instead of raw tar bytes. The advantage of this
   713  // api is that it is cheaper in terms of cpu power to
   714  // modify or check the files in the fuzzer with TarFiles()
   715  // because it avoids creating a tar reader.
   716  func (f *ConsumeFuzzer) TarFiles() ([]*TarFile, error) {
   717  	numberOfFiles, err := f.GetInt()
   718  	if err != nil {
   719  		return nil, err
   720  	}
   721  	var tarFiles []*TarFile
   722  	tarFiles = make([]*TarFile, 0)
   723  
   724  	const maxNoOfFiles = 100
   725  	for i := 0; i < numberOfFiles%maxNoOfFiles; i++ {
   726  		filename, err := f.getTarFilename()
   727  		if err != nil {
   728  			return tarFiles, err
   729  		}
   730  		filebody, err := f.createTarFileBody()
   731  		if err != nil {
   732  			return tarFiles, err
   733  		}
   734  
   735  		sec, err := f.GetInt()
   736  		if err != nil {
   737  			return tarFiles, err
   738  		}
   739  		nsec, err := f.GetInt()
   740  		if err != nil {
   741  			return tarFiles, err
   742  		}
   743  
   744  		hdr := &tar.Header{
   745  			Name:    filename,
   746  			Size:    int64(len(filebody)),
   747  			Mode:    0o600,
   748  			ModTime: time.Unix(int64(sec), int64(nsec)),
   749  		}
   750  		if err := setTarHeaderTypeflag(hdr, f); err != nil {
   751  			hdr.Typeflag = tar.TypeReg
   752  		}
   753  		if err := setTarHeaderFormat(hdr, f); err != nil {
   754  			return tarFiles, err // should not happend
   755  		}
   756  		tf := &TarFile{
   757  			Hdr:  hdr,
   758  			Body: filebody,
   759  		}
   760  		tarFiles = append(tarFiles, tf)
   761  	}
   762  	return tarFiles, nil
   763  }
   764  
   765  // CreateFiles creates pseudo-random files in rootDir.
   766  // It creates subdirs and places the files there.
   767  // It is the callers responsibility to ensure that
   768  // rootDir exists.
   769  func (f *ConsumeFuzzer) CreateFiles(rootDir string) error {
   770  	numberOfFiles, err := f.GetInt()
   771  	if err != nil {
   772  		return err
   773  	}
   774  	maxNumberOfFiles := numberOfFiles % 4000 // This is completely arbitrary
   775  	if maxNumberOfFiles == 0 {
   776  		return errors.New("maxNumberOfFiles is nil")
   777  	}
   778  
   779  	var noOfCreatedFiles int
   780  	for i := 0; i < maxNumberOfFiles; i++ {
   781  		// The file to create:
   782  		fileName, err := f.GetString()
   783  		if err != nil {
   784  			if noOfCreatedFiles > 0 {
   785  				// If files have been created, we don't return an error.
   786  				break
   787  			} else {
   788  				return errors.New("could not get fileName")
   789  			}
   790  		}
   791  		if strings.Contains(fileName, "..") || (len(fileName) > 0 && fileName[0] == 47) || strings.Contains(fileName, "\\") {
   792  			continue
   793  		}
   794  		fullFilePath := filepath.Join(rootDir, fileName)
   795  
   796  		// Find the subdirectory of the file
   797  		if subDir := filepath.Dir(fileName); subDir != "" && subDir != "." {
   798  			// create the dir first; avoid going outside the root dir
   799  			if strings.Contains(subDir, "../") || (len(subDir) > 0 && subDir[0] == 47) || strings.Contains(subDir, "\\") {
   800  				continue
   801  			}
   802  			dirPath := filepath.Join(rootDir, subDir)
   803  			if _, err := os.Stat(dirPath); os.IsNotExist(err) {
   804  				err2 := os.MkdirAll(dirPath, 0o777)
   805  				if err2 != nil {
   806  					continue
   807  				}
   808  			}
   809  			fullFilePath = filepath.Join(dirPath, fileName)
   810  		} else {
   811  			// Create symlink
   812  			createSymlink, err := f.GetBool()
   813  			if err != nil {
   814  				if noOfCreatedFiles > 0 {
   815  					break
   816  				} else {
   817  					return errors.New("could not create the symlink")
   818  				}
   819  			}
   820  			if createSymlink {
   821  				symlinkTarget, err := f.GetString()
   822  				if err != nil {
   823  					return err
   824  				}
   825  				err = os.Symlink(symlinkTarget, fullFilePath)
   826  				if err != nil {
   827  					return err
   828  				}
   829  				// stop loop here, since a symlink needs no further action
   830  				noOfCreatedFiles++
   831  				continue
   832  			}
   833  			// We create a normal file
   834  			fileContents, err := f.GetBytes()
   835  			if err != nil {
   836  				if noOfCreatedFiles > 0 {
   837  					break
   838  				} else {
   839  					return errors.New("could not create the file")
   840  				}
   841  			}
   842  			err = os.WriteFile(fullFilePath, fileContents, 0o666)
   843  			if err != nil {
   844  				continue
   845  			}
   846  			noOfCreatedFiles++
   847  		}
   848  	}
   849  	return nil
   850  }
   851  
   852  // GetStringFrom returns a string that can only consist of characters
   853  // included in possibleChars. It returns an error if the created string
   854  // does not have the specified length.
   855  func (f *ConsumeFuzzer) GetStringFrom(possibleChars string, length int) (string, error) {
   856  	if (f.dataTotal - f.position) < uint32(length) {
   857  		return "", errors.New("not enough bytes to create a string")
   858  	}
   859  	output := make([]byte, 0, length)
   860  	for i := 0; i < length; i++ {
   861  		charIndex, err := f.GetInt()
   862  		if err != nil {
   863  			return string(output), err
   864  		}
   865  		output = append(output, possibleChars[charIndex%len(possibleChars)])
   866  	}
   867  	return string(output), nil
   868  }
   869  
   870  func (f *ConsumeFuzzer) GetRune() ([]rune, error) {
   871  	stringToConvert, err := f.GetString()
   872  	if err != nil {
   873  		return []rune("nil"), err
   874  	}
   875  	return []rune(stringToConvert), nil
   876  }
   877  
   878  func (f *ConsumeFuzzer) GetFloat32() (float32, error) {
   879  	u32, err := f.GetNBytes(4)
   880  	if err != nil {
   881  		return 0, err
   882  	}
   883  	littleEndian, err := f.GetBool()
   884  	if err != nil {
   885  		return 0, err
   886  	}
   887  	if littleEndian {
   888  		u32LE := binary.LittleEndian.Uint32(u32)
   889  		return math.Float32frombits(u32LE), nil
   890  	}
   891  	u32BE := binary.BigEndian.Uint32(u32)
   892  	return math.Float32frombits(u32BE), nil
   893  }
   894  
   895  func (f *ConsumeFuzzer) GetFloat64() (float64, error) {
   896  	u64, err := f.GetNBytes(8)
   897  	if err != nil {
   898  		return 0, err
   899  	}
   900  	littleEndian, err := f.GetBool()
   901  	if err != nil {
   902  		return 0, err
   903  	}
   904  	if littleEndian {
   905  		u64LE := binary.LittleEndian.Uint64(u64)
   906  		return math.Float64frombits(u64LE), nil
   907  	}
   908  	u64BE := binary.BigEndian.Uint64(u64)
   909  	return math.Float64frombits(u64BE), nil
   910  }
   911  
   912  func (f *ConsumeFuzzer) CreateSlice(targetSlice interface{}) error {
   913  	return f.GenerateStruct(targetSlice)
   914  }
   915  

View as plain text