github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/report/gvisor.go (about) 1 // Copyright 2018 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 report 5 6 import ( 7 "bytes" 8 "regexp" 9 10 "github.com/google/syzkaller/pkg/report/crash" 11 ) 12 13 type gvisor struct { 14 *config 15 } 16 17 func ctorGvisor(cfg *config) (reporterImpl, []string, error) { 18 ctx := &gvisor{ 19 config: cfg, 20 } 21 suppressions := []string{ 22 "panic: ptrace sysemu failed: no such process", // OOM kill 23 `panic: ptrace (s|g)et fpregs.* failed: no such process`, // OOM kill 24 `panic: ptrace (s|g)et regs.* failed: no such process`, // OOM kill 25 "panic: error initializing first thread: resource temporarily unavailable", // PID exhaustion 26 "panic: unable to activate mm: creating stub process: resource temporarily unavailable", // PID exhaustion 27 "panic: executor failed: pthread_create failed", // PID exhaustion 28 "panic: failed to start executor binary", 29 "panic: error mapping run data: error mapping runData: cannot allocate memory", 30 "race: limit on 8128 simultaneously alive goroutines is exceeded, dying", 31 "ERROR: ThreadSanitizer", // Go race failing due to OOM. 32 "FATAL: ThreadSanitizer", 33 "ThreadSanitizer: clock allocator overflow \\(65536\\*1024\\). Dying.", 34 } 35 return ctx, suppressions, nil 36 } 37 38 func (ctx *gvisor) ContainsCrash(output []byte) bool { 39 return containsCrash(output, gvisorOopses, ctx.ignores) 40 } 41 42 func (ctx *gvisor) Parse(output []byte) *Report { 43 rep := simpleLineParser(output, gvisorOopses, nil, ctx.ignores) 44 if rep == nil { 45 return nil 46 } 47 rep.Title = replaceTable(gvisorTitleReplacement, rep.Title) 48 rep.Report = ctx.shortenReport(rep.Report) 49 return rep 50 } 51 52 func (ctx *gvisor) shortenReport(report []byte) []byte { 53 // gvisor panics include stacks of all goroutines. 54 // This output is too lengthy for report and not very useful. 55 // So we always take 5 lines from report and then cut it at the next empty line. 56 // The intention is to capture panic header and traceback of the first goroutine. 57 pos := 0 58 for i := 0; i < 5; i++ { 59 pos1 := bytes.IndexByte(report[pos:], '\n') 60 if pos1 == -1 { 61 return report 62 } 63 pos += pos1 + 1 64 } 65 end := bytes.Index(report[pos:], []byte{'\n', '\n'}) 66 if end == -1 { 67 return report 68 } 69 if bytes.Contains(report, []byte("WARNING: DATA RACE")) { 70 // For data races extract both stacks. 71 end2 := bytes.Index(report[pos+end+2:], []byte{'\n', '\n'}) 72 if end2 != -1 { 73 end += end2 + 2 74 } 75 } 76 return report[:pos+end+1] 77 } 78 79 func (ctx *gvisor) Symbolize(rep *Report) error { 80 return nil 81 } 82 83 var gvisorTitleReplacement = []replacement{ 84 { 85 regexp.MustCompile(`container ".*"`), 86 "container NAME", 87 }, 88 { 89 regexp.MustCompile(`sandbox ".*"`), 90 "sandbox NAME", 91 }, 92 { 93 regexp.MustCompile(`(pid|PID) [0-9]+`), 94 "pid X", 95 }, 96 } 97 98 var gvisorOopses = append([]*oops{ 99 { 100 []byte("Panic:"), 101 []oopsFormat{ 102 { 103 title: compile("Panic:(.*)"), 104 fmt: "Panic:%[1]v", 105 noStackTrace: true, 106 }, 107 }, 108 []*regexp.Regexp{}, 109 crash.UnknownType, 110 }, 111 { 112 []byte("SIGSEGV:"), 113 []oopsFormat{ 114 { 115 title: compile("SIGSEGV:(.*)"), 116 fmt: "SIGSEGV:%[1]v", 117 noStackTrace: true, 118 }, 119 }, 120 []*regexp.Regexp{}, 121 crash.UnknownType, 122 }, 123 { 124 []byte("SIGBUS:"), 125 []oopsFormat{ 126 { 127 title: compile("SIGBUS:(.*)"), 128 fmt: "SIGBUS:%[1]v", 129 noStackTrace: true, 130 }, 131 }, 132 []*regexp.Regexp{}, 133 crash.UnknownType, 134 }, 135 { 136 []byte("FATAL ERROR:"), 137 []oopsFormat{ 138 { 139 title: compile("FATAL ERROR:(.*)"), 140 fmt: "FATAL ERROR:%[1]v", 141 noStackTrace: true, 142 }, 143 }, 144 []*regexp.Regexp{}, 145 crash.UnknownType, 146 }, 147 { 148 []byte("WARNING: DATA RACE"), 149 []oopsFormat{ 150 { 151 title: compile("WARNING: DATA RACE"), 152 report: compile("WARNING: DATA RACE\n(?:.*\n)*? (?:[a-zA-Z0-9./_-]+/)([a-zA-Z0-9.()*_]+)\\(\\)\n"), 153 fmt: "DATA RACE in %[1]v", 154 noStackTrace: true, 155 }, 156 }, 157 []*regexp.Regexp{}, 158 crash.UnknownType, 159 }, 160 { 161 []byte("Invalid request partialResult"), 162 []oopsFormat{ 163 { 164 title: compile("Invalid request partialResult"), 165 report: compile("Invalid request partialResult .* for (.*) operation"), 166 fmt: "Invalid request partialResult in %[1]v", 167 noStackTrace: true, 168 }, 169 }, 170 []*regexp.Regexp{}, 171 crash.UnknownType, 172 }, 173 { 174 []byte("fatal error:"), 175 []oopsFormat{ 176 { 177 title: compile("fatal error:(.*)"), 178 fmt: "fatal error:%[1]v", 179 noStackTrace: true, 180 }, 181 }, 182 []*regexp.Regexp{}, 183 crash.UnknownType, 184 }, 185 }, commonOopses...)