github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/syz-verifier/execresult.go (about) 1 // Copyright 2021 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package main 5 6 import ( 7 "fmt" 8 "syscall" 9 10 "github.com/google/syzkaller/pkg/ipc" 11 "github.com/google/syzkaller/prog" 12 ) 13 14 // ExecResult stores the results of executing a program. 15 type ExecResult struct { 16 // Pool is the index of the pool. 17 Pool int 18 // Hanged is set to true when a program was killed due to hanging. 19 Hanged bool 20 // Info contains information about the execution of each system call 21 // in the generated programs. 22 Info ipc.ProgInfo 23 // Crashed is set to true if a crash occurred while executing the program. 24 // TODO: is not used properly. Crashes are just an errors now. 25 Crashed bool 26 // Source task ID is used to route result back to the caller. 27 ExecTaskID int64 28 // To signal the processing errors. 29 Error error 30 } 31 32 func (l *ExecResult) IsEqual(r *ExecResult) bool { 33 if l.Crashed || r.Crashed { 34 return false 35 } 36 37 lCalls := l.Info.Calls 38 rCalls := r.Info.Calls 39 40 if len(lCalls) != len(rCalls) { 41 return false 42 } 43 44 for i := 0; i < len(lCalls); i++ { 45 if lCalls[i].Errno != rCalls[i].Errno || 46 lCalls[i].Flags != rCalls[i].Flags { 47 return false 48 } 49 } 50 51 return true 52 } 53 54 type ResultReport struct { 55 // Prog is the serialized program. 56 Prog string 57 // Reports contains information about each system call. 58 Reports []*CallReport 59 // Mismatch says whether the Reports differ. 60 Mismatch bool 61 } 62 63 type CallReport struct { 64 // Call is the name of the system call. 65 Call string 66 // States is a map between pools and their return state when executing the system call. 67 States map[int]ReturnState 68 // Mismatch is set to true if the returned error codes were not the same. 69 Mismatch bool 70 } 71 72 // ReturnState stores the results of executing a system call. 73 type ReturnState struct { 74 // Errno is returned by executing the system call. 75 Errno int 76 // Flags stores the call flags (see pkg/ipc/ipc.go). 77 Flags ipc.CallFlags 78 // Crashed is set to true if the kernel crashed while executing the program 79 // that contains the system call. 80 Crashed bool 81 } 82 83 func (s ReturnState) String() string { 84 state := "" 85 86 if s.Crashed { 87 return "Crashed" 88 } 89 90 state += fmt.Sprintf("Flags: %d, ", s.Flags) 91 errDesc := "success" 92 if s.Errno != 0 { 93 errDesc = syscall.Errno(s.Errno).Error() 94 } 95 state += fmt.Sprintf("Errno: %d (%s)", s.Errno, errDesc) 96 return state 97 } 98 99 // CompareResults checks whether the ExecResult of the same program, 100 // executed on different kernels, are the same. 101 // It returns s ResultReport, highlighting the differences. 102 func CompareResults(res []*ExecResult, prog *prog.Prog) *ResultReport { 103 rr := &ResultReport{ 104 Prog: string(prog.Serialize()), 105 } 106 107 // Build the CallReport for each system call in the program. 108 for idx, call := range prog.Calls { 109 cn := call.Meta.Name 110 111 cr := &CallReport{ 112 Call: cn, 113 States: map[int]ReturnState{}, 114 } 115 116 for _, r := range res { 117 if r.Crashed { 118 cr.States[r.Pool] = ReturnState{Crashed: true} 119 continue 120 } 121 122 ci := r.Info.Calls[idx] 123 cr.States[r.Pool] = ReturnState{Errno: ci.Errno, Flags: ci.Flags} 124 } 125 rr.Reports = append(rr.Reports, cr) 126 } 127 128 pool0 := res[0].Pool 129 for _, cr := range rr.Reports { 130 for _, state := range cr.States { 131 // For each CallReport, verify whether the ReturnStates from all 132 // the pools that executed the program are the same 133 if state0 := cr.States[pool0]; state0 != state { 134 cr.Mismatch = true 135 rr.Mismatch = true 136 } 137 } 138 } 139 140 return rr 141 }