mirror of
https://github.com/reactos/syzkaller.git
synced 2024-10-07 17:13:26 +00:00
sys: compile all supported targets into the package
Currently we compile in only GOOS/GOARCH target. Compile in all targets so that they can be selected at runtime.
This commit is contained in:
parent
b16ba6390d
commit
34bc139642
@ -50,7 +50,8 @@ func (w *writer) do(v reflect.Value, sliceElem bool) {
|
||||
w.string("nil")
|
||||
} else {
|
||||
w.typ(v.Type())
|
||||
if sub := v.Type().Elem().Kind(); sub == reflect.Ptr || sub == reflect.Interface {
|
||||
sub := v.Type().Elem().Kind()
|
||||
if sub == reflect.Ptr || sub == reflect.Interface || sub == reflect.Struct {
|
||||
// Elem per-line.
|
||||
w.string("{\n")
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
|
@ -283,6 +283,11 @@ type KeyedStruct struct {
|
||||
Desc *StructDesc
|
||||
}
|
||||
|
||||
type ConstValue struct {
|
||||
Name string
|
||||
Value uint64
|
||||
}
|
||||
|
||||
func ForeachType(meta *Syscall, f func(Type)) {
|
||||
seen := make(map[*StructDesc]bool)
|
||||
var rec func(t Type)
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -9,27 +9,27 @@ import (
|
||||
"github.com/google/syzkaller/prog"
|
||||
)
|
||||
|
||||
func init() {
|
||||
lazyInit()
|
||||
func initArch(syscalls []*prog.Syscall, resources []*prog.ResourceDesc,
|
||||
structDescs []*prog.KeyedStruct, consts []prog.ConstValue, archName string, ptrSize uint64) {
|
||||
arch := makeArch(syscalls, resources, structDescs, consts, archName)
|
||||
target := &prog.Target{
|
||||
OS: runtime.GOOS,
|
||||
Arch: runtime.GOARCH,
|
||||
OS: "linux",
|
||||
Arch: archName,
|
||||
PtrSize: ptrSize,
|
||||
PageSize: pageSize,
|
||||
DataOffset: dataOffset,
|
||||
Syscalls: syscalls,
|
||||
Resources: resources,
|
||||
MakeMmap: makeMmap,
|
||||
AnalyzeMmap: analyzeMmap,
|
||||
SanitizeCall: sanitizeCall,
|
||||
MakeMmap: arch.makeMmap,
|
||||
AnalyzeMmap: arch.analyzeMmap,
|
||||
SanitizeCall: arch.sanitizeCall,
|
||||
SpecialStructs: map[string]func(g *prog.Gen, typ *prog.StructType, old *prog.GroupArg) (prog.Arg, []*prog.Call){
|
||||
"timespec": generateTimespec,
|
||||
"timeval": generateTimespec,
|
||||
"timespec": arch.generateTimespec,
|
||||
"timeval": arch.generateTimespec,
|
||||
},
|
||||
StringDictionary: stringDictionary,
|
||||
}
|
||||
prog.RegisterTarget(target)
|
||||
prog.SetDefaultTarget(runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
const (
|
||||
@ -39,8 +39,10 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
mmapSyscall *prog.Syscall
|
||||
clockGettimeSyscall *prog.Syscall
|
||||
// This should not be here, but for now we expose this for syz-fuzzer.
|
||||
KCOV_INIT_TRACE uintptr
|
||||
KCOV_ENABLE uintptr
|
||||
KCOV_TRACE_CMP uintptr
|
||||
|
||||
stringDictionary = []string{"user", "keyring", "trusted", "system", "security", "selinux",
|
||||
"posix_acl_access", "mime_type", "md5sum", "nodev", "self",
|
||||
@ -49,23 +51,49 @@ var (
|
||||
"vboxnet0", "vboxnet1", "vmnet0", "vmnet1", "GPL"}
|
||||
)
|
||||
|
||||
type arch struct {
|
||||
mmapSyscall *prog.Syscall
|
||||
clockGettimeSyscall *prog.Syscall
|
||||
|
||||
PROT_READ uint64
|
||||
PROT_WRITE uint64
|
||||
MAP_ANONYMOUS uint64
|
||||
MAP_PRIVATE uint64
|
||||
MAP_FIXED uint64
|
||||
MREMAP_MAYMOVE uint64
|
||||
MREMAP_FIXED uint64
|
||||
S_IFREG uint64
|
||||
S_IFCHR uint64
|
||||
S_IFBLK uint64
|
||||
S_IFIFO uint64
|
||||
S_IFSOCK uint64
|
||||
SYSLOG_ACTION_CONSOLE_OFF uint64
|
||||
SYSLOG_ACTION_CONSOLE_ON uint64
|
||||
SYSLOG_ACTION_SIZE_UNREAD uint64
|
||||
FIFREEZE uint64
|
||||
FITHAW uint64
|
||||
PTRACE_TRACEME uint64
|
||||
CLOCK_REALTIME uint64
|
||||
}
|
||||
|
||||
// createMmapCall creates a "normal" mmap call that maps [start, start+npages) page range.
|
||||
func makeMmap(start, npages uint64) *prog.Call {
|
||||
func (arch *arch) makeMmap(start, npages uint64) *prog.Call {
|
||||
meta := arch.mmapSyscall
|
||||
return &prog.Call{
|
||||
Meta: mmapSyscall,
|
||||
Meta: meta,
|
||||
Args: []prog.Arg{
|
||||
prog.MakePointerArg(mmapSyscall.Args[0], start, 0, npages, nil),
|
||||
prog.MakeConstArg(mmapSyscall.Args[1], npages*pageSize),
|
||||
prog.MakeConstArg(mmapSyscall.Args[2], PROT_READ|PROT_WRITE),
|
||||
prog.MakeConstArg(mmapSyscall.Args[3], MAP_ANONYMOUS|MAP_PRIVATE|MAP_FIXED),
|
||||
prog.MakeResultArg(mmapSyscall.Args[4], nil, invalidFD),
|
||||
prog.MakeConstArg(mmapSyscall.Args[5], 0),
|
||||
prog.MakePointerArg(meta.Args[0], start, 0, npages, nil),
|
||||
prog.MakeConstArg(meta.Args[1], npages*pageSize),
|
||||
prog.MakeConstArg(meta.Args[2], arch.PROT_READ|arch.PROT_WRITE),
|
||||
prog.MakeConstArg(meta.Args[3], arch.MAP_ANONYMOUS|arch.MAP_PRIVATE|arch.MAP_FIXED),
|
||||
prog.MakeResultArg(meta.Args[4], nil, invalidFD),
|
||||
prog.MakeConstArg(meta.Args[5], 0),
|
||||
},
|
||||
Ret: prog.MakeReturnArg(mmapSyscall.Ret),
|
||||
Ret: prog.MakeReturnArg(meta.Ret),
|
||||
}
|
||||
}
|
||||
|
||||
func analyzeMmap(c *prog.Call) (start, npages uint64, mapped bool) {
|
||||
func (arch *arch) analyzeMmap(c *prog.Call) (start, npages uint64, mapped bool) {
|
||||
switch c.Meta.Name {
|
||||
case "mmap":
|
||||
// Filter out only very wrong arguments.
|
||||
@ -75,7 +103,7 @@ func analyzeMmap(c *prog.Call) (start, npages uint64, mapped bool) {
|
||||
}
|
||||
flags := c.Args[3].(*prog.ConstArg).Val
|
||||
fd := c.Args[4].(*prog.ResultArg).Val
|
||||
if flags&MAP_ANONYMOUS == 0 && fd == invalidFD {
|
||||
if flags&arch.MAP_ANONYMOUS == 0 && fd == invalidFD {
|
||||
return
|
||||
}
|
||||
start = c.Args[0].(*prog.PointerArg).PageIndex
|
||||
@ -96,16 +124,16 @@ func analyzeMmap(c *prog.Call) (start, npages uint64, mapped bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func sanitizeCall(c *prog.Call) {
|
||||
func (arch *arch) sanitizeCall(c *prog.Call) {
|
||||
switch c.Meta.CallName {
|
||||
case "mmap":
|
||||
// Add MAP_FIXED flag, otherwise it produces non-deterministic results.
|
||||
c.Args[3].(*prog.ConstArg).Val |= MAP_FIXED
|
||||
c.Args[3].(*prog.ConstArg).Val |= arch.MAP_FIXED
|
||||
case "mremap":
|
||||
// Add MREMAP_FIXED flag, otherwise it produces non-deterministic results.
|
||||
flags := c.Args[3].(*prog.ConstArg)
|
||||
if flags.Val&MREMAP_MAYMOVE != 0 {
|
||||
flags.Val |= MREMAP_FIXED
|
||||
if flags.Val&arch.MREMAP_MAYMOVE != 0 {
|
||||
flags.Val |= arch.MREMAP_FIXED
|
||||
}
|
||||
case "mknod", "mknodat":
|
||||
pos := 1
|
||||
@ -116,37 +144,41 @@ func sanitizeCall(c *prog.Call) {
|
||||
dev := c.Args[pos+1].(*prog.ConstArg)
|
||||
// Char and block devices read/write io ports, kernel memory and do other nasty things.
|
||||
// TODO: not required if executor drops privileges.
|
||||
switch mode.Val & (S_IFREG | S_IFCHR | S_IFBLK | S_IFIFO | S_IFSOCK) {
|
||||
case S_IFREG, S_IFIFO, S_IFSOCK:
|
||||
case S_IFBLK:
|
||||
switch mode.Val & (arch.S_IFREG | arch.S_IFCHR | arch.S_IFBLK | arch.S_IFIFO | arch.S_IFSOCK) {
|
||||
case arch.S_IFREG, arch.S_IFIFO, arch.S_IFSOCK:
|
||||
case arch.S_IFBLK:
|
||||
// TODO(dvyukov): mknod dev argument is uint32,
|
||||
// but prog arguments contain not-truncated uint64 values,
|
||||
// so we can mistakenly assume that this is not loop, when it actually is.
|
||||
// This is not very harmful, but need to verify other arguments in this function.
|
||||
if dev.Val>>8 == 7 {
|
||||
break // loop
|
||||
}
|
||||
mode.Val &^= S_IFBLK
|
||||
mode.Val |= S_IFREG
|
||||
case S_IFCHR:
|
||||
mode.Val &^= S_IFCHR
|
||||
mode.Val |= S_IFREG
|
||||
mode.Val &^= arch.S_IFBLK
|
||||
mode.Val |= arch.S_IFREG
|
||||
case arch.S_IFCHR:
|
||||
mode.Val &^= arch.S_IFCHR
|
||||
mode.Val |= arch.S_IFREG
|
||||
}
|
||||
case "syslog":
|
||||
cmd := c.Args[0].(*prog.ConstArg)
|
||||
// These disable console output, but we need it.
|
||||
if cmd.Val == SYSLOG_ACTION_CONSOLE_OFF || cmd.Val == SYSLOG_ACTION_CONSOLE_ON {
|
||||
cmd.Val = SYSLOG_ACTION_SIZE_UNREAD
|
||||
if cmd.Val == arch.SYSLOG_ACTION_CONSOLE_OFF || cmd.Val == arch.SYSLOG_ACTION_CONSOLE_ON {
|
||||
cmd.Val = arch.SYSLOG_ACTION_SIZE_UNREAD
|
||||
}
|
||||
case "ioctl":
|
||||
cmd := c.Args[1].(*prog.ConstArg)
|
||||
// Freeze kills machine. Though, it is an interesting functions,
|
||||
// so we need to test it somehow.
|
||||
// TODO: not required if executor drops privileges.
|
||||
if uint32(cmd.Val) == FIFREEZE {
|
||||
cmd.Val = FITHAW
|
||||
if uint64(uint32(cmd.Val)) == arch.FIFREEZE {
|
||||
cmd.Val = arch.FITHAW
|
||||
}
|
||||
case "ptrace":
|
||||
req := c.Args[0].(*prog.ConstArg)
|
||||
// PTRACE_TRACEME leads to unkillable processes, see:
|
||||
// https://groups.google.com/forum/#!topic/syzkaller/uGzwvhlCXAw
|
||||
if req.Val == PTRACE_TRACEME {
|
||||
if req.Val == arch.PTRACE_TRACEME {
|
||||
req.Val = ^uint64(0)
|
||||
}
|
||||
case "exit", "exit_group":
|
||||
@ -158,7 +190,7 @@ func sanitizeCall(c *prog.Call) {
|
||||
}
|
||||
}
|
||||
|
||||
func generateTimespec(g *prog.Gen, typ *prog.StructType, old *prog.GroupArg) (arg prog.Arg, calls []*prog.Call) {
|
||||
func (arch *arch) generateTimespec(g *prog.Gen, typ *prog.StructType, old *prog.GroupArg) (arg prog.Arg, calls []*prog.Call) {
|
||||
// We need to generate timespec/timeval that are either
|
||||
// (1) definitely in the past, or
|
||||
// (2) definitely in unreachable fututre, or
|
||||
@ -195,7 +227,7 @@ func generateTimespec(g *prog.Gen, typ *prog.StructType, old *prog.GroupArg) (ar
|
||||
})
|
||||
default:
|
||||
// Few ms ahead for absolute.
|
||||
meta := clockGettimeSyscall
|
||||
meta := arch.clockGettimeSyscall
|
||||
ptrArgType := meta.Args[1].(*prog.PtrType)
|
||||
argType := ptrArgType.Type.(*prog.StructType)
|
||||
tp := prog.MakeGroupArg(argType, []prog.Arg{
|
||||
@ -207,7 +239,7 @@ func generateTimespec(g *prog.Gen, typ *prog.StructType, old *prog.GroupArg) (ar
|
||||
gettime := &prog.Call{
|
||||
Meta: meta,
|
||||
Args: []prog.Arg{
|
||||
prog.MakeConstArg(meta.Args[0], CLOCK_REALTIME),
|
||||
prog.MakeConstArg(meta.Args[0], arch.CLOCK_REALTIME),
|
||||
tpaddr,
|
||||
},
|
||||
Ret: prog.MakeReturnArg(meta.Ret),
|
||||
@ -230,7 +262,8 @@ func generateTimespec(g *prog.Gen, typ *prog.StructType, old *prog.GroupArg) (ar
|
||||
return
|
||||
}
|
||||
|
||||
func lazyInit() {
|
||||
func makeArch(syscalls []*prog.Syscall, resources []*prog.ResourceDesc,
|
||||
structDescs []*prog.KeyedStruct, consts []prog.ConstValue, archName string) *arch {
|
||||
resourceMap := make(map[string]*prog.ResourceDesc)
|
||||
for _, res := range resources {
|
||||
resourceMap[res.Name] = res
|
||||
@ -240,8 +273,8 @@ func lazyInit() {
|
||||
for _, desc := range structDescs {
|
||||
keyedStructs[desc.Key] = desc.Desc
|
||||
}
|
||||
structDescs = nil
|
||||
|
||||
arch := &arch{}
|
||||
for _, c := range syscalls {
|
||||
prog.ForeachType(c, func(t0 prog.Type) {
|
||||
switch t := t0.(type) {
|
||||
@ -264,9 +297,65 @@ func lazyInit() {
|
||||
})
|
||||
switch c.Name {
|
||||
case "mmap":
|
||||
mmapSyscall = c
|
||||
arch.mmapSyscall = c
|
||||
case "clock_gettime":
|
||||
clockGettimeSyscall = c
|
||||
arch.clockGettimeSyscall = c
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range consts {
|
||||
switch c.Name {
|
||||
case "KCOV_INIT_TRACE":
|
||||
if archName == runtime.GOARCH {
|
||||
KCOV_INIT_TRACE = uintptr(c.Value)
|
||||
}
|
||||
case "KCOV_ENABLE":
|
||||
if archName == runtime.GOARCH {
|
||||
KCOV_ENABLE = uintptr(c.Value)
|
||||
}
|
||||
case "KCOV_TRACE_CMP":
|
||||
if archName == runtime.GOARCH {
|
||||
KCOV_TRACE_CMP = uintptr(c.Value)
|
||||
}
|
||||
case "PROT_READ":
|
||||
arch.PROT_READ = c.Value
|
||||
case "PROT_WRITE":
|
||||
arch.PROT_WRITE = c.Value
|
||||
case "MAP_ANONYMOUS":
|
||||
arch.MAP_ANONYMOUS = c.Value
|
||||
case "MAP_PRIVATE":
|
||||
arch.MAP_PRIVATE = c.Value
|
||||
case "MAP_FIXED":
|
||||
arch.MAP_FIXED = c.Value
|
||||
case "MREMAP_MAYMOVE":
|
||||
arch.MREMAP_MAYMOVE = c.Value
|
||||
case "MREMAP_FIXED":
|
||||
arch.MREMAP_FIXED = c.Value
|
||||
case "S_IFREG":
|
||||
arch.S_IFREG = c.Value
|
||||
case "S_IFCHR":
|
||||
arch.S_IFCHR = c.Value
|
||||
case "S_IFBLK":
|
||||
arch.S_IFBLK = c.Value
|
||||
case "S_IFIFO":
|
||||
arch.S_IFIFO = c.Value
|
||||
case "S_IFSOCK":
|
||||
arch.S_IFSOCK = c.Value
|
||||
case "SYSLOG_ACTION_CONSOLE_OFF":
|
||||
arch.SYSLOG_ACTION_CONSOLE_OFF = c.Value
|
||||
case "SYSLOG_ACTION_CONSOLE_ON":
|
||||
arch.SYSLOG_ACTION_CONSOLE_ON = c.Value
|
||||
case "SYSLOG_ACTION_SIZE_UNREAD":
|
||||
arch.SYSLOG_ACTION_SIZE_UNREAD = c.Value
|
||||
case "FIFREEZE":
|
||||
arch.FIFREEZE = c.Value
|
||||
case "FITHAW":
|
||||
arch.FITHAW = c.Value
|
||||
case "PTRACE_TRACEME":
|
||||
arch.PTRACE_TRACEME = c.Value
|
||||
case "CLOCK_REALTIME":
|
||||
arch.CLOCK_REALTIME = c.Value
|
||||
}
|
||||
}
|
||||
return arch
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,5 +4,14 @@
|
||||
package sys
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/google/syzkaller/prog"
|
||||
_ "github.com/google/syzkaller/sys/linux"
|
||||
)
|
||||
|
||||
func init() {
|
||||
if err := prog.SetDefaultTarget("linux", runtime.GOARCH); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
"github.com/google/syzkaller/pkg/ast"
|
||||
"github.com/google/syzkaller/pkg/compiler"
|
||||
"github.com/google/syzkaller/pkg/serializer"
|
||||
"github.com/google/syzkaller/prog"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -63,7 +64,7 @@ func main() {
|
||||
}
|
||||
res.Unsupported = prog.Unsupported
|
||||
|
||||
sysFile := filepath.Join("sys", "linux", "sys_"+arch.Name+".go")
|
||||
sysFile := filepath.Join("sys", "linux", arch.Name+".go")
|
||||
out := new(bytes.Buffer)
|
||||
generate(arch, prog, consts, out)
|
||||
writeSource(sysFile, out.Bytes())
|
||||
@ -113,49 +114,38 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func generate(arch *Arch, prog *compiler.Prog, consts map[string]uint64, out io.Writer) {
|
||||
func generate(arch *Arch, prg *compiler.Prog, consts map[string]uint64, out io.Writer) {
|
||||
fmt.Fprintf(out, "// AUTOGENERATED FILE\n")
|
||||
fmt.Fprintf(out, "package linux\n\n")
|
||||
fmt.Fprintf(out, "import . \"github.com/google/syzkaller/prog\"\n\n")
|
||||
|
||||
fmt.Fprintf(out, "var resources = ")
|
||||
serializer.Write(out, prog.Resources)
|
||||
fmt.Fprintf(out, "func init() {\n")
|
||||
fmt.Fprintf(out, "\tinitArch(syscalls_%v, resources_%v, structDescs_%v, consts_%v, %q, %v)\n",
|
||||
arch.Name, arch.Name, arch.Name, arch.Name, arch.Name, arch.PtrSize)
|
||||
fmt.Fprintf(out, "}\n\n")
|
||||
|
||||
fmt.Fprintf(out, "var resources_%v = ", arch.Name)
|
||||
serializer.Write(out, prg.Resources)
|
||||
fmt.Fprintf(out, "\n\n")
|
||||
|
||||
// Struct fields can refer to other structs. Go compiler won't like if
|
||||
// we refer to Structs during Structs initialization. So we do
|
||||
// it in 2 passes: on the first pass create struct types without fields,
|
||||
// on the second pass we fill in fields.
|
||||
|
||||
// Since structs of the same type can be fields with different names
|
||||
// of multiple other structs, we have an instance of those structs
|
||||
// for each field indexed by the name of the parent struct, field name and dir.
|
||||
fmt.Fprintf(out, "var structDescs = ")
|
||||
serializer.Write(out, prog.StructDescs)
|
||||
fmt.Fprintf(out, "var structDescs_%v = ", arch.Name)
|
||||
serializer.Write(out, prg.StructDescs)
|
||||
fmt.Fprintf(out, "\n\n")
|
||||
|
||||
fmt.Fprintf(out, "var syscalls = ")
|
||||
serializer.Write(out, prog.Syscalls)
|
||||
fmt.Fprintf(out, "var syscalls_%v = ", arch.Name)
|
||||
serializer.Write(out, prg.Syscalls)
|
||||
fmt.Fprintf(out, "\n\n")
|
||||
|
||||
type NameValue struct {
|
||||
name string
|
||||
val uint64
|
||||
}
|
||||
constArr := make([]NameValue, 0, len(consts))
|
||||
constArr := make([]prog.ConstValue, 0, len(consts))
|
||||
for name, val := range consts {
|
||||
constArr = append(constArr, NameValue{name, val})
|
||||
constArr = append(constArr, prog.ConstValue{name, val})
|
||||
}
|
||||
sort.Slice(constArr, func(i, j int) bool {
|
||||
return constArr[i].name < constArr[j].name
|
||||
return constArr[i].Name < constArr[j].Name
|
||||
})
|
||||
|
||||
fmt.Fprintf(out, "const (\n")
|
||||
fmt.Fprintf(out, "ptrSize = %v\n", arch.PtrSize)
|
||||
for _, nv := range constArr {
|
||||
fmt.Fprintf(out, "%v = %v\n", nv.name, nv.val)
|
||||
}
|
||||
fmt.Fprintf(out, ")\n")
|
||||
fmt.Fprintf(out, "var consts_%v = ", arch.Name)
|
||||
serializer.Write(out, constArr)
|
||||
fmt.Fprintf(out, "\n")
|
||||
}
|
||||
|
||||
func writeSource(file string, data []byte) {
|
||||
|
Loading…
Reference in New Issue
Block a user