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