diff options
55 files changed, 665 insertions, 628 deletions
diff --git a/executor/executor_akaros.cc b/executor/executor_akaros.cc index 90b589e77..fc28fb8f7 100644 --- a/executor/executor_akaros.cc +++ b/executor/executor_akaros.cc @@ -12,6 +12,8 @@ #include "syscalls_akaros.h" +#include <sys/mman.h> + uint32 output; int main(int argc, char** argv) @@ -21,6 +23,10 @@ int main(int argc, char** argv) return 0; } + if (mmap((void*)SYZ_DATA_OFFSET, SYZ_NUM_PAGES * SYZ_PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0) != (void*)SYZ_DATA_OFFSET) + fail("mmap of data segment failed"); + use_temporary_dir(); install_segv_handler(); setup_control_pipes(); diff --git a/executor/executor_bsd.cc b/executor/executor_bsd.cc index 2500a2a12..ee14d84a6 100644 --- a/executor/executor_bsd.cc +++ b/executor/executor_bsd.cc @@ -50,6 +50,9 @@ int main(int argc, char** argv) output_data = (uint32*)mmap(kOutputDataAddr, kMaxOutput, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, kOutFd, 0); if (output_data != kOutputDataAddr) fail("mmap of output file failed"); + if (mmap((void*)SYZ_DATA_OFFSET, SYZ_NUM_PAGES * SYZ_PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0) != (void*)SYZ_DATA_OFFSET) + fail("mmap of data segment failed"); // Prevent random programs to mess with these fds. // Due to races in collider mode, a program can e.g. ftruncate one of these fds, // which will cause fuzzer to crash. diff --git a/executor/executor_fuchsia.cc b/executor/executor_fuchsia.cc index bd66762a7..7fad95f4e 100644 --- a/executor/executor_fuchsia.cc +++ b/executor/executor_fuchsia.cc @@ -21,6 +21,9 @@ int main(int argc, char** argv) return 0; } + if (syz_mmap(SYZ_DATA_OFFSET, SYZ_NUM_PAGES * SYZ_PAGE_SIZE) != ZX_OK) + fail("mmap of data segment failed"); + install_segv_handler(); setup_control_pipes(); receive_execute(true); diff --git a/executor/executor_linux.cc b/executor/executor_linux.cc index 8fec5ac6d..4ca358231 100644 --- a/executor/executor_linux.cc +++ b/executor/executor_linux.cc @@ -56,9 +56,13 @@ int main(int argc, char** argv) // If it is corrupted ipc package will fail to parse its contents and panic. // But fuzzer constantly invents new ways of how to currupt the region, // so we map the region at a (hopefully) hard to guess address surrounded by unmapped pages. - output_data = (uint32*)mmap(kOutputDataAddr, kMaxOutput, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, kOutFd, 0); + output_data = (uint32*)mmap(kOutputDataAddr, kMaxOutput, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, kOutFd, 0); if (output_data != kOutputDataAddr) fail("mmap of output file failed"); + if (mmap((void*)SYZ_DATA_OFFSET, SYZ_NUM_PAGES * SYZ_PAGE_SIZE, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0) != (void*)SYZ_DATA_OFFSET) + fail("mmap of data segment failed"); // Prevent random programs to mess with these fds. // Due to races in collider mode, a program can e.g. ftruncate one of these fds, // which will cause fuzzer to crash. diff --git a/executor/executor_windows.cc b/executor/executor_windows.cc index 778387b42..374151ef2 100644 --- a/executor/executor_windows.cc +++ b/executor/executor_windows.cc @@ -23,6 +23,10 @@ int main(int argc, char** argv) return 0; } + if (VirtualAlloc((void*)SYZ_DATA_OFFSET, SYZ_NUM_PAGES * SYZ_PAGE_SIZE, + MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE) != (void*)SYZ_DATA_OFFSET) + fail("mmap of data segment failed"); + setup_control_pipes(); receive_execute(true); execute_one(); diff --git a/executor/syscalls_akaros.h b/executor/syscalls_akaros.h index 238b68cc0..90c1f09b9 100644 --- a/executor/syscalls_akaros.h +++ b/executor/syscalls_akaros.h @@ -2,7 +2,10 @@ #if defined(__x86_64__) || 0 #define GOARCH "amd64" -#define SYZ_REVISION "0e5dbbd94e4838b9729df440c4c53e581768eaf8" +#define SYZ_REVISION "43f665d2468516ae8ffc137aec39649a4a1dc7ce" +#define SYZ_PAGE_SIZE 4096 +#define SYZ_NUM_PAGES 4096 +#define SYZ_DATA_OFFSET 536870912 unsigned syscall_count = 35; call_t syscalls[] = { {"abort_sysc_fd", 33}, diff --git a/executor/syscalls_freebsd.h b/executor/syscalls_freebsd.h index 7d72d51f1..437c80a37 100644 --- a/executor/syscalls_freebsd.h +++ b/executor/syscalls_freebsd.h @@ -2,7 +2,10 @@ #if defined(__x86_64__) || 0 #define GOARCH "amd64" -#define SYZ_REVISION "8faf3b6e65172d4a9e098d5eda39563a082f8078" +#define SYZ_REVISION "b41d0c0723ec3704417120a5a63657cc522f14cf" +#define SYZ_PAGE_SIZE 4096 +#define SYZ_NUM_PAGES 4096 +#define SYZ_DATA_OFFSET 536870912 unsigned syscall_count = 254; call_t syscalls[] = { {"accept", 30}, diff --git a/executor/syscalls_fuchsia.h b/executor/syscalls_fuchsia.h index 59e941d7a..cb7a68a16 100644 --- a/executor/syscalls_fuchsia.h +++ b/executor/syscalls_fuchsia.h @@ -2,7 +2,10 @@ #if defined(__x86_64__) || 0 #define GOARCH "amd64" -#define SYZ_REVISION "16f8d2a14dffe8465559442d33e3ca296f7ea4bf" +#define SYZ_REVISION "4eadf9151d47a3744fe9277b15a0447970eba0cb" +#define SYZ_PAGE_SIZE 4096 +#define SYZ_NUM_PAGES 4096 +#define SYZ_DATA_OFFSET 536870912 unsigned syscall_count = 164; call_t syscalls[] = { {"chdir", 0, (syscall_t)chdir}, @@ -175,7 +178,10 @@ call_t syscalls[] = { #if defined(__aarch64__) || 0 #define GOARCH "arm64" -#define SYZ_REVISION "c04cb066cf7fc135f9f85388423f3e65aedc5028" +#define SYZ_REVISION "bb0e27a08caeecf468bb53c76ebf97388e4d3c6d" +#define SYZ_PAGE_SIZE 4096 +#define SYZ_NUM_PAGES 4096 +#define SYZ_DATA_OFFSET 536870912 unsigned syscall_count = 164; call_t syscalls[] = { {"chdir", 0, (syscall_t)chdir}, diff --git a/executor/syscalls_linux.h b/executor/syscalls_linux.h index 0bbab652a..b1dac1c50 100644 --- a/executor/syscalls_linux.h +++ b/executor/syscalls_linux.h @@ -2,7 +2,10 @@ #if defined(__i386__) || 0 #define GOARCH "386" -#define SYZ_REVISION "1d92abf94e3a94a587c23e34ff517226557eb39b" +#define SYZ_REVISION "fdfb3bacd26e9af78ca89d10c2c2e06726f2b744" +#define SYZ_PAGE_SIZE 4096 +#define SYZ_NUM_PAGES 4096 +#define SYZ_DATA_OFFSET 536870912 unsigned syscall_count = 1583; call_t syscalls[] = { {"accept4", 364}, @@ -1594,7 +1597,10 @@ call_t syscalls[] = { #if defined(__x86_64__) || 0 #define GOARCH "amd64" -#define SYZ_REVISION "c063297cc1f7a742899148ea3e480a503975e1a3" +#define SYZ_REVISION "3b495371d7017730eef962bb58f8674114796711" +#define SYZ_PAGE_SIZE 4096 +#define SYZ_NUM_PAGES 4096 +#define SYZ_DATA_OFFSET 536870912 unsigned syscall_count = 1636; call_t syscalls[] = { {"accept", 43}, @@ -3239,7 +3245,10 @@ call_t syscalls[] = { #if defined(__arm__) || 0 #define GOARCH "arm" -#define SYZ_REVISION "2a035864a56374d1ef4eafcffb968f43fd5b075c" +#define SYZ_REVISION "1da52823d9d718efc3156b97b25ad96b0e8e7ea9" +#define SYZ_PAGE_SIZE 4096 +#define SYZ_NUM_PAGES 4096 +#define SYZ_DATA_OFFSET 536870912 unsigned syscall_count = 1593; call_t syscalls[] = { {"accept", 285}, @@ -4841,7 +4850,10 @@ call_t syscalls[] = { #if defined(__aarch64__) || 0 #define GOARCH "arm64" -#define SYZ_REVISION "033a3d40f0ba2f8c5ebeb2a344a44e89db17e105" +#define SYZ_REVISION "8747be63243fed6597fc673a88611c56b9be61ec" +#define SYZ_PAGE_SIZE 4096 +#define SYZ_NUM_PAGES 4096 +#define SYZ_DATA_OFFSET 536870912 unsigned syscall_count = 1565; call_t syscalls[] = { {"accept", 202}, @@ -6415,7 +6427,10 @@ call_t syscalls[] = { #if defined(__ppc64__) || defined(__PPC64__) || defined(__powerpc64__) || 0 #define GOARCH "ppc64le" -#define SYZ_REVISION "c996439d4a7c1dc76b269b6869f8bb2b505550b3" +#define SYZ_REVISION "1b0002aaf7519f39f849b6abcc3c35add0d6f112" +#define SYZ_PAGE_SIZE 4096 +#define SYZ_NUM_PAGES 4096 +#define SYZ_DATA_OFFSET 536870912 unsigned syscall_count = 1555; call_t syscalls[] = { {"accept", 330}, diff --git a/executor/syscalls_netbsd.h b/executor/syscalls_netbsd.h index 04c9c6d7a..aa16f0644 100644 --- a/executor/syscalls_netbsd.h +++ b/executor/syscalls_netbsd.h @@ -2,7 +2,10 @@ #if defined(__x86_64__) || 0 #define GOARCH "amd64" -#define SYZ_REVISION "8a10b163677425b6f340b2e4e277358c7c1a4237" +#define SYZ_REVISION "350c03f12de803ca8775df640249eae7e2425419" +#define SYZ_PAGE_SIZE 4096 +#define SYZ_NUM_PAGES 4096 +#define SYZ_DATA_OFFSET 536870912 unsigned syscall_count = 188; call_t syscalls[] = { {"accept", 30}, diff --git a/executor/syscalls_test.h b/executor/syscalls_test.h index 13e643dfc..9ea69df00 100644 --- a/executor/syscalls_test.h +++ b/executor/syscalls_test.h @@ -2,7 +2,10 @@ #if 0 #define GOARCH "32" -#define SYZ_REVISION "229a33891b79d4c76384836d58be89caaab83684" +#define SYZ_REVISION "6f7cae371c55b5afdfbc7f518e21c58894cfce5b" +#define SYZ_PAGE_SIZE 8192 +#define SYZ_NUM_PAGES 2048 +#define SYZ_DATA_OFFSET 536870912 unsigned syscall_count = 85; call_t syscalls[] = { {"mmap", 0, (syscall_t)mmap}, @@ -96,7 +99,10 @@ call_t syscalls[] = { #if 0 #define GOARCH "64" -#define SYZ_REVISION "72bf9b428d7ccdf1adbb2ef093b656ca3564ee14" +#define SYZ_REVISION "e5ba3c9ee8fe997bfacae016e4bbebd8ecb2f573" +#define SYZ_PAGE_SIZE 4096 +#define SYZ_NUM_PAGES 4096 +#define SYZ_DATA_OFFSET 536870912 unsigned syscall_count = 85; call_t syscalls[] = { {"mmap", 0, (syscall_t)mmap}, diff --git a/executor/syscalls_windows.h b/executor/syscalls_windows.h index c5b61339d..d62aa9d6c 100644 --- a/executor/syscalls_windows.h +++ b/executor/syscalls_windows.h @@ -2,7 +2,10 @@ #if defined(_M_X64) || 0 #define GOARCH "amd64" -#define SYZ_REVISION "5d63c10c1e139f4a33dae8f94809285dae73a415" +#define SYZ_REVISION "38e754fb8319bf26f8642703cab9d9acbcec5109" +#define SYZ_PAGE_SIZE 4096 +#define SYZ_NUM_PAGES 4096 +#define SYZ_DATA_OFFSET 536870912 unsigned syscall_count = 2955; call_t syscalls[] = { {"AbortDoc", 0, (syscall_t)AbortDoc}, diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go index bede09122..5c1b0208e 100644 --- a/pkg/csource/csource.go +++ b/pkg/csource/csource.go @@ -26,7 +26,19 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { w: new(bytes.Buffer), calls: make(map[string]uint64), } - for _, c := range p.Calls { + + calls, nvar, err := ctx.generateProgCalls(ctx.p) + if err != nil { + return nil, err + } + + mmapProg := p.Target.GenerateUberMmapProg() + mmapCalls, _, err := ctx.generateProgCalls(mmapProg) + if err != nil { + return nil, err + } + + for _, c := range append(mmapProg.Calls, p.Calls...) { ctx.calls[c.Meta.CallName] = c.Meta.NR } @@ -41,16 +53,6 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { ctx.generateSyscallDefines() - exec := make([]byte, prog.ExecBufferSize) - progSize, err := ctx.p.SerializeForExec(exec) - if err != nil { - return nil, fmt.Errorf("failed to serialize program: %v", err) - } - decoded, err := ctx.target.DeserializeExec(exec[:progSize]) - if err != nil { - return nil, err - } - calls, nvar := ctx.generateCalls(decoded) if nvar != 0 { ctx.printf("long r[%v];\n", nvar) } @@ -62,6 +64,9 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { ctx.generateTestFunc(calls, nvar, "loop") ctx.print("int main()\n{\n") + for _, c := range mmapCalls { + ctx.printf("%s", c) + } if opts.HandleSegv { ctx.printf("\tinstall_segv_handler();\n") } @@ -83,6 +88,9 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { ctx.generateTestFunc(calls, nvar, "test") if opts.Procs <= 1 { ctx.print("int main()\n{\n") + for _, c := range mmapCalls { + ctx.printf("%s", c) + } if opts.HandleSegv { ctx.print("\tinstall_segv_handler();\n") } @@ -108,6 +116,9 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) { ctx.print("\t}\n}\n") } else { ctx.print("int main()\n{\n") + for _, c := range mmapCalls { + ctx.printf("%s", c) + } if opts.UseTmpDir { ctx.print("\tchar *cwd = get_current_dir_name();\n") } @@ -254,6 +265,20 @@ func (ctx *context) generateSyscallDefines() { ctx.printf("\n") } +func (ctx *context) generateProgCalls(p *prog.Prog) ([]string, uint64, error) { + exec := make([]byte, prog.ExecBufferSize) + progSize, err := p.SerializeForExec(exec) + if err != nil { + return nil, 0, fmt.Errorf("failed to serialize program: %v", err) + } + decoded, err := ctx.target.DeserializeExec(exec[:progSize]) + if err != nil { + return nil, 0, err + } + calls, nvar := ctx.generateCalls(decoded) + return calls, nvar, nil +} + func (ctx *context) generateCalls(p prog.ExecProg) ([]string, uint64) { var calls []string csumSeq := 0 diff --git a/prog/alloc.go b/prog/alloc.go new file mode 100644 index 000000000..c47fc703d --- /dev/null +++ b/prog/alloc.go @@ -0,0 +1,164 @@ +// Copyright 2018 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 prog + +import ( + "fmt" +) + +// memAlloc keeps track of allocated objects in a program +// and decides where to allocate new objects. +// It has 2 main methods: noteAlloc which is called for existing allocations +// in a program as we analyze it; and alloc which decides where to allocate +// a new object. +// The implementation is based on a 2-level bitmap where each bit represents +// 64 bytes (memAllocGranule) of program memory. +type memAlloc struct { + size uint64 + mem [memAllocL1Size]*[memAllocL0Size]uint64 + buf [memAllocL0Size]uint64 +} + +const ( + memAllocGranule = 64 // 1 bit per that many bytes (all allocations are rounded to this size) + memAllocMaxMem = 16 << 20 + memAllocL0Size = 64 + bitsPerUint64 = 8 * 8 + memAllocL0Mem = memAllocL0Size * memAllocGranule * bitsPerUint64 + memAllocL1Size = memAllocMaxMem / memAllocL0Mem +) + +func newMemAlloc(totalMemSize uint64) *memAlloc { + if totalMemSize > memAllocMaxMem { + panic(fmt.Sprintf("newMemAlloc: too much mem %v (max: %v)", totalMemSize, memAllocMaxMem)) + } + if totalMemSize%memAllocL0Mem != 0 { + panic(fmt.Sprintf("newMemAlloc: unaligned size %v (align: %v)", totalMemSize, memAllocL0Mem)) + } + ma := &memAlloc{ + size: totalMemSize / memAllocGranule, + } + ma.mem[0] = &ma.buf + return ma +} + +func (ma *memAlloc) noteAlloc(addr0, size0 uint64) { + addr := addr0 / memAllocGranule + size := (addr0+size0+memAllocGranule-1)/memAllocGranule - addr + for i := uint64(0); i < size; i++ { + ma.set(addr + i) + } +} + +func (ma *memAlloc) alloc(r *randGen, size0 uint64) uint64 { + if size0 == 0 { + size0 = 1 + } + size := (size0 + memAllocGranule - 1) / memAllocGranule + end := ma.size - size + for start := uint64(0); start < end; start++ { + empty := true + for i := uint64(0); i < size; i++ { + if ma.get(start + i) { + empty = false + break + } + } + if empty { + start0 := start * memAllocGranule + ma.noteAlloc(start0, size0) + return start0 + } + } + ma.bankruptcy() + return ma.alloc(r, size0) +} + +func (ma *memAlloc) bankruptcy() { + for i1 := uint64(0); i1 < ma.size/(memAllocL0Size*bitsPerUint64); i1++ { + if ma.mem[i1] == nil { + continue + } + for i0 := range ma.mem[i1] { + ma.mem[i1][i0] = 0 + } + } +} + +func (ma *memAlloc) pos(idx uint64) (i1, i0, bit uint64) { + i1 = idx / (memAllocL0Size * bitsPerUint64) + r1 := idx % (memAllocL0Size * bitsPerUint64) + i0 = r1 / bitsPerUint64 + bit = 1 << (r1 % bitsPerUint64) + return +} + +func (ma *memAlloc) set(idx uint64) { + i1, i0, bit := ma.pos(idx) + if ma.mem[i1] == nil { + ma.mem[i1] = new([memAllocL0Size]uint64) + } + ma.mem[i1][i0] |= bit +} + +func (ma *memAlloc) get(idx uint64) bool { + i1, i0, bit := ma.pos(idx) + if ma.mem[i1] == nil { + return false + } + return ma.mem[i1][i0]&bit != 0 +} + +type vmaAlloc struct { + numPages uint64 + used []uint64 + m map[uint64]struct{} +} + +func newVmaAlloc(totalPages uint64) *vmaAlloc { + return &vmaAlloc{ + numPages: totalPages, + m: make(map[uint64]struct{}), + } +} + +func (va *vmaAlloc) noteAlloc(page, size uint64) { + for i := page; i < page+size; i++ { + if _, ok := va.m[i]; ok { + continue + } + va.m[i] = struct{}{} + va.used = append(va.used, i) + } +} + +func (va *vmaAlloc) alloc(r *randGen, size uint64) uint64 { + if size > va.numPages { + panic(fmt.Sprintf("vmaAlloc: bad size=%v numPages=%v", size, va.numPages)) + } + var page uint64 + if len(va.used) == 0 || r.oneOf(5) { + page = r.rand(4) + if !r.oneOf(100) { + page = va.numPages - page - size + } + } else { + page = va.used[r.rand(len(va.used))] + if size > 1 && r.bin() { + off := r.rand(int(size)) + if off > page { + off = page + } + page -= off + } + if page+size > va.numPages { + page = va.numPages - size + } + } + if page >= va.numPages || size > va.numPages || page+size > va.numPages { + panic(fmt.Sprintf("vmaAlloc: bad page=%v size=%v numPages=%v", page, size, va.numPages)) + } + va.noteAlloc(page, size) + return page +} diff --git a/prog/alloc_test.go b/prog/alloc_test.go new file mode 100644 index 000000000..261b18d0c --- /dev/null +++ b/prog/alloc_test.go @@ -0,0 +1,72 @@ +// Copyright 2018 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 prog + +import ( + "fmt" + "testing" +) + +func TestMemAlloc(t *testing.T) { + t.Parallel() + type op struct { + addr uint64 + size int // if positive do noteAlloc, otherwise -- alloc + } + tests := [][]op{ + []op{ + // Just sequential allocation. + {0, -1}, + {64, -64}, + {128, -65}, + {256, -16}, + {320, -8}, + }, + []op{ + // First reserve some memory and then allocate. + {0, 1}, + {64, 63}, + {128, 64}, + {192, 65}, + {320, -1}, + {448, 1}, + {384, -1}, + {576, 1}, + {640, -128}, + }, + } + for ti, test := range tests { + test := test + t.Run(fmt.Sprint(ti), func(t *testing.T) { + ma := newMemAlloc(16 << 20) + for i, op := range test { + if op.size > 0 { + t.Logf("#%v: noteAlloc(%v, %v)", i, op.addr, op.size) + ma.noteAlloc(op.addr, uint64(op.size)) + continue + } + t.Logf("#%v: alloc(%v) = %v", i, -op.size, op.addr) + addr := ma.alloc(nil, uint64(-op.size)) + if addr != op.addr { + t.Fatalf("bad result %v", addr) + } + } + }) + } +} + +func TestVmaAlloc(t *testing.T) { + t.Parallel() + target, err := GetTarget("test", "64") + if err != nil { + t.Fatal(err) + } + r := newRand(target, randSource(t)) + va := newVmaAlloc(1000) + for i := 0; i < 30; i++ { + size := r.rand(4) + 1 + page := va.alloc(r, size) + t.Logf("alloc(%v) = %3v-%3v\n", size, page, page+size) + } +} diff --git a/prog/analysis.go b/prog/analysis.go index ea3a98dd0..c93a13e6c 100644 --- a/prog/analysis.go +++ b/prog/analysis.go @@ -12,17 +12,14 @@ import ( "fmt" ) -const ( - maxPages = 4 << 10 -) - type state struct { target *Target ct *ChoiceTable files map[string]bool resources map[string][]Arg strings map[string]bool - pages [maxPages]bool + ma *memAlloc + va *vmaAlloc } // analyze analyzes the program p up to but not including call c. @@ -44,12 +41,24 @@ func newState(target *Target, ct *ChoiceTable) *state { files: make(map[string]bool), resources: make(map[string][]Arg), strings: make(map[string]bool), + ma: newMemAlloc(target.NumPages * target.PageSize), + va: newVmaAlloc(target.NumPages), } return s } func (s *state) analyze(c *Call) { ForeachArg(c, func(arg Arg, _ *ArgCtx) { + switch a := arg.(type) { + case *PointerArg: + switch { + case a.IsNull(): + case a.VmaSize != 0: + s.va.noteAlloc(a.Address/s.target.PageSize, a.VmaSize/s.target.PageSize) + default: + s.ma.noteAlloc(a.Address, a.Res.Size()) + } + } switch typ := arg.Type().(type) { case *ResourceType: if typ.Dir() != DirIn { @@ -68,16 +77,6 @@ func (s *state) analyze(c *Call) { } } }) - start, npages, mapped := s.target.AnalyzeMmap(c) - if npages != 0 { - if start+npages > uint64(len(s.pages)) { - panic(fmt.Sprintf("address is out of bounds: page=%v len=%v bound=%v", - start, npages, len(s.pages))) - } - for i := uint64(0); i < npages; i++ { - s.pages[start+i] = mapped - } - } } type ArgCtx struct { diff --git a/prog/encoding.go b/prog/encoding.go index 0261d4772..daa7eb71d 100644 --- a/prog/encoding.go +++ b/prog/encoding.go @@ -46,14 +46,14 @@ func (p *Prog) Serialize() []byte { if i != 0 { fmt.Fprintf(buf, ", ") } - serialize(a, buf, vars, &varSeq) + p.Target.serialize(a, buf, vars, &varSeq) } fmt.Fprintf(buf, ")\n") } return buf.Bytes() } -func serialize(arg Arg, buf *bytes.Buffer, vars map[Arg]int, varSeq *int) { +func (target *Target) serialize(arg Arg, buf *bytes.Buffer, vars map[Arg]int, varSeq *int) { if arg == nil { fmt.Fprintf(buf, "nil") return @@ -67,14 +67,14 @@ func serialize(arg Arg, buf *bytes.Buffer, vars map[Arg]int, varSeq *int) { case *ConstArg: fmt.Fprintf(buf, "0x%x", a.Val) case *PointerArg: - if a.Res == nil && a.PagesNum == 0 { + if a.IsNull() { fmt.Fprintf(buf, "0x0") break } - fmt.Fprintf(buf, "&%v", serializeAddr(arg)) - if a.Res == nil || !isDefaultArg(a.Res) { + fmt.Fprintf(buf, "&%v", target.serializeAddr(a)) + if a.Res == nil || !target.isDefaultArg(a.Res) { fmt.Fprintf(buf, "=") - serialize(a.Res, buf, vars, varSeq) + target.serialize(a.Res, buf, vars, varSeq) } case *DataArg: if a.Type().Dir() == DirOut { @@ -104,7 +104,7 @@ func serialize(arg Arg, buf *bytes.Buffer, vars map[Arg]int, varSeq *int) { lastNonDefault := len(a.Inner) - 1 if a.fixedInnerSize() { for ; lastNonDefault >= 0; lastNonDefault-- { - if !isDefaultArg(a.Inner[lastNonDefault]) { + if !target.isDefaultArg(a.Inner[lastNonDefault]) { break } } @@ -117,14 +117,14 @@ func serialize(arg Arg, buf *bytes.Buffer, vars map[Arg]int, varSeq *int) { if i != 0 { fmt.Fprintf(buf, ", ") } - serialize(arg1, buf, vars, varSeq) + target.serialize(arg1, buf, vars, varSeq) } buf.Write([]byte{delims[1]}) case *UnionArg: fmt.Fprintf(buf, "@%v", a.Option.Type().FieldName()) - if !isDefaultArg(a.Option) { + if !target.isDefaultArg(a.Option) { fmt.Fprintf(buf, "=") - serialize(a.Option, buf, vars, varSeq) + target.serialize(a.Option, buf, vars, varSeq) } case *ResultArg: if a.Res == nil { @@ -198,7 +198,7 @@ func (target *Target) Deserialize(data []byte) (prog *Prog, err error) { } if len(c.Args) < len(meta.Args) { for i := len(c.Args); i < len(meta.Args); i++ { - c.Args = append(c.Args, defaultArg(meta.Args[i])) + c.Args = append(c.Args, target.defaultArg(meta.Args[i])) } } if len(c.Args) != len(meta.Args) { @@ -241,10 +241,8 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e arg = MakeConstArg(typ, v) case *ResourceType: arg = MakeResultArg(typ, nil, v) - case *PtrType: - arg = MakePointerArg(typ, 0, 0, 0, nil) - case *VmaType: - arg = MakePointerArg(typ, 0, 0, 0, nil) + case *PtrType, *VmaType: + arg = MakeNullPointerArg(typ) default: return nil, fmt.Errorf("bad const type %+v", typ) } @@ -288,7 +286,7 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e return nil, fmt.Errorf("& arg is not a pointer: %#v", typ) } p.Parse('&') - page, off, size, err := parseAddr(p, true) + addr, vmaSize, err := target.parseAddr(p) if err != nil { return nil, err } @@ -300,17 +298,13 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e return nil, err } } else { - inner = defaultArg(typ1) + inner = target.defaultArg(typ1) } - arg = MakePointerArg(typ, page, off, size, inner) - case '(': - // This used to parse length of VmaType and return ArgPageSize, which is now removed. - // Leaving this for now for backwards compatibility. - pages, _, _, err := parseAddr(p, false) - if err != nil { - return nil, err + if typ1 != nil { + arg = MakePointerArg(typ, addr, inner) + } else { + arg = MakeVmaPointerArg(typ, addr, vmaSize) } - arg = MakeConstArg(typ, pages*target.PageSize) case '"', '\'': data, err := deserializeData(p) if err != nil { @@ -366,7 +360,7 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e } p.Parse('}') for len(inner) < len(t1.Fields) { - inner = append(inner, defaultArg(t1.Fields[len(inner)])) + inner = append(inner, target.defaultArg(t1.Fields[len(inner)])) } arg = MakeGroupArg(typ, inner) case '[': @@ -389,7 +383,7 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e p.Parse(']') if t1.Kind == ArrayRangeLen && t1.RangeBegin == t1.RangeEnd { for uint64(len(inner)) < t1.RangeBegin { - inner = append(inner, defaultArg(t1.Type)) + inner = append(inner, target.defaultArg(t1.Type)) } inner = inner[:t1.RangeBegin] } @@ -420,7 +414,7 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e return nil, err } } else { - opt = defaultArg(optType) + opt = target.defaultArg(optType) } arg = MakeUnionArg(typ, opt) case 'n': @@ -441,58 +435,29 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e const ( encodingAddrBase = 0x7f0000000000 - encodingPageSize = 4 << 10 maxLineLen = 256 << 10 ) -func serializeAddr(arg Arg) string { - var pageIndex, pagesNum uint64 - var pageOffset int - switch a := arg.(type) { - case *PointerArg: - pageIndex = a.PageIndex - pageOffset = a.PageOffset - pagesNum = a.PagesNum - default: - panic("bad addr arg") - } - page := pageIndex * encodingPageSize - page += encodingAddrBase - soff := "" - if off := pageOffset; off != 0 { - sign := "+" - if off < 0 { - sign = "-" - off = -off - page += encodingPageSize - } - soff = fmt.Sprintf("%v0x%x", sign, off) - } +func (target *Target) serializeAddr(arg *PointerArg) string { ssize := "" - if size := pagesNum; size != 0 { - size *= encodingPageSize - ssize = fmt.Sprintf("/0x%x", size) + if arg.VmaSize != 0 { + ssize = fmt.Sprintf("/0x%x", arg.VmaSize) } - return fmt.Sprintf("(0x%x%v%v)", page, soff, ssize) + return fmt.Sprintf("(0x%x%v)", encodingAddrBase+arg.Address, ssize) } -func parseAddr(p *parser, base bool) (uint64, int, uint64, error) { +func (target *Target) parseAddr(p *parser) (uint64, uint64, error) { p.Parse('(') pstr := p.Ident() - page, err := strconv.ParseUint(pstr, 0, 64) + addr, err := strconv.ParseUint(pstr, 0, 64) if err != nil { - return 0, 0, 0, fmt.Errorf("failed to parse addr page: '%v'", pstr) - } - if page%encodingPageSize != 0 { - return 0, 0, 0, fmt.Errorf("address base is not page size aligned: '%v'", pstr) + return 0, 0, fmt.Errorf("failed to parse addr: %q", pstr) } - if base { - if page < encodingAddrBase { - return 0, 0, 0, fmt.Errorf("address without base offset: '%v'", pstr) - } - page -= encodingAddrBase + if addr < encodingAddrBase { + return 0, 0, fmt.Errorf("address without base offset: %q", pstr) } - var off int64 + addr -= encodingAddrBase + // This is not used anymore, but left here to parse old programs. if p.Char() == '+' || p.Char() == '-' { minus := false if p.Char() == '-' { @@ -502,28 +467,38 @@ func parseAddr(p *parser, base bool) (uint64, int, uint64, error) { p.Parse('+') } ostr := p.Ident() - off, err = strconv.ParseInt(ostr, 0, 64) + off, err := strconv.ParseUint(ostr, 0, 64) if err != nil { - return 0, 0, 0, fmt.Errorf("failed to parse addr offset: '%v'", ostr) + return 0, 0, fmt.Errorf("failed to parse addr offset: %q", ostr) } if minus { - page -= encodingPageSize off = -off } + addr += off } - var size uint64 + maxMem := target.NumPages * target.PageSize + var vmaSize uint64 if p.Char() == '/' { p.Parse('/') pstr := p.Ident() - size, err = strconv.ParseUint(pstr, 0, 64) + size, err := strconv.ParseUint(pstr, 0, 64) if err != nil { - return 0, 0, 0, fmt.Errorf("failed to parse addr size: '%v'", pstr) + return 0, 0, fmt.Errorf("failed to parse addr size: %q", pstr) + } + addr = addr & ^(target.PageSize - 1) + vmaSize = (size + target.PageSize - 1) & ^(target.PageSize - 1) + if vmaSize == 0 { + vmaSize = target.PageSize + } + if vmaSize > maxMem { + vmaSize = maxMem + } + if addr > maxMem-vmaSize { + addr = maxMem - vmaSize } } p.Parse(')') - page /= encodingPageSize - size /= encodingPageSize - return page, int(off), size, nil + return addr, vmaSize, nil } func serializeData(buf *bytes.Buffer, data []byte) { diff --git a/prog/encodingexec.go b/prog/encodingexec.go index ae885d3b1..27fa63350 100644 --- a/prog/encodingexec.go +++ b/prog/encodingexec.go @@ -194,16 +194,10 @@ func (p *Prog) SerializeForExec(buffer []byte) (int, error) { } func (target *Target) PhysicalAddr(arg *PointerArg) uint64 { - if arg.Res == nil && arg.PagesNum == 0 { + if arg.IsNull() { return 0 } - addr := arg.PageIndex*target.PageSize + target.DataOffset - if arg.PageOffset >= 0 { - addr += uint64(arg.PageOffset) - } else { - addr += target.PageSize - uint64(-arg.PageOffset) - } - return addr + return target.DataOffset + arg.Address } type execContext struct { diff --git a/prog/export_test.go b/prog/export_test.go index 10dc6dbe5..e22c903f4 100644 --- a/prog/export_test.go +++ b/prog/export_test.go @@ -30,16 +30,19 @@ func initTargetTest(t *testing.T, os, arch string) *Target { return target } +func randSource(t *testing.T) rand.Source { + seed := int64(time.Now().UnixNano()) + t.Logf("seed=%v", seed) + return rand.NewSource(seed) +} + func initRandomTargetTest(t *testing.T, os, arch string) (*Target, rand.Source, int) { target := initTargetTest(t, os, arch) iters := 10000 if testing.Short() { iters = 100 } - seed := int64(time.Now().UnixNano()) - rs := rand.NewSource(seed) - t.Logf("seed=%v", seed) - return target, rs, iters + return target, randSource(t), iters } func initTest(t *testing.T) (*Target, rand.Source, int) { @@ -53,9 +56,7 @@ func testEachTargetRandom(t *testing.T, fn func(t *testing.T, target *Target, rs } targets := AllTargets() iters /= len(targets) - seed := int64(time.Now().UnixNano()) - rs0 := rand.NewSource(seed) - t.Logf("seed=%v", seed) + rs0 := randSource(t) for _, target := range targets { target := target rs := rand.NewSource(rs0.Int63()) diff --git a/prog/hints.go b/prog/hints.go index e6406124b..88cb6b029 100644 --- a/prog/hints.go +++ b/prog/hints.go @@ -64,9 +64,6 @@ func (m CompMap) String() string { // Mutates the program using the comparison operands stored in compMaps. // For each of the mutants executes the exec callback. func (p *Prog) MutateWithHints(callIndex int, comps CompMap, exec func(p *Prog)) { - if p.Calls[callIndex].Meta == p.Target.MmapSyscall { - return - } p = p.Clone() c := p.Calls[callIndex] execValidate := func() { diff --git a/prog/hints_test.go b/prog/hints_test.go index 9a87d3014..a3fd94c62 100644 --- a/prog/hints_test.go +++ b/prog/hints_test.go @@ -421,7 +421,7 @@ func TestHintsData(t *testing.T) { Target: target, Calls: []*Call{{ Meta: call, - Args: []Arg{MakePointerArg(call.Args[0], 0, 0, 0, + Args: []Arg{MakePointerArg(call.Args[0], 0, MakeDataArg(call.Args[0].(*PtrType).Type, input))}, Ret: MakeReturnArg(call.Ret), }}, diff --git a/prog/minimization.go b/prog/minimization.go index 8a77eec03..f74ad0252 100644 --- a/prog/minimization.go +++ b/prog/minimization.go @@ -29,44 +29,6 @@ func Minimize(p0 *Prog, callIndex0 int, crash bool, pred0 func(*Prog, int) bool) name0 = p0.Calls[callIndex0].Meta.Name } - // Try to glue all mmap's together. - s := analyze(nil, p0, nil) - hi := -1 - lo := -1 - for i := 0; i < maxPages; i++ { - if s.pages[i] { - hi = i - if lo == -1 { - lo = i - } - } - } - if hi != -1 { - p := p0.Clone() - callIndex := callIndex0 - // Remove all mmaps. - for i := 0; i < len(p.Calls); i++ { - c := p.Calls[i] - if i != callIndex && c.Meta == p.Target.MmapSyscall { - p.removeCall(i) - if i < callIndex { - callIndex-- - } - i-- - } - } - // Prepend uber-mmap. - mmap := p0.Target.MakeMmap(uint64(lo), uint64(hi-lo)+1) - p.Calls = append([]*Call{mmap}, p.Calls...) - if callIndex != -1 { - callIndex++ - } - if pred(p, callIndex) { - p0 = p - callIndex0 = callIndex - } - } - // Try to remove all calls except the last one one-by-one. for i := len(p0.Calls) - 1; i >= 0; i-- { if i == callIndex0 { diff --git a/prog/minimization_test.go b/prog/minimization_test.go index 641b9a9b9..5979ce7a2 100644 --- a/prog/minimization_test.go +++ b/prog/minimization_test.go @@ -99,22 +99,6 @@ func TestMinimize(t *testing.T) { "sched_yield()\n", -1, }, - // Glue several mmaps together. - { - "sched_yield()\n" + - "mmap(&(0x7f0000010000/0x1000)=nil, 0x1000, 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" + - "mmap(&(0x7f0000011000/0x1000)=nil, 0x1000, 0x3, 0x32, 0xffffffffffffffff, 0x0)\n" + - "getpid()\n" + - "mmap(&(0x7f0000015000/0x5000)=nil, 0x2000, 0x3, 0x32, 0xffffffffffffffff, 0x0)\n", - 3, - func(p *Prog, callIndex int) bool { - return p.String() == "mmap-sched_yield-getpid" - }, - "mmap(&(0x7f0000010000/0x7000)=nil, 0x7000, 0x0, 0x0, 0xffffffffffffffff, 0x0)\n" + - "sched_yield()\n" + - "getpid()\n", - 2, - }, } target, _, _ := initTest(t) for ti, test := range tests { diff --git a/prog/mutation.go b/prog/mutation.go index 5bb839f04..dff40a8ec 100644 --- a/prog/mutation.go +++ b/prog/mutation.go @@ -57,11 +57,6 @@ outer: retry = true continue } - // Mutating mmap() arguments almost certainly doesn't give us new coverage. - if c.Meta == p.Target.MmapSyscall && r.nOutOf(99, 100) { - retry = true - continue - } s := analyze(ct, p, c) updateSizes := true retryArg := false @@ -200,17 +195,8 @@ func (target *Target) mutateArg(r *randGen, s *state, arg Arg, ctx ArgCtx, updat } // TODO: swap elements of the array case *PtrType: - a, ok := arg.(*PointerArg) - if !ok { - break - } - // TODO: we don't know size for out args - size := uint64(1) - if a.Res != nil { - size = a.Res.Size() - } - var newArg Arg - newArg, calls = r.addr(s, t, size, a.Res) + a := arg.(*PointerArg) + newArg := r.allocAddr(s, t, a.Res.Size(), a.Res) replaceArg(arg, newArg) case *StructType: gen := target.SpecialTypes[t.Name()] @@ -260,12 +246,8 @@ func (target *Target) mutateArg(r *randGen, s *state, arg Arg, ctx ArgCtx, updat // Update base pointer if size has increased. if base := ctx.Base; base != nil { if baseSize < base.Res.Size() { - newArg, newCalls := r.addr(s, base.Type(), base.Res.Size(), base.Res) - calls = append(calls, newCalls...) - a1 := newArg.(*PointerArg) - base.PageIndex = a1.PageIndex - base.PageOffset = a1.PageOffset - base.PagesNum = a1.PagesNum + newArg := r.allocAddr(s, base.Type(), base.Res.Size(), base.Res) + *base = *newArg } } for _, c := range calls { @@ -309,6 +291,11 @@ func (ma *mutationArgs) collectArg(arg Arg, ctx *ArgCtx) { if typ.Kind == BufferString && len(typ.Values) == 1 { return // string const } + case *PtrType: + if arg.(*PointerArg).IsNull() { + // TODO: we ought to mutate this, but we don't have code for this yet. + return + } } typ := arg.Type() if typ == nil || typ.Dir() == DirOut || !typ.Varlen() && typ.Size() == 0 { diff --git a/prog/mutation_test.go b/prog/mutation_test.go index 5c5ac232a..2267dd254 100644 --- a/prog/mutation_test.go +++ b/prog/mutation_test.go @@ -135,7 +135,6 @@ mutate5(&(0x7f0000001000)="2e2f66696c653100", 0x22c0) {` mutate3(&(0x7f0000000000)=[0x1, 0x1], 0x2) `, ` -mmap(&(0x7f0000000000/0x1000)=nil, 0x1000) mutate3(&(0x7f0000000000)=[0x1, 0x1, 0x1], 0x3) `}, // Mutate size from it's natural value. @@ -206,3 +205,22 @@ func BenchmarkMutate(b *testing.B) { } }) } + +func BenchmarkGenerate(b *testing.B) { + olddebug := debug + debug = false + defer func() { debug = olddebug }() + target, err := GetTarget("linux", "amd64") + if err != nil { + b.Fatal(err) + } + prios := target.CalculatePriorities(nil) + ct := target.BuildChoiceTable(prios, nil) + const progLen = 30 + b.RunParallel(func(pb *testing.PB) { + rs := rand.NewSource(0) + for pb.Next() { + target.Generate(rs, progLen, ct) + } + }) +} diff --git a/prog/prio.go b/prog/prio.go index 832234dde..35eb6e9d9 100644 --- a/prog/prio.go +++ b/prog/prio.go @@ -140,11 +140,6 @@ func (target *Target) calcDynamicPrio(corpus []*Prog) [][]float32 { for _, c1 := range p.Calls { id0 := c0.Meta.ID id1 := c1.Meta.ID - // There are too many mmap's anyway. - if id0 == id1 || c0.Meta == target.MmapSyscall || - c1.Meta == target.MmapSyscall { - continue - } prios[id0][id1] += 1.0 } } diff --git a/prog/prog.go b/prog/prog.go index 68179541c..dc6121662 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -91,23 +91,38 @@ func (arg *ConstArg) Value() (uint64, uint64, bool) { } // Used for PtrType and VmaType. -// Even if these are always constant (for reproducibility), we use a separate -// type because they are represented in an abstract (base+page+offset) form. type PointerArg struct { ArgCommon - PageIndex uint64 - PageOffset int // offset within a page - PagesNum uint64 // number of available pages - Res Arg // pointee + Address uint64 + VmaSize uint64 // size of the referenced region for vma args + Res Arg // pointee (nil for vma) } -func MakePointerArg(t Type, page uint64, off int, npages uint64, obj Arg) Arg { +func MakePointerArg(t Type, addr uint64, data Arg) *PointerArg { + if data == nil { + panic("nil pointer data arg") + } return &PointerArg{ - ArgCommon: ArgCommon{typ: t}, - PageIndex: page, - PageOffset: off, - PagesNum: npages, - Res: obj, + ArgCommon: ArgCommon{typ: t}, + Address: addr, + Res: data, + } +} + +func MakeVmaPointerArg(t Type, addr, size uint64) *PointerArg { + if addr%1024 != 0 { + panic("unaligned vma address") + } + return &PointerArg{ + ArgCommon: ArgCommon{typ: t}, + Address: addr, + VmaSize: size, + } +} + +func MakeNullPointerArg(t Type) *PointerArg { + return &PointerArg{ + ArgCommon: ArgCommon{typ: t}, } } @@ -115,6 +130,10 @@ func (arg *PointerArg) Size() uint64 { return arg.typ.Size() } +func (arg *PointerArg) IsNull() bool { + return arg.Address == 0 && arg.VmaSize == 0 && arg.Res == nil +} + // Used for BufferType. type DataArg struct { ArgCommon @@ -291,7 +310,7 @@ func InnerArg(arg Arg) Arg { return arg // Not a pointer. } -func defaultArg(t Type) Arg { +func (target *Target) defaultArg(t Type) Arg { switch typ := t.(type) { case *IntType, *ConstType, *FlagsType, *LenType, *ProcType, *CsumType: return MakeConstArg(t, t.Default()) @@ -314,32 +333,31 @@ func defaultArg(t Type) Arg { var elems []Arg if typ.Kind == ArrayRangeLen && typ.RangeBegin == typ.RangeEnd { for i := uint64(0); i < typ.RangeBegin; i++ { - elems = append(elems, defaultArg(typ.Type)) + elems = append(elems, target.defaultArg(typ.Type)) } } return MakeGroupArg(t, elems) case *StructType: var inner []Arg for _, field := range typ.Fields { - inner = append(inner, defaultArg(field)) + inner = append(inner, target.defaultArg(field)) } return MakeGroupArg(t, inner) case *UnionType: - return MakeUnionArg(t, defaultArg(typ.Fields[0])) + return MakeUnionArg(t, target.defaultArg(typ.Fields[0])) case *VmaType: - return MakePointerArg(t, 0, 0, 1, nil) + return MakeVmaPointerArg(t, 0, target.PageSize) case *PtrType: - var res Arg - if !t.Optional() && t.Dir() != DirOut { - res = defaultArg(typ.Type) + if t.Optional() { + return MakeNullPointerArg(t) } - return MakePointerArg(t, 0, 0, 0, res) + return MakePointerArg(t, 0, target.defaultArg(typ.Type)) default: panic("unknown arg type") } } -func isDefaultArg(arg Arg) bool { +func (target *Target) isDefaultArg(arg Arg) bool { if IsPad(arg.Type()) { return true } @@ -356,7 +374,7 @@ func isDefaultArg(arg Arg) bool { return false } for _, elem := range a.Inner { - if !isDefaultArg(elem) { + if !target.isDefaultArg(elem) { return false } } @@ -364,7 +382,7 @@ func isDefaultArg(arg Arg) bool { case *UnionArg: t := a.Type().(*UnionType) return a.Option.Type().FieldName() == t.Fields[0].Name() && - isDefaultArg(a.Option) + target.isDefaultArg(a.Option) case *DataArg: if a.Size() == 0 { return true @@ -384,11 +402,12 @@ func isDefaultArg(arg Arg) bool { case *PointerArg: switch t := a.Type().(type) { case *PtrType: - return a.PageIndex == 0 && a.PageOffset == 0 && a.PagesNum == 0 && - (((t.Optional() || t.Dir() == DirOut) && a.Res == nil) || - (!t.Optional() && t.Dir() != DirOut && a.Res != nil && isDefaultArg(a.Res))) + if t.Optional() { + return a.IsNull() + } + return a.Address == 0 && target.isDefaultArg(a.Res) case *VmaType: - return a.PageIndex == 0 && a.PageOffset == 0 && a.PagesNum == 1 && a.Res == nil + return a.Address == 0 && a.VmaSize == target.PageSize default: panic("unknown pointer type") } diff --git a/prog/prog_test.go b/prog/prog_test.go index 146694f45..1dc310456 100644 --- a/prog/prog_test.go +++ b/prog/prog_test.go @@ -25,7 +25,7 @@ func TestDefault(t *testing.T) { target, _, _ := initTest(t) for _, meta := range target.SyscallMap { for _, t := range meta.Args { - defaultArg(t) + target.defaultArg(t) } } } @@ -91,16 +91,18 @@ func TestVmaType(t *testing.T) { if !ok { t.Fatalf("len has bad type: %v", l) } - if va.PagesNum < min || va.PagesNum > max { - t.Fatalf("vma has bad number of pages: %v, want [%v-%v]", va.PagesNum, min, max) + if va.VmaSize < min || va.VmaSize > max { + t.Fatalf("vma has bad size: %v, want [%v-%v]", + va.VmaSize, min, max) } - if la.Val/pageSize < min || la.Val/pageSize > max { - t.Fatalf("len has bad number of pages: %v, want [%v-%v]", la.Val/pageSize, min, max) + if la.Val < min || la.Val > max { + t.Fatalf("len has bad value: %v, want [%v-%v]", + la.Val, min, max) } } - check(c.Args[0], c.Args[1], 1, 1e5) - check(c.Args[2], c.Args[3], 5, 5) - check(c.Args[4], c.Args[5], 7, 9) + check(c.Args[0], c.Args[1], 1*pageSize, 1e5*pageSize) + check(c.Args[2], c.Args[3], 5*pageSize, 5*pageSize) + check(c.Args[4], c.Args[5], 7*pageSize, 9*pageSize) } } diff --git a/prog/rand.go b/prog/rand.go index 5afd00c9d..b9aa77a8a 100644 --- a/prog/rand.go +++ b/prog/rand.go @@ -9,13 +9,10 @@ import ( "math" "math/rand" "strings" - "sync" "github.com/google/syzkaller/pkg/ifuzz" ) -var pageStartPool = sync.Pool{New: func() interface{} { return new([]uint64) }} - type randGen struct { *rand.Rand target *Target @@ -132,7 +129,7 @@ func (r *randGen) randPageCount() (n uint64) { case r.nOutOf(5, 6): n = r.rand(20) + 1 default: - n = (r.rand(3) + 1) * 1024 + n = (r.rand(3) + 1) * 512 } return } @@ -217,82 +214,13 @@ func (r *randGen) randString(s *state, t *BufferType) []byte { return buf.Bytes() } -func (r *randGen) addr1(s *state, typ Type, size uint64, data Arg) (Arg, []*Call) { - npages := (size + r.target.PageSize - 1) / r.target.PageSize - if npages == 0 { - npages = 1 - } - if r.bin() { - return r.randPageAddr(s, typ, npages, data, false), nil - } - for i := uint64(0); i < maxPages-npages; i++ { - free := true - for j := uint64(0); j < npages; j++ { - if s.pages[i+j] { - free = false - break - } - } - if !free { - continue - } - c := r.target.MakeMmap(i, npages) - return MakePointerArg(typ, i, 0, 0, data), []*Call{c} - } - return r.randPageAddr(s, typ, npages, data, false), nil +func (r *randGen) allocAddr(s *state, typ Type, size uint64, data Arg) *PointerArg { + return MakePointerArg(typ, s.ma.alloc(r, size), data) } -func (r *randGen) addr(s *state, typ Type, size uint64, data Arg) (Arg, []*Call) { - arg, calls := r.addr1(s, typ, size, data) - a, ok := arg.(*PointerArg) - if !ok { - panic("bad") - } - // Patch offset of the address. - switch { - case r.nOutOf(50, 102): - case r.nOutOf(50, 52): - a.PageOffset = -int(size) - case r.nOutOf(1, 2): - a.PageOffset = r.Intn(int(r.target.PageSize)) - default: - if size > 0 { - a.PageOffset = -r.Intn(int(size)) - } - } - return arg, calls -} - -func (r *randGen) randPageAddr(s *state, typ Type, npages uint64, data Arg, vma bool) Arg { - poolPtr := pageStartPool.Get().(*[]uint64) - starts := (*poolPtr)[:0] - for i := uint64(0); i < maxPages-npages; i++ { - busy := true - for j := uint64(0); j < npages; j++ { - if !s.pages[i+j] { - busy = false - break - } - } - // TODO: it does not need to be completely busy, - // for example, mmap addr arg can be new memory. - if !busy { - continue - } - starts = append(starts, i) - } - var page uint64 - if len(starts) != 0 { - page = starts[r.rand(len(starts))] - } else { - page = r.rand(int(maxPages - npages)) - } - if !vma { - npages = 0 - } - *poolPtr = starts - pageStartPool.Put(poolPtr) - return MakePointerArg(typ, page, 0, npages, data) +func (r *randGen) allocVMA(s *state, typ Type, numPages uint64) *PointerArg { + page := s.va.alloc(r, numPages) + return MakeVmaPointerArg(typ, page*r.target.PageSize, numPages*r.target.PageSize) } func (r *randGen) createResource(s *state, res *ResourceType) (arg Arg, calls []*Call) { @@ -348,6 +276,9 @@ func (r *randGen) createResource(s *state, res *ResourceType) (arg Arg, calls [] return arg, calls } // Discard unsuccessful calls. + // Note: s.ma/va have already noted allocations of the new objects + // in discarded syscalls, ideally we should recreate state + // by analyzing the program again. for _, c := range calls { ForeachArg(c, func(arg Arg, _ *ArgCtx) { if a, ok := arg.(*ResultArg); ok && a.Res != nil { @@ -429,22 +360,14 @@ func (r *randGen) nOutOf(n, outOf int) bool { } func (r *randGen) generateCall(s *state, p *Prog) []*Call { - call := -1 - if len(p.Calls) != 0 { - for i := 0; i < 5; i++ { - c := p.Calls[r.Intn(len(p.Calls))].Meta - call = c.ID - // There is roughly half of mmap's so ignore them. - if c != r.target.MmapSyscall { - break - } - } - } - idx := 0 if s.ct == nil { idx = r.Intn(len(r.target.Syscalls)) } else { + call := -1 + if len(p.Calls) != 0 { + call = p.Calls[r.Intn(len(p.Calls))].Meta.ID + } idx = s.ct.Choose(r.Rand, call) } meta := r.target.Syscalls[idx] @@ -495,7 +418,14 @@ func (target *Target) GenerateAllSyzProg(rs rand.Source) *Prog { func (target *Target) GenerateSimpleProg() *Prog { return &Prog{ Target: target, - Calls: []*Call{target.MakeMmap(0, 1)}, + Calls: []*Call{target.MakeMmap(0, target.PageSize)}, + } +} + +func (target *Target) GenerateUberMmapProg() *Prog { + return &Prog{ + Target: target, + Calls: []*Call{target.MakeMmap(0, target.NumPages*target.PageSize)}, } } @@ -529,12 +459,12 @@ func (r *randGen) generateArgImpl(s *state, typ Type, ignoreSpecial bool) (arg A switch typ.(type) { case *IntType, *FlagsType, *ConstType, *ProcType, *VmaType, *ResourceType: - return defaultArg(typ), nil + return r.target.defaultArg(typ), nil } } if typ.Optional() && r.oneOf(5) { - return defaultArg(typ), nil + return r.target.defaultArg(typ), nil } // Allow infinite recursion for optional pointers. @@ -548,7 +478,7 @@ func (r *randGen) generateArgImpl(s *state, typ Type, ignoreSpecial bool) (arg A } }() if r.recDepth[str.Name()] >= 3 { - return MakePointerArg(typ, 0, 0, 0, nil), nil + return MakeNullPointerArg(typ), nil } } } @@ -629,7 +559,7 @@ func (r *randGen) generateArgImpl(s *state, typ Type, ignoreSpecial bool) (arg A if a.RangeBegin != 0 || a.RangeEnd != 0 { npages = a.RangeBegin + uint64(r.Intn(int(a.RangeEnd-a.RangeBegin+1))) } - arg := r.randPageAddr(s, a, npages, nil, true) + arg := r.allocVMA(s, a, npages) return arg, nil case *FlagsType: return MakeConstArg(a, r.flags(a.Vals)), nil @@ -697,11 +627,10 @@ func (r *randGen) generateArgImpl(s *state, typ Type, ignoreSpecial bool) (arg A // So try to reuse a previously used address. addrs := s.resources["iocbptr"] addr := addrs[r.Intn(len(addrs))].(*PointerArg) - arg = MakePointerArg(a, addr.PageIndex, addr.PageOffset, addr.PagesNum, inner) + arg = MakePointerArg(a, addr.Address, inner) return arg, calls } - arg, calls1 := r.addr(s, a, inner.Size(), inner) - calls = append(calls, calls1...) + arg := r.allocAddr(s, a, inner.Size(), inner) return arg, calls case *LenType: // Return placeholder value of 0 while generating len arg. diff --git a/prog/size.go b/prog/size.go index 9f2258c82..ab8d97717 100644 --- a/prog/size.go +++ b/prog/size.go @@ -21,7 +21,7 @@ func (target *Target) generateSize(arg Arg, lenType *LenType) uint64 { switch arg.Type().(type) { case *VmaType: a := arg.(*PointerArg) - return a.PagesNum * target.PageSize * 8 / bitSize + return a.VmaSize * 8 / bitSize case *ArrayType: a := arg.(*GroupArg) if lenType.BitSize != 0 { diff --git a/prog/target.go b/prog/target.go index 946839159..2b044977c 100644 --- a/prog/target.go +++ b/prog/target.go @@ -17,6 +17,7 @@ type Target struct { Revision string // unique hash representing revision of the descriptions PtrSize uint64 PageSize uint64 + NumPages uint64 DataOffset uint64 Syscalls []*Syscall @@ -24,17 +25,8 @@ type Target struct { Structs []*KeyedStruct Consts []ConstValue - // Syscall used by MakeMmap. - // It has some special meaning because there are usually too many of them. - MmapSyscall *Syscall - - // MakeMmap creates call that maps [start, start+npages) page range. - MakeMmap func(start, npages uint64) *Call - - // AnalyzeMmap analyzes the call c regarding mapping/unmapping memory. - // If it maps/unmaps any memory returns [start, start+npages) range, - // otherwise returns npages = 0. - AnalyzeMmap func(c *Call) (start, npages uint64, mapped bool) + // MakeMmap creates call that maps [addr, addr+size) memory range. + MakeMmap func(addr, size uint64) *Call // SanitizeCall neutralizes harmful calls. SanitizeCall func(c *Call) @@ -175,7 +167,7 @@ func (g *Gen) NOutOf(n, outOf int) bool { } func (g *Gen) Alloc(ptrType Type, data Arg) (Arg, []*Call) { - return g.r.addr(g.s, ptrType, data.Size(), data) + return g.r.allocAddr(g.s, ptrType, data.Size(), data), nil } func (g *Gen) GenerateArg(typ Type, pcalls *[]*Call) Arg { diff --git a/prog/validation.go b/prog/validation.go index 400b13140..8f01d6df5 100644 --- a/prog/validation.go +++ b/prog/validation.go @@ -17,7 +17,7 @@ type validCtx struct { func (p *Prog) validate() error { ctx := &validCtx{make(map[Arg]bool), make(map[Arg]Arg)} for _, c := range p.Calls { - if err := c.validate(ctx); err != nil { + if err := p.validateCall(ctx, c); err != nil { return err } } @@ -29,7 +29,7 @@ func (p *Prog) validate() error { return nil } -func (c *Call) validate(ctx *validCtx) error { +func (p *Prog) validateCall(ctx *validCtx, c *Call) error { if c.Meta == nil { return fmt.Errorf("call does not have meta information") } @@ -157,13 +157,23 @@ func (c *Call) validate(ctx *validCtx) error { switch a := arg.(type) { case *ConstArg: case *PointerArg: + maxMem := p.Target.NumPages * p.Target.PageSize + size := a.VmaSize + if size == 0 && a.Res != nil { + size = a.Res.Size() + } + if a.Address >= maxMem || a.Address+size > maxMem { + return fmt.Errorf("syscall %v: ptr %v has bad address %v/%v/%v", + c.Meta.Name, a.Type().Name(), a.Address, a.VmaSize, size) + } switch t := a.Type().(type) { case *VmaType: if a.Res != nil { return fmt.Errorf("syscall %v: vma arg '%v' has data", c.Meta.Name, a.Type().Name()) } - if a.PagesNum == 0 && t.Dir() != DirOut && !t.Optional() { - return fmt.Errorf("syscall %v: vma arg '%v' has size 0", c.Meta.Name, a.Type().Name()) + if a.VmaSize == 0 && t.Dir() != DirOut && !t.Optional() { + return fmt.Errorf("syscall %v: vma arg '%v' has size 0", + c.Meta.Name, a.Type().Name()) } case *PtrType: if a.Res != nil { @@ -171,8 +181,9 @@ func (c *Call) validate(ctx *validCtx) error { return err } } - if a.PagesNum != 0 { - return fmt.Errorf("syscall %v: pointer arg '%v' has nonzero size", c.Meta.Name, a.Type().Name()) + if a.VmaSize != 0 { + return fmt.Errorf("syscall %v: pointer arg '%v' has nonzero size", + c.Meta.Name, a.Type().Name()) } default: return fmt.Errorf("syscall %v: pointer arg '%v' has bad meta type %+v", c.Meta.Name, arg.Type().Name(), arg.Type()) diff --git a/sys/akaros/amd64.go b/sys/akaros/amd64.go index 3c966da58..098e47bae 100644 --- a/sys/akaros/amd64.go +++ b/sys/akaros/amd64.go @@ -4,7 +4,7 @@ package akaros import . "github.com/google/syzkaller/prog" func init() { - RegisterTarget(&Target{OS: "akaros", Arch: "amd64", Revision: revision_amd64, PtrSize: 8, Syscalls: syscalls_amd64, Resources: resources_amd64, Structs: structDescs_amd64, Consts: consts_amd64}, initTarget) + RegisterTarget(&Target{OS: "akaros", Arch: "amd64", Revision: revision_amd64, PtrSize: 8, PageSize: 4096, NumPages: 4096, DataOffset: 536870912, Syscalls: syscalls_amd64, Resources: resources_amd64, Structs: structDescs_amd64, Consts: consts_amd64}, initTarget) } var resources_amd64 = []*ResourceDesc{ @@ -285,4 +285,4 @@ var consts_amd64 = []ConstValue{ {Name: "__O_TMPFILE", Value: 4259840}, } -const revision_amd64 = "0e5dbbd94e4838b9729df440c4c53e581768eaf8" +const revision_amd64 = "43f665d2468516ae8ffc137aec39649a4a1dc7ce" diff --git a/sys/akaros/init.go b/sys/akaros/init.go index 02b9f09a6..3d525f95a 100644 --- a/sys/akaros/init.go +++ b/sys/akaros/init.go @@ -17,17 +17,11 @@ func initTarget(target *prog.Target) { 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) + invalidFD = ^uint64(0) ) type arch struct { @@ -41,13 +35,13 @@ type arch struct { } // createMmapCall creates a "normal" mmap call that maps [start, start+npages) page range. -func (arch *arch) makeMmap(start, npages uint64) *prog.Call { +func (arch *arch) makeMmap(addr, size 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.MakeVmaPointerArg(meta.Args[0], addr, size), + prog.MakeConstArg(meta.Args[1], size), 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), @@ -56,19 +50,3 @@ func (arch *arch) makeMmap(start, npages uint64) *prog.Call { Ret: prog.MakeReturnArg(meta.Ret), } } - -func (arch *arch) analyzeMmap(c *prog.Call) (start, npages uint64, mapped bool) { - switch c.Meta.Name { - case "mmap": - 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/amd64.go b/sys/freebsd/amd64.go index 34236ab63..e6c41eaa6 100644 --- a/sys/freebsd/amd64.go +++ b/sys/freebsd/amd64.go @@ -4,7 +4,7 @@ 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) + RegisterTarget(&Target{OS: "freebsd", Arch: "amd64", Revision: revision_amd64, PtrSize: 8, PageSize: 4096, NumPages: 4096, DataOffset: 536870912, Syscalls: syscalls_amd64, Resources: resources_amd64, Structs: structDescs_amd64, Consts: consts_amd64}, initTarget) } var resources_amd64 = []*ResourceDesc{ @@ -2440,4 +2440,4 @@ var consts_amd64 = []ConstValue{ {Name: "WUNTRACED", Value: 2}, } -const revision_amd64 = "8faf3b6e65172d4a9e098d5eda39563a082f8078" +const revision_amd64 = "b41d0c0723ec3704417120a5a63657cc522f14cf" diff --git a/sys/freebsd/init.go b/sys/freebsd/init.go index d1a1ffec5..ed02e712e 100644 --- a/sys/freebsd/init.go +++ b/sys/freebsd/init.go @@ -22,18 +22,12 @@ func initTarget(target *prog.Target) { S_IFSOCK: target.ConstMap["S_IFSOCK"], } - target.PageSize = pageSize - target.DataOffset = dataOffset - target.MmapSyscall = arch.mmapSyscall target.MakeMmap = arch.makeMmap - target.AnalyzeMmap = arch.analyzeMmap target.SanitizeCall = arch.sanitizeCall } const ( - pageSize = 4 << 10 - dataOffset = 512 << 20 - invalidFD = ^uint64(0) + invalidFD = ^uint64(0) ) type arch struct { @@ -52,14 +46,13 @@ type arch struct { S_IFSOCK uint64 } -// createMmapCall creates a "normal" mmap call that maps [start, start+npages) page range. -func (arch *arch) makeMmap(start, npages uint64) *prog.Call { +func (arch *arch) makeMmap(addr, size 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.MakeVmaPointerArg(meta.Args[0], addr, size), + prog.MakeConstArg(meta.Args[1], size), prog.MakeConstArg(meta.Args[2], arch.PROT_READ|arch.PROT_WRITE), prog.MakeConstArg(meta.Args[3], arch.MAP_ANON|arch.MAP_PRIVATE|arch.MAP_FIXED), prog.MakeResultArg(meta.Args[4], nil, invalidFD), @@ -69,32 +62,6 @@ func (arch *arch) makeMmap(start, npages uint64) *prog.Call { } } -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_ANON == 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 - } -} - func (arch *arch) sanitizeCall(c *prog.Call) { switch c.Meta.CallName { case "mmap": diff --git a/sys/fuchsia/amd64.go b/sys/fuchsia/amd64.go index 9798e8eb3..aeb63b203 100644 --- a/sys/fuchsia/amd64.go +++ b/sys/fuchsia/amd64.go @@ -4,7 +4,7 @@ package fuchsia import . "github.com/google/syzkaller/prog" func init() { - RegisterTarget(&Target{OS: "fuchsia", Arch: "amd64", Revision: revision_amd64, PtrSize: 8, Syscalls: syscalls_amd64, Resources: resources_amd64, Structs: structDescs_amd64, Consts: consts_amd64}, initTarget) + RegisterTarget(&Target{OS: "fuchsia", Arch: "amd64", Revision: revision_amd64, PtrSize: 8, PageSize: 4096, NumPages: 4096, DataOffset: 536870912, Syscalls: syscalls_amd64, Resources: resources_amd64, Structs: structDescs_amd64, Consts: consts_amd64}, initTarget) } var resources_amd64 = []*ResourceDesc{ @@ -1243,4 +1243,4 @@ var consts_amd64 = []ConstValue{ {Name: "ZX_WAIT_ASYNC_REPEATING", Value: 1}, } -const revision_amd64 = "16f8d2a14dffe8465559442d33e3ca296f7ea4bf" +const revision_amd64 = "4eadf9151d47a3744fe9277b15a0447970eba0cb" diff --git a/sys/fuchsia/arm64.go b/sys/fuchsia/arm64.go index 826bfb44c..6f1e9b7e2 100644 --- a/sys/fuchsia/arm64.go +++ b/sys/fuchsia/arm64.go @@ -4,7 +4,7 @@ package fuchsia import . "github.com/google/syzkaller/prog" func init() { - RegisterTarget(&Target{OS: "fuchsia", Arch: "arm64", Revision: revision_arm64, PtrSize: 8, Syscalls: syscalls_arm64, Resources: resources_arm64, Structs: structDescs_arm64, Consts: consts_arm64}, initTarget) + RegisterTarget(&Target{OS: "fuchsia", Arch: "arm64", Revision: revision_arm64, PtrSize: 8, PageSize: 4096, NumPages: 4096, DataOffset: 536870912, Syscalls: syscalls_arm64, Resources: resources_arm64, Structs: structDescs_arm64, Consts: consts_arm64}, initTarget) } var resources_arm64 = []*ResourceDesc{ @@ -1243,4 +1243,4 @@ var consts_arm64 = []ConstValue{ {Name: "ZX_WAIT_ASYNC_REPEATING", Value: 1}, } -const revision_arm64 = "c04cb066cf7fc135f9f85388423f3e65aedc5028" +const revision_arm64 = "bb0e27a08caeecf468bb53c76ebf97388e4d3c6d" diff --git a/sys/fuchsia/init.go b/sys/fuchsia/init.go index 12ee37daf..f3299e178 100644 --- a/sys/fuchsia/init.go +++ b/sys/fuchsia/init.go @@ -12,40 +12,21 @@ func initTarget(target *prog.Target) { mmapSyscall: target.SyscallMap["syz_mmap"], } - 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 -) - type arch struct { mmapSyscall *prog.Syscall } -func (arch *arch) makeMmap(start, npages uint64) *prog.Call { +func (arch *arch) makeMmap(addr, size 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.MakeVmaPointerArg(meta.Args[0], addr, size), + prog.MakeConstArg(meta.Args[1], size), }, Ret: prog.MakeReturnArg(meta.Ret), } } - -func (arch *arch) analyzeMmap(c *prog.Call) (start, npages uint64, mapped bool) { - switch c.Meta.Name { - case "syz_mmap": - npages = c.Args[1].(*prog.ConstArg).Val / pageSize - start = c.Args[0].(*prog.PointerArg).PageIndex - mapped = true - } - return -} diff --git a/sys/linux/386.go b/sys/linux/386.go index 8de78231f..8aa83b9ca 100644 --- a/sys/linux/386.go +++ b/sys/linux/386.go @@ -4,7 +4,7 @@ package linux import . "github.com/google/syzkaller/prog" func init() { - RegisterTarget(&Target{OS: "linux", Arch: "386", Revision: revision_386, PtrSize: 4, Syscalls: syscalls_386, Resources: resources_386, Structs: structDescs_386, Consts: consts_386}, initTarget) + RegisterTarget(&Target{OS: "linux", Arch: "386", Revision: revision_386, PtrSize: 4, PageSize: 4096, NumPages: 4096, DataOffset: 536870912, Syscalls: syscalls_386, Resources: resources_386, Structs: structDescs_386, Consts: consts_386}, initTarget) } var resources_386 = []*ResourceDesc{ @@ -24970,4 +24970,4 @@ var consts_386 = []ConstValue{ {Name: "bpf_insn_load_imm_dw", Value: 24}, } -const revision_386 = "1d92abf94e3a94a587c23e34ff517226557eb39b" +const revision_386 = "fdfb3bacd26e9af78ca89d10c2c2e06726f2b744" diff --git a/sys/linux/amd64.go b/sys/linux/amd64.go index 2f1b95a6a..ff9f6272f 100644 --- a/sys/linux/amd64.go +++ b/sys/linux/amd64.go @@ -4,7 +4,7 @@ package linux import . "github.com/google/syzkaller/prog" func init() { - RegisterTarget(&Target{OS: "linux", Arch: "amd64", Revision: revision_amd64, PtrSize: 8, Syscalls: syscalls_amd64, Resources: resources_amd64, Structs: structDescs_amd64, Consts: consts_amd64}, initTarget) + RegisterTarget(&Target{OS: "linux", Arch: "amd64", Revision: revision_amd64, PtrSize: 8, PageSize: 4096, NumPages: 4096, DataOffset: 536870912, Syscalls: syscalls_amd64, Resources: resources_amd64, Structs: structDescs_amd64, Consts: consts_amd64}, initTarget) } var resources_amd64 = []*ResourceDesc{ @@ -25563,4 +25563,4 @@ var consts_amd64 = []ConstValue{ {Name: "bpf_insn_load_imm_dw", Value: 24}, } -const revision_amd64 = "c063297cc1f7a742899148ea3e480a503975e1a3" +const revision_amd64 = "3b495371d7017730eef962bb58f8674114796711" diff --git a/sys/linux/arm.go b/sys/linux/arm.go index 3830f25d3..de4cfc1a9 100644 --- a/sys/linux/arm.go +++ b/sys/linux/arm.go @@ -4,7 +4,7 @@ package linux import . "github.com/google/syzkaller/prog" func init() { - RegisterTarget(&Target{OS: "linux", Arch: "arm", Revision: revision_arm, PtrSize: 4, Syscalls: syscalls_arm, Resources: resources_arm, Structs: structDescs_arm, Consts: consts_arm}, initTarget) + RegisterTarget(&Target{OS: "linux", Arch: "arm", Revision: revision_arm, PtrSize: 4, PageSize: 4096, NumPages: 4096, DataOffset: 536870912, Syscalls: syscalls_arm, Resources: resources_arm, Structs: structDescs_arm, Consts: consts_arm}, initTarget) } var resources_arm = []*ResourceDesc{ @@ -24828,4 +24828,4 @@ var consts_arm = []ConstValue{ {Name: "bpf_insn_load_imm_dw", Value: 24}, } -const revision_arm = "2a035864a56374d1ef4eafcffb968f43fd5b075c" +const revision_arm = "1da52823d9d718efc3156b97b25ad96b0e8e7ea9" diff --git a/sys/linux/arm64.go b/sys/linux/arm64.go index 0b964d54f..367f34e3f 100644 --- a/sys/linux/arm64.go +++ b/sys/linux/arm64.go @@ -4,7 +4,7 @@ package linux import . "github.com/google/syzkaller/prog" func init() { - RegisterTarget(&Target{OS: "linux", Arch: "arm64", Revision: revision_arm64, PtrSize: 8, Syscalls: syscalls_arm64, Resources: resources_arm64, Structs: structDescs_arm64, Consts: consts_arm64}, initTarget) + RegisterTarget(&Target{OS: "linux", Arch: "arm64", Revision: revision_arm64, PtrSize: 8, PageSize: 4096, NumPages: 4096, DataOffset: 536870912, Syscalls: syscalls_arm64, Resources: resources_arm64, Structs: structDescs_arm64, Consts: consts_arm64}, initTarget) } var resources_arm64 = []*ResourceDesc{ @@ -24945,4 +24945,4 @@ var consts_arm64 = []ConstValue{ {Name: "bpf_insn_load_imm_dw", Value: 24}, } -const revision_arm64 = "033a3d40f0ba2f8c5ebeb2a344a44e89db17e105" +const revision_arm64 = "8747be63243fed6597fc673a88611c56b9be61ec" diff --git a/sys/linux/init.go b/sys/linux/init.go index 8f8fbfcc3..a411ed97b 100644 --- a/sys/linux/init.go +++ b/sys/linux/init.go @@ -34,11 +34,7 @@ func initTarget(target *prog.Target) { CLOCK_REALTIME: target.ConstMap["CLOCK_REALTIME"], } - target.PageSize = pageSize - target.DataOffset = dataOffset - target.MmapSyscall = arch.mmapSyscall target.MakeMmap = arch.makeMmap - target.AnalyzeMmap = arch.analyzeMmap target.SanitizeCall = arch.sanitizeCall target.SpecialTypes = map[string]func(g *prog.Gen, typ prog.Type, old prog.Arg) ( prog.Arg, []*prog.Call){ @@ -64,9 +60,7 @@ func initTarget(target *prog.Target) { } const ( - pageSize = 4 << 10 - dataOffset = 512 << 20 - invalidFD = ^uint64(0) + invalidFD = ^uint64(0) ) var ( @@ -108,14 +102,14 @@ type arch struct { CLOCK_REALTIME uint64 } -// createMmapCall creates a "normal" mmap call that maps [start, start+npages) page range. -func (arch *arch) makeMmap(start, npages uint64) *prog.Call { +// createMmapCall creates a "normal" mmap call that maps [addr, addr+size) memory range. +func (arch *arch) makeMmap(addr, size 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.MakeVmaPointerArg(meta.Args[0], addr, size), + prog.MakeConstArg(meta.Args[1], addr), 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), @@ -125,37 +119,6 @@ func (arch *arch) makeMmap(start, npages uint64) *prog.Call { } } -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 - case "mremap": - start = c.Args[4].(*prog.PointerArg).PageIndex - npages = c.Args[2].(*prog.ConstArg).Val / pageSize - mapped = true - return - default: - return - } -} - func (arch *arch) sanitizeCall(c *prog.Call) { switch c.Meta.CallName { case "mmap": diff --git a/sys/linux/ppc64le.go b/sys/linux/ppc64le.go index 47f3c096a..ab4b66c28 100644 --- a/sys/linux/ppc64le.go +++ b/sys/linux/ppc64le.go @@ -4,7 +4,7 @@ package linux import . "github.com/google/syzkaller/prog" func init() { - RegisterTarget(&Target{OS: "linux", Arch: "ppc64le", Revision: revision_ppc64le, PtrSize: 8, Syscalls: syscalls_ppc64le, Resources: resources_ppc64le, Structs: structDescs_ppc64le, Consts: consts_ppc64le}, initTarget) + RegisterTarget(&Target{OS: "linux", Arch: "ppc64le", Revision: revision_ppc64le, PtrSize: 8, PageSize: 4096, NumPages: 4096, DataOffset: 536870912, Syscalls: syscalls_ppc64le, Resources: resources_ppc64le, Structs: structDescs_ppc64le, Consts: consts_ppc64le}, initTarget) } var resources_ppc64le = []*ResourceDesc{ @@ -24707,4 +24707,4 @@ var consts_ppc64le = []ConstValue{ {Name: "bpf_insn_load_imm_dw", Value: 24}, } -const revision_ppc64le = "c996439d4a7c1dc76b269b6869f8bb2b505550b3" +const revision_ppc64le = "1b0002aaf7519f39f849b6abcc3c35add0d6f112" diff --git a/sys/netbsd/amd64.go b/sys/netbsd/amd64.go index 66abbe3cc..cff461cd4 100644 --- a/sys/netbsd/amd64.go +++ b/sys/netbsd/amd64.go @@ -4,7 +4,7 @@ package netbsd import . "github.com/google/syzkaller/prog" func init() { - RegisterTarget(&Target{OS: "netbsd", Arch: "amd64", Revision: revision_amd64, PtrSize: 8, Syscalls: syscalls_amd64, Resources: resources_amd64, Structs: structDescs_amd64, Consts: consts_amd64}, initTarget) + RegisterTarget(&Target{OS: "netbsd", Arch: "amd64", Revision: revision_amd64, PtrSize: 8, PageSize: 4096, NumPages: 4096, DataOffset: 536870912, Syscalls: syscalls_amd64, Resources: resources_amd64, Structs: structDescs_amd64, Consts: consts_amd64}, initTarget) } var resources_amd64 = []*ResourceDesc{ @@ -1674,4 +1674,4 @@ var consts_amd64 = []ConstValue{ {Name: "WUNTRACED", Value: 2}, } -const revision_amd64 = "8a10b163677425b6f340b2e4e277358c7c1a4237" +const revision_amd64 = "350c03f12de803ca8775df640249eae7e2425419" diff --git a/sys/netbsd/init.go b/sys/netbsd/init.go index f44753e82..3af3619b6 100644 --- a/sys/netbsd/init.go +++ b/sys/netbsd/init.go @@ -17,18 +17,12 @@ func initTarget(target *prog.Target) { MAP_FIXED: target.ConstMap["MAP_FIXED"], } - target.PageSize = pageSize - target.DataOffset = dataOffset - target.MmapSyscall = arch.mmapSyscall target.MakeMmap = arch.makeMmap - target.AnalyzeMmap = arch.analyzeMmap target.SanitizeCall = arch.sanitizeCall } const ( - pageSize = 4 << 10 - dataOffset = 512 << 20 - invalidFD = ^uint64(0) + invalidFD = ^uint64(0) ) type arch struct { @@ -42,14 +36,13 @@ type arch struct { 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 { +func (arch *arch) makeMmap(addr, size 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.MakeVmaPointerArg(meta.Args[0], addr, size), + prog.MakeConstArg(meta.Args[1], size), 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), @@ -60,32 +53,6 @@ func (arch *arch) makeMmap(start, npages uint64) *prog.Call { } } -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 - } -} - func (arch *arch) sanitizeCall(c *prog.Call) { switch c.Meta.CallName { case "mmap": diff --git a/sys/syz-sysgen/sysgen.go b/sys/syz-sysgen/sysgen.go index aafc44feb..d91970f59 100644 --- a/sys/syz-sysgen/sysgen.go +++ b/sys/syz-sysgen/sysgen.go @@ -135,10 +135,12 @@ func generate(target *targets.Target, prg *compiler.Prog, consts map[string]uint fmt.Fprintf(out, "import . \"github.com/google/syzkaller/prog\"\n\n") fmt.Fprintf(out, "func init() {\n") - fmt.Fprintf(out, "\tRegisterTarget(&Target{OS: %q, Arch: %q, Revision: revision_%v, PtrSize: %v,"+ - "Syscalls: syscalls_%v, Resources: resources_%v, Structs: structDescs_%v, Consts: consts_%v}, "+ + fmt.Fprintf(out, "\tRegisterTarget(&Target{OS: %q, Arch: %q, Revision: revision_%v, PtrSize: %v, "+ + "PageSize: %v, NumPages: %v, DataOffset: %v, Syscalls: syscalls_%v, "+ + "Resources: resources_%v, Structs: structDescs_%v, Consts: consts_%v}, "+ "initTarget)\n", target.OS, target.Arch, target.Arch, target.PtrSize, + target.PageSize, target.NumPages, target.DataOffset, target.Arch, target.Arch, target.Arch, target.Arch) fmt.Fprintf(out, "}\n\n") @@ -174,15 +176,21 @@ func generateExecutorSyscalls(target *targets.Target, syscalls []*prog.Syscall, NeedCall bool } type ArchData struct { - Revision string - GOARCH string - CARCH []string - Calls []SyscallData + Revision string + GOARCH string + CARCH []string + PageSize uint64 + NumPages uint64 + DataOffset uint64 + Calls []SyscallData } data := ArchData{ - Revision: rev, - GOARCH: target.Arch, - CARCH: target.CArch, + Revision: rev, + GOARCH: target.Arch, + CARCH: target.CArch, + PageSize: target.PageSize, + NumPages: target.NumPages, + DataOffset: target.DataOffset, } for _, c := range syscalls { data.Calls = append(data.Calls, SyscallData{ @@ -247,6 +255,9 @@ var archTempl = template.Must(template.New("").Parse(` #if {{range $cdef := $.CARCH}}defined({{$cdef}}) || {{end}}0 #define GOARCH "{{.GOARCH}}" #define SYZ_REVISION "{{.Revision}}" +#define SYZ_PAGE_SIZE {{.PageSize}} +#define SYZ_NUM_PAGES {{.NumPages}} +#define SYZ_DATA_OFFSET {{.DataOffset}} unsigned syscall_count = {{len $.Calls}}; call_t syscalls[] = { {{range $c := $.Calls}} {"{{$c.Name}}", {{$c.NR}}{{if $c.NeedCall}}, (syscall_t){{$c.CallName}}{{end}}}, diff --git a/sys/targets/targets.go b/sys/targets/targets.go index bfd31df6c..a40121c47 100644 --- a/sys/targets/targets.go +++ b/sys/targets/targets.go @@ -8,6 +8,9 @@ type Target struct { OS string Arch string PtrSize uint64 + PageSize uint64 + NumPages uint64 + DataOffset uint64 CArch []string CFlags []string CrossCFlags []string @@ -34,15 +37,18 @@ type os struct { var List = map[string]map[string]*Target{ "test": map[string]*Target{ "32": { - PtrSize: 4, + PtrSize: 4, + PageSize: 8 << 10, }, "64": { - PtrSize: 8, + PtrSize: 8, + PageSize: 4 << 10, }, }, "linux": map[string]*Target{ "amd64": { PtrSize: 8, + PageSize: 4 << 10, CArch: []string{"__x86_64__"}, CFlags: []string{"-m64"}, CrossCFlags: []string{"-m64"}, @@ -57,6 +63,7 @@ var List = map[string]map[string]*Target{ }, "386": { PtrSize: 4, + PageSize: 4 << 10, CArch: []string{"__i386__"}, CFlags: []string{"-m32"}, CrossCFlags: []string{"-m32"}, @@ -66,6 +73,7 @@ var List = map[string]map[string]*Target{ }, "arm64": { PtrSize: 8, + PageSize: 4 << 10, CArch: []string{"__aarch64__"}, CCompilerPrefix: "aarch64-linux-gnu-", KernelArch: "arm64", @@ -73,6 +81,7 @@ var List = map[string]map[string]*Target{ }, "arm": { PtrSize: 4, + PageSize: 4 << 10, CArch: []string{"__arm__"}, CFlags: []string{"-D__LINUX_ARM_ARCH__=6", "-m32", "-D__ARM_EABI__"}, CrossCFlags: []string{"-D__LINUX_ARM_ARCH__=6", "-march=armv6t2"}, @@ -82,6 +91,7 @@ var List = map[string]map[string]*Target{ }, "ppc64le": { PtrSize: 8, + PageSize: 4 << 10, CArch: []string{"__ppc64__", "__PPC64__", "__powerpc64__"}, CFlags: []string{"-D__powerpc64__"}, CrossCFlags: []string{"-D__powerpc64__"}, @@ -92,37 +102,44 @@ var List = map[string]map[string]*Target{ }, "freebsd": map[string]*Target{ "amd64": { - PtrSize: 8, - CArch: []string{"__x86_64__"}, - CFlags: []string{"-m64"}, + PtrSize: 8, + PageSize: 4 << 10, + CArch: []string{"__x86_64__"}, + CFlags: []string{"-m64"}, }, }, "netbsd": map[string]*Target{ "amd64": { - PtrSize: 8, - CArch: []string{"__x86_64__"}, - CFlags: []string{"-m64"}, + PtrSize: 8, + PageSize: 4 << 10, + CArch: []string{"__x86_64__"}, + CFlags: []string{"-m64"}, }, }, "fuchsia": map[string]*Target{ "amd64": { - PtrSize: 8, - CArch: []string{"__x86_64__"}, + PtrSize: 8, + PageSize: 4 << 10, + CArch: []string{"__x86_64__"}, }, "arm64": { - PtrSize: 8, - CArch: []string{"__aarch64__"}, + PtrSize: 8, + PageSize: 4 << 10, + CArch: []string{"__aarch64__"}, }, }, "windows": map[string]*Target{ "amd64": { PtrSize: 8, - CArch: []string{"_M_X64"}, + // TODO(dvyukov): what should we do about 4k vs 64k? + PageSize: 4 << 10, + CArch: []string{"_M_X64"}, }, }, "akaros": map[string]*Target{ "amd64": { PtrSize: 8, + PageSize: 4 << 10, CArch: []string{"__x86_64__"}, NeedSyscallDefine: dontNeedSyscallDefine, }, @@ -175,6 +192,8 @@ func init() { if target.NeedSyscallDefine == nil { target.NeedSyscallDefine = needSyscallDefine } + target.DataOffset = 512 << 20 + target.NumPages = (16 << 20) / target.PageSize } } } diff --git a/sys/test/32.go b/sys/test/32.go index 7eb9ad351..0be1916c6 100644 --- a/sys/test/32.go +++ b/sys/test/32.go @@ -4,7 +4,7 @@ package test import . "github.com/google/syzkaller/prog" func init() { - RegisterTarget(&Target{OS: "test", Arch: "32", Revision: revision_32, PtrSize: 4, Syscalls: syscalls_32, Resources: resources_32, Structs: structDescs_32, Consts: consts_32}, initTarget) + RegisterTarget(&Target{OS: "test", Arch: "32", Revision: revision_32, PtrSize: 4, PageSize: 8192, NumPages: 2048, DataOffset: 536870912, Syscalls: syscalls_32, Resources: resources_32, Structs: structDescs_32, Consts: consts_32}, initTarget) } var resources_32 = []*ResourceDesc{ @@ -695,4 +695,4 @@ var consts_32 = []ConstValue{ {Name: "ONLY_32BITS_CONST", Value: 1}, } -const revision_32 = "229a33891b79d4c76384836d58be89caaab83684" +const revision_32 = "6f7cae371c55b5afdfbc7f518e21c58894cfce5b" diff --git a/sys/test/64.go b/sys/test/64.go index 943bd9ee0..251f12a5f 100644 --- a/sys/test/64.go +++ b/sys/test/64.go @@ -4,7 +4,7 @@ package test import . "github.com/google/syzkaller/prog" func init() { - RegisterTarget(&Target{OS: "test", Arch: "64", Revision: revision_64, PtrSize: 8, Syscalls: syscalls_64, Resources: resources_64, Structs: structDescs_64, Consts: consts_64}, initTarget) + RegisterTarget(&Target{OS: "test", Arch: "64", Revision: revision_64, PtrSize: 8, PageSize: 4096, NumPages: 4096, DataOffset: 536870912, Syscalls: syscalls_64, Resources: resources_64, Structs: structDescs_64, Consts: consts_64}, initTarget) } var resources_64 = []*ResourceDesc{ @@ -693,4 +693,4 @@ var consts_64 = []ConstValue{ {Name: "IPPROTO_UDP", Value: 17}, } -const revision_64 = "72bf9b428d7ccdf1adbb2ef093b656ca3564ee14" +const revision_64 = "e5ba3c9ee8fe997bfacae016e4bbebd8ecb2f573" diff --git a/sys/test/init.go b/sys/test/init.go index 860654878..5df5ba0b4 100644 --- a/sys/test/init.go +++ b/sys/test/init.go @@ -10,39 +10,23 @@ import ( func initTarget(target *prog.Target) { arch := &arch{ mmapSyscall: target.SyscallMap["mmap"], - pageSize: (12 - target.PtrSize) << 10, } - target.PageSize = arch.pageSize - target.DataOffset = 100 << 20 - target.MmapSyscall = arch.mmapSyscall target.MakeMmap = arch.makeMmap - target.AnalyzeMmap = arch.analyzeMmap } type arch struct { mmapSyscall *prog.Syscall - pageSize uint64 } -func (arch *arch) makeMmap(start, npages uint64) *prog.Call { +func (arch *arch) makeMmap(addr, size 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*arch.pageSize), + prog.MakeVmaPointerArg(meta.Args[0], addr, size), + prog.MakeConstArg(meta.Args[1], size), }, Ret: prog.MakeReturnArg(meta.Ret), } } - -func (arch *arch) analyzeMmap(c *prog.Call) (start, npages uint64, mapped bool) { - switch c.Meta.Name { - case "mmap": - npages = c.Args[1].(*prog.ConstArg).Val / arch.pageSize - start = c.Args[0].(*prog.PointerArg).PageIndex - mapped = true - } - return -} diff --git a/sys/windows/amd64.go b/sys/windows/amd64.go index d35f653a3..b3d2a4c16 100644 --- a/sys/windows/amd64.go +++ b/sys/windows/amd64.go @@ -4,7 +4,7 @@ package windows import . "github.com/google/syzkaller/prog" func init() { - RegisterTarget(&Target{OS: "windows", Arch: "amd64", Revision: revision_amd64, PtrSize: 8, Syscalls: syscalls_amd64, Resources: resources_amd64, Structs: structDescs_amd64, Consts: consts_amd64}, initTarget) + RegisterTarget(&Target{OS: "windows", Arch: "amd64", Revision: revision_amd64, PtrSize: 8, PageSize: 4096, NumPages: 4096, DataOffset: 536870912, Syscalls: syscalls_amd64, Resources: resources_amd64, Structs: structDescs_amd64, Consts: consts_amd64}, initTarget) } var resources_amd64 = []*ResourceDesc{ @@ -14612,4 +14612,4 @@ var consts_amd64 = []ConstValue{ {Name: "WRITE_OWNER", Value: 524288}, } -const revision_amd64 = "5d63c10c1e139f4a33dae8f94809285dae73a415" +const revision_amd64 = "38e754fb8319bf26f8642703cab9d9acbcec5109" diff --git a/sys/windows/init.go b/sys/windows/init.go index 8e3761024..7729f3260 100644 --- a/sys/windows/init.go +++ b/sys/windows/init.go @@ -15,19 +15,9 @@ func initTarget(target *prog.Target) { PAGE_EXECUTE_READWRITE: target.ConstMap["PAGE_EXECUTE_READWRITE"], } - target.PageSize = pageSize - target.DataOffset = dataOffset - target.MmapSyscall = arch.virtualAllocSyscall target.MakeMmap = arch.makeMmap - target.AnalyzeMmap = arch.analyzeMmap } -const ( - // TODO(dvyukov): what should we do about 4k vs 64k? - pageSize = 4 << 10 - dataOffset = 512 << 20 -) - type arch struct { virtualAllocSyscall *prog.Syscall @@ -36,26 +26,16 @@ type arch struct { PAGE_EXECUTE_READWRITE uint64 } -func (arch *arch) makeMmap(start, npages uint64) *prog.Call { +func (arch *arch) makeMmap(addr, size uint64) *prog.Call { meta := arch.virtualAllocSyscall 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.MakeVmaPointerArg(meta.Args[0], addr, size), + prog.MakeConstArg(meta.Args[1], size), prog.MakeConstArg(meta.Args[2], arch.MEM_COMMIT|arch.MEM_RESERVE), prog.MakeConstArg(meta.Args[3], arch.PAGE_EXECUTE_READWRITE), }, Ret: prog.MakeReturnArg(meta.Ret), } } - -func (arch *arch) analyzeMmap(c *prog.Call) (start, npages uint64, mapped bool) { - switch c.Meta.Name { - case "VirtualAlloc": - npages = c.Args[1].(*prog.ConstArg).Val / pageSize - start = c.Args[0].(*prog.PointerArg).PageIndex - mapped = true - } - return -} diff --git a/syz-manager/manager.go b/syz-manager/manager.go index 868ee2911..7b4c5c939 100644 --- a/syz-manager/manager.go +++ b/syz-manager/manager.go @@ -102,7 +102,7 @@ const ( phaseTriagedHub ) -const currentDBVersion = 1 +const currentDBVersion = 2 type Fuzzer struct { name string @@ -134,8 +134,6 @@ func main() { if err != nil { Fatalf("%v", err) } - // mmap is used to allocate memory. - syscalls[target.MmapSyscall.ID] = true initAllCover(cfg.Vmlinux) RunManager(cfg, target, syscalls) } @@ -196,6 +194,10 @@ func RunManager(cfg *mgrconfig.Config, target *prog.Target, syscalls map[int]boo // Version 0 had broken minimization, so we need to re-minimize. minimized = false fallthrough + case 1: + // Version 1->2: memory is preallocated so lots of mmaps become unnecessary. + minimized = false + fallthrough case currentDBVersion: } deleted := 0 |
