aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/kfuzztest/types.go
blob: b533f95c3afa88575479252a3187839c7f3493b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright 2025 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
package kfuzztest

import (
	"debug/elf"
	"fmt"
)

// The parsableFromBytes interface describes a kftf object that can be parsed
// from a vmlinux binary. All objects are expected to satisfy the following
// constraints
//   - Must be statically sized. I.e. the size() function should return some
//     fixed value
//   - Densely packed: size must exactly describe the number of bytes between
//     the start address of instance i and that of instance i+1.
//
// No further assumptions are made about the semantics of the object. For
// example if some field is a pointer to a string (*const char) this will not
// be read from the binary. This responsibility is offloaded to the caller.
type parsableFromBytes interface {
	fromBytes(elfFile *elf.File, data []byte) error
	size() uint64
	startSymbol() string
	endSymbol() string
}

type kfuzztestTarget struct {
	name    uint64
	argType uint64
	writeCb uint64
	readCb  uint64
}

const kfuzztestTargetStart string = "__kfuzztest_targets_start"
const kfuzztestTargetEnd string = "__kfuzztest_targets_end"
const kfuzztestTargetSize uint64 = 32

func incorrectByteSizeErr(expected, actual uint64) error {
	return fmt.Errorf("incorrect number of bytes: expected %d, got %d", expected, actual)
}

func (targ *kfuzztestTarget) fromBytes(elfFile *elf.File, data []byte) error {
	if targ.size() != uint64(len(data)) {
		return incorrectByteSizeErr(targ.size(), uint64(len(data)))
	}
	targ.name = elfFile.ByteOrder.Uint64(data[0:8])
	targ.argType = elfFile.ByteOrder.Uint64(data[8:16])
	targ.writeCb = elfFile.ByteOrder.Uint64(data[16:24])
	targ.readCb = elfFile.ByteOrder.Uint64(data[24:32])
	return nil
}

func (targ *kfuzztestTarget) size() uint64 {
	return kfuzztestTargetSize
}

func (targ *kfuzztestTarget) startSymbol() string {
	return kfuzztestTargetStart
}

func (targ *kfuzztestTarget) endSymbol() string {
	return kfuzztestTargetEnd
}

type kfuzztestConstraint struct {
	inputType      uint64
	fieldName      uint64
	value1         uintptr
	value2         uintptr
	constraintType uint8
}

const kfuzztestConstraintStart string = "__kfuzztest_constraints_start"
const kfuzztestConstraintEnd string = "__kfuzztest_constraints_end"
const kfuzztestConstraintSize uint64 = 64

func (c *kfuzztestConstraint) fromBytes(elfFile *elf.File, data []byte) error {
	if c.size() != uint64(len(data)) {
		return incorrectByteSizeErr(c.size(), uint64(len(data)))
	}
	constraintTypeBytes := elfFile.ByteOrder.Uint64(data[32:40])
	c.inputType = elfFile.ByteOrder.Uint64(data[0:8])
	c.fieldName = elfFile.ByteOrder.Uint64(data[8:16])
	c.value1 = uintptr(elfFile.ByteOrder.Uint64(data[16:24]))
	c.value2 = uintptr(elfFile.ByteOrder.Uint64(data[24:32]))
	c.constraintType = uint8(constraintTypeBytes & 0xFF)
	return nil
}

func (c *kfuzztestConstraint) size() uint64 {
	return kfuzztestConstraintSize
}

func (c *kfuzztestConstraint) startSymbol() string {
	return kfuzztestConstraintStart
}

func (c *kfuzztestConstraint) endSymbol() string {
	return kfuzztestConstraintEnd
}

type kfuzztestAnnotation struct {
	inputType           uint64
	fieldName           uint64
	linkedFieldName     uint64
	annotationAttribute uint8
}

func (a *kfuzztestAnnotation) fromBytes(elfFile *elf.File, data []byte) error {
	if a.size() != uint64(len(data)) {
		return incorrectByteSizeErr(a.size(), uint64(len(data)))
	}
	a.inputType = elfFile.ByteOrder.Uint64(data[0:8])
	a.fieldName = elfFile.ByteOrder.Uint64(data[8:16])
	a.linkedFieldName = elfFile.ByteOrder.Uint64(data[16:24])
	a.annotationAttribute = data[24]
	return nil
}

const kftfAnnotationStart string = "__kfuzztest_annotations_start"
const kftfAnnotationEnd string = "__kfuzztest_annotations_end"
const kftfAnnotationSize uint64 = 32

func (a *kfuzztestAnnotation) size() uint64 {
	return kftfAnnotationSize
}

func (a *kfuzztestAnnotation) startSymbol() string {
	return kftfAnnotationStart
}

func (a *kfuzztestAnnotation) endSymbol() string {
	return kftfAnnotationEnd
}