From 179a860885dd9c300d13ae9965e6ed10d9aea404 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 2 Oct 2017 14:14:48 +0200 Subject: [PATCH] all: basic freebsd support For now we just make Go part build for freebsd. --- Makefile | 3 ++ executor/syscalls_freebsd.h | 12 +++++ pkg/compiler/consts.go | 6 ++- pkg/csource/csource_test.go | 3 ++ pkg/host/host_freebsd.go | 17 ++++++++ pkg/ipc/ipc_simple.go | 2 +- pkg/osutil/osutil_unix.go | 2 +- sys/freebsd/amd64.go | 34 +++++++++++++++ sys/freebsd/init.go | 85 ++++++++++++++++++++++++++++++++++++ sys/freebsd/sys.txt | 9 ++++ sys/freebsd/sys_amd64.const | 6 +++ sys/sys.go | 1 + sys/targets/targets.go | 13 ++++++ syz-fuzzer/fuzzer_freebsd.go | 21 +++++++++ 14 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 executor/syscalls_freebsd.h create mode 100644 pkg/host/host_freebsd.go create mode 100644 sys/freebsd/amd64.go create mode 100644 sys/freebsd/init.go create mode 100644 sys/freebsd/sys.txt create mode 100644 sys/freebsd/sys_amd64.const create mode 100644 syz-fuzzer/fuzzer_freebsd.go diff --git a/Makefile b/Makefile index e191e2de..823e5585 100644 --- a/Makefile +++ b/Makefile @@ -191,6 +191,7 @@ bin/syz-sysgen: format: bin/syz-fmt $(GO) fmt ./... clang-format --style=file -i executor/*.cc executor/*.h tools/kcovtrace/*.c + bin/syz-fmt sys/freebsd bin/syz-fmt sys/linux bin/syz-fmt sys/fuchsia bin/syz-fmt sys/windows @@ -230,6 +231,8 @@ arch: env TARGETOS=linux TARGETARCH=amd64 TARGETVMARCH=386 $(MAKE) target env GOOG=windows go install github.com/google/syzkaller/syz-fuzzer env TARGETOS=windows TARGETARCH=amd64 $(MAKE) fuzzer execprog stress + env GOOG=freebsd go install github.com/google/syzkaller/syz-fuzzer + env TARGETOS=freebsd TARGETARCH=amd64 $(MAKE) fuzzer execprog stress presubmit: $(MAKE) generate diff --git a/executor/syscalls_freebsd.h b/executor/syscalls_freebsd.h new file mode 100644 index 00000000..555161e9 --- /dev/null +++ b/executor/syscalls_freebsd.h @@ -0,0 +1,12 @@ +// AUTOGENERATED FILE + +#if defined(__x86_64__) || 0 +#define GOARCH "amd64" +#define SYZ_REVISION "8e89c92ba6210bfbb714647598abe10b8cbb4edf" + +unsigned syscall_count = 1; +call_t syscalls[] = { + {"mmap", 1}, + +}; +#endif diff --git a/pkg/compiler/consts.go b/pkg/compiler/consts.go index c2051ab5..f4337cab 100644 --- a/pkg/compiler/consts.go +++ b/pkg/compiler/consts.go @@ -43,6 +43,7 @@ func ExtractConsts(desc *ast.Description, target *targets.Target, eh0 ast.ErrorH incdirMap := make(map[string]bool) constMap := make(map[string]bool) syscallNumbers := targets.OSList[target.OS].SyscallNumbers + syscallPrefix := targets.OSList[target.OS].SyscallPrefix ast.Walk(desc, func(n1 ast.Node) { switch n := n1.(type) { @@ -76,7 +77,7 @@ func ExtractConsts(desc *ast.Description, target *targets.Target, eh0 ast.ErrorH constMap[name] = true case *ast.Call: if syscallNumbers && !strings.HasPrefix(n.CallName, "syz_") { - constMap["__NR_"+n.CallName] = true + constMap[syscallPrefix+n.CallName] = true } case *ast.Type: if c := typeConstIdentifier(n); c != nil { @@ -118,6 +119,7 @@ func (comp *compiler) assignSyscallNumbers(consts map[string]uint64) { } var top []ast.Node + syscallPrefix := targets.OSList[comp.target.OS].SyscallPrefix for _, decl := range comp.desc.Nodes { switch decl.(type) { case *ast.Call: @@ -132,7 +134,7 @@ func (comp *compiler) assignSyscallNumbers(consts map[string]uint64) { continue } // Lookup in consts. - str := "__NR_" + c.CallName + str := syscallPrefix + c.CallName nr, ok := consts[str] top = append(top, decl) if ok { diff --git a/pkg/csource/csource_test.go b/pkg/csource/csource_test.go index 6334c40b..913ea9bf 100644 --- a/pkg/csource/csource_test.go +++ b/pkg/csource/csource_test.go @@ -122,6 +122,9 @@ func TestOne(t *testing.T) { t.Parallel() rs := rand.NewSource(0) p := target.GenerateAllSyzProg(rs) + if len(p.Calls) == 0 { + t.Skip("no syz syscalls") + } testOne(t, p, opts) }) } diff --git a/pkg/host/host_freebsd.go b/pkg/host/host_freebsd.go new file mode 100644 index 00000000..b931b5c6 --- /dev/null +++ b/pkg/host/host_freebsd.go @@ -0,0 +1,17 @@ +// Copyright 2017 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 host + +import ( + "github.com/google/syzkaller/prog" +) + +// DetectSupportedSyscalls returns list on supported syscalls on host. +func DetectSupportedSyscalls(target *prog.Target) (map[*prog.Syscall]bool, error) { + supported := make(map[*prog.Syscall]bool) + for _, c := range target.Syscalls { + supported[c] = true + } + return supported, nil +} diff --git a/pkg/ipc/ipc_simple.go b/pkg/ipc/ipc_simple.go index 445c44c0..a870001e 100644 --- a/pkg/ipc/ipc_simple.go +++ b/pkg/ipc/ipc_simple.go @@ -1,7 +1,7 @@ // Copyright 2017 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. -// +build fuchsia windows +// +build freebsd fuchsia windows package ipc diff --git a/pkg/osutil/osutil_unix.go b/pkg/osutil/osutil_unix.go index 818cc1f7..87dc6a72 100644 --- a/pkg/osutil/osutil_unix.go +++ b/pkg/osutil/osutil_unix.go @@ -1,7 +1,7 @@ // Copyright 2017 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. -// +build linux,!appengine darwin,!appengine +// +build freebsd,!appengine linux,!appengine darwin,!appengine package osutil diff --git a/sys/freebsd/amd64.go b/sys/freebsd/amd64.go new file mode 100644 index 00000000..01ff3787 --- /dev/null +++ b/sys/freebsd/amd64.go @@ -0,0 +1,34 @@ +// AUTOGENERATED FILE +package freebsd + +import . "github.com/google/syzkaller/prog" + +func init() { + RegisterTarget(&Target{OS: "freebsd", Arch: "amd64", Revision: revision_amd64, PtrSize: 8, Syscalls: syscalls_amd64, Resources: resources_amd64, Structs: structDescs_amd64, Consts: consts_amd64}, initTarget) +} + +var resources_amd64 = []*ResourceDesc(nil) + +var structDescs_amd64 = []*KeyedStruct(nil) + +var syscalls_amd64 = []*Syscall{ + {NR: 1, Name: "mmap", CallName: "mmap", Args: []Type{ + &VmaType{TypeCommon: TypeCommon{TypeName: "vma", FldName: "addr", TypeSize: 8}}, + &LenType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "len", FldName: "len", TypeSize: 8}}, Buf: "addr"}, + &FlagsType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "mmap_prot", FldName: "prot", TypeSize: 8}}, Vals: []uint64{2, 3}}, + &FlagsType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "mmap_flags", FldName: "flags", TypeSize: 8}}, Vals: []uint64{4, 5, 6}}, + &ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "const", FldName: "fd", TypeSize: 8}}, Val: 18446744073709551615}, + &ConstType{IntTypeCommon: IntTypeCommon{TypeCommon: TypeCommon{TypeName: "const", FldName: "offset", TypeSize: 8}}}, + }, Ret: &VmaType{TypeCommon: TypeCommon{TypeName: "vma", FldName: "ret", TypeSize: 8, ArgDir: 1}}}, +} + +var consts_amd64 = []ConstValue{ + {Name: "MAP_ANONYMOUS", Value: 5}, + {Name: "MAP_FIXED", Value: 6}, + {Name: "MAP_PRIVATE", Value: 4}, + {Name: "PROT_READ", Value: 2}, + {Name: "PROT_WRITE", Value: 3}, + {Name: "SYS_mmap", Value: 1}, +} + +const revision_amd64 = "8e89c92ba6210bfbb714647598abe10b8cbb4edf" diff --git a/sys/freebsd/init.go b/sys/freebsd/init.go new file mode 100644 index 00000000..28241370 --- /dev/null +++ b/sys/freebsd/init.go @@ -0,0 +1,85 @@ +// Copyright 2017 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 freebsd + +import ( + "github.com/google/syzkaller/prog" +) + +func initTarget(target *prog.Target) { + arch := &arch{ + mmapSyscall: target.SyscallMap["mmap"], + PROT_READ: target.ConstMap["PROT_READ"], + PROT_WRITE: target.ConstMap["PROT_WRITE"], + MAP_ANONYMOUS: target.ConstMap["MAP_ANONYMOUS"], + MAP_PRIVATE: target.ConstMap["MAP_PRIVATE"], + MAP_FIXED: target.ConstMap["MAP_FIXED"], + } + + target.PageSize = pageSize + target.DataOffset = dataOffset + target.MmapSyscall = arch.mmapSyscall + target.MakeMmap = arch.makeMmap + target.AnalyzeMmap = arch.analyzeMmap +} + +const ( + pageSize = 4 << 10 + dataOffset = 512 << 20 + invalidFD = ^uint64(0) +) + +type arch struct { + mmapSyscall *prog.Syscall + clockGettimeSyscall *prog.Syscall + + PROT_READ uint64 + PROT_WRITE uint64 + MAP_ANONYMOUS uint64 + MAP_PRIVATE uint64 + MAP_FIXED uint64 +} + +// createMmapCall creates a "normal" mmap call that maps [start, start+npages) page range. +func (arch *arch) makeMmap(start, npages uint64) *prog.Call { + meta := arch.mmapSyscall + return &prog.Call{ + Meta: meta, + Args: []prog.Arg{ + 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(meta.Ret), + } +} + +func (arch *arch) analyzeMmap(c *prog.Call) (start, npages uint64, mapped bool) { + switch c.Meta.Name { + case "mmap": + // Filter out only very wrong arguments. + npages = c.Args[1].(*prog.ConstArg).Val / pageSize + if npages == 0 { + return + } + flags := c.Args[3].(*prog.ConstArg).Val + fd := c.Args[4].(*prog.ResultArg).Val + if flags&arch.MAP_ANONYMOUS == 0 && fd == invalidFD { + return + } + start = c.Args[0].(*prog.PointerArg).PageIndex + mapped = true + return + case "munmap": + start = c.Args[0].(*prog.PointerArg).PageIndex + npages = c.Args[1].(*prog.ConstArg).Val / pageSize + mapped = false + return + default: + return + } +} diff --git a/sys/freebsd/sys.txt b/sys/freebsd/sys.txt new file mode 100644 index 00000000..6bb52429 --- /dev/null +++ b/sys/freebsd/sys.txt @@ -0,0 +1,9 @@ +# Copyright 2017 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. + +include + +mmap(addr vma, len len[addr], prot flags[mmap_prot], flags flags[mmap_flags], fd const[0xffffffffffffffff], offset const[0]) vma + +mmap_prot = PROT_READ, PROT_WRITE +mmap_flags = MAP_PRIVATE, MAP_ANONYMOUS, MAP_FIXED diff --git a/sys/freebsd/sys_amd64.const b/sys/freebsd/sys_amd64.const new file mode 100644 index 00000000..16b86025 --- /dev/null +++ b/sys/freebsd/sys_amd64.const @@ -0,0 +1,6 @@ +SYS_mmap = 1 +PROT_READ = 2 +PROT_WRITE = 3 +MAP_PRIVATE = 4 +MAP_ANONYMOUS = 5 +MAP_FIXED = 6 diff --git a/sys/sys.go b/sys/sys.go index 7ba783e5..e2f291fe 100644 --- a/sys/sys.go +++ b/sys/sys.go @@ -4,6 +4,7 @@ package sys import ( + _ "github.com/google/syzkaller/sys/freebsd" _ "github.com/google/syzkaller/sys/fuchsia" _ "github.com/google/syzkaller/sys/linux" _ "github.com/google/syzkaller/sys/windows" diff --git a/sys/targets/targets.go b/sys/targets/targets.go index 3c0011be..4b92eaeb 100644 --- a/sys/targets/targets.go +++ b/sys/targets/targets.go @@ -62,6 +62,13 @@ var List = map[string]map[string]*Target{ KernelHeaderArch: "powerpc", }, }, + "freebsd": map[string]*Target{ + "amd64": { + PtrSize: 8, + CArch: []string{"__x86_64__"}, + CFlags: []string{"-m64"}, + }, + }, "fuchsia": map[string]*Target{ "amd64": { PtrSize: 8, @@ -83,11 +90,17 @@ var List = map[string]map[string]*Target{ type OS struct { // Does the OS use syscall numbers (e.g. Linux) or has interface based on functions (e.g. fuchsia). SyscallNumbers bool + SyscallPrefix string } var OSList = map[string]*OS{ "linux": { SyscallNumbers: true, + SyscallPrefix: "__NR_", + }, + "freebsd": { + SyscallNumbers: true, + SyscallPrefix: "SYS_", }, "fuchsia": { SyscallNumbers: false, diff --git a/syz-fuzzer/fuzzer_freebsd.go b/syz-fuzzer/fuzzer_freebsd.go new file mode 100644 index 00000000..656e87f1 --- /dev/null +++ b/syz-fuzzer/fuzzer_freebsd.go @@ -0,0 +1,21 @@ +// Copyright 2017 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 main + +import ( + "github.com/google/syzkaller/pkg/log" +) + +func kmemleakInit() { + if *flagLeak { + log.Fatalf("leak checking is not supported on fuchsia") + } +} + +func kmemleakScan(report bool) { +} + +func checkCompsSupported() (kcov, comps bool) { + return false, false +}