diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2015-12-17 17:11:08 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2015-12-17 17:31:11 +0100 |
| commit | bbf4e353234e99f4a25ef85a8b02419b652e7401 (patch) | |
| tree | 965fe1ab0b8b257bfdb2ea8000a2c1a029b609fc | |
| parent | bfc05fb926e5004fbe1b7dae29c44d8e301b2b72 (diff) | |
executor: export syscall execution results
Errno can be used to guide fuzzing, or detect not implemented syscalls.
| -rw-r--r-- | executor/executor.cc | 7 | ||||
| -rw-r--r-- | ipc/ipc.go | 13 | ||||
| -rw-r--r-- | syz-fuzzer/fuzzer.go | 3 | ||||
| -rw-r--r-- | tools/syz-execprog/execprog.go | 2 | ||||
| -rw-r--r-- | tools/syz-stress/stress.go | 2 |
5 files changed, 22 insertions, 5 deletions
diff --git a/executor/executor.cc b/executor/executor.cc index 6fbaa6218..1ac518f3f 100644 --- a/executor/executor.cc +++ b/executor/executor.cc @@ -99,6 +99,7 @@ struct thread_t { int num_args; uint64_t args[kMaxArgs]; uint64_t res; + uint64_t errno; uint32_t cover_size; int cover_fd; }; @@ -502,6 +503,7 @@ void handle_completion(thread_t* th) write_output(th->call_index); write_output(th->call_num); + write_output(th->res != -1 ? 0 : th->errno); write_output(th->cover_size); for (uint32_t i = 0; i < th->cover_size; i++) write_output(th->cover_data[i + 1]); @@ -556,6 +558,7 @@ void execute_call(thread_t* th) if (th->num_args > 6) fail("bad number of arguments"); th->res = syscall(call->sys_nr, th->args[0], th->args[1], th->args[2], th->args[3], th->args[4], th->args[5]); + th->errno = errno; break; } case __NR_syz_openpts: { @@ -569,12 +572,14 @@ void execute_call(thread_t* th) else { th->res = -1; } + th->errno = errno; } case __NR_syz_dri_open: { // syz_dri_open(card_id intptr, flags flags[open_flags]) fd[dri] char buf[128]; sprintf(buf, "/dev/dri/card%lu", th->args[0]); th->res = open(buf, th->args[1], 0); + th->errno = errno; } case __NR_syz_fuse_mount: { // syz_fuse_mount(target filename, mode flags[fuse_mode], uid uid, gid gid, maxread intptr, flags flags[mount_flags]) fd[fuse] @@ -599,6 +604,7 @@ void execute_call(thread_t* th) // Ignore errors, maybe fuzzer can do something useful with fd alone. } th->res = fd; + th->errno = errno; } case __NR_syz_fuseblk_mount: { // syz_fuseblk_mount(target filename, blkdev filename, mode flags[fuse_mode], uid uid, gid gid, maxread intptr, blksize intptr, flags flags[mount_flags]) fd[fuse] @@ -629,6 +635,7 @@ void execute_call(thread_t* th) } } th->res = fd; + th->errno = errno; } } int errno0 = errno; diff --git a/ipc/ipc.go b/ipc/ipc.go index 360125053..876d75cde 100644 --- a/ipc/ipc.go +++ b/ipc/ipc.go @@ -111,7 +111,7 @@ func (env *Env) Close() error { // failed: true if executor has detected a kernel bug // hanged: program hanged and was killed // err0: failed to start process, or executor has detected a logical error -func (env *Env) Exec(p *prog.Prog) (output, strace []byte, cov [][]uint32, failed, hanged bool, err0 error) { +func (env *Env) Exec(p *prog.Prog) (output, strace []byte, cov [][]uint32, errnos []int, failed, hanged bool, err0 error) { if p != nil { // Copy-in serialized program. progData := p.SerializeForExec() @@ -154,8 +154,12 @@ func (env *Env) Exec(p *prog.Prog) (output, strace []byte, cov [][]uint32, faile return } cov = make([][]uint32, len(p.Calls)) + errnos = make([]int, len(p.Calls)) + for i := range errnos { + errnos[i] = -1 // not executed + } for i := uint32(0); i < ncmd; i++ { - var callIndex, callNum, coverSize, pc uint32 + var callIndex, callNum, errno, coverSize, pc uint32 if err := binary.Read(r, binary.LittleEndian, &callIndex); err != nil { err0 = fmt.Errorf("failed to read output coverage: %v", err) return @@ -164,6 +168,10 @@ func (env *Env) Exec(p *prog.Prog) (output, strace []byte, cov [][]uint32, faile err0 = fmt.Errorf("failed to read output coverage: %v", err) return } + if err := binary.Read(r, binary.LittleEndian, &errno); err != nil { + err0 = fmt.Errorf("failed to read output errno: %v", err) + return + } if err := binary.Read(r, binary.LittleEndian, &coverSize); err != nil { err0 = fmt.Errorf("failed to read output coverage: %v", err) return @@ -190,6 +198,7 @@ func (env *Env) Exec(p *prog.Prog) (output, strace []byte, cov [][]uint32, faile cov1[j] = pc } cov[callIndex] = cov1 + errnos[callIndex] = int(errno) } return } diff --git a/syz-fuzzer/fuzzer.go b/syz-fuzzer/fuzzer.go index 99a8741e3..002052736 100644 --- a/syz-fuzzer/fuzzer.go +++ b/syz-fuzzer/fuzzer.go @@ -445,7 +445,8 @@ func execute1(pid int, env *ipc.Env, p *prog.Prog, stat *uint64) []cover.Cover { try := 0 retry: atomic.AddUint64(stat, 1) - output, strace, rawCover, failed, hanged, err := env.Exec(p) + output, strace, rawCover, errnos, failed, hanged, err := env.Exec(p) + _ = errnos if failed { // BUG in output should be recognized by manager. logf(0, "BUG: executor-detected bug:\n%s", output) diff --git a/tools/syz-execprog/execprog.go b/tools/syz-execprog/execprog.go index dcb2a0b8b..a94b87878 100644 --- a/tools/syz-execprog/execprog.go +++ b/tools/syz-execprog/execprog.go @@ -103,7 +103,7 @@ func main() { return } p := progs[idx%len(progs)] - output, strace, cov, failed, hanged, err := env.Exec(p) + output, strace, cov, _, failed, hanged, err := env.Exec(p) if *flagDebug || err != nil { fmt.Printf("result: failed=%v hanged=%v err=%v\n\n%s", failed, hanged, err, output) } diff --git a/tools/syz-stress/stress.go b/tools/syz-stress/stress.go index e4f1a506c..da013507f 100644 --- a/tools/syz-stress/stress.go +++ b/tools/syz-stress/stress.go @@ -106,7 +106,7 @@ func execute(pid int, env *ipc.Env, p *prog.Prog) { outMu.Unlock() } - output, _, _, _, _, err := env.Exec(p) + output, _, _, _, _, _, err := env.Exec(p) if err != nil { fmt.Printf("failed to execute executor: %v\n", err) } |
