github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/kfuzztest/types.go (about)

     1  // Copyright 2025 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  package kfuzztest
     4  
     5  import (
     6  	"debug/elf"
     7  	"fmt"
     8  )
     9  
    10  // The parsableFromBytes interface describes a kftf object that can be parsed
    11  // from a vmlinux binary. All objects are expected to satisfy the following
    12  // constraints
    13  //   - Must be statically sized. I.e. the size() function should return some
    14  //     fixed value
    15  //   - Densely packed: size must exactly describe the number of bytes between
    16  //     the start address of instance i and that of instance i+1.
    17  //
    18  // No further assumptions are made about the semantics of the object. For
    19  // example if some field is a pointer to a string (*const char) this will not
    20  // be read from the binary. This responsibility is offloaded to the caller.
    21  type parsableFromBytes interface {
    22  	fromBytes(elfFile *elf.File, data []byte) error
    23  	size() uint64
    24  	startSymbol() string
    25  	endSymbol() string
    26  }
    27  
    28  type kfuzztestTarget struct {
    29  	name    uint64
    30  	argType uint64
    31  	writeCb uint64
    32  	readCb  uint64
    33  }
    34  
    35  const kfuzztestTargetStart string = "__kfuzztest_targets_start"
    36  const kfuzztestTargetEnd string = "__kfuzztest_targets_end"
    37  const kfuzztestTargetSize uint64 = 32
    38  
    39  func incorrectByteSizeErr(expected, actual uint64) error {
    40  	return fmt.Errorf("incorrect number of bytes: expected %d, got %d", expected, actual)
    41  }
    42  
    43  func (targ *kfuzztestTarget) fromBytes(elfFile *elf.File, data []byte) error {
    44  	if targ.size() != uint64(len(data)) {
    45  		return incorrectByteSizeErr(targ.size(), uint64(len(data)))
    46  	}
    47  	targ.name = elfFile.ByteOrder.Uint64(data[0:8])
    48  	targ.argType = elfFile.ByteOrder.Uint64(data[8:16])
    49  	targ.writeCb = elfFile.ByteOrder.Uint64(data[16:24])
    50  	targ.readCb = elfFile.ByteOrder.Uint64(data[24:32])
    51  	return nil
    52  }
    53  
    54  func (targ *kfuzztestTarget) size() uint64 {
    55  	return kfuzztestTargetSize
    56  }
    57  
    58  func (targ *kfuzztestTarget) startSymbol() string {
    59  	return kfuzztestTargetStart
    60  }
    61  
    62  func (targ *kfuzztestTarget) endSymbol() string {
    63  	return kfuzztestTargetEnd
    64  }
    65  
    66  type kfuzztestConstraint struct {
    67  	inputType      uint64
    68  	fieldName      uint64
    69  	value1         uintptr
    70  	value2         uintptr
    71  	constraintType uint8
    72  }
    73  
    74  const kfuzztestConstraintStart string = "__kfuzztest_constraints_start"
    75  const kfuzztestConstraintEnd string = "__kfuzztest_constraints_end"
    76  const kfuzztestConstraintSize uint64 = 64
    77  
    78  func (c *kfuzztestConstraint) fromBytes(elfFile *elf.File, data []byte) error {
    79  	if c.size() != uint64(len(data)) {
    80  		return incorrectByteSizeErr(c.size(), uint64(len(data)))
    81  	}
    82  	constraintTypeBytes := elfFile.ByteOrder.Uint64(data[32:40])
    83  	c.inputType = elfFile.ByteOrder.Uint64(data[0:8])
    84  	c.fieldName = elfFile.ByteOrder.Uint64(data[8:16])
    85  	c.value1 = uintptr(elfFile.ByteOrder.Uint64(data[16:24]))
    86  	c.value2 = uintptr(elfFile.ByteOrder.Uint64(data[24:32]))
    87  	c.constraintType = uint8(constraintTypeBytes & 0xFF)
    88  	return nil
    89  }
    90  
    91  func (c *kfuzztestConstraint) size() uint64 {
    92  	return kfuzztestConstraintSize
    93  }
    94  
    95  func (c *kfuzztestConstraint) startSymbol() string {
    96  	return kfuzztestConstraintStart
    97  }
    98  
    99  func (c *kfuzztestConstraint) endSymbol() string {
   100  	return kfuzztestConstraintEnd
   101  }
   102  
   103  type kfuzztestAnnotation struct {
   104  	inputType           uint64
   105  	fieldName           uint64
   106  	linkedFieldName     uint64
   107  	annotationAttribute uint8
   108  }
   109  
   110  func (a *kfuzztestAnnotation) fromBytes(elfFile *elf.File, data []byte) error {
   111  	if a.size() != uint64(len(data)) {
   112  		return incorrectByteSizeErr(a.size(), uint64(len(data)))
   113  	}
   114  	a.inputType = elfFile.ByteOrder.Uint64(data[0:8])
   115  	a.fieldName = elfFile.ByteOrder.Uint64(data[8:16])
   116  	a.linkedFieldName = elfFile.ByteOrder.Uint64(data[16:24])
   117  	a.annotationAttribute = data[24]
   118  	return nil
   119  }
   120  
   121  const kftfAnnotationStart string = "__kfuzztest_annotations_start"
   122  const kftfAnnotationEnd string = "__kfuzztest_annotations_end"
   123  const kftfAnnotationSize uint64 = 32
   124  
   125  func (a *kfuzztestAnnotation) size() uint64 {
   126  	return kftfAnnotationSize
   127  }
   128  
   129  func (a *kfuzztestAnnotation) startSymbol() string {
   130  	return kftfAnnotationStart
   131  }
   132  
   133  func (a *kfuzztestAnnotation) endSymbol() string {
   134  	return kftfAnnotationEnd
   135  }