mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-23 11:29:46 +00:00
prog: introduce call attributes
Add common infrastructure for syscall attributes. Add few attributes we want, but they are not implemented for now (don't affect behavior, this will follow).
This commit is contained in:
parent
0781895e0f
commit
90d17ab898
6
executor/defs.h
generated
6
executor/defs.h
generated
@ -1,5 +1,11 @@
|
||||
// AUTOGENERATED FILE
|
||||
|
||||
struct call_attrs_t {
|
||||
uint64_t disabled;
|
||||
uint64_t timeout;
|
||||
uint64_t prog_timeout;
|
||||
};
|
||||
|
||||
#if GOOS_akaros
|
||||
#define GOOS "akaros"
|
||||
|
||||
|
@ -172,6 +172,7 @@ typedef intptr_t(SYSCALLAPI* syscall_t)(intptr_t, intptr_t, intptr_t, intptr_t,
|
||||
struct call_t {
|
||||
const char* name;
|
||||
int sys_nr;
|
||||
call_attrs_t attrs;
|
||||
syscall_t call;
|
||||
};
|
||||
|
||||
@ -686,6 +687,9 @@ retry:
|
||||
// Normal syscall.
|
||||
if (call_num >= ARRAY_SIZE(syscalls))
|
||||
fail("invalid command number %llu", call_num);
|
||||
const call_t* call = &syscalls[call_num];
|
||||
if (call->attrs.disabled)
|
||||
fail("executing disabled syscall %s", call->name);
|
||||
// call_extra_timeout must match timeout in pkg/csource/csource.go.
|
||||
int call_extra_timeout = 0;
|
||||
// TODO: find a way to tune timeout values.
|
||||
|
9120
executor/syscalls.h
generated
9120
executor/syscalls.h
generated
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,10 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/google/syzkaller/pkg/ast"
|
||||
"github.com/google/syzkaller/prog"
|
||||
)
|
||||
|
||||
type attrDesc struct {
|
||||
@ -23,9 +26,12 @@ var (
|
||||
|
||||
structAttrs = makeAttrs(attrPacked, attrSize, attrAlign)
|
||||
unionAttrs = makeAttrs(attrVarlen, attrSize)
|
||||
callAttrs = make(map[string]*attrDesc)
|
||||
)
|
||||
|
||||
func init() {
|
||||
initCallAttrs()
|
||||
|
||||
attrSize.CheckConsts = func(comp *compiler, parent ast.Node, attr *ast.Type) {
|
||||
_, typ, name := parent.Info()
|
||||
if comp.structIsVarlen(name) {
|
||||
@ -46,6 +52,22 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
func initCallAttrs() {
|
||||
attrs := reflect.TypeOf(prog.SyscallAttrs{})
|
||||
for i := 0; i < attrs.NumField(); i++ {
|
||||
attr := attrs.Field(i)
|
||||
desc := &attrDesc{Name: attr.Name}
|
||||
switch attr.Type.Kind() {
|
||||
case reflect.Bool:
|
||||
case reflect.Uint64:
|
||||
desc.HasArg = true
|
||||
default:
|
||||
panic("unsupported syscall attribute type")
|
||||
}
|
||||
callAttrs[prog.CppName(desc.Name)] = desc
|
||||
}
|
||||
}
|
||||
|
||||
func structOrUnionAttrs(n *ast.Struct) map[string]*attrDesc {
|
||||
if n.IsUnion {
|
||||
return unionAttrs
|
||||
|
@ -713,6 +713,7 @@ func (comp *compiler) checkCall(n *ast.Call) {
|
||||
if n.Ret != nil {
|
||||
comp.checkType(checkCtx{}, n.Ret, checkIsArg|checkIsRet)
|
||||
}
|
||||
comp.parseAttrs(callAttrs, n, n.Attrs)
|
||||
}
|
||||
|
||||
type checkFlags int
|
||||
|
@ -77,32 +77,11 @@ func (comp *compiler) extractConsts() map[string]*ConstInfo {
|
||||
if comp.target.SyscallNumbers && !strings.HasPrefix(n.CallName, "syz_") {
|
||||
comp.addConst(infos, pos, comp.target.SyscallPrefix+n.CallName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, decl := range comp.desc.Nodes {
|
||||
switch decl.(type) {
|
||||
case *ast.Call, *ast.Struct, *ast.Resource, *ast.TypeDef:
|
||||
comp.foreachType(decl, func(t *ast.Type, desc *typeDesc,
|
||||
args []*ast.Type, _ prog.IntTypeCommon) {
|
||||
for i, arg := range args {
|
||||
if desc.Args[i].Type.Kind == kindInt {
|
||||
if arg.Ident != "" {
|
||||
comp.addConst(infos, arg.Pos, arg.Ident)
|
||||
}
|
||||
for _, col := range arg.Colon {
|
||||
if col.Ident != "" {
|
||||
comp.addConst(infos, col.Pos, col.Ident)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, attr := range n.Attrs {
|
||||
if callAttrs[attr.Ident].HasArg {
|
||||
comp.addConst(infos, attr.Pos, attr.Args[0].Ident)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for _, decl := range comp.desc.Nodes {
|
||||
switch n := decl.(type) {
|
||||
}
|
||||
case *ast.Struct:
|
||||
for _, attr := range n.Attrs {
|
||||
if structOrUnionAttrs(n)[attr.Ident].HasArg {
|
||||
@ -110,17 +89,36 @@ func (comp *compiler) extractConsts() map[string]*ConstInfo {
|
||||
}
|
||||
}
|
||||
}
|
||||
switch decl.(type) {
|
||||
case *ast.Call, *ast.Struct, *ast.Resource, *ast.TypeDef:
|
||||
comp.extractTypeConsts(infos, decl)
|
||||
}
|
||||
}
|
||||
|
||||
comp.desc.Walk(ast.Recursive(func(n0 ast.Node) {
|
||||
if n, ok := n0.(*ast.Int); ok {
|
||||
comp.addConst(infos, n.Pos, n.Ident)
|
||||
}
|
||||
}))
|
||||
|
||||
return convertConstInfo(infos)
|
||||
}
|
||||
|
||||
func (comp *compiler) extractTypeConsts(infos map[string]*constInfo, n ast.Node) {
|
||||
comp.foreachType(n, func(t *ast.Type, desc *typeDesc, args []*ast.Type, _ prog.IntTypeCommon) {
|
||||
for i, arg := range args {
|
||||
if desc.Args[i].Type.Kind == kindInt {
|
||||
if arg.Ident != "" {
|
||||
comp.addConst(infos, arg.Pos, arg.Ident)
|
||||
}
|
||||
for _, col := range arg.Colon {
|
||||
if col.Ident != "" {
|
||||
comp.addConst(infos, col.Pos, col.Ident)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (comp *compiler) addConst(infos map[string]*constInfo, pos ast.Pos, name string) {
|
||||
if _, builtin := comp.builtinConsts[name]; builtin {
|
||||
return
|
||||
@ -220,12 +218,18 @@ func (comp *compiler) patchConsts(consts0 map[string]uint64) {
|
||||
}
|
||||
}
|
||||
})
|
||||
if n, ok := decl.(*ast.Resource); ok {
|
||||
switch n := decl.(type) {
|
||||
case *ast.Resource:
|
||||
for _, v := range n.Values {
|
||||
comp.patchIntConst(v, consts, &missing)
|
||||
}
|
||||
}
|
||||
if n, ok := decl.(*ast.Struct); ok {
|
||||
case *ast.Call:
|
||||
for _, attr := range n.Attrs {
|
||||
if callAttrs[attr.Ident].HasArg {
|
||||
comp.patchTypeConst(attr.Args[0], consts, &missing)
|
||||
}
|
||||
}
|
||||
case *ast.Struct:
|
||||
for _, attr := range n.Attrs {
|
||||
if structOrUnionAttrs(n)[attr.Ident].HasArg {
|
||||
comp.patchTypeConst(attr.Args[0], consts, &missing)
|
||||
|
@ -5,6 +5,7 @@ package compiler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
||||
"github.com/google/syzkaller/pkg/ast"
|
||||
@ -111,6 +112,16 @@ func (comp *compiler) genSyscall(n *ast.Call, argSizes []uint64) *prog.Syscall {
|
||||
if n.Ret != nil {
|
||||
ret = comp.genType(n.Ret, "ret", prog.DirOut, comp.ptrSize)
|
||||
}
|
||||
var attrs prog.SyscallAttrs
|
||||
descAttrs := comp.parseAttrs(callAttrs, n, n.Attrs)
|
||||
for desc, val := range descAttrs {
|
||||
fld := reflect.ValueOf(&attrs).Elem().FieldByName(desc.Name)
|
||||
if desc.HasArg {
|
||||
fld.SetUint(val)
|
||||
} else {
|
||||
fld.SetBool(val != 0)
|
||||
}
|
||||
}
|
||||
return &prog.Syscall{
|
||||
Name: n.Name.Name,
|
||||
CallName: n.CallName,
|
||||
@ -118,6 +129,7 @@ func (comp *compiler) genSyscall(n *ast.Call, argSizes []uint64) *prog.Syscall {
|
||||
MissingArgs: len(argSizes) - len(n.Args),
|
||||
Args: comp.genFieldArray(n.Args, prog.DirIn, argSizes),
|
||||
Ret: ret,
|
||||
Attrs: attrs,
|
||||
}
|
||||
}
|
||||
|
||||
|
3
pkg/compiler/testdata/all.txt
vendored
3
pkg/compiler/testdata/all.txt
vendored
@ -14,6 +14,9 @@ foo_9(a ptr[out, ptr[in, string]])
|
||||
foo_10(a ptr[out, buffer[in]])
|
||||
foo_11(a int64[1:100, 2])
|
||||
foo_12(a int64[0:-1, 0x1000])
|
||||
foo_13() (disabled)
|
||||
foo_14() r0 (timeout[100])
|
||||
foo_15() r0 (disabled, timeout[C1], prog_timeout[C2])
|
||||
|
||||
resource r0[intptr]
|
||||
|
||||
|
3
pkg/compiler/testdata/errors.txt
vendored
3
pkg/compiler/testdata/errors.txt
vendored
@ -125,6 +125,9 @@ foo$65(a int32, b len[1]) ### unexpected int 1 for len target argument of len ty
|
||||
foo$66(a int32, b len[a:1]) ### unexpected int 1 after colon, expect identifier
|
||||
foo$67(x int32[1:2:3, opt]) ### unexpected ':'
|
||||
foo$68(a int32[15, 2]) ### first argument of int32 needs to be a range
|
||||
foo$69() (foo) ### unknown syscall foo$69 attribute foo
|
||||
foo$70() ("foo") ### unexpected string "foo", expect attribute
|
||||
foo$71() (42) ### unexpected int 42, expect attribute
|
||||
|
||||
opt { ### struct uses reserved name opt
|
||||
f1 int32
|
||||
|
@ -555,6 +555,9 @@ func (r *randGen) generateCall(s *state, p *Prog, insertionPoint int) []*Call {
|
||||
}
|
||||
|
||||
func (r *randGen) generateParticularCall(s *state, meta *Syscall) (calls []*Call) {
|
||||
if meta.Attrs.Disabled {
|
||||
panic(fmt.Sprintf("generating disabled call %v", meta.Name))
|
||||
}
|
||||
c := &Call{
|
||||
Meta: meta,
|
||||
Ret: MakeReturnArg(meta.Ret),
|
||||
|
@ -6,6 +6,7 @@ package prog
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
type Syscall struct {
|
||||
@ -16,11 +17,29 @@ type Syscall struct {
|
||||
MissingArgs int // number of trailing args that should be zero-filled
|
||||
Args []Type
|
||||
Ret Type
|
||||
Attrs SyscallAttrs
|
||||
|
||||
inputResources []*ResourceDesc
|
||||
outputResources []*ResourceDesc
|
||||
}
|
||||
|
||||
// SyscallAttrs represents call attributes in syzlang.
|
||||
//
|
||||
// This structure is the source of truth for the all other parts of the system.
|
||||
// pkg/compiler uses this structure to parse descriptions.
|
||||
// syz-sysgen uses this structure to generate code for executor.
|
||||
//
|
||||
// Only bool's and uint64's are currently supported.
|
||||
type SyscallAttrs struct {
|
||||
// Never enable this system call in fuzzing.
|
||||
Disabled bool
|
||||
// Additional execution timeout (in ms) for the call on top of some default value.
|
||||
Timeout uint64
|
||||
// Additional execution timeout (in ms) for the whole program if it contains this call.
|
||||
// If a program contains several such calls, the max value is used.
|
||||
ProgTimeout uint64
|
||||
}
|
||||
|
||||
// MaxArgs is maximum number of syscall arguments.
|
||||
// Executor also knows about this value.
|
||||
const MaxArgs = 9
|
||||
@ -653,3 +672,16 @@ func ForeachType(meta *Syscall, f func(Type)) {
|
||||
rec(meta.Ret)
|
||||
}
|
||||
}
|
||||
|
||||
// CppName transforms PascalStyleNames to cpp_style_names.
|
||||
func CppName(name string) string {
|
||||
var res []byte
|
||||
for i := range name {
|
||||
c := rune(name[i])
|
||||
if unicode.IsUpper(c) && i != 0 && !unicode.IsUpper(rune(name[i-1])) {
|
||||
res = append(res, '_')
|
||||
}
|
||||
res = append(res, byte(unicode.ToLower(c)))
|
||||
}
|
||||
return string(res)
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"sort"
|
||||
@ -37,6 +38,7 @@ type SyscallData struct {
|
||||
CallName string
|
||||
NR int32
|
||||
NeedCall bool
|
||||
Attrs []uint64
|
||||
}
|
||||
|
||||
type ArchData struct {
|
||||
@ -55,6 +57,11 @@ type OSData struct {
|
||||
Archs []ArchData
|
||||
}
|
||||
|
||||
type ExecutorData struct {
|
||||
OSes []OSData
|
||||
CallAttrs []string
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
@ -64,7 +71,7 @@ func main() {
|
||||
}
|
||||
sort.Strings(OSList)
|
||||
|
||||
var oses []OSData
|
||||
data := &ExecutorData{}
|
||||
for _, OS := range OSList {
|
||||
top := ast.ParseGlob(filepath.Join("sys", OS, "*.txt"), nil)
|
||||
if top == nil {
|
||||
@ -150,7 +157,7 @@ func main() {
|
||||
unsupported[u]++
|
||||
}
|
||||
}
|
||||
oses = append(oses, OSData{
|
||||
data.OSes = append(data.OSes, OSData{
|
||||
GOOS: OS,
|
||||
Archs: syscallArchs,
|
||||
})
|
||||
@ -162,7 +169,12 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
writeExecutorSyscalls(oses)
|
||||
attrs := reflect.TypeOf(prog.SyscallAttrs{})
|
||||
for i := 0; i < attrs.NumField(); i++ {
|
||||
data.CallAttrs = append(data.CallAttrs, prog.CppName(attrs.Field(i).Name))
|
||||
}
|
||||
|
||||
writeExecutorSyscalls(data)
|
||||
|
||||
if *flagMemProfile != "" {
|
||||
f, err := os.Create(*flagMemProfile)
|
||||
@ -246,11 +258,33 @@ func generateExecutorSyscalls(target *targets.Target, syscalls []*prog.Syscall,
|
||||
data.Shmem = 1
|
||||
}
|
||||
for _, c := range syscalls {
|
||||
var attrVals []uint64
|
||||
attrs := reflect.ValueOf(c.Attrs)
|
||||
last := -1
|
||||
for i := 0; i < attrs.NumField(); i++ {
|
||||
attr := attrs.Field(i)
|
||||
val := uint64(0)
|
||||
switch attr.Type().Kind() {
|
||||
case reflect.Bool:
|
||||
if attr.Bool() {
|
||||
val = 1
|
||||
}
|
||||
case reflect.Uint64:
|
||||
val = attr.Uint()
|
||||
default:
|
||||
panic("unsupported syscall attribute type")
|
||||
}
|
||||
attrVals = append(attrVals, val)
|
||||
if val != 0 {
|
||||
last = i
|
||||
}
|
||||
}
|
||||
data.Calls = append(data.Calls, SyscallData{
|
||||
Name: c.Name,
|
||||
CallName: c.CallName,
|
||||
NR: int32(c.NR),
|
||||
NeedCall: !target.SyscallNumbers || strings.HasPrefix(c.CallName, "syz_"),
|
||||
Attrs: attrVals[:last+1],
|
||||
})
|
||||
}
|
||||
sort.Slice(data.Calls, func(i, j int) bool {
|
||||
@ -259,17 +293,17 @@ func generateExecutorSyscalls(target *targets.Target, syscalls []*prog.Syscall,
|
||||
return data
|
||||
}
|
||||
|
||||
func writeExecutorSyscalls(oses []OSData) {
|
||||
sort.Slice(oses, func(i, j int) bool {
|
||||
return oses[i].GOOS < oses[j].GOOS
|
||||
func writeExecutorSyscalls(data *ExecutorData) {
|
||||
sort.Slice(data.OSes, func(i, j int) bool {
|
||||
return data.OSes[i].GOOS < data.OSes[j].GOOS
|
||||
})
|
||||
buf := new(bytes.Buffer)
|
||||
if err := defsTempl.Execute(buf, oses); err != nil {
|
||||
if err := defsTempl.Execute(buf, data); err != nil {
|
||||
failf("failed to execute defs template: %v", err)
|
||||
}
|
||||
writeFile(filepath.FromSlash("executor/defs.h"), buf.Bytes())
|
||||
buf.Reset()
|
||||
if err := syscallsTempl.Execute(buf, oses); err != nil {
|
||||
if err := syscallsTempl.Execute(buf, data); err != nil {
|
||||
failf("failed to execute syscalls template: %v", err)
|
||||
}
|
||||
writeFile(filepath.FromSlash("executor/syscalls.h"), buf.Bytes())
|
||||
@ -302,7 +336,11 @@ func failf(msg string, args ...interface{}) {
|
||||
}
|
||||
|
||||
var defsTempl = template.Must(template.New("").Parse(`// AUTOGENERATED FILE
|
||||
{{range $os := $}}
|
||||
|
||||
struct call_attrs_t { {{range $attr := $.CallAttrs}}
|
||||
uint64_t {{$attr}};{{end}}
|
||||
};
|
||||
{{range $os := $.OSes}}
|
||||
#if GOOS_{{$os.GOOS}}
|
||||
#define GOOS "{{$os.GOOS}}"
|
||||
{{range $arch := $os.Archs}}
|
||||
@ -320,13 +358,14 @@ var defsTempl = template.Must(template.New("").Parse(`// AUTOGENERATED FILE
|
||||
{{end}}
|
||||
`))
|
||||
|
||||
// nolint: lll
|
||||
var syscallsTempl = template.Must(template.New("").Parse(`// AUTOGENERATED FILE
|
||||
{{range $os := $}}
|
||||
{{range $os := $.OSes}}
|
||||
#if GOOS_{{$os.GOOS}}
|
||||
{{range $arch := $os.Archs}}
|
||||
#if GOARCH_{{$arch.GOARCH}}
|
||||
const call_t syscalls[] = {
|
||||
{{range $c := $arch.Calls}} {"{{$c.Name}}", {{$c.NR}}{{if $c.NeedCall}}, (syscall_t){{$c.CallName}}{{end}}},
|
||||
{{range $c := $arch.Calls}} {"{{$c.Name}}", {{$c.NR}}{{if or $c.Attrs $c.NeedCall}}, { {{range $attr := $c.Attrs}}{{$attr}},{{end}} }{{end}}{{if $c.NeedCall}}, (syscall_t){{$c.CallName}}{{end}}},
|
||||
{{end}}
|
||||
};
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user