syz-manager, syz-fuzzer, executor: ensure that binaries are consistent

Check that manager/fuzzer/executor are build on the same git revision,
use the same syscall descriptions and the same target arch.

Update #336
This commit is contained in:
Dmitry Vyukov 2017-09-15 10:15:00 +02:00
parent 19f9bc13d3
commit 539e603206
15 changed files with 100 additions and 18 deletions

View File

@ -15,6 +15,13 @@ endif
android \
format tidy test arch cross-compile presubmit clean
GITREV=$(shell git rev-parse HEAD)
ifeq ($(`git diff --shortstat`), "")
REV=$(GITREV)
else
REV=$(GITREV)+
endif
all:
$(MAKE) main
$(MAKE) tools
@ -29,13 +36,14 @@ tools: execprog mutate prog2c stress repro upgrade db
# executor uses stacks of limited size, so no jumbo frames.
executor:
$(CC) -o ./bin/syz-executor executor/executor.cc -pthread -Wall -Wframe-larger-than=8192 -Wparentheses -Werror -O1 -g $(STATIC_FLAG) $(CFLAGS)
$(CC) -o ./bin/syz-executor executor/executor.cc -pthread -Wall -Wframe-larger-than=8192 \
-Wparentheses -Werror -O1 -g $(STATIC_FLAG) $(CFLAGS) -DGIT_REVISION=\"$(REV)\"
# Don't generate symbol table and DWARF debug info.
# Reduces build time and binary sizes considerably.
# That's only needed if you use gdb or nm.
# If you need that, build manually without these flags.
GOFLAGS="-ldflags=-s -w"
GOFLAGS="-ldflags=-s -w -X github.com/google/syzkaller/sys.GitRevision=$(REV)"
manager:
go build $(GOFLAGS) -o ./bin/syz-manager github.com/google/syzkaller/syz-manager

View File

@ -228,8 +228,17 @@ uint64_t read_cover_size(thread_t* th);
static uint32_t hash(uint32_t a);
static bool dedup(uint32_t sig);
#ifndef GIT_REVISION
#define GIT_REVISION "unknown"
#endif
int main(int argc, char** argv)
{
if (argc == 2 && strcmp(argv[1], "version") == 0) {
puts("linux " GOARCH " " SYZ_REVISION " " GIT_REVISION);
return 0;
}
prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
if (mmap(&input_data[0], kMaxInput, PROT_READ, MAP_PRIVATE | MAP_FIXED, kInFd, 0) != &input_data[0])
fail("mmap of input file failed");

View File

@ -6,6 +6,8 @@ struct call_t {
};
#if defined(__i386__) || 0
#define GOARCH "386"
#define SYZ_REVISION "fb26afa29ccd7317f2c0796cf1386b493eeb955f"
#define __NR_syz_emit_ethernet 1000000
#define __NR_syz_extract_tcp_res 1000001
#define __NR_syz_fuse_mount 1000002
@ -1564,6 +1566,8 @@ static call_t syscalls[] = {
#endif
#if defined(__x86_64__) || 0
#define GOARCH "amd64"
#define SYZ_REVISION "c14ec0f07c2984481a0bf1453ea928549382eb25"
#define __NR_syz_emit_ethernet 1000000
#define __NR_syz_extract_tcp_res 1000001
#define __NR_syz_fuse_mount 1000002
@ -3122,6 +3126,8 @@ static call_t syscalls[] = {
#endif
#if defined(__arm__) || 0
#define GOARCH "arm"
#define SYZ_REVISION "f73cb445fdead3417b165eec037a0d892cc3253e"
#define __NR_syz_emit_ethernet 1000000
#define __NR_syz_extract_tcp_res 1000001
#define __NR_syz_fuse_mount 1000002
@ -4680,6 +4686,8 @@ static call_t syscalls[] = {
#endif
#if defined(__aarch64__) || 0
#define GOARCH "arm64"
#define SYZ_REVISION "72353a7ede1fe6cb903fcb02eb5eb11407bea5d8"
#define __NR_syz_emit_ethernet 1000000
#define __NR_syz_extract_tcp_res 1000001
#define __NR_syz_fuse_mount 1000002
@ -6238,6 +6246,8 @@ static call_t syscalls[] = {
#endif
#if defined(__ppc64__) || defined(__PPC64__) || defined(__powerpc64__) || 0
#define GOARCH "ppc64le"
#define SYZ_REVISION "cec4f3697757a69ac044be83bac5ba45df7f2fbf"
#define __NR_syz_emit_ethernet 1000000
#define __NR_syz_extract_tcp_res 1000001
#define __NR_syz_fuse_mount 1000002

View File

@ -39,6 +39,11 @@ type CheckArgs struct {
UserNamespaces bool
CompsSupported bool
Calls []string
FuzzerGitRev string
FuzzerSyzRev string
ExecutorGitRev string
ExecutorSyzRev string
ExecutorArch string
}
type NewInputArgs struct {

View File

@ -12,6 +12,7 @@ import (
type Target struct {
OS string
Arch string
Revision string // unique hash representing revision of the descriptions
PtrSize uint64
PageSize uint64
DataOffset uint64

View File

@ -4,7 +4,7 @@ package linux
import . "github.com/google/syzkaller/prog"
func init() {
initArch(syscalls_386, resources_386, structDescs_386, consts_386, "386", 4)
initArch(revision_386, syscalls_386, resources_386, structDescs_386, consts_386, "386", 4)
}
var resources_386 = []*ResourceDesc{
@ -17186,3 +17186,5 @@ var consts_386 = []ConstValue{
{Name: "__WCLONE", Value: 2147483648},
{Name: "__WNOTHREAD", Value: 536870912},
}
const revision_386 = "fb26afa29ccd7317f2c0796cf1386b493eeb955f"

View File

@ -4,7 +4,7 @@ package linux
import . "github.com/google/syzkaller/prog"
func init() {
initArch(syscalls_amd64, resources_amd64, structDescs_amd64, consts_amd64, "amd64", 8)
initArch(revision_amd64, syscalls_amd64, resources_amd64, structDescs_amd64, consts_amd64, "amd64", 8)
}
var resources_amd64 = []*ResourceDesc{
@ -17268,3 +17268,5 @@ var consts_amd64 = []ConstValue{
{Name: "__WCLONE", Value: 2147483648},
{Name: "__WNOTHREAD", Value: 536870912},
}
const revision_amd64 = "c14ec0f07c2984481a0bf1453ea928549382eb25"

View File

@ -4,7 +4,7 @@ package linux
import . "github.com/google/syzkaller/prog"
func init() {
initArch(syscalls_arm, resources_arm, structDescs_arm, consts_arm, "arm", 4)
initArch(revision_arm, syscalls_arm, resources_arm, structDescs_arm, consts_arm, "arm", 4)
}
var resources_arm = []*ResourceDesc{
@ -17140,3 +17140,5 @@ var consts_arm = []ConstValue{
{Name: "__WCLONE", Value: 2147483648},
{Name: "__WNOTHREAD", Value: 536870912},
}
const revision_arm = "f73cb445fdead3417b165eec037a0d892cc3253e"

View File

@ -4,7 +4,7 @@ package linux
import . "github.com/google/syzkaller/prog"
func init() {
initArch(syscalls_arm64, resources_arm64, structDescs_arm64, consts_arm64, "arm64", 8)
initArch(revision_arm64, syscalls_arm64, resources_arm64, structDescs_arm64, consts_arm64, "arm64", 8)
}
var resources_arm64 = []*ResourceDesc{
@ -17182,3 +17182,5 @@ var consts_arm64 = []ConstValue{
{Name: "__WCLONE", Value: 2147483648},
{Name: "__WNOTHREAD", Value: 536870912},
}
const revision_arm64 = "72353a7ede1fe6cb903fcb02eb5eb11407bea5d8"

View File

@ -9,12 +9,13 @@ import (
"github.com/google/syzkaller/prog"
)
func initArch(syscalls []*prog.Syscall, resources []*prog.ResourceDesc,
func initArch(rev string, 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: "linux",
Arch: archName,
Revision: rev,
PtrSize: ptrSize,
PageSize: pageSize,
DataOffset: dataOffset,

View File

@ -4,7 +4,7 @@ package linux
import . "github.com/google/syzkaller/prog"
func init() {
initArch(syscalls_ppc64le, resources_ppc64le, structDescs_ppc64le, consts_ppc64le, "ppc64le", 8)
initArch(revision_ppc64le, syscalls_ppc64le, resources_ppc64le, structDescs_ppc64le, consts_ppc64le, "ppc64le", 8)
}
var resources_ppc64le = []*ResourceDesc{
@ -17172,3 +17172,5 @@ var consts_ppc64le = []ConstValue{
{Name: "__WCLONE", Value: 2147483648},
{Name: "__WNOTHREAD", Value: 536870912},
}
const revision_ppc64le = "cec4f3697757a69ac044be83bac5ba45df7f2fbf"

View File

@ -74,3 +74,6 @@ func init() {
}
}
}
// Emitted by Makefile.
var GitRevision string

View File

@ -21,6 +21,7 @@ import (
"github.com/google/syzkaller/pkg/ast"
"github.com/google/syzkaller/pkg/compiler"
"github.com/google/syzkaller/pkg/hash"
"github.com/google/syzkaller/pkg/serializer"
"github.com/google/syzkaller/prog"
"github.com/google/syzkaller/sys"
@ -79,9 +80,11 @@ func main() {
sysFile := filepath.Join("sys", OS, job.Target.Arch+".go")
out := new(bytes.Buffer)
generate(job.Target, prog, consts, out)
rev := hash.String(out.Bytes())
fmt.Fprintf(out, "const revision_%v = %q\n", job.Target.Arch, rev)
writeSource(sysFile, out.Bytes())
job.ArchData = generateExecutorSyscalls(job.Target, prog.Syscalls)
job.ArchData = generateExecutorSyscalls(job.Target, prog.Syscalls, rev)
job.OK = true
}()
}
@ -132,8 +135,8 @@ func generate(target *sys.Target, prg *compiler.Prog, consts map[string]uint64,
fmt.Fprintf(out, "import . \"github.com/google/syzkaller/prog\"\n\n")
fmt.Fprintf(out, "func init() {\n")
fmt.Fprintf(out, "\tinitArch(syscalls_%v, resources_%v, structDescs_%v, consts_%v, %q, %v)\n",
target.Arch, target.Arch, target.Arch, target.Arch, target.Arch, target.PtrSize)
fmt.Fprintf(out, "\tinitArch(revision_%v, syscalls_%v, resources_%v, structDescs_%v, consts_%v, %q, %v)\n",
target.Arch, target.Arch, target.Arch, target.Arch, target.Arch, target.Arch, target.PtrSize)
fmt.Fprintf(out, "}\n\n")
fmt.Fprintf(out, "var resources_%v = ", target.Arch)
@ -157,21 +160,25 @@ func generate(target *sys.Target, prg *compiler.Prog, consts map[string]uint64,
})
fmt.Fprintf(out, "var consts_%v = ", target.Arch)
serializer.Write(out, constArr)
fmt.Fprintf(out, "\n")
fmt.Fprintf(out, "\n\n")
}
func generateExecutorSyscalls(target *sys.Target, syscalls []*prog.Syscall) []byte {
func generateExecutorSyscalls(target *sys.Target, syscalls []*prog.Syscall, rev string) []byte {
type SyscallData struct {
Name string
NR int32
}
type ArchData struct {
CARCH []string
Calls []SyscallData
Fake []SyscallData
Revision string
GOARCH string
CARCH []string
Calls []SyscallData
Fake []SyscallData
}
data := ArchData{
CARCH: target.CArch,
Revision: rev,
GOARCH: target.Arch,
CARCH: target.CArch,
}
fake := make(map[string]uint64)
for _, c := range syscalls {
@ -247,6 +254,8 @@ struct call_t {
var archTempl = template.Must(template.New("").Parse(`
#if {{range $cdef := $.CARCH}}defined({{$cdef}}) || {{end}}0
#define GOARCH "{{.GOARCH}}"
#define SYZ_REVISION "{{.Revision}}"
{{range $c := $.Fake}}#define __NR_{{$c.Name}} {{$c.NR}}
{{end}}
static call_t syscalls[] = {

View File

@ -29,6 +29,7 @@ import (
"github.com/google/syzkaller/pkg/osutil"
. "github.com/google/syzkaller/pkg/rpctype"
"github.com/google/syzkaller/prog"
"github.com/google/syzkaller/sys"
"github.com/google/syzkaller/sys/linux"
)
@ -175,9 +176,22 @@ func main() {
kcov, compsSupported := checkCompsSupported()
Logf(1, "KCOV_CHECK: compsSupported=%v", compsSupported)
if r.NeedCheck {
out, err := osutil.RunCmd(time.Minute, "", *flagExecutor, "version")
if err != nil {
panic(err)
}
vers := strings.Split(strings.TrimSpace(string(out)), " ")
if len(vers) != 4 {
panic(fmt.Sprintf("bad executor version: %q", string(out)))
}
a := &CheckArgs{
Name: *flagName,
UserNamespaces: osutil.IsExist("/proc/self/ns/user"),
FuzzerGitRev: sys.GitRevision,
FuzzerSyzRev: target.Revision,
ExecutorGitRev: vers[3],
ExecutorSyzRev: vers[2],
ExecutorArch: vers[1],
}
a.Kcov = kcov
if fd, err := syscall.Open("/sys/kernel/debug/kmemleak", syscall.O_RDWR, 0); err == nil {

View File

@ -29,7 +29,7 @@ import (
"github.com/google/syzkaller/pkg/repro"
. "github.com/google/syzkaller/pkg/rpctype"
"github.com/google/syzkaller/prog"
_ "github.com/google/syzkaller/sys"
"github.com/google/syzkaller/sys"
"github.com/google/syzkaller/syz-manager/mgrconfig"
"github.com/google/syzkaller/vm"
)
@ -870,6 +870,18 @@ func (mgr *Manager) Check(a *CheckArgs, r *int) error {
if mgr.cfg.Sandbox == "namespace" && !a.UserNamespaces {
Fatalf("/proc/self/ns/user is missing or permission is denied. Requested namespace sandbox but user namespaces are not enabled. Enable CONFIG_USER_NS")
}
if mgr.target.Arch != a.ExecutorArch {
Fatalf("mismatching target/executor arch: target=%v executor=%v",
mgr.target.Arch, a.ExecutorArch)
}
if sys.GitRevision != a.FuzzerGitRev || sys.GitRevision != a.ExecutorGitRev {
Fatalf("mismatching git revisions:\nmanager= %v\nfuzzer= %v\nexecutor=%v",
sys.GitRevision, a.FuzzerGitRev, a.ExecutorGitRev)
}
if mgr.target.Revision != a.FuzzerSyzRev || mgr.target.Revision != a.ExecutorSyzRev {
Fatalf("mismatching syscall descriptions:\nmanager= %v\nfuzzer= %v\nexecutor=%v",
mgr.target.Revision, a.FuzzerSyzRev, a.ExecutorSyzRev)
}
mgr.vmChecked = true
mgr.enabledCalls = a.Calls
return nil