syzkaller/sys/decl.go

678 lines
11 KiB
Go
Raw Normal View History

// Copyright 2015/2016 syzkaller project authors. All rights reserved.
2015-10-12 08:16:57 +00:00
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
package sys
import (
"fmt"
)
const ptrSize = 8
2015-10-12 08:16:57 +00:00
type Call struct {
ID int
NR int // kernel syscall number
2015-10-12 08:16:57 +00:00
CallID int
Name string
CallName string
Args []Type
Ret Type
}
type Type interface {
Name() string
Optional() bool
Default() uintptr
Size() uintptr
Align() uintptr
2015-10-12 08:16:57 +00:00
}
func IsPad(t Type) bool {
if ct, ok := t.(ConstType); ok && ct.IsPad {
return true
}
return false
}
2015-10-12 08:16:57 +00:00
type TypeCommon struct {
TypeName string
IsOptional bool
}
func (t TypeCommon) Name() string {
return t.TypeName
}
func (t TypeCommon) Optional() bool {
return t.IsOptional
}
func (t TypeCommon) Default() uintptr {
return 0
}
type (
ResourceKind int
ResourceSubkind int
)
const (
ResFD ResourceKind = iota
ResIOCtx
ResIPC
ResKey
ResInotifyDesc
ResPid
ResUid
ResGid
ResTimerid
2015-10-13 15:06:01 +00:00
ResIocbPtr
2016-01-15 23:23:47 +00:00
ResDrmCtx
2015-10-12 08:16:57 +00:00
)
const (
ResAny ResourceSubkind = iota
FdFile
FdSock
FdPipe
FdSignal
FdEvent
FdTimer
FdEpoll
FdDir
FdMq
FdInotify
FdFanotify
2015-11-16 18:14:05 +00:00
FdTty
2015-11-18 20:22:17 +00:00
FdDRI
2015-11-19 16:16:36 +00:00
FdFuse
2015-11-19 16:27:23 +00:00
FdKdbus
2015-11-29 10:05:08 +00:00
FdBpfMap
FdBpfProg
2015-11-29 11:19:58 +00:00
FdPerf
2015-11-30 15:31:45 +00:00
FdUserFault
2015-12-09 15:43:47 +00:00
FdAlg
FdAlgConn
2015-12-11 18:50:21 +00:00
FdNfcRaw
FdNfcLlcp
2015-12-16 17:38:50 +00:00
FdBtHci
FdBtSco
FdBtL2cap
FdBtRfcomm
FdBtHidp
FdBtCmtp
FdBtBnep
2015-12-28 18:11:03 +00:00
FdUnix
2015-12-30 12:04:00 +00:00
FdSctp
2016-01-22 23:54:53 +00:00
FdNetlink
2016-01-08 21:33:40 +00:00
FdKvm
FdKvmVm
FdKvmCpu
2016-01-11 21:16:14 +00:00
FdSndSeq
2016-01-12 19:14:56 +00:00
FdSndTimer
2016-01-13 14:20:09 +00:00
FdSndControl
FdInputEvent
FdTun
FdRandom
2016-06-10 13:57:19 +00:00
FdKcm
FdNetRom
2015-10-12 08:16:57 +00:00
IPCMsq
IPCSem
IPCShm
)
func ResourceKinds() []ResourceKind {
return []ResourceKind{
ResFD,
ResIOCtx,
ResIPC,
ResKey,
ResInotifyDesc,
ResPid,
ResUid,
ResGid,
ResTimerid,
ResIocbPtr,
}
}
func ResourceSubkinds(kind ResourceKind) []ResourceSubkind {
switch kind {
case ResFD:
return []ResourceSubkind{ResAny, FdFile, FdSock, FdPipe, FdSignal, FdEvent,
FdTimer, FdEpoll, FdDir, FdMq, FdInotify, FdFanotify, FdTty,
FdDRI, FdFuse, FdKdbus, FdBpfMap, FdBpfProg, FdPerf, FdUserFault,
FdAlg, FdAlgConn, FdNfcRaw, FdNfcLlcp, FdBtHci, FdBtSco, FdBtL2cap,
2016-01-22 23:54:53 +00:00
FdBtRfcomm, FdBtHidp, FdBtCmtp, FdBtBnep, FdUnix, FdSctp, FdNetlink, FdKvm, FdKvmVm,
2016-06-10 13:57:19 +00:00
FdKvmCpu, FdSndSeq, FdSndTimer, FdSndControl, FdInputEvent, FdTun, FdRandom, FdKcm,
FdNetRom}
case ResIPC:
return []ResourceSubkind{IPCMsq, IPCSem, IPCShm}
2016-01-15 23:23:47 +00:00
case ResIOCtx, ResKey, ResInotifyDesc, ResPid, ResUid, ResGid, ResTimerid, ResIocbPtr, ResDrmCtx:
return []ResourceSubkind{ResAny}
default:
panic("unknown resource kind")
}
}
func SocketSubkinds() []ResourceSubkind {
return []ResourceSubkind{FdAlg, FdAlgConn, FdNfcRaw, FdNfcLlcp, FdBtHci, FdBtSco,
2016-01-22 23:54:53 +00:00
FdBtL2cap, FdBtRfcomm, FdBtHidp, FdBtCmtp, FdBtBnep, FdUnix, FdSctp, FdNetlink}
}
2015-10-12 08:16:57 +00:00
const (
InvalidFD = ^uintptr(0)
BogusFD = uintptr(100000 - 1)
)
type ResourceType struct {
TypeCommon
Kind ResourceKind
Subkind ResourceSubkind
}
func (t ResourceType) Default() uintptr {
switch t.Kind {
case ResFD:
return InvalidFD
case ResIOCtx:
return 0
case ResIPC:
return 0
case ResKey:
return 0
case ResInotifyDesc:
return 0
case ResPid:
return 0
case ResUid:
return 0
case ResGid:
return 0
case ResTimerid:
return 0
2016-01-15 23:23:47 +00:00
case ResDrmCtx:
return 0
2015-10-12 08:16:57 +00:00
default:
panic("unknown resource type")
}
}
func (t ResourceType) SpecialValues() []uintptr {
switch t.Kind {
case ResFD:
return []uintptr{InvalidFD, BogusFD, AT_FDCWD}
2015-10-12 08:16:57 +00:00
case ResIOCtx:
return []uintptr{0}
case ResIPC:
return []uintptr{0, ^uintptr(0)}
case ResKey:
2015-11-06 20:15:31 +00:00
// KEY_SPEC_THREAD_KEYRING values
2015-11-29 10:05:08 +00:00
return []uintptr{0, ^uintptr(0), ^uintptr(0) - 1, ^uintptr(0) - 2, ^uintptr(0) - 3,
^uintptr(0) - 4, ^uintptr(0) - 5, ^uintptr(0) - 6, ^uintptr(0) - 7}
2015-10-12 08:16:57 +00:00
case ResInotifyDesc:
return []uintptr{0}
case ResPid:
return []uintptr{0, ^uintptr(0)}
case ResUid:
return []uintptr{0, ^uintptr(0)}
case ResGid:
return []uintptr{0, ^uintptr(0)}
case ResTimerid:
return []uintptr{0}
2016-01-15 23:23:47 +00:00
case ResDrmCtx:
return []uintptr{0}
2015-10-12 08:16:57 +00:00
default:
panic("unknown resource kind")
}
}
func (t ResourceType) Size() uintptr {
switch t.Kind {
case ResFD:
return 4
case ResIOCtx:
return 8
case ResIPC:
return 4
case ResKey:
return 4
case ResInotifyDesc:
return 4
case ResPid:
return 4
case ResUid:
return 4
case ResGid:
return 4
case ResTimerid:
return 4
2016-01-15 23:23:47 +00:00
case ResDrmCtx:
return 4
2015-10-12 08:16:57 +00:00
default:
panic("unknown resource kind")
}
}
func (t ResourceType) Align() uintptr {
return t.Size()
}
2015-10-12 08:16:57 +00:00
func (t ResourceType) SubKinds() []ResourceSubkind {
return ResourceSubkinds(t.Kind)
2015-10-12 08:16:57 +00:00
}
type FileoffType struct {
TypeCommon
TypeSize uintptr
File string
}
func (t FileoffType) Size() uintptr {
return t.TypeSize
}
func (t FileoffType) Align() uintptr {
return t.Size()
}
2015-10-12 08:16:57 +00:00
type BufferKind int
const (
BufferBlob BufferKind = iota
BufferString
BufferSockaddr
2015-10-15 15:58:37 +00:00
BufferFilesystem
2015-12-09 15:43:47 +00:00
BufferAlgType
BufferAlgName
2015-10-12 08:16:57 +00:00
)
type BufferType struct {
TypeCommon
Kind BufferKind
}
func (t BufferType) Size() uintptr {
switch t.Kind {
case BufferAlgType:
return 14
case BufferAlgName:
return 64
default:
panic(fmt.Sprintf("buffer size is not statically known: %v", t.Name()))
}
}
func (t BufferType) Align() uintptr {
return 1
}
2015-10-12 08:16:57 +00:00
type VmaType struct {
TypeCommon
}
func (t VmaType) Size() uintptr {
return ptrSize
}
func (t VmaType) Align() uintptr {
return t.Size()
}
2015-10-12 08:16:57 +00:00
type LenType struct {
TypeCommon
TypeSize uintptr
ByteSize bool // want size in bytes instead of array size
2015-10-12 08:16:57 +00:00
Buf string
}
func (t LenType) Size() uintptr {
return t.TypeSize
}
func (t LenType) Align() uintptr {
return t.Size()
}
2015-10-12 08:16:57 +00:00
type FlagsType struct {
TypeCommon
TypeSize uintptr
Vals []uintptr
}
func (t FlagsType) Size() uintptr {
return t.TypeSize
}
func (t FlagsType) Align() uintptr {
return t.Size()
}
type ConstType struct {
TypeCommon
TypeSize uintptr
Val uintptr
IsPad bool
}
func (t ConstType) Size() uintptr {
return t.TypeSize
}
func (t ConstType) Align() uintptr {
return t.Size()
}
2015-11-16 18:14:05 +00:00
type StrConstType struct {
TypeCommon
TypeSize uintptr
Val string
}
func (t StrConstType) Size() uintptr {
return ptrSize
}
func (t StrConstType) Align() uintptr {
return t.Size()
}
2015-10-13 18:10:22 +00:00
type IntKind int
const (
IntPlain IntKind = iota
IntSignalno
IntInaddr
2015-12-30 12:04:00 +00:00
IntInport
IntRange
2015-10-13 18:10:22 +00:00
)
2015-10-12 08:16:57 +00:00
type IntType struct {
TypeCommon
2016-08-13 16:02:44 +00:00
TypeSize uintptr
Kind IntKind
RangeBegin int64
2016-08-13 16:02:44 +00:00
RangeEnd int64
2015-10-12 08:16:57 +00:00
}
func (t IntType) Size() uintptr {
return t.TypeSize
}
func (t IntType) Align() uintptr {
return t.Size()
}
2015-10-12 08:16:57 +00:00
type FilenameType struct {
TypeCommon
}
func (t FilenameType) Size() uintptr {
panic("filename size is not statically known")
}
func (t FilenameType) Align() uintptr {
return 1
}
2015-10-12 08:16:57 +00:00
type ArrayType struct {
TypeCommon
Type Type
2015-12-16 17:38:50 +00:00
Len uintptr // 0 if variable-length, unused for now
2015-10-12 08:16:57 +00:00
}
func (t ArrayType) Size() uintptr {
2015-12-16 18:17:46 +00:00
if t.Len == 0 {
return 0 // for trailing embed arrays
}
return t.Len * t.Type.Size()
}
func (t ArrayType) Align() uintptr {
return t.Type.Align()
}
2015-10-12 08:16:57 +00:00
type PtrType struct {
TypeCommon
Type Type
Dir Dir
}
func (t PtrType) Size() uintptr {
return ptrSize
}
func (t PtrType) Align() uintptr {
return t.Size()
}
2015-10-12 08:16:57 +00:00
type StructType struct {
TypeCommon
Fields []Type
padded bool
packed bool
align uintptr
}
func (t StructType) Size() uintptr {
if !t.padded {
panic("struct is not padded yet")
}
var size uintptr
for _, f := range t.Fields {
size += f.Size()
}
return size
}
func (t StructType) Align() uintptr {
if t.align != 0 {
return t.align // overrided by user attribute
}
var align uintptr
for _, f := range t.Fields {
if a1 := f.Align(); align < a1 {
align = a1
}
}
return align
2015-10-12 08:16:57 +00:00
}
2015-12-29 14:00:57 +00:00
type UnionType struct {
TypeCommon
Options []Type
2016-01-11 21:16:14 +00:00
varlen bool
2015-12-29 14:00:57 +00:00
}
func (t UnionType) Size() uintptr {
2016-01-11 21:16:14 +00:00
if t.varlen {
panic("union size is not statically known")
}
2015-12-31 14:44:06 +00:00
size := t.Options[0].Size()
for _, opt := range t.Options {
2016-01-11 21:16:14 +00:00
if size < opt.Size() {
size = opt.Size()
2015-12-31 14:44:06 +00:00
}
}
return size
2015-12-29 14:00:57 +00:00
}
func (t UnionType) Align() uintptr {
var align uintptr
for _, opt := range t.Options {
if a1 := opt.Align(); align < a1 {
align = a1
}
}
return align
}
2015-10-12 08:16:57 +00:00
type Dir int
const (
DirIn Dir = iota
DirOut
DirInOut
)
var ctors = make(map[ResourceKind]map[ResourceSubkind][]*Call)
// ResourceConstructors returns a list of calls that can create a resource of the given kind/subkind.
func ResourceConstructors(kind ResourceKind, sk ResourceSubkind) []*Call {
return ctors[kind][sk]
}
func initResources() {
for _, kind := range ResourceKinds() {
ctors[kind] = make(map[ResourceSubkind][]*Call)
for _, sk := range ResourceSubkinds(kind) {
ctors[kind][sk] = ResourceCtors(kind, sk, false)
}
}
}
func ResourceCtors(kind ResourceKind, sk ResourceSubkind, precise bool) []*Call {
// Find calls that produce the necessary resources.
var metas []*Call
// Recurse into arguments to see if there is an out/inout arg of necessary type.
var checkArg func(typ Type, dir Dir) bool
checkArg = func(typ Type, dir Dir) bool {
if resarg, ok := typ.(ResourceType); ok && dir != DirIn && resarg.Kind == kind &&
(sk == resarg.Subkind || sk == ResAny || (resarg.Subkind == ResAny && !precise)) {
return true
}
switch typ1 := typ.(type) {
case ArrayType:
if checkArg(typ1.Type, dir) {
return true
}
case StructType:
for _, fld := range typ1.Fields {
if checkArg(fld, dir) {
return true
}
}
2015-12-29 14:00:57 +00:00
case UnionType:
for _, opt := range typ1.Options {
if checkArg(opt, dir) {
return true
}
}
case PtrType:
if checkArg(typ1.Type, typ1.Dir) {
return true
}
}
return false
}
for _, meta := range Calls {
ok := false
for _, arg := range meta.Args {
if checkArg(arg, DirIn) {
ok = true
break
}
}
if !ok && meta.Ret != nil && checkArg(meta.Ret, DirOut) {
ok = true
}
if ok {
metas = append(metas, meta)
}
}
return metas
}
func (c *Call) InputResources() []ResourceType {
var resources []ResourceType
var checkArg func(typ Type, dir Dir)
checkArg = func(typ Type, dir Dir) {
switch typ1 := typ.(type) {
case ResourceType:
if dir != DirOut && !typ1.IsOptional {
resources = append(resources, typ1)
}
case ArrayType:
checkArg(typ1.Type, dir)
case PtrType:
checkArg(typ1.Type, typ1.Dir)
case StructType:
for _, fld := range typ1.Fields {
checkArg(fld, dir)
}
2015-12-29 14:00:57 +00:00
case UnionType:
for _, opt := range typ1.Options {
checkArg(opt, dir)
}
}
}
for _, arg := range c.Args {
checkArg(arg, DirIn)
}
return resources
}
func TransitivelyEnabledCalls(enabled map[*Call]bool) map[*Call]bool {
supported := make(map[*Call]bool)
for c := range enabled {
supported[c] = true
}
for {
n := len(supported)
for c := range enabled {
if !supported[c] {
continue
}
canCreate := true
for _, res := range c.InputResources() {
noctors := true
for _, ctor := range ResourceCtors(res.Kind, res.Subkind, true) {
if supported[ctor] {
noctors = false
break
}
}
if noctors {
canCreate = false
break
}
}
if !canCreate {
delete(supported, c)
}
}
if n == len(supported) {
break
}
}
return supported
}
2015-10-12 08:16:57 +00:00
var (
CallCount int
CallMap = make(map[string]*Call)
CallID = make(map[string]int)
)
func init() {
initCalls()
initResources()
2015-12-31 14:44:06 +00:00
initAlign()
2015-10-12 08:16:57 +00:00
for _, c := range Calls {
if CallMap[c.Name] != nil {
println(c.Name)
panic("duplicate syscall")
}
id, ok := CallID[c.CallName]
if !ok {
id = len(CallID)
CallID[c.CallName] = id
}
c.CallID = id
CallMap[c.Name] = c
}
CallCount = len(CallID)
}