aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2015-12-17 17:11:08 +0100
committerDmitry Vyukov <dvyukov@google.com>2015-12-17 17:31:11 +0100
commitbbf4e353234e99f4a25ef85a8b02419b652e7401 (patch)
tree965fe1ab0b8b257bfdb2ea8000a2c1a029b609fc
parentbfc05fb926e5004fbe1b7dae29c44d8e301b2b72 (diff)
executor: export syscall execution results
Errno can be used to guide fuzzing, or detect not implemented syscalls.
-rw-r--r--executor/executor.cc7
-rw-r--r--ipc/ipc.go13
-rw-r--r--syz-fuzzer/fuzzer.go3
-rw-r--r--tools/syz-execprog/execprog.go2
-rw-r--r--tools/syz-stress/stress.go2
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)
}