1
2
3
4
5
6
7
8
9
10
11
12
13
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
81 commandPart := f.data[1 : numberOfCalls+1]
82 restOfArray := f.data[numberOfCalls+1:]
83
84
85 if len(commandPart) != numberOfCalls {
86 return errors.New("length of commandPart does not match number of calls")
87 }
88
89
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
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
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
152 return nil
153 }
154 f.curDepth++
155 defer func() { f.curDepth-- }()
156
157
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
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
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
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
430
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
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
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
601 }
602
603
604
605
606 func (f *ConsumeFuzzer) getTarFilename() (string, error) {
607 return f.GetString()
608
634 }
635
636 type TarFile struct {
637 Hdr *tar.Header
638 Body []byte
639 }
640
641
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
675 }
676 nsec, err = f.GetInt()
677 if err != nil {
678 nsec = 1703980800
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
712
713
714
715
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
755 }
756 tf := &TarFile{
757 Hdr: hdr,
758 Body: filebody,
759 }
760 tarFiles = append(tarFiles, tf)
761 }
762 return tarFiles, nil
763 }
764
765
766
767
768
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
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
782 fileName, err := f.GetString()
783 if err != nil {
784 if noOfCreatedFiles > 0 {
785
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
797 if subDir := filepath.Dir(fileName); subDir != "" && subDir != "." {
798
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
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
830 noOfCreatedFiles++
831 continue
832 }
833
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
853
854
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