aboutsummaryrefslogtreecommitdiffstats
path: root/syz-verifier/execresult.go
diff options
context:
space:
mode:
Diffstat (limited to 'syz-verifier/execresult.go')
-rw-r--r--syz-verifier/execresult.go139
1 files changed, 139 insertions, 0 deletions
diff --git a/syz-verifier/execresult.go b/syz-verifier/execresult.go
new file mode 100644
index 000000000..d3db18882
--- /dev/null
+++ b/syz-verifier/execresult.go
@@ -0,0 +1,139 @@
+// Copyright 2021 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+ "syscall"
+
+ "github.com/google/syzkaller/pkg/ipc"
+ "github.com/google/syzkaller/prog"
+)
+
+// ExecResult stores the results of executing a program.
+type ExecResult struct {
+ // Pool is the index of the pool.
+ Pool int
+ // Hanged is set to true when a program was killed due to hanging.
+ Hanged bool
+ // Info contains information about the execution of each system call
+ // in the generated programs.
+ Info ipc.ProgInfo
+ // Crashed is set to true if a crash occurred while executing the program.
+ Crashed bool
+
+ RunIdx int
+}
+
+type ResultReport struct {
+ // Prog is the serialized program.
+ Prog string
+ // Reports contains information about each system call.
+ Reports []*CallReport
+}
+
+type CallReport struct {
+ // Call is the name of the system call.
+ Call string
+ // States is a map between pools and their return state when executing the system call.
+ States map[int]ReturnState
+ // Mismatch is set to true if the returned error codes were not the same.
+ Mismatch bool
+}
+
+// ReturnState stores the results of executing a system call.
+type ReturnState struct {
+ // Errno is returned by executing the system call.
+ Errno int
+ // Flags stores the call flags (see pkg/ipc/ipc.go).
+ Flags ipc.CallFlags
+ // Crashed is set to true if the kernel crashed while executing the program
+ // that contains the system call.
+ Crashed bool
+}
+
+func (s ReturnState) String() string {
+ state := ""
+
+ if s.Crashed {
+ return "Crashed"
+ }
+
+ state += fmt.Sprintf("Flags: %d, ", s.Flags)
+ errDesc := "success"
+ if s.Errno != 0 {
+ errDesc = syscall.Errno(s.Errno).Error()
+ }
+ state += fmt.Sprintf("Errno: %d (%s)", s.Errno, errDesc)
+ return state
+}
+
+// VeifyRerun compares the results obtained from rerunning a program with what
+// was reported in the initial result report.
+func VerifyRerun(res []*ExecResult, rr *ResultReport) bool {
+ for idx, cr := range rr.Reports {
+ for _, r := range res {
+ var state ReturnState
+ if r.Crashed {
+ state = ReturnState{Crashed: true}
+ } else {
+ ci := r.Info.Calls[idx]
+ state = ReturnState{Errno: ci.Errno, Flags: ci.Flags}
+ }
+ if state != cr.States[r.Pool] {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+// Verify checks whether the Results of the same program, executed on different
+// kernels, are the same. If that's not the case, it returns a ResultReport,
+// highlighting the differences.
+func Verify(res []*ExecResult, prog *prog.Prog, s *Stats) *ResultReport {
+ rr := &ResultReport{
+ Prog: string(prog.Serialize()),
+ }
+
+ // Build the CallReport for each system call in the program.
+ for idx, call := range prog.Calls {
+ cn := call.Meta.Name
+ s.Calls[cn].Occurrences++
+
+ cr := &CallReport{
+ Call: cn,
+ States: map[int]ReturnState{},
+ }
+
+ for _, r := range res {
+ if r.Crashed {
+ cr.States[r.Pool] = ReturnState{Crashed: true}
+ continue
+ }
+
+ ci := r.Info.Calls[idx]
+ cr.States[r.Pool] = ReturnState{Errno: ci.Errno, Flags: ci.Flags}
+ }
+ rr.Reports = append(rr.Reports, cr)
+ }
+
+ var send bool
+ pool0 := res[0].Pool
+ for _, cr := range rr.Reports {
+ for _, state := range cr.States {
+ // For each CallReport, verify whether the ReturnStates from all
+ // the pools that executed the program are the same
+ if state0 := cr.States[pool0]; state0 != state {
+ cr.Mismatch = true
+ send = true
+ }
+ }
+ }
+
+ if send {
+ return rr
+ }
+ return nil
+}