github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/report/linux.go (about) 1 // Copyright 2017 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 "fmt" 9 "path/filepath" 10 "regexp" 11 "strconv" 12 "strings" 13 "time" 14 15 "github.com/google/syzkaller/pkg/cover/backend" 16 "github.com/google/syzkaller/pkg/osutil" 17 "github.com/google/syzkaller/pkg/report/crash" 18 "github.com/google/syzkaller/pkg/symbolizer" 19 "github.com/google/syzkaller/pkg/vcs" 20 "github.com/google/syzkaller/sys/targets" 21 "github.com/ianlancetaylor/demangle" 22 ) 23 24 type linux struct { 25 *config 26 vmlinux string 27 symbols map[string]map[string][]symbolizer.Symbol 28 consoleOutputRe *regexp.Regexp 29 taskContext *regexp.Regexp 30 cpuContext *regexp.Regexp 31 questionableFrame *regexp.Regexp 32 guiltyFileIgnores []*regexp.Regexp 33 guiltyLineIgnore *regexp.Regexp 34 reportStartIgnores []*regexp.Regexp 35 infoMessagesWithStack [][]byte 36 eoi []byte 37 symbolizerCache symbolizer.Cache 38 } 39 40 func ctorLinux(cfg *config) (reporterImpl, []string, error) { 41 symbols := make(map[string]map[string][]symbolizer.Symbol) 42 vmlinux := "" 43 if cfg.kernelDirs.Obj != "" { 44 vmlinux = filepath.Join(cfg.kernelDirs.Obj, cfg.target.KernelObject) 45 var err error 46 symbols[""], err = symbolizer.ReadTextSymbols(vmlinux) 47 if err != nil { 48 return nil, nil, err 49 } 50 for _, mod := range cfg.kernelModules { 51 if mod.Name == "" { 52 continue 53 } 54 ss, err := symbolizer.ReadTextSymbols(mod.Path) 55 if err != nil { 56 continue 57 } 58 symbols[mod.Name] = ss 59 } 60 } 61 ctx := &linux{ 62 config: cfg, 63 vmlinux: vmlinux, 64 symbols: symbols, 65 } 66 // nolint: lll 67 ctx.consoleOutputRe = regexp.MustCompile(`^(?:\*\* [0-9]+ printk messages dropped \*\* )?(?:.* login: )?(?:\<[0-9]+\>)?\[ *[0-9]+\.[0-9]+\](\[ *(?:C|T)[0-9]+\])? `) 68 ctx.taskContext = regexp.MustCompile(`\[ *T[0-9]+\]`) 69 ctx.cpuContext = regexp.MustCompile(`\[ *C[0-9]+\]`) 70 ctx.questionableFrame = regexp.MustCompile(`(\[\<[0-9a-f]+\>\])? \? `) 71 ctx.eoi = []byte("<EOI>") 72 ctx.guiltyFileIgnores = []*regexp.Regexp{ 73 regexp.MustCompile(`.*\.h`), 74 regexp.MustCompile(`^lib/.*`), 75 regexp.MustCompile(`^virt/lib/.*`), 76 regexp.MustCompile(`^mm/kasan/.*`), 77 regexp.MustCompile(`^mm/kmsan/.*`), 78 regexp.MustCompile(`^kernel/kcov.c`), 79 regexp.MustCompile(`^mm/sl.b.c`), 80 regexp.MustCompile(`^mm/filemap.c`), 81 regexp.MustCompile(`^mm/folio-compat.c`), 82 regexp.MustCompile(`^mm/truncate.c`), 83 regexp.MustCompile(`^mm/memory.c`), 84 regexp.MustCompile(`^mm/percpu.*`), 85 regexp.MustCompile(`^mm/vmalloc.c`), 86 regexp.MustCompile(`^mm/page_alloc.c`), 87 regexp.MustCompile(`^mm/mempool.c`), 88 regexp.MustCompile(`^mm/util.c`), 89 regexp.MustCompile(`^kernel/rcu/.*`), 90 regexp.MustCompile(`^arch/.*/kernel/traps.c`), 91 regexp.MustCompile(`^arch/.*/kernel/unwind.*.c`), 92 regexp.MustCompile(`^arch/.*/mm/fault.c`), 93 regexp.MustCompile(`^arch/.*/mm/physaddr.c`), 94 regexp.MustCompile(`^arch/.*/kernel/stacktrace.c`), 95 regexp.MustCompile(`^arch/.*/kernel/apic/apic.c`), 96 regexp.MustCompile(`^arch/arm64/kernel/entry.*.c`), 97 regexp.MustCompile(`^arch/arm64/kernel/process\.c`), 98 regexp.MustCompile(`^kernel/locking/.*`), 99 regexp.MustCompile(`^kernel/panic.c`), 100 regexp.MustCompile(`^kernel/printk/printk.*.c`), 101 regexp.MustCompile(`^kernel/softirq.c`), 102 regexp.MustCompile(`^kernel/kthread.c`), 103 regexp.MustCompile(`^kernel/sched/.*.c`), 104 regexp.MustCompile(`^kernel/stacktrace.c`), 105 regexp.MustCompile(`^kernel/time/timer.c`), 106 regexp.MustCompile(`^kernel/workqueue.c`), 107 regexp.MustCompile(`^net/core/dev.c`), 108 regexp.MustCompile(`^net/core/sock.c`), 109 regexp.MustCompile(`^net/core/skbuff.c`), 110 regexp.MustCompile(`^fs/proc/generic.c`), 111 regexp.MustCompile(`^trusty/`), // Trusty sources are not in linux kernel tree. 112 regexp.MustCompile(`^drivers/usb/core/urb.c`), // WARNING in urb.c usually means a bug in a driver 113 // Crashes in these files are almost always caused by the calling code. 114 regexp.MustCompile(`^arch/.*/lib/crc.*`), 115 } 116 ctx.guiltyLineIgnore = regexp.MustCompile(`(hardirqs|softirqs)\s+last\s+(enabled|disabled)|^Register r\d+ information`) 117 // These pattern do _not_ start a new report, i.e. can be in a middle of another report. 118 ctx.reportStartIgnores = []*regexp.Regexp{ 119 compile(`invalid opcode: 0000`), 120 compile(`Kernel panic - not syncing`), 121 compile(`unregister_netdevice: waiting for`), 122 // Double fault can happen during handling of paging faults 123 // if memory is badly corrupted. Also it usually happens 124 // synchronously, which means that maybe the report is not corrupted. 125 // But of course it can come from another CPU as well. 126 compile(`PANIC: double fault`), 127 compile(`Internal error:`), 128 } 129 // These pattern math kernel reports which are not bugs in itself but contain stack traces. 130 // If we see them in the middle of another report, we know that the report is potentially corrupted. 131 ctx.infoMessagesWithStack = [][]byte{ 132 []byte("vmalloc: allocation failure:"), 133 []byte("FAULT_INJECTION: forcing a failure"), 134 []byte("FAULT_FLAG_ALLOW_RETRY missing"), 135 } 136 suppressions := []string{ 137 "panic: failed to start executor binary", 138 "panic: executor failed: pthread_create failed", 139 "panic: failed to create temp dir", 140 "fatal error: unexpected signal during runtime execution", // presubmably OOM turned into SIGBUS 141 "signal SIGBUS: bus error", // presubmably OOM turned into SIGBUS 142 "SYZFAIL: SIGBUS", 143 "Out of memory: Kill process .* \\(syz-executor\\)", 144 "Out of memory: Kill process .* \\(sshd\\)", 145 "Killed process .* \\(syz-executor\\)", 146 "Killed process .* \\(sshd\\)", 147 "lowmemorykiller: Killing 'syz-executor'", 148 "lowmemorykiller: Killing 'sshd'", 149 "INIT: PANIC: segmentation violation!", 150 "\\*\\*\\* stack smashing detected \\*\\*\\*: terminated", 151 } 152 return ctx, suppressions, nil 153 } 154 155 const contextConsole = "console" 156 157 func (ctx *linux) ContainsCrash(output []byte) bool { 158 return containsCrash(output, linuxOopses, ctx.ignores) 159 } 160 161 func (ctx *linux) Parse(output []byte) *Report { 162 oops, startPos, context := ctx.findFirstOops(output) 163 if oops == nil { 164 return nil 165 } 166 for questionable := false; ; questionable = true { 167 rep := &Report{ 168 Output: output, 169 StartPos: startPos, 170 } 171 endPos, reportEnd, report, prefix := ctx.findReport(output, oops, startPos, context, questionable) 172 rep.EndPos = endPos 173 title, corrupted, altTitles, format := extractDescription(report[:reportEnd], oops, linuxStackParams) 174 if title == "" { 175 prefix = nil 176 report = output[rep.StartPos:rep.EndPos] 177 title, corrupted, altTitles, format = extractDescription(report, oops, linuxStackParams) 178 if title == "" { 179 panic(fmt.Sprintf("non matching oops for %q context=%q in:\n%s\n", 180 oops.header, context, report)) 181 } 182 } 183 rep.Title = title 184 rep.AltTitles = altTitles 185 rep.Corrupted = corrupted != "" 186 rep.CorruptedReason = corrupted 187 for _, line := range prefix { 188 rep.Report = append(rep.Report, line...) 189 rep.Report = append(rep.Report, '\n') 190 } 191 rep.reportPrefixLen = len(rep.Report) 192 rep.Report = append(rep.Report, report...) 193 rep.Type = TitleToCrashType(rep.Title) 194 setExecutorInfo(rep) 195 if !rep.Corrupted { 196 rep.Corrupted, rep.CorruptedReason = isCorrupted(title, report, format) 197 } 198 if rep.CorruptedReason == corruptedNoFrames && context != contextConsole && !questionable { 199 // We used to look at questionable frame with the following incentive: 200 // """ 201 // Some crash reports have all frames questionable. 202 // So if we get a corrupted report because there are no frames, 203 // try again now looking at questionable frames. 204 // Only do this if we have a real context (CONFIG_PRINTK_CALLER=y), 205 // to be on the safer side. Without context it's too easy to use 206 // a stray frame from a wrong context. 207 // """ 208 // Most likely reports without proper stack traces were caused by a bug 209 // in the unwinder and are now fixed in 187b96db5ca7 "x86/unwind/orc: 210 // Fix unwind_get_return_address_ptr() for inactive tasks". 211 // Disable trying to use questionable frames for now. 212 useQuestionableFrames := false 213 if useQuestionableFrames { 214 continue 215 } 216 } 217 return rep 218 } 219 } 220 221 func (ctx *linux) findFirstOops(output []byte) (oops *oops, startPos int, context string) { 222 for pos, next := 0, 0; pos < len(output); pos = next + 1 { 223 next = bytes.IndexByte(output[pos:], '\n') 224 if next != -1 { 225 next += pos 226 } else { 227 next = len(output) 228 } 229 line := output[pos:next] 230 for _, oops1 := range linuxOopses { 231 if matchOops(line, oops1, ctx.ignores) { 232 oops = oops1 233 startPos = pos 234 context = ctx.extractContext(line) 235 return 236 } 237 } 238 } 239 return 240 } 241 242 // This method decides if the report prefix is already long enough to be cut on "Kernel panic - not 243 // syncing: panic_on_kmsan set ...". 244 func (ctx *linux) reportMinLines(oopsLine []byte) int { 245 if bytes.Contains(oopsLine, []byte("BUG: KMSAN:")) { 246 // KMSAN reports do not have the "Call trace" and some of the other lines which are 247 // present e.g. in KASAN reports. So we use a lower threshold for them. 248 return 16 249 } 250 return 22 251 } 252 253 // Yes, it is complex, but all state and logic are tightly coupled. It's unclear how to simplify it. 254 // nolint: gocyclo, gocognit 255 func (ctx *linux) findReport(output []byte, oops *oops, startPos int, context string, useQuestionable bool) ( 256 endPos, reportEnd int, report []byte, prefix [][]byte) { 257 // Prepend 5 lines preceding start of the report, 258 // they can contain additional info related to the report. 259 maxPrefix := 5 260 if ctx.taskContext.MatchString(context) { 261 // If we have CONFIG_PRINTK_CALLER, we collect more b/c it comes from the same task. 262 maxPrefix = 50 263 } 264 secondReportPos := 0 265 textLines := 0 266 skipText, cpuTraceback := false, false 267 oopsLine := []byte{} 268 for pos, next := 0, 0; pos < len(output); pos = next + 1 { 269 next = bytes.IndexByte(output[pos:], '\n') 270 if next != -1 { 271 next += pos 272 } else { 273 next = len(output) 274 } 275 line := output[pos:next] 276 context1 := ctx.extractContext(line) 277 stripped, questionable := ctx.stripLinePrefix(line, context1, useQuestionable) 278 if pos < startPos { 279 if context1 == context && len(stripped) != 0 && !questionable { 280 prefix = append(prefix, append([]byte{}, stripped...)) 281 if len(prefix) > maxPrefix { 282 prefix = prefix[1:] 283 } 284 } 285 continue 286 } 287 isOopsLine := pos == startPos 288 if isOopsLine { 289 oopsLine = line 290 } 291 292 for _, oops1 := range linuxOopses { 293 if !matchOops(line, oops1, ctx.ignores) { 294 if !isOopsLine && secondReportPos == 0 { 295 for _, pattern := range ctx.infoMessagesWithStack { 296 if bytes.Contains(line, pattern) { 297 secondReportPos = pos 298 break 299 } 300 } 301 } 302 continue 303 } 304 endPos = next 305 if !isOopsLine && secondReportPos == 0 { 306 if !matchesAny(line, ctx.reportStartIgnores) { 307 secondReportPos = pos 308 } 309 } 310 } 311 if !isOopsLine && (questionable || 312 context1 != context && (!cpuTraceback || !ctx.cpuContext.MatchString(context1))) { 313 continue 314 } 315 textLines++ 316 skipLine := skipText 317 if bytes.Contains(line, []byte("Disabling lock debugging due to kernel taint")) { 318 skipLine = true 319 } else if bytes.Contains(line, []byte("Sending NMI from CPU")) { 320 // If we are doing traceback of all CPUs, then we also need to preserve output 321 // from other CPUs regardless of what is the current context. 322 // Otherwise we will throw traceback away because it does not match the oops context. 323 cpuTraceback = true 324 } else if (bytes.Contains(line, []byte("Kernel panic - not syncing")) || 325 bytes.Contains(line, []byte("WARNING: possible circular locking dependency detected"))) && 326 textLines > ctx.reportMinLines(oopsLine) { 327 // If panic_on_warn set, then we frequently have 2 stacks: 328 // one for the actual report (or maybe even more than one), 329 // and then one for panic caused by panic_on_warn. This makes 330 // reports unnecessary long and the panic (current) stack 331 // is always present in the actual report. So we strip the 332 // panic message. However, we check that we have enough lines 333 // before the panic, because sometimes we have, for example, 334 // a single WARNING line without a stack and then the panic 335 // with the stack. 336 // Oops messages frequently induce possible deadlock reports 337 // because oops reporting introduces unexpected locking chains. 338 // So if we have enough of the actual oops, strip the deadlock message. 339 skipText = true 340 skipLine = true 341 } 342 if !isOopsLine && skipLine { 343 continue 344 } 345 report = append(report, stripped...) 346 report = append(report, '\n') 347 if secondReportPos == 0 || context != "" && context != contextConsole { 348 reportEnd = len(report) 349 } 350 } 351 return 352 } 353 354 func (ctx *linux) stripLinePrefix(line []byte, context string, useQuestionable bool) ([]byte, bool) { 355 if context == "" { 356 return line, false 357 } 358 start := bytes.Index(line, []byte("] ")) 359 line = line[start+2:] 360 if !bytes.Contains(line, ctx.eoi) { 361 // x86_64 prefix. 362 if ctx.questionableFrame.Match(line) { 363 pos := bytes.Index(line, []byte(" ? ")) 364 return line[pos+2:], !useQuestionable 365 } 366 // PowerPC suffix. 367 if bytes.HasSuffix(line, []byte(" (unreliable)")) { 368 return line[:len(line)-13], !useQuestionable 369 } 370 } 371 return line, false 372 } 373 374 func (ctx *linux) extractContext(line []byte) string { 375 match := ctx.consoleOutputRe.FindSubmatchIndex(line) 376 if match == nil { 377 return "" 378 } 379 if match[2] == -1 { 380 return contextConsole 381 } 382 return string(line[match[2]:match[3]]) 383 } 384 385 func (ctx *linux) Symbolize(rep *Report) error { 386 var symbFunc symbFuncCb 387 if ctx.vmlinux != "" { 388 symb := symbolizer.Make(ctx.config.target) 389 defer symb.Close() 390 symbFunc = func(bin string, pc uint64) ([]symbolizer.Frame, error) { 391 return ctx.symbolizerCache.Symbolize(symb.Symbolize, bin, pc) 392 } 393 } 394 if err := ctx.symbolize(rep, symbFunc); err != nil { 395 return err 396 } 397 rep.Report = ctx.decompileOpcodes(rep.Report, rep) 398 399 // Skip getting maintainers for Android fuzzing since the kernel source 400 // directory structure is different. 401 if ctx.config.vmType == "cuttlefish" || ctx.config.vmType == "proxyapp" { 402 return nil 403 } 404 405 // We still do this even if we did not symbolize, 406 // because tests pass in already symbolized input. 407 rep.GuiltyFile = ctx.extractGuiltyFile(rep) 408 if rep.GuiltyFile != "" { 409 maintainers, err := ctx.getMaintainers(rep.GuiltyFile) 410 if err != nil { 411 return err 412 } 413 rep.Recipients = maintainers 414 } 415 return nil 416 } 417 418 type symbFuncCb = func(string, uint64) ([]symbolizer.Frame, error) 419 420 func (ctx *linux) symbolize(rep *Report, symbFunc symbFuncCb) error { 421 var symbolized []byte 422 prefix := rep.reportPrefixLen 423 for _, line := range bytes.SplitAfter(rep.Report, []byte("\n")) { 424 var newLine []byte 425 parsed, ok := parseLinuxBacktraceLine(line) 426 if ok { 427 lines := []linuxBacktraceLine{parsed} 428 if symbFunc != nil { 429 lines = symbolizeLine(symbFunc, ctx, parsed) 430 } 431 for _, line := range lines { 432 line.Name = demangle.Filter(line.Name, demangle.NoParams) 433 newLine = append(newLine, line.Assemble()...) 434 } 435 } else { 436 newLine = line 437 } 438 if prefix > len(symbolized) { 439 prefix += len(newLine) - len(line) 440 } 441 symbolized = append(symbolized, newLine...) 442 } 443 oldReport := rep.Report 444 rep.Report = symbolized 445 oldPrefixLen := rep.reportPrefixLen 446 rep.reportPrefixLen = prefix 447 448 if len(rep.Report) > 0 && rep.reportPrefixLen > len(rep.Report) { 449 panic(fmt.Sprintf("invalid reportPrefixLen after symbolize: prefix %d -> %d,"+ 450 "report len: %d -> %d, old report: %q", 451 oldPrefixLen, rep.reportPrefixLen, len(oldReport), len(rep.Report), oldReport, 452 )) 453 } 454 return nil 455 } 456 457 type linuxBacktraceLine struct { 458 // Fields and corresponding indices in the indices array. 459 Name string // 2:3 460 Offset uint64 // 4:5 461 Size uint64 // 6:7 462 // ... 8:9 is a ModName + its enclosing parentheses. 463 ModName string // 10:11 464 BuildID string // 12:13 465 IsRipFrame bool 466 // These fields are to be set externally. 467 Inline bool 468 FileLine string 469 // These fields are not to be modified outside of the type's methods. 470 raw []byte 471 indices []int 472 } 473 474 func parseLinuxBacktraceLine(line []byte) (info linuxBacktraceLine, ok bool) { 475 match := linuxSymbolizeRe.FindSubmatchIndex(line) 476 if match == nil { 477 return 478 } 479 info.raw = line 480 info.indices = match 481 info.Name = string(line[match[2]:match[3]]) 482 var err error 483 info.Offset, err = strconv.ParseUint(string(line[match[4]:match[5]]), 16, 64) 484 if err != nil { 485 return 486 } 487 info.Size, err = strconv.ParseUint(string(line[match[6]:match[7]]), 16, 64) 488 if err != nil { 489 return 490 } 491 if match[10] != -1 && match[11] != -1 { 492 info.ModName = string(line[match[10]:match[11]]) 493 } 494 if match[12] != -1 && match[13] != -1 { 495 info.BuildID = string(line[match[12]:match[13]]) 496 } 497 info.IsRipFrame = linuxRipFrame.Match(line) 498 return info, true 499 } 500 501 // Note that Assemble() ignores changes to Offset and Size (no reason as these are not updated anywhere). 502 func (line linuxBacktraceLine) Assemble() []byte { 503 match := line.indices 504 modified := append([]byte{}, line.raw...) 505 if line.BuildID != "" { 506 modified = replace(modified, match[8], match[9], []byte(" ["+line.ModName+"]")) 507 } 508 if line.FileLine != "" { 509 modified = replace(modified, match[7], match[7], []byte(line.FileLine)) 510 } 511 if line.Inline { 512 end := match[7] + len(line.FileLine) 513 modified = replace(modified, end, end, []byte(" [inline]")) 514 modified = replace(modified, match[2], match[7], []byte(line.Name)) 515 } else { 516 modified = replace(modified, match[2], match[3], []byte(line.Name)) 517 } 518 return modified 519 } 520 521 func symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, error), ctx *linux, 522 parsed linuxBacktraceLine) []linuxBacktraceLine { 523 symb := ctx.symbols[parsed.ModName][parsed.Name] 524 if len(symb) == 0 { 525 return []linuxBacktraceLine{parsed} 526 } 527 var funcStart uint64 528 for _, s := range symb { 529 if funcStart == 0 || int(parsed.Size) == s.Size { 530 funcStart = s.Addr 531 } 532 } 533 pc := funcStart + parsed.Offset 534 if !parsed.IsRipFrame { 535 // Usually we have return PCs, so we need to look at the previous instruction. 536 // But RIP lines contain the exact faulting PC. 537 pc-- 538 } 539 var bin string 540 for _, mod := range ctx.config.kernelModules { 541 if mod.Name == parsed.ModName { 542 bin = mod.Path 543 break 544 } 545 } 546 frames, err := symbFunc(bin, pc) 547 if err != nil || len(frames) == 0 { 548 return []linuxBacktraceLine{parsed} 549 } 550 var ret []linuxBacktraceLine 551 for _, frame := range frames { 552 path, _ := backend.CleanPath(frame.File, &ctx.kernelDirs, nil) 553 copy := parsed 554 copy.FileLine = fmt.Sprintf(" %v:%v", path, frame.Line) 555 if frame.Inline { 556 copy.Inline = true 557 copy.Name = frame.Func 558 } 559 ret = append(ret, copy) 560 } 561 return ret 562 } 563 564 type parsedOpcodes struct { 565 rawBytes []byte 566 decompileFlags DecompilerFlagMask 567 offset int 568 } 569 570 type decompiledOpcodes struct { 571 opcodes []DecompiledOpcode 572 trappingOpcodeIdx int 573 leftBytesCut int 574 } 575 576 // processOpcodes converts a string representation of opcodes used by the Linux kernel into 577 // a sequence of the machine instructions, that surround the one that crashed the kernel. 578 // If the input does not start on a boundary of an instruction, it is attempted to adjust the 579 // strting position. 580 // The method returns an error if it did not manage to correctly decompile the opcodes or 581 // of the decompiled code is not of interest to the reader (e.g. it is a user-space code). 582 func (ctx *linux) processOpcodes(codeSlice string) (*decompiledOpcodes, error) { 583 parsed, err := ctx.parseOpcodes(codeSlice) 584 if err != nil { 585 return nil, err 586 } 587 588 decompiled, err := ctx.decompileWithOffset(parsed) 589 if err != nil { 590 return nil, err 591 } 592 593 if linuxSkipTrapInstrRe.MatchString(decompiled.opcodes[decompiled.trappingOpcodeIdx].Instruction) { 594 // For some reports (like WARNINGs) the trapping instruction is an intentionally 595 // invalid instruction. Decompilation of such code only allows to see the 596 // mechanism, through which the kernel implements such assertions and does not 597 // aid in finding the real issue. 598 return nil, fmt.Errorf("these opcodes are not of interest") 599 } 600 601 return decompiled, nil 602 } 603 604 func (ctx *linux) decompileWithOffset(parsed parsedOpcodes) (*decompiledOpcodes, error) { 605 // It is not guaranteed that the fragment of opcodes starts exactly at the boundary 606 // of a machine instruction. In order to simplify debugging process, we are trying 607 // to find the right starting position. 608 // 609 // We iterate over a fixed number of left boundaries. The exact number of iterations 610 // should strike a balance between the potential usefulness and the extra time needed 611 // to invoke the decompiler. 612 const opcodeAdjustmentLimit = 8 613 614 var bestResult *decompiledOpcodes 615 616 for leftCut := 0; leftCut <= parsed.offset && leftCut < opcodeAdjustmentLimit; leftCut++ { 617 newBytes := parsed.rawBytes[leftCut:] 618 newOffset := parsed.offset - leftCut 619 instructions, err := DecompileOpcodes(newBytes, parsed.decompileFlags, ctx.target) 620 if err != nil { 621 return nil, err 622 } 623 624 // We only want to return the response, where there exists a decoded instruction that 625 // perfectly aligns with the trapping instruction offset. 626 // At the same time, we'll do out best to find a code listing that does not contain 627 // unrecognized (bad) instuctions - this serves as an indicator of a valid result. 628 629 hasBad := false 630 trappingIdx := -1 631 for idx, instruction := range instructions { 632 if instruction.Offset == newOffset { 633 trappingIdx = idx 634 } 635 if instruction.Offset >= newOffset { 636 // Do not take into account instructions after the target offset. Once 637 // decompiler begins to find the right boundary, we cannot improve them. 638 break 639 } 640 hasBad = hasBad || instruction.IsBad 641 } 642 643 if trappingIdx < 0 { 644 continue 645 } 646 647 if !hasBad || bestResult == nil { 648 bestResult = &decompiledOpcodes{ 649 opcodes: instructions, 650 trappingOpcodeIdx: trappingIdx, 651 leftBytesCut: leftCut, 652 } 653 if !hasBad { 654 // The best offset is already found. 655 break 656 } 657 } 658 } 659 if bestResult == nil { 660 return nil, fmt.Errorf("unable to align decompiled code and the trapping instruction offset") 661 } 662 return bestResult, nil 663 } 664 665 func (ctx *linux) parseOpcodes(codeSlice string) (parsedOpcodes, error) { 666 width := 0 667 bytes := []byte{} 668 trapOffset := -1 669 for _, part := range strings.Split(strings.TrimSpace(codeSlice), " ") { 670 if part == "" || len(part)%2 != 0 { 671 return parsedOpcodes{}, fmt.Errorf("invalid opcodes string %#v", part) 672 } 673 674 // Check if this is a marker of a trapping instruction. 675 if part[0] == '(' || part[0] == '<' { 676 if trapOffset >= 0 { 677 return parsedOpcodes{}, fmt.Errorf("invalid opcodes string: multiple trap intructions") 678 } 679 trapOffset = len(bytes) 680 681 if len(part) < 3 { 682 return parsedOpcodes{}, fmt.Errorf("invalid opcodes string: invalid trap opcode") 683 } 684 part = part[1 : len(part)-1] 685 } 686 687 if width == 0 { 688 width = len(part) / 2 689 } 690 691 number, err := strconv.ParseUint(part, 16, 64) 692 if err != nil { 693 return parsedOpcodes{}, fmt.Errorf("invalid opcodes string: failed to parse %#v", part) 694 } 695 696 extraBytes := make([]byte, width) 697 switch len(extraBytes) { 698 case 1: 699 extraBytes[0] = byte(number) 700 case 2: 701 ctx.target.HostEndian.PutUint16(extraBytes, uint16(number)) 702 case 4: 703 ctx.target.HostEndian.PutUint32(extraBytes, uint32(number)) 704 case 8: 705 ctx.target.HostEndian.PutUint64(extraBytes, number) 706 default: 707 return parsedOpcodes{}, fmt.Errorf("invalid opcodes string: invalid width %v", width) 708 } 709 bytes = append(bytes, extraBytes...) 710 } 711 712 if trapOffset < 0 { 713 return parsedOpcodes{}, fmt.Errorf("invalid opcodes string: no trapping instructions") 714 } 715 716 var flags DecompilerFlagMask 717 if ctx.target.Arch == targets.ARM && width == 2 { 718 flags |= FlagForceArmThumbMode 719 } 720 return parsedOpcodes{ 721 rawBytes: bytes, 722 decompileFlags: flags, 723 offset: trapOffset, 724 }, nil 725 } 726 727 // decompileOpcodes detects the most meaningful "Code: " lines from the report, decompiles 728 // them and appends a human-readable listing to the end of the report. 729 func (ctx *linux) decompileOpcodes(text []byte, report *Report) []byte { 730 if report.Type == crash.Hang { 731 // Even though Hang reports do contain the Code: section, there's no point in 732 // decompiling that. So just return the text. 733 return text 734 } 735 // Iterate over all "Code: " lines and pick the first that could be decompiled 736 // that might be of interest to the user. 737 var decompiled *decompiledOpcodes 738 lines := lines(text) 739 for i, line := range lines { 740 var prevLine []byte 741 if i > 0 { 742 prevLine = lines[i-1] 743 } 744 // We want to avoid decompiling code from user-space as it is not of big interest during 745 // debugging kernel problems. 746 // For now this check only works for x86/amd64, but Linux on other architectures supported 747 // by syzkaller does not seem to include user-space code in its oops messages. 748 if linuxUserSegmentRe.Match(prevLine) { 749 continue 750 } 751 match := linuxCodeRe.FindSubmatch(line) 752 if match == nil { 753 continue 754 } 755 decompiledLine, err := ctx.processOpcodes(string(match[1])) 756 if err != nil { 757 continue 758 } 759 decompiled = decompiledLine 760 break 761 } 762 763 if decompiled == nil { 764 return text 765 } 766 767 skipInfo := "" 768 if decompiled.leftBytesCut > 0 { 769 skipInfo = fmt.Sprintf(", %v bytes skipped", decompiled.leftBytesCut) 770 } 771 772 // The decompiled instructions are intentionally put to the bottom of the report instead 773 // being inlined below the corresponding "Code:" line. The intent is to continue to keep 774 // the most important information at the top of the report, so that it is visible from 775 // the syzbot dashboard without scrolling. 776 headLine := fmt.Sprintf("----------------\nCode disassembly (best guess)%v:\n", skipInfo) 777 text = append(text, headLine...) 778 779 for idx, opcode := range decompiled.opcodes { 780 line := opcode.FullDescription 781 if idx == decompiled.trappingOpcodeIdx { 782 line = fmt.Sprintf("*%s <-- trapping instruction\n", line[1:]) 783 } else { 784 line += "\n" 785 } 786 text = append(text, line...) 787 } 788 return text 789 } 790 791 func (ctx *linux) extractGuiltyFile(rep *Report) string { 792 return ctx.extractGuiltyFileRaw(rep.Title, rep.Report[rep.reportPrefixLen:]) 793 } 794 795 func (ctx *linux) extractGuiltyFileRaw(title string, report []byte) string { 796 if strings.HasPrefix(title, "INFO: rcu detected stall") { 797 // Special case for rcu stalls. 798 // There are too many frames that we want to skip before actual guilty frames, 799 // we would need to ignore too many files and that would be fragile. 800 // So instead we try to extract guilty file starting from the known 801 // interrupt entry point first. 802 for _, interruptEnd := range []string{"apic_timer_interrupt+0x", 803 "el1h_64_irq+0x", "Exception stack"} { 804 if pos := bytes.Index(report, []byte(interruptEnd)); pos != -1 { 805 if file := ctx.extractGuiltyFileImpl(report[pos:]); file != "" { 806 return file 807 } 808 } 809 } 810 } 811 return ctx.extractGuiltyFileImpl(report) 812 } 813 814 func (ctx *linux) extractGuiltyFileImpl(report []byte) string { 815 // Extract the first possible guilty file. 816 guilty := "" 817 var line []byte 818 lines := lines(report) 819 for len(lines) > 0 { 820 line, lines = lines[0], lines[1:] 821 match := filenameRe.FindSubmatch(line) 822 if match == nil { 823 continue 824 } 825 file := match[1] 826 if guilty == "" { 827 // Avoid producing no guilty file at all, otherwise we mail the report to nobody. 828 // It's unclear if it's better to return the first one or the last one. 829 // So far the only test we have has only one file anyway. 830 guilty = string(file) 831 } 832 833 if matchesAny(file, ctx.guiltyFileIgnores) || ctx.guiltyLineIgnore.Match(line) { 834 continue 835 } 836 guilty = filepath.Clean(string(file)) 837 break 838 } 839 840 // Search for deeper filepaths in the stack trace below the first possible guilty file. 841 deepestPath := filepath.Dir(guilty) 842 for len(lines) > 0 { 843 line, lines = lines[0], lines[1:] 844 match := filenameRe.FindSubmatch(line) 845 if match == nil { 846 continue 847 } 848 file := match[1] 849 if matchesAny(file, ctx.guiltyFileIgnores) || ctx.guiltyLineIgnore.Match(line) { 850 continue 851 } 852 clean := filepath.Clean(string(file)) 853 854 // Check if the new path has *both* the same directory prefix *and* a deeper suffix. 855 if strings.HasPrefix(clean, deepestPath) { 856 suffix := strings.TrimPrefix(clean, deepestPath) 857 if deeperPathRe.Match([]byte(suffix)) { 858 guilty = clean 859 deepestPath = filepath.Dir(guilty) 860 } 861 } 862 } 863 864 return guilty 865 } 866 867 func (ctx *linux) getMaintainers(file string) (vcs.Recipients, error) { 868 if ctx.kernelDirs.Src == "" { 869 return nil, nil 870 } 871 return GetLinuxMaintainers(ctx.kernelDirs.Src, file) 872 } 873 874 func GetLinuxMaintainers(kernelSrc, file string) (vcs.Recipients, error) { 875 mtrs, err := getMaintainersImpl(kernelSrc, file, false) 876 if err != nil { 877 return nil, err 878 } 879 if len(mtrs) <= 1 { 880 mtrs, err = getMaintainersImpl(kernelSrc, file, true) 881 if err != nil { 882 return nil, err 883 } 884 } 885 return mtrs, nil 886 } 887 888 func getMaintainersImpl(kernelSrc, file string, blame bool) (vcs.Recipients, error) { 889 // See #1441 re --git-min-percent. 890 args := []string{"--git-min-percent=15"} 891 if blame { 892 args = append(args, "--git-blame") 893 } 894 args = append(args, "-f", file) 895 script := filepath.FromSlash("scripts/get_maintainer.pl") 896 output, err := osutil.RunCmd(time.Minute, kernelSrc, script, args...) 897 if err != nil { 898 return nil, err 899 } 900 return vcs.ParseMaintainersLinux(output), nil 901 } 902 903 func isCorrupted(title string, report []byte, format oopsFormat) (bool, string) { 904 // Check for common title corruptions. 905 for _, re := range linuxCorruptedTitles { 906 if re.MatchString(title) { 907 return true, "title matches corrupted regexp" 908 } 909 } 910 // If the report hasn't matched any of the oops titles, don't mark it as corrupted. 911 if format.title == nil { 912 return false, "" 913 } 914 if format.noStackTrace { 915 return false, "" 916 } 917 // When a report contains 'Call Trace', 'backtrace', 'Allocated' or 'Freed' keywords, 918 // it must also contain at least a single stack frame after each of them. 919 hasStackTrace := false 920 for _, key := range linuxStackParams.stackStartRes { 921 match := key.FindSubmatchIndex(report) 922 if match == nil { 923 continue 924 } 925 frames := lines(report[match[0]:]) 926 if len(frames) < 4 { 927 return true, "call trace is missed" 928 } 929 corrupted := true 930 frames = frames[1:] 931 // Check that at least one of the next few lines contains a frame. 932 outer: 933 for i := 0; i < 15 && i < len(frames); i++ { 934 for _, key1 := range linuxStackParams.stackStartRes { 935 // Next stack trace starts. 936 if key1.Match(frames[i]) { 937 break outer 938 } 939 } 940 if bytes.Contains(frames[i], []byte("(stack is not available)")) || 941 matchesAny(frames[i], linuxStackParams.frameRes) { 942 hasStackTrace = true 943 corrupted = false 944 break 945 } 946 } 947 if corrupted { 948 return true, "no frames in a stack trace" 949 } 950 } 951 if !hasStackTrace { 952 return true, "no stack trace in report" 953 } 954 return false, "" 955 } 956 957 var syzLinuxCommRe = regexp.MustCompile(` Comm: syz\.(\d+)\.(\d+) `) 958 959 func setExecutorInfo(rep *Report) { 960 match := syzLinuxCommRe.FindSubmatch(rep.Report) 961 if match == nil { 962 return 963 } 964 info := &ExecutorInfo{} 965 var err error 966 info.ProcID, err = strconv.Atoi(string(match[1])) 967 if err != nil { 968 return 969 } 970 info.ExecID, err = strconv.Atoi(string(match[2])) 971 if err != nil { 972 return 973 } 974 rep.Executor = info 975 } 976 977 func linuxStallFrameExtractor(frames []string) (string, int) { 978 // During rcu stalls and cpu lockups kernel loops in some part of code, 979 // usually across several functions. When the stall is detected, traceback 980 // points to a random stack within the looping code. We generally take 981 // the top function in the stack (with few exceptions) as the bug identity. 982 // As the result stalls with the same root would produce multiple reports 983 // in different functions, which is bad. 984 // Instead we identify a representative function deeper in the stack. 985 // For most syscalls it can be the syscall entry function (e.g. SyS_timer_create). 986 // However, for highly discriminated functions syscalls like ioctl/read/write/connect 987 // we take the previous function (e.g. for connect the one that points to exact 988 // protocol, or for ioctl the one that is related to the device). 989 prev, prevIdx := frames[0], 0 990 for i, frame := range frames { 991 if matchesAny([]byte(frame), linuxStallAnchorFrames) { 992 if strings.Contains(frame, "smp_call_function") { 993 // In this case we want this function rather than the previous one 994 // (there can be several variations on the next one). 995 prev = "smp_call_function" 996 prevIdx = i 997 } 998 return prev, prevIdx 999 } 1000 prev, prevIdx = frame, i 1001 } 1002 return "", -1 1003 } 1004 1005 func linuxHangTaskFrameExtractor(frames []string) (string, int) { 1006 // The problem with task hung reports is that they manifest at random victim stacks, 1007 // rather at the root cause stack. E.g. if there is something wrong with RCU subsystem, 1008 // we are getting hangs all over the kernel on all synchronize_* calls. 1009 // So before resotring to the common logic of skipping some common frames, 1010 // we look for 2 common buckets: hangs on synchronize_rcu and hangs on rtnl_lock 1011 // and group these together. 1012 const synchronizeRCU = "synchronize_rcu" 1013 anchorFrames := map[string]string{ 1014 "rtnl_lock": "", 1015 "synchronize_rcu": synchronizeRCU, 1016 "synchronize_srcu": synchronizeRCU, 1017 "synchronize_net": synchronizeRCU, 1018 "synchronize_sched": synchronizeRCU, 1019 } 1020 for i, frame := range frames { 1021 for anchor, replacement := range anchorFrames { 1022 if strings.Contains(frame, anchor) { 1023 if replacement != "" { 1024 frame = replacement 1025 } 1026 return frame, i 1027 } 1028 } 1029 } 1030 skip := []string{"sched", "_lock", "_slowlock", "down", "rwsem", "completion", "kthread", 1031 "wait", "synchronize", "context_switch", "__switch_to", "cancel_delayed_work", 1032 "rcu_barrier"} 1033 nextFrame: 1034 for i, frame := range frames { 1035 for _, ignore := range skip { 1036 if strings.Contains(frame, ignore) { 1037 continue nextFrame 1038 } 1039 } 1040 return frame, i 1041 } 1042 return "", -1 1043 } 1044 1045 var linuxStallAnchorFrames = []*regexp.Regexp{ 1046 // Various generic functions that dispatch work. 1047 // We also include some of their callers, so that if some names change 1048 // we don't skip whole stacks and proceed parsing the next one. 1049 compile("process_one_work"), // workqueue callback 1050 compile("do_syscall_"), // syscall entry 1051 compile("do_fast_syscall_"), // syscall entry 1052 compile("sysenter_dispatch"), // syscall entry 1053 compile("tracesys_phase2"), // syscall entry 1054 compile("el0_svc_handler"), // syscall entry 1055 compile("invoke_syscall"), // syscall entry 1056 compile("ret_fast_syscall"), // arm syscall entry 1057 compile("netif_receive_skb"), // net receive entry point 1058 compile("do_softirq"), 1059 compile("call_timer_fn"), 1060 compile("_run_timers"), 1061 compile("run_timer_softirq"), 1062 compile("hrtimer_run"), 1063 compile("run_ksoftirqd"), 1064 compile("smpboot_thread_fn"), 1065 compile("^kthread$"), 1066 compile("start_secondary"), 1067 compile("cpu_startup_entry"), 1068 compile("ret_from_fork"), 1069 // Important discriminated syscalls (file_operations callbacks, etc): 1070 compile("vfs_write"), 1071 compile("vfs_read"), 1072 compile("vfs_iter_read"), 1073 compile("vfs_iter_write"), 1074 compile("do_iter_read"), 1075 compile("do_iter_write"), 1076 compile("call_read_iter"), 1077 compile("call_write_iter"), 1078 compile("new_sync_read"), 1079 compile("new_sync_write"), 1080 compile("vfs_ioctl"), 1081 compile("ksys_ioctl"), // vfs_ioctl may be inlined 1082 compile("compat_ioctl"), 1083 compile("compat_sys_ioctl"), 1084 compile("blkdev_driver_ioctl"), 1085 compile("blkdev_ioctl"), 1086 compile("^call_read_iter"), 1087 compile("^call_write_iter"), 1088 compile("do_iter_readv_writev"), 1089 compile("^call_mmap"), 1090 compile("mmap_region"), 1091 compile("do_mmap"), 1092 compile("do_dentry_open"), 1093 compile("vfs_open"), 1094 // Socket operations: 1095 compile("^sock_sendmsg"), 1096 compile("^sock_recvmsg"), 1097 compile("^sock_release"), 1098 compile("^__sock_release"), 1099 compile("^setsockopt$"), 1100 compile("kernel_setsockopt"), 1101 compile("sock_common_setsockopt"), 1102 compile("^listen$"), 1103 compile("kernel_listen"), 1104 compile("sk_common_release"), 1105 compile("^sock_mmap"), 1106 compile("^accept$"), 1107 compile("kernel_accept"), 1108 compile("^sock_do_ioctl"), 1109 compile("^sock_ioctl"), 1110 compile("^compat_sock_ioctl"), 1111 compile("^nfnetlink_rcv_msg"), 1112 compile("^rtnetlink_rcv_msg"), 1113 compile("^netlink_dump"), 1114 compile("^(sys_)?(socketpair|connect|ioctl)"), 1115 // Page fault entry points: 1116 compile("__do_fault"), 1117 compile("do_page_fault"), 1118 compile("^page_fault$"), 1119 // exit_to_usermode_loop callbacks: 1120 compile("__fput"), 1121 compile("task_work_run"), 1122 compile("exit_to_usermode"), 1123 compile("smp_call_function"), 1124 compile("tasklet_action"), 1125 compile("tasklet_hi_action"), 1126 } 1127 1128 // nolint: lll 1129 var ( 1130 linuxSymbolizeRe = regexp.MustCompile(`(?:\[\<(?:(?:0x)?[0-9a-f]+)\>\])?[ \t]+\(?(?:[0-9]+:)?([a-zA-Z0-9_.]+)\+0x([0-9a-f]+)/0x([0-9a-f]+)( ?\[([a-zA-Z0-9_.]+)( .*)?\])?\)?`) 1131 linuxRipFrame = compile(`(?:IP|NIP|pc |PC is at):? (?:(?:[0-9]+:)?(?:{{PC}} +){0,2}{{FUNC}}|(?:[0-9]+:)?0x[0-9a-f]+|(?:[0-9]+:)?{{PC}} +\[< *\(null\)>\] +\(null\)|[0-9]+: +\(null\))`) 1132 linuxCallTrace = compile(`(?:Call (?:T|t)race:)|(?:Backtrace:)`) 1133 linuxCodeRe = regexp.MustCompile(`(?m)^\s*Code\:\s+((?:[A-Fa-f0-9\(\)\<\>]{2,8}\s*)*)\s*$`) 1134 linuxSkipTrapInstrRe = regexp.MustCompile(`^ud2|brk\s+#0x800$`) 1135 linuxUserSegmentRe = regexp.MustCompile(`^RIP:\s+0033:`) 1136 ) 1137 1138 var linuxCorruptedTitles = []*regexp.Regexp{ 1139 // Sometimes timestamps get merged into the middle of report description. 1140 regexp.MustCompile(`\[ *[0-9]+\.[0-9]+\]`), 1141 } 1142 1143 var linuxStackParams = &stackParams{ 1144 stackStartRes: []*regexp.Regexp{ 1145 regexp.MustCompile(`Call (?:T|t)race`), 1146 regexp.MustCompile(`Allocated:`), 1147 regexp.MustCompile(`Allocated by task [0-9]+:`), 1148 regexp.MustCompile(`Freed:`), 1149 regexp.MustCompile(`Freed by task [0-9]+:`), 1150 // Match 'backtrace:', but exclude 'stack backtrace:' 1151 // Also match optional crc hash for KMEMLEAK reports. 1152 regexp.MustCompile(`[^k] backtrace(?: \(crc [[:xdigit:]]*\))?:`), 1153 regexp.MustCompile(`Backtrace:`), 1154 regexp.MustCompile(`Uninit was stored to memory at`), 1155 }, 1156 frameRes: []*regexp.Regexp{ 1157 compile("^ *(?:{{PC}} ){0,2}{{FUNC}}"), 1158 // Arm is totally different. 1159 // Extract both current and next frames. This is needed for the top 1160 // frame which is present only in LR register which we don't parse. 1161 compile(`^ *{{PC}} \(([a-zA-Z0-9_.]+)\) from {{PC}} \({{FUNC}}`), 1162 }, 1163 skipPatterns: []string{ 1164 "__sanitizer", 1165 "__asan", 1166 "kasan", 1167 "hwasan", 1168 "__msan", 1169 "kmsan", 1170 "kcsan_setup_watchpoint", 1171 "check_memory_region", 1172 "check_heap_object", 1173 "check_object", 1174 "read_word_at_a_time", 1175 "(read|write)_once_.*nocheck", 1176 "print_address_description", 1177 "panic", 1178 "invalid_op", 1179 "report_bug", 1180 "fixup_bug", 1181 "print_report", 1182 "print_usage_bug", 1183 "do_error", 1184 "invalid_op", 1185 `_trap$|do_trap`, 1186 "show_stack", 1187 "dump_stack", 1188 "walk_stack", 1189 "dump_backtrace", 1190 "warn_slowpath", 1191 "warn_alloc", 1192 "warn_bogus", 1193 "__warn", 1194 "alloc_page", 1195 "k?v?(?:m|z|c)alloc", 1196 "krealloc", 1197 "kmem_cache", 1198 "allocate_slab", 1199 "__alloc_frozen_pages_noprof", 1200 "folio_(?:alloc|unlock)", 1201 "filemap_alloc_folio", 1202 "__filemap_get_folio", 1203 "find_or_create_page", 1204 "do_read_cache_folio", 1205 "read_cache_page", 1206 "pagecache_get_page", 1207 "grab_cache_page_write_begin", 1208 "slab_", 1209 "debug_object", 1210 "timer_is_static_object", 1211 "work_is_static_object", 1212 "__might_fault", 1213 "print_unlock", 1214 "imbalance_bug", 1215 "lockdep", 1216 "bh_enable", 1217 "bh_disable", 1218 "perf_trace", 1219 "lock_acquire", 1220 "lock_release", 1221 "lock_class", 1222 "mark_lock", 1223 "(reacquire|mark)_held_locks", 1224 "raw_spin_rq", 1225 "spin_lock", 1226 "spin_trylock", 1227 "spin_unlock", 1228 "read_lock", 1229 "read_trylock", 1230 "write_lock", 1231 "write_trylock", 1232 "read_unlock", 1233 "write_unlock", 1234 "^down$", 1235 "down_read", 1236 "down_write", 1237 "down_read_trylock", 1238 "down_write_trylock", 1239 "down_trylock", 1240 "up_read", 1241 "up_write", 1242 "^mutex_", 1243 "^__mutex_", 1244 "^rt_mutex_", 1245 "owner_on_cpu", 1246 "osq_lock", 1247 "osq_unlock", 1248 "atomic(64)?_(dec|inc|read|set|or|xor|and|add|sub|fetch|xchg|cmpxchg|try)", 1249 "(set|clear|change|test)_bit", 1250 "__wake_up", 1251 "^refcount_", 1252 "^kref_", 1253 "ref_tracker", 1254 "seqprop_assert", 1255 "memcpy", 1256 "memcmp", 1257 "memset", 1258 "memchr", 1259 "memmove", 1260 "memdup", 1261 "strcmp", 1262 "strncmp", 1263 "strcpy", 1264 "strlcpy", 1265 "strncpy", 1266 "strscpy", 1267 "strlen", 1268 "strstr", 1269 "strnstr", 1270 "strnlen", 1271 "strchr", 1272 "strdup", 1273 "strndup", 1274 "copy_to_user", 1275 "copy_from_user", 1276 "copy_to_iter", 1277 "copy_from_iter", 1278 "copy_page_to_iter", 1279 "copy_page_from_iter", 1280 "copy_folio_to_iter", 1281 "^copyin$", 1282 "^copyout$", 1283 "put_user", 1284 "get_user", 1285 "might_fault", 1286 "might_sleep", 1287 "list_add", 1288 "list_del", 1289 "list_replace", 1290 "list_move", 1291 "list_splice", 1292 "^rb_", 1293 "^__rb_", 1294 "_indirect_thunk_", // retpolines 1295 "string", 1296 "pointer", 1297 "snprintf", 1298 "scnprintf", 1299 "kasprintf", 1300 "kvasprintf", 1301 "printk", 1302 "va_format", 1303 "dev_info", 1304 "dev_notice", 1305 "dev_warn", 1306 "dev_err", 1307 "dev_alert", 1308 "dev_crit", 1309 "dev_emerg", 1310 "program_check_exception", 1311 "program_check_common", 1312 "del_timer", 1313 "flush_work", 1314 "__cancel_work_timer", 1315 "cancel_work_sync", 1316 "try_to_grab_pending", 1317 "flush_workqueue", 1318 "drain_workqueue", 1319 "destroy_workqueue", 1320 "queue_work", 1321 "finish_wait", 1322 "kthread_stop", 1323 "kobject_", 1324 "add_uevent_var", 1325 "get_device_parent", 1326 "device_add", 1327 "device_del", 1328 "device_unregister", 1329 "device_destroy", 1330 "device_release", 1331 "devres_release_all", 1332 "hwrng_unregister", 1333 "i2c_del_adapter", 1334 "__unregister_client", 1335 "device_for_each_child", 1336 "rollback_registered", 1337 "unregister_netdev", 1338 "sysfs_remove", 1339 "device_remove_file", 1340 "tty_unregister_device", 1341 "dummy_urb_enqueue", 1342 "usb_kill_urb", 1343 "usb_kill_anchored_urbs", 1344 "usb_control_msg", 1345 "usb_hcd_submit_urb", 1346 "usb_submit_urb", 1347 "^complete$", 1348 "wait_for_completion", 1349 "^kv?free$", 1350 "kfree_skb", 1351 "readb$", 1352 "readw$", 1353 "readl$", 1354 "readq$", 1355 "writeb$", 1356 "writew$", 1357 "writel$", 1358 "writeq$", 1359 "logic_in", 1360 "logic_out", 1361 "^crc\\d+", 1362 "crc_itu_t", 1363 "__might_resched", 1364 "assertfail", 1365 "^iput$", 1366 "^iput_final$", 1367 "^ihold$", 1368 "hex_dump_to_buffer", 1369 "print_hex_dump", 1370 "^klist_", 1371 "(trace|lockdep)_(hard|soft)irq", 1372 "^(un)?lock_page", 1373 "stack_trace_consume_entry", 1374 "arch_stack_walk", 1375 "stack_trace_save", 1376 "insert_work", 1377 "__queue_delayed_work", 1378 "queue_delayed_work_on", 1379 "ida_free", 1380 // arm64 translation exception handling path. 1381 "do_(kernel|translation)_fault", 1382 "do_mem_abort", 1383 "el1_abort", 1384 "el1h_64_sync(?:_handler)?", 1385 "print_tainted", 1386 "xas_(?:start|load|find)", 1387 "find_lock_entries", 1388 "truncate_inode_pages_range", 1389 "__phys_addr", 1390 "__fortify_report", 1391 "cleanup_srcu_struct", 1392 "rhashtable_lookup", 1393 "extract_(user|iter)_to_sg", 1394 "drop_nlink", 1395 "^get_taint$", 1396 "^put_device$", 1397 "lock_timer_base", 1398 "__timer_delete_sync", 1399 "sk_stop_timer_sync", 1400 "__mod_timer", 1401 "fast_dput", 1402 "dput", 1403 }, 1404 corruptedLines: []*regexp.Regexp{ 1405 // Fault injection stacks are frequently intermixed with crash reports. 1406 // Note: the actual symbol can have all kinds of weird suffixes like ".isra.7", ".cold" or ".isra.56.cold.74". 1407 compile(`^( \[\<?(?:0x)?[0-9a-f]+\>?\])? should_fail(slab)?(\.[a-z0-9.]+)?\+0x`), 1408 }, 1409 stripFramePrefixes: []string{ 1410 "SYSC_", 1411 "SyS_", 1412 "sys_", 1413 "__x64_", 1414 "__ia32_", 1415 "__arm64_", 1416 "____sys_", 1417 "___sys_", 1418 "__sys_", 1419 "__se_", 1420 "__se_sys_", 1421 "__do_sys_", 1422 "compat_SYSC_", 1423 "compat_SyS_", 1424 "ksys_", 1425 }, 1426 } 1427 1428 func warningStackFmt(skip ...string) *stackFmt { 1429 return &stackFmt{ 1430 // In newer kernels WARNING traps and actual stack starts after invalid_op frame, 1431 // older kernels just print stack. 1432 parts: []*regexp.Regexp{ 1433 // x86_64 warning stack starts with "RIP:" line, 1434 // while powerpc64 starts with "--- interrupt:". 1435 compile("(?:" + linuxRipFrame.String() + "|--- interrupt: [0-9]+ at {{FUNC}})"), 1436 parseStackTrace, 1437 }, 1438 parts2: []*regexp.Regexp{ 1439 linuxCallTrace, 1440 parseStackTrace, 1441 }, 1442 skip: skip, 1443 } 1444 } 1445 1446 // nolint: lll 1447 var linuxOopses = append([]*oops{ 1448 { 1449 []byte("BUG:"), 1450 []oopsFormat{ 1451 { 1452 title: compile("BUG: KASAN:"), 1453 report: compile("BUG: KASAN: ([a-z\\-]+) in {{FUNC}}(?:.*\\n)+?.*(Read|Write) (?:of size|at addr) (?:[0-9a-f]+)"), 1454 fmt: "KASAN: %[1]v %[3]v in %[4]v", 1455 alt: []string{"bad-access in %[4]v"}, 1456 stack: &stackFmt{ 1457 parts: []*regexp.Regexp{ 1458 compile("BUG: KASAN: (?:[a-z\\-]+) in {{FUNC}}"), 1459 linuxCallTrace, 1460 parseStackTrace, 1461 }, 1462 // These frames are present in KASAN_HW_TAGS reports. 1463 skip: []string{"kernel_fault", "tag_check", "mem_abort", "^el1_", "^el1h_"}, 1464 }, 1465 }, 1466 { 1467 title: compile("BUG: KASAN:"), 1468 report: compile("BUG: KASAN: (?:double-free or invalid-free|double-free|invalid-free) in {{FUNC}}"), 1469 fmt: "KASAN: invalid-free in %[2]v", 1470 alt: []string{"invalid-free in %[2]v"}, 1471 stack: &stackFmt{ 1472 parts: []*regexp.Regexp{ 1473 compile("BUG: KASAN: (?:double-free or invalid-free|double-free|invalid-free) in {{FUNC}}"), 1474 linuxCallTrace, 1475 parseStackTrace, 1476 }, 1477 skip: []string{"slab_", "kfree", "vunmap", "vfree"}, 1478 }, 1479 }, 1480 { 1481 title: compile("BUG: KASAN: ([a-z\\-]+) on address(?:.*\\n)+?.*(Read|Write) of size ([0-9]+)"), 1482 fmt: "KASAN: %[1]v %[2]v", 1483 }, 1484 { 1485 title: compile("BUG: KASAN: (.*)"), 1486 fmt: "KASAN: %[1]v", 1487 corrupted: true, 1488 }, 1489 { 1490 title: compile("BUG: KMSAN: kernel-usb-infoleak"), 1491 report: compile("BUG: KMSAN: kernel-usb-infoleak in {{FUNC}}"), 1492 fmt: "KMSAN: kernel-usb-infoleak in %[2]v", 1493 alt: []string{"KMSAN origin in %[3]v"}, 1494 stack: &stackFmt{ 1495 parts: []*regexp.Regexp{ 1496 parseStackTrace, 1497 compile("(Local variable .* created at:|Uninit was created at:)"), 1498 parseStackTrace, 1499 }, 1500 skip: []string{"alloc_skb", "usb_submit_urb", "usb_start_wait_urb", "usb_bulk_msg", "usb_interrupt_msg", "usb_control_msg"}, 1501 }, 1502 noStackTrace: true, 1503 }, 1504 { 1505 title: compile("BUG: KMSAN:"), 1506 report: compile("BUG: KMSAN: ([a-z\\-]+) in {{FUNC}}"), 1507 fmt: "KMSAN: %[1]v in %[3]v", 1508 alt: []string{ 1509 "bad-access in %[3]v", 1510 }, 1511 stack: &stackFmt{ 1512 parts: []*regexp.Regexp{ 1513 parseStackTrace, 1514 compile("(Local variable .* created at:|Uninit was created at:)"), 1515 parseStackTrace, 1516 }, 1517 skip: []string{ 1518 "alloc_skb", "netlink_ack", "netlink_rcv_skb", 1519 // Encryption routines are the place where we hit the bug, but 1520 // the generic code is a bad candidate for bug titles. 1521 "_encrypt$", "^(?:crypto|cipher|drbg|rng)_"}, 1522 }, 1523 noStackTrace: true, 1524 }, 1525 { 1526 title: compile("BUG: KCSAN: data-race"), 1527 report: compile("BUG: KCSAN: (.*)"), 1528 fmt: "KCSAN: %[1]v", 1529 noStackTrace: true, 1530 }, 1531 { 1532 title: compile("BUG: KCSAN:"), 1533 report: compile("BUG: KCSAN: (.*)"), 1534 fmt: "KCSAN: %[1]v", 1535 noStackTrace: true, 1536 }, 1537 { 1538 title: compile("BUG: KFENCE: (use-after-free|out-of-bounds) (read|write) in {{FUNC}}"), 1539 fmt: "KFENCE: %[1]v %[2]v in %[4]v", 1540 alt: []string{"bad-access in %[4]v"}, 1541 stack: &stackFmt{ 1542 parts: []*regexp.Regexp{ 1543 compile("BUG: KFENCE: (?:[a-z\\- ]+) in {{FUNC}}"), 1544 parseStackTrace, 1545 }, 1546 }, 1547 }, 1548 { 1549 title: compile("BUG: KFENCE: invalid free in {{FUNC}}"), 1550 fmt: "KFENCE: invalid free in %[2]v", 1551 alt: []string{"invalid-free in %[2]v"}, 1552 noStackTrace: true, 1553 stack: &stackFmt{ 1554 parts: []*regexp.Regexp{ 1555 compile("BUG: KFENCE: (?:[a-z\\- ]+) in {{FUNC}}"), 1556 parseStackTrace, 1557 }, 1558 }, 1559 }, 1560 { 1561 title: compile("BUG: KFENCE: invalid (read|write) in {{FUNC}}"), 1562 fmt: "KFENCE: invalid %[1]v in %[3]v", 1563 alt: []string{"bad-access in %[3]v"}, 1564 stack: &stackFmt{ 1565 parts: []*regexp.Regexp{ 1566 compile("BUG: KFENCE: (?:[a-z\\- ]+) in {{FUNC}}"), 1567 parseStackTrace, 1568 }, 1569 }, 1570 }, 1571 { 1572 title: compile("BUG: KFENCE: memory corruption in {{FUNC}}"), 1573 fmt: "KFENCE: memory corruption in %[2]v", 1574 noStackTrace: true, 1575 stack: &stackFmt{ 1576 parts: []*regexp.Regexp{ 1577 compile("BUG: KFENCE: (?:[a-z\\- ]+) in {{FUNC}}"), 1578 parseStackTrace, 1579 }, 1580 }, 1581 }, 1582 { 1583 title: compile("BUG: (?:unable to handle kernel paging request|unable to handle page fault for address|Unable to handle kernel data access)"), 1584 fmt: "BUG: unable to handle kernel paging request in %[1]v", 1585 alt: []string{"bad-access in %[1]v"}, 1586 stack: &stackFmt{ 1587 parts: []*regexp.Regexp{ 1588 linuxRipFrame, 1589 linuxCallTrace, 1590 parseStackTrace, 1591 }, 1592 }, 1593 }, 1594 { 1595 title: compile("BUG: (?:unable to handle kernel NULL pointer dereference|kernel NULL pointer dereference|Kernel NULL pointer dereference)"), 1596 fmt: "BUG: unable to handle kernel NULL pointer dereference in %[1]v", 1597 alt: []string{"bad-access in %[1]v"}, 1598 stack: &stackFmt{ 1599 parts: []*regexp.Regexp{ 1600 linuxRipFrame, 1601 linuxCallTrace, 1602 parseStackTrace, 1603 }, 1604 }, 1605 }, 1606 { 1607 // Sometimes with such BUG failures, the second part of the header doesn't get printed 1608 // or gets corrupted, because kernel prints it as two separate printk() calls. 1609 title: compile("BUG: (?:unable to handle kernel|Unable to handle kernel)"), 1610 fmt: "BUG: unable to handle kernel", 1611 corrupted: true, 1612 }, 1613 { 1614 title: compile("BUG: (spinlock|rwlock) (lockup suspected|already unlocked|recursion" + 1615 "|cpu recursion|bad magic|wrong owner|wrong CPU|trylock failure on UP)"), 1616 fmt: "BUG: %[1]v %[2]v in %[3]v", 1617 stack: &stackFmt{ 1618 parts: []*regexp.Regexp{ 1619 linuxCallTrace, 1620 parseStackTrace, 1621 }, 1622 skip: []string{"spin_", "_lock", "_unlock"}, 1623 }, 1624 }, 1625 { 1626 title: compile("BUG: soft lockup"), 1627 fmt: "BUG: soft lockup in %[1]v", 1628 alt: []string{"stall in %[1]v"}, 1629 stack: &stackFmt{ 1630 parts: []*regexp.Regexp{ 1631 linuxRipFrame, 1632 linuxCallTrace, 1633 parseStackTrace, 1634 }, 1635 extractor: linuxStallFrameExtractor, 1636 }, 1637 }, 1638 { 1639 title: compile("BUG: .*still has locks held!"), 1640 report: compile("BUG: .*still has locks held!(?:.*\\n)+?.*{{PC}} +{{FUNC}}"), 1641 fmt: "BUG: still has locks held in %[1]v", 1642 }, 1643 { 1644 title: compile("BUG: scheduling while atomic"), 1645 fmt: "BUG: scheduling while atomic in %[1]v", 1646 stack: &stackFmt{ 1647 parts: []*regexp.Regexp{ 1648 linuxCallTrace, 1649 parseStackTrace, 1650 }, 1651 skip: []string{"schedule"}, 1652 }, 1653 }, 1654 { 1655 title: compile("BUG: lock held when returning to user space"), 1656 report: compile("BUG: lock held when returning to user space(?:.*\\n)+?.*leaving the kernel with locks still held(?:.*\\n)+?.*at: (?:{{PC}} +)?{{FUNC}}"), 1657 fmt: "BUG: lock held when returning to user space in %[1]v", 1658 noStackTrace: true, 1659 }, 1660 { 1661 title: compile("BUG: bad unlock balance detected!"), 1662 fmt: "BUG: bad unlock balance in %[1]v", 1663 stack: &stackFmt{ 1664 parts: []*regexp.Regexp{ 1665 compile("{{PC}} +{{FUNC}}"), 1666 linuxCallTrace, 1667 parseStackTrace, 1668 }, 1669 }, 1670 }, 1671 { 1672 title: compile("BUG: held lock freed!"), 1673 report: compile("BUG: held lock freed!(?:.*\\n)+?.*{{PC}} +{{FUNC}}"), 1674 fmt: "BUG: held lock freed in %[1]v", 1675 }, 1676 { 1677 title: compile("BUG: Bad rss-counter state"), 1678 fmt: "BUG: Bad rss-counter state", 1679 noStackTrace: true, 1680 }, 1681 { 1682 title: compile("BUG: non-zero nr_ptes on freeing mm"), 1683 fmt: "BUG: non-zero nr_ptes on freeing mm", 1684 noStackTrace: true, 1685 }, 1686 { 1687 title: compile("BUG: non-zero nr_pmds on freeing mm"), 1688 fmt: "BUG: non-zero nr_pmds on freeing mm", 1689 noStackTrace: true, 1690 }, 1691 { 1692 // Kernel includes filesystem type and block device name into the message. 1693 // We used to include them, but block devices are plain harmful (loop0/1/2), 1694 // and filesystem type also leads to duplicates. So now we exclude them. 1695 title: compile("BUG: Dentry .* still in use"), 1696 report: compile("BUG: Dentry .* still in use \\([0-9]+\\) \\[(unmount) of ([^\\]]+)\\]"), 1697 fmt: "BUG: Dentry still in use in %[1]v", 1698 alt: []string{"BUG: Dentry still in use [%[1]v of %[2]v]"}, 1699 }, 1700 { 1701 title: compile("BUG: Bad page (state|cache)"), 1702 fmt: "BUG: Bad page %[1]v in %[2]v", 1703 stack: &stackFmt{ 1704 // TODO: on arm64, for some reason we don't see the page origin backtrace. 1705 // We see the stack trace where the bug was detected, but we consider it to be 1706 // not sufficient to reliably group crashes. 1707 // So Bad page reports on arm64 for now will end up marked as corrupted. 1708 parts: []*regexp.Regexp{ 1709 compile(`page last allocated`), 1710 parseStackTrace, 1711 }, 1712 skip: []string{"(free|put|get|update|release)_page", 1713 "free_unref", "^_*folio", "truncate_inode_pages", 1714 "page_frag_free", "alloc", "vmap", "page_owner"}, 1715 }, 1716 }, 1717 { 1718 title: compile("BUG: Bad page map"), 1719 fmt: "BUG: Bad page map", 1720 }, 1721 { 1722 title: compile("BUG: workqueue lockup"), 1723 fmt: "BUG: workqueue lockup", 1724 noStackTrace: true, 1725 }, 1726 { 1727 title: compile("BUG: sleeping function called from invalid context at (.*)"), 1728 fmt: "BUG: sleeping function called from invalid context in %[2]v", 1729 stack: &stackFmt{ 1730 parts: []*regexp.Regexp{ 1731 linuxCallTrace, 1732 parseStackTrace, 1733 }, 1734 }, 1735 }, 1736 { 1737 title: compile("BUG: using ([a-z_]+)\\(\\) in preemptible"), 1738 fmt: "BUG: using %[1]v() in preemptible code in %[2]v", 1739 stack: &stackFmt{ 1740 parts: []*regexp.Regexp{ 1741 linuxCallTrace, 1742 parseStackTrace, 1743 }, 1744 skip: []string{"dump_stack", "preemption", "preempt", "debug_", 1745 "processor_id", "this_cpu"}, 1746 }, 1747 }, 1748 { 1749 title: compile("BUG: workqueue leaked lock or atomic"), 1750 report: compile("BUG: workqueue leaked lock or atomic(?:.*\\n)+?" + 1751 ".*last function: ([a-zA-Z0-9_]+)\\n"), 1752 fmt: "BUG: workqueue leaked lock or atomic in %[1]v", 1753 noStackTrace: true, 1754 }, 1755 { 1756 title: compile("BUG: memory leak"), 1757 fmt: "memory leak in %[1]v", 1758 stack: &stackFmt{ 1759 parts: []*regexp.Regexp{ 1760 compile("backtrace(?: \\(crc [[:xdigit:]]*\\))?:"), 1761 parseStackTrace, 1762 }, 1763 skip: []string{"kmemleak", "mmap", "kmem", "slab", "alloc", "create_object", 1764 "idr_get", "list_lru_init", "kasprintf", "kvasprintf", 1765 "pcpu_create", "strdup", "strndup", "memdup"}, 1766 }, 1767 }, 1768 { 1769 title: compile("BUG: .*stack guard page was hit at"), 1770 fmt: "BUG: stack guard page was hit in %[1]v", 1771 alt: []string{"stack-overflow in %[1]v"}, 1772 stack: &stackFmt{ 1773 parts: []*regexp.Regexp{ 1774 linuxRipFrame, 1775 linuxCallTrace, 1776 parseStackTrace, 1777 }, 1778 extractor: linuxStallFrameExtractor, 1779 }, 1780 }, 1781 { 1782 title: compile("BUG: Invalid wait context"), 1783 // Somehow amd64 and arm/arm64 report this bug completely differently. 1784 // This is arm/arm64 format, but we match amd64 title to not duplicate bug reports. 1785 fmt: "WARNING: locking bug in %[1]v", 1786 stack: &stackFmt{ 1787 parts: []*regexp.Regexp{ 1788 linuxCallTrace, 1789 parseStackTrace, 1790 }, 1791 skip: []string{"lock_sock", "release_sock"}, 1792 }, 1793 }, 1794 { 1795 title: compile(`BUG:[[:space:]]*(?:\n|$)`), 1796 fmt: "BUG: corrupted", 1797 corrupted: true, 1798 }, 1799 }, 1800 []*regexp.Regexp{ 1801 // CONFIG_DEBUG_OBJECTS output. 1802 compile("ODEBUG:"), 1803 // Android prints this sometimes during boot. 1804 compile("Boot_DEBUG:"), 1805 compile("xlog_status:"), 1806 // Android ART debug output. 1807 compile("DEBUG:"), 1808 // pkg/host output in debug mode. 1809 compile("BUG: no syscalls can create resource"), 1810 }, 1811 }, 1812 { 1813 []byte("WARNING:"), 1814 []oopsFormat{ 1815 { 1816 title: compile("WARNING: .*lib/debugobjects\\.c.* (?:debug_print|debug_check|at)"), 1817 fmt: "WARNING: ODEBUG bug in %[1]v", 1818 // Skip all users of ODEBUG as well. 1819 stack: warningStackFmt("debug_", "rcu", "hrtimer_", "timer_", 1820 "work_", "percpu_", "vunmap", 1821 "vfree", "__free_", "debug_check", "kobject_"), 1822 }, 1823 { 1824 title: compile("WARNING: .*mm/usercopy\\.c.* (?:usercopy_warn|at)"), 1825 fmt: "WARNING: bad usercopy in %[1]v", 1826 stack: warningStackFmt("usercopy", "__check"), 1827 }, 1828 { 1829 title: compile("WARNING: .*lib/kobject\\.c.* (?:kobject_|at)"), 1830 fmt: "WARNING: kobject bug in %[1]v", 1831 stack: warningStackFmt("kobject_"), 1832 }, 1833 { 1834 title: compile("WARNING: .*fs/proc/generic\\.c.* (?:proc_register|at)"), 1835 fmt: "WARNING: proc registration bug in %[1]v", 1836 stack: warningStackFmt("proc_"), 1837 }, 1838 { 1839 title: compile("WARNING: .*lib/refcount\\.c.* (?:refcount_|at)"), 1840 fmt: "WARNING: refcount bug in %[1]v", 1841 stack: warningStackFmt("refcount", "kobject_"), 1842 }, 1843 { 1844 title: compile("WARNING: .*kernel/locking/lockdep\\.c.*lock_"), 1845 fmt: "WARNING: locking bug in %[1]v", 1846 stack: warningStackFmt("lock_sock", "release_sock"), 1847 }, 1848 { 1849 title: compile("WARNING: .*still has locks held!"), 1850 report: compile("WARNING: .*still has locks held!(?:.*\\n)+?.*at: {{FUNC}}"), 1851 fmt: "WARNING: still has locks held in %[1]v", 1852 }, 1853 { 1854 title: compile("WARNING: Nested lock was not taken"), 1855 fmt: "WARNING: nested lock was not taken in %[1]v", 1856 stack: warningStackFmt(), 1857 }, 1858 { 1859 title: compile("WARNING: lock held when returning to user space"), 1860 report: compile("WARNING: lock held when returning to user space(?:.*\\n)+?.*leaving the kernel with locks still held(?:.*\\n)+?.*at: (?:{{PC}} +)?{{FUNC}}"), 1861 fmt: "WARNING: lock held when returning to user space in %[1]v", 1862 noStackTrace: true, 1863 }, 1864 { 1865 title: compile("WARNING: .*mm/.*\\.c.* k?.?malloc"), 1866 fmt: "WARNING: kmalloc bug in %[1]v", 1867 stack: warningStackFmt("kmalloc", "krealloc", "slab", "kmem"), 1868 }, 1869 { 1870 title: compile("WARNING: .*mm/vmalloc.c.*__vmalloc_node"), 1871 fmt: "WARNING: zero-size vmalloc in %[1]v", 1872 stack: warningStackFmt(), 1873 }, 1874 { 1875 title: compile("WARNING: .* usb_submit_urb"), 1876 fmt: "WARNING in %[1]v/usb_submit_urb", 1877 stack: warningStackFmt("usb_submit_urb", "usb_start_wait_urb", "usb_bulk_msg", "usb_interrupt_msg", "usb_control_msg"), 1878 }, 1879 { 1880 // Format introduced in https://lore.kernel.org/all/20251110114633.202485143@infradead.org/. 1881 title: compile(`WARNING: {{SRC}} at 0x\d+, CPU#\d+`), 1882 fmt: "WARNING in %[2]v", 1883 stack: warningStackFmt(), 1884 }, 1885 { 1886 title: compile("WARNING: .* at {{SRC}} {{FUNC}}"), 1887 fmt: "WARNING in %[3]v", 1888 stack: warningStackFmt(), 1889 }, 1890 { 1891 title: compile("WARNING: {{SRC}} at {{FUNC}}"), 1892 fmt: "WARNING in %[3]v", 1893 stack: warningStackFmt(), 1894 }, 1895 { 1896 title: compile("WARNING: possible circular locking dependency detected"), 1897 report: compile("WARNING: possible circular locking dependency detected(?:.*\\n)+?.*is trying to acquire lock"), 1898 fmt: "possible deadlock in %[1]v", 1899 stack: &stackFmt{ 1900 parts: []*regexp.Regexp{ 1901 compile("at: (?:{{PC}} +)?{{FUNC}}"), 1902 compile("at: (?:{{PC}} +)?{{FUNC}}"), 1903 parseStackTrace, 1904 }, 1905 // These workqueue functions take locks associated with work items. 1906 // All deadlocks observed in these functions are 1907 // work-item-subsystem-related. 1908 skip: []string{"process_one_work", "flush_workqueue", 1909 "drain_workqueue", "destroy_workqueue"}, 1910 }, 1911 }, 1912 { 1913 title: compile("WARNING: possible irq lock inversion dependency detected"), 1914 report: compile("WARNING: possible irq lock inversion dependency detected(?:.*\\n)+?.*just changed the state of lock(?:.*\\n)+?.*at: (?:{{PC}} +)?{{FUNC}}"), 1915 fmt: "possible deadlock in %[1]v", 1916 }, 1917 { 1918 title: compile("WARNING: .*-safe -> .*-unsafe lock order detected"), 1919 fmt: "possible deadlock in %[1]v", 1920 stack: &stackFmt{ 1921 parts: []*regexp.Regexp{ 1922 compile("which became (?:.*) at:"), 1923 parseStackTrace, 1924 }, 1925 }, 1926 }, 1927 { 1928 title: compile("WARNING: possible recursive locking detected"), 1929 report: compile("WARNING: possible recursive locking detected(?:.*\\n)+?.*is trying to acquire lock(?:.*\\n)+?.*at: (?:{{PC}} +)?{{FUNC}}"), 1930 fmt: "possible deadlock in %[1]v", 1931 }, 1932 { 1933 title: compile("WARNING: inconsistent lock state"), 1934 report: compile("WARNING: inconsistent lock state(?:.*\\n)+?.*takes(?:.*\\n)+?.*at: (?:{{PC}} +)?{{FUNC}}"), 1935 fmt: "inconsistent lock state in %[2]v", 1936 stack: &stackFmt{ 1937 parts: []*regexp.Regexp{ 1938 linuxCallTrace, 1939 parseStackTrace, 1940 }, 1941 }, 1942 }, 1943 { 1944 title: compile("WARNING: suspicious RCU usage"), 1945 report: compile("WARNING: suspicious RCU usage(?:.*\n)+?.*?{{SRC}}"), 1946 fmt: "WARNING: suspicious RCU usage in %[2]v", 1947 stack: &stackFmt{ 1948 parts: []*regexp.Regexp{ 1949 linuxCallTrace, 1950 parseStackTrace, 1951 }, 1952 skip: []string{"rcu", "kmem", "slab"}, 1953 }, 1954 }, 1955 { 1956 title: compile("WARNING: kernel stack regs at [0-9a-f]+ in [^ ]* has bad '([^']+)' value"), 1957 fmt: "WARNING: kernel stack regs has bad '%[1]v' value", 1958 noStackTrace: true, 1959 }, 1960 { 1961 title: compile("WARNING: kernel stack frame pointer at [0-9a-f]+ in [^ ]* has bad value"), 1962 fmt: "WARNING: kernel stack frame pointer has bad value", 1963 noStackTrace: true, 1964 }, 1965 { 1966 title: compile("WARNING: bad unlock balance detected!"), 1967 fmt: "WARNING: bad unlock balance in %[1]v", 1968 stack: &stackFmt{ 1969 parts: []*regexp.Regexp{ 1970 compile("{{PC}} +{{FUNC}}"), 1971 linuxCallTrace, 1972 parseStackTrace, 1973 }, 1974 }, 1975 }, 1976 { 1977 title: compile("WARNING: held lock freed!"), 1978 report: compile("WARNING: held lock freed!(?:.*\\n)+?.*at:(?: {{PC}})? +{{FUNC}}"), 1979 fmt: "WARNING: held lock freed in %[1]v", 1980 }, 1981 { 1982 title: compile("WARNING: kernel stack regs .* has bad 'bp' value"), 1983 fmt: "WARNING: kernel stack regs has bad value", 1984 noStackTrace: true, 1985 }, 1986 { 1987 title: compile("WARNING: kernel stack frame pointer .* has bad value"), 1988 fmt: "WARNING: kernel stack regs has bad value", 1989 noStackTrace: true, 1990 }, 1991 { 1992 title: compile(`WARNING:[[:space:]]*(?:\n|$)`), 1993 fmt: "WARNING: corrupted", 1994 corrupted: true, 1995 }, 1996 }, 1997 []*regexp.Regexp{ 1998 compile("WARNING: /etc/ssh/moduli does not exist, using fixed modulus"), // printed by sshd 1999 compile("WARNING: workqueue cpumask: online intersect > possible intersect"), 2000 compile("WARNING: [Tt]he mand mount option"), 2001 compile("WARNING: Unsupported flag value\\(s\\) of 0x%x in DT_FLAGS_1"), // printed when glibc is dumped 2002 compile("WARNING: Unprivileged eBPF is enabled with eIBRS"), 2003 compile(`WARNING: fbcon: Driver '(.*)' missed to adjust virtual screen size (\((?:\d+)x(?:\d+) vs\. (?:\d+)x(?:\d+)\))`), 2004 compile(`WARNING: See https.* for mitigation options.`), 2005 compile(`WARNING: kernel not compiled with CPU_SRSO`), 2006 compile(`EXT4-[Ff][Ss](?: \(.*\))?:`), // printed in __ext4_msg 2007 compile(`(?i)warning: .* uses (deprecated v2 capabilities|wireless extensions)`), 2008 compile(`XFS \(\w+\): WARNING`), 2009 }, 2010 }, 2011 { 2012 []byte("INFO:"), 2013 []oopsFormat{ 2014 { 2015 title: compile("INFO: possible circular locking dependency detected"), 2016 report: compile("INFO: possible circular locking dependency detected \\](?:.*\\n)+?.*is trying to acquire lock(?:.*\\n)+?.*at: {{PC}} +{{FUNC}}"), 2017 fmt: "possible deadlock in %[1]v", 2018 }, 2019 { 2020 title: compile("INFO: possible irq lock inversion dependency detected"), 2021 report: compile("INFO: possible irq lock inversion dependency detected \\](?:.*\\n)+?.*just changed the state of lock(?:.*\\n)+?.*at: {{PC}} +{{FUNC}}"), 2022 fmt: "possible deadlock in %[1]v", 2023 }, 2024 { 2025 title: compile("INFO: SOFTIRQ-safe -> SOFTIRQ-unsafe lock order detected"), 2026 report: compile("INFO: SOFTIRQ-safe -> SOFTIRQ-unsafe lock order detected \\](?:.*\\n)+?.*is trying to acquire(?:.*\\n)+?.*at: {{PC}} +{{FUNC}}"), 2027 fmt: "possible deadlock in %[1]v", 2028 }, 2029 { 2030 title: compile("INFO: possible recursive locking detected"), 2031 report: compile("INFO: possible recursive locking detected \\](?:.*\\n)+?.*is trying to acquire lock(?:.*\\n)+?.*at: {{PC}} +{{FUNC}}"), 2032 fmt: "possible deadlock in %[1]v", 2033 }, 2034 { 2035 title: compile("INFO: inconsistent lock state"), 2036 report: compile("INFO: inconsistent lock state \\](?:.*\\n)+?.*takes(?:.*\\n)+?.*at: {{PC}} +{{FUNC}}"), 2037 fmt: "inconsistent lock state in %[1]v", 2038 }, 2039 { 2040 title: compile("INFO: rcu_(?:preempt|sched|bh) (?:self-)?detected(?: expedited)? stall"), 2041 fmt: "INFO: rcu detected stall in %[1]v", 2042 alt: []string{"stall in %[1]v"}, 2043 stack: &stackFmt{ 2044 parts: []*regexp.Regexp{ 2045 compile("apic_timer_interrupt"), 2046 linuxRipFrame, 2047 parseStackTrace, 2048 }, 2049 parts2: []*regexp.Regexp{ 2050 compile("(?:apic_timer_interrupt|Exception stack|el1h_64_irq)"), 2051 parseStackTrace, 2052 }, 2053 skip: []string{"apic_timer_interrupt", "rcu"}, 2054 extractor: linuxStallFrameExtractor, 2055 }, 2056 }, 2057 { 2058 title: compile("INFO: trying to register non-static key"), 2059 fmt: "INFO: trying to register non-static key in %[1]v", 2060 stack: &stackFmt{ 2061 parts: []*regexp.Regexp{ 2062 linuxCallTrace, 2063 parseStackTrace, 2064 }, 2065 skip: []string{"stack", "lock", "IRQ"}, 2066 }, 2067 }, 2068 { 2069 title: compile("INFO: suspicious RCU usage"), 2070 report: compile("INFO: suspicious RCU usage(?:.*\n)+?.*?{{SRC}}"), 2071 fmt: "INFO: suspicious RCU usage in %[2]v", 2072 stack: &stackFmt{ 2073 parts: []*regexp.Regexp{ 2074 linuxCallTrace, 2075 parseStackTrace, 2076 }, 2077 skip: []string{"rcu", "kmem", "slab"}, 2078 }, 2079 }, 2080 { 2081 title: compile("INFO: task .* blocked for more than [0-9]+ seconds"), 2082 fmt: "INFO: task hung in %[1]v", 2083 alt: []string{"hang in %[1]v"}, 2084 stack: &stackFmt{ 2085 parts: []*regexp.Regexp{ 2086 linuxCallTrace, 2087 parseStackTrace, 2088 }, 2089 extractor: linuxHangTaskFrameExtractor, 2090 }, 2091 }, 2092 { 2093 title: compile("INFO: task .* can't die for more than .* seconds"), 2094 fmt: "INFO: task can't die in %[1]v", 2095 alt: []string{"hang in %[1]v"}, 2096 stack: &stackFmt{ 2097 parts: []*regexp.Regexp{ 2098 linuxCallTrace, 2099 parseStackTrace, 2100 }, 2101 skip: []string{"schedule"}, 2102 }, 2103 }, 2104 { 2105 // This gets captured for corrupted old-style KASAN reports. 2106 title: compile("INFO: (Freed|Allocated) in (.*)"), 2107 fmt: "INFO: %[1]v in %[2]v", 2108 corrupted: true, 2109 }, 2110 { 2111 title: compile(`INFO:[[:space:]]*(?:\n|$)`), 2112 fmt: "INFO: corrupted", 2113 corrupted: true, 2114 }, 2115 }, 2116 []*regexp.Regexp{ 2117 compile("INFO: lockdep is turned off"), 2118 compile("INFO: Stall ended before state dump start"), 2119 compile("INFO: NMI handler"), 2120 compile("INFO: recovery required on readonly filesystem"), 2121 compile("(handler|interrupt).*took too long"), 2122 compile("INFO: sys_.* is not present in /proc/kallsyms"), // pkg/host output in debug mode 2123 compile("INFO: no syscalls can create resource"), // pkg/host output in debug mode 2124 compile("rmt_storage:INFO:"), // Android prints this. 2125 compile("_INFO:"), // To filter out "INVALID BTF_INFO:NUM". 2126 }, 2127 }, 2128 { 2129 []byte("Unable to handle kernel"), 2130 []oopsFormat{ 2131 { 2132 title: compile("Unable to handle kernel (paging request|NULL pointer dereference|access to user memory)"), 2133 fmt: "BUG: unable to handle kernel %[1]v in %[2]v", 2134 alt: []string{"bad-access in %[2]v"}, 2135 stack: &stackFmt{ 2136 parts: []*regexp.Regexp{ 2137 linuxRipFrame, 2138 linuxCallTrace, 2139 parseStackTrace, 2140 }, 2141 }, 2142 }, 2143 }, 2144 []*regexp.Regexp{}, 2145 }, 2146 { 2147 []byte("general protection fault"), 2148 []oopsFormat{ 2149 { 2150 title: compile("general protection fault.*:"), 2151 fmt: "general protection fault in %[1]v", 2152 alt: []string{"bad-access in %[1]v"}, 2153 stack: &stackFmt{ 2154 parts: []*regexp.Regexp{ 2155 linuxRipFrame, 2156 linuxCallTrace, 2157 parseStackTrace, 2158 }, 2159 }, 2160 }, 2161 }, 2162 []*regexp.Regexp{ 2163 compile(`general protection fault .* error:\d+ in `), 2164 }, 2165 }, 2166 { 2167 []byte("stack segment: "), 2168 []oopsFormat{ 2169 { 2170 title: compile("stack segment: "), 2171 fmt: "stack segment fault in %[1]v", 2172 stack: &stackFmt{ 2173 parts: []*regexp.Regexp{ 2174 linuxRipFrame, 2175 linuxCallTrace, 2176 parseStackTrace, 2177 }, 2178 }, 2179 }, 2180 }, 2181 []*regexp.Regexp{}, 2182 }, 2183 { 2184 []byte("Kernel panic"), 2185 []oopsFormat{ 2186 // Note: for stack corruption reports kernel may fail 2187 // to print function symbol name and/or unwind stack. 2188 { 2189 title: compile("Kernel panic - not syncing: stack-protector:"), 2190 report: compile("Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: {{FUNC}}"), 2191 fmt: "kernel panic: stack is corrupted in %[1]v", 2192 noStackTrace: true, 2193 }, 2194 { 2195 title: compile("Kernel panic - not syncing: stack-protector:"), 2196 report: compile("Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: [a-f0-9]+"), 2197 fmt: "kernel panic: stack is corrupted in %[1]v", 2198 stack: &stackFmt{ 2199 parts: []*regexp.Regexp{ 2200 linuxCallTrace, 2201 parseStackTrace, 2202 }, 2203 skip: []string{"stack_chk"}, 2204 }, 2205 }, 2206 { 2207 title: compile("Kernel panic - not syncing: corrupted stack end"), 2208 report: compile("Kernel panic - not syncing: corrupted stack end detected inside scheduler"), 2209 fmt: "kernel panic: corrupted stack end in %[1]v", 2210 alt: []string{"stack-overflow in %[1]v"}, 2211 stack: &stackFmt{ 2212 parts: []*regexp.Regexp{ 2213 linuxCallTrace, 2214 parseStackTrace, 2215 }, 2216 skip: []string{"schedule", "retint_kernel"}, 2217 extractor: linuxStallFrameExtractor, 2218 }, 2219 }, 2220 { 2221 title: compile("Kernel panic - not syncing: kernel stack overflow"), 2222 fmt: "kernel stack overflow in %[1]v", 2223 alt: []string{"stack-overflow in %[1]v"}, 2224 stack: &stackFmt{ 2225 parts: []*regexp.Regexp{ 2226 linuxCallTrace, 2227 parseStackTrace, 2228 }, 2229 skip: []string{"bad_stack"}, 2230 extractor: linuxStallFrameExtractor, 2231 }, 2232 }, 2233 { 2234 title: compile("Kernel panic - not syncing: Attempted to kill init!"), 2235 fmt: "kernel panic: Attempted to kill init!", 2236 }, 2237 { 2238 title: compile("Kernel panic - not syncing: Couldn't open N_TTY ldisc for [^ ]+ --- error -[0-9]+"), 2239 fmt: "kernel panic: Couldn't open N_TTY ldisc", 2240 }, 2241 { 2242 // 'kernel panic: Fatal exception' is usually printed after BUG, 2243 // so if we captured it as a report description, that means the 2244 // report got truncated and we missed the actual BUG header. 2245 title: compile("Kernel panic - not syncing: Fatal exception"), 2246 fmt: "kernel panic: Fatal exception", 2247 corrupted: true, 2248 }, 2249 { 2250 // Same, but for WARNINGs and KASAN reports. 2251 title: compile("Kernel panic - not syncing: panic_on_warn set"), 2252 fmt: "kernel panic: panic_on_warn set", 2253 corrupted: true, 2254 }, 2255 { 2256 // Same, but for task hung reports. 2257 title: compile("Kernel panic - not syncing: hung_task: blocked tasks"), 2258 fmt: "kernel panic: hung_task: blocked tasks", 2259 corrupted: true, 2260 }, 2261 { 2262 title: compile("Kernel panic - not syncing: (.*)"), 2263 fmt: "kernel panic: %[1]v", 2264 }, 2265 }, 2266 []*regexp.Regexp{}, 2267 }, 2268 { 2269 []byte("PANIC: double fault"), 2270 []oopsFormat{ 2271 { 2272 title: compile("PANIC: double fault"), 2273 fmt: "PANIC: double fault in %[1]v", 2274 stack: &stackFmt{ 2275 parts: []*regexp.Regexp{ 2276 linuxRipFrame, 2277 }, 2278 }, 2279 }, 2280 }, 2281 []*regexp.Regexp{}, 2282 }, 2283 { 2284 []byte("rust_kernel: panicked"), 2285 []oopsFormat{ 2286 { 2287 title: compile("rust_kernel: panicked"), 2288 report: compile("rust_kernel: panicked at [^\n]*?\n(.+?)\n"), 2289 fmt: "%[1]v in %[2]v", 2290 stack: &stackFmt{ 2291 parts: []*regexp.Regexp{ 2292 linuxCallTrace, 2293 parseStackTrace, 2294 }, 2295 skip: []string{ 2296 regexp.QuoteMeta(`__rustc::rust_begin_unwind`), 2297 }, 2298 }, 2299 }, 2300 }, 2301 []*regexp.Regexp{}, 2302 }, 2303 { 2304 []byte("kernel BUG"), 2305 []oopsFormat{ 2306 { 2307 title: compile("kernel BUG at mm/usercopy.c"), 2308 fmt: "BUG: bad usercopy in %[1]v", 2309 stack: &stackFmt{ 2310 parts: []*regexp.Regexp{ 2311 linuxCallTrace, 2312 parseStackTrace, 2313 }, 2314 skip: []string{"usercopy", "__check"}, 2315 }, 2316 }, 2317 { 2318 title: compile("kernel BUG at lib/list_debug.c"), 2319 fmt: "BUG: corrupted list in %[1]v", 2320 alt: []string{"bad-access in %[1]v"}, // also sometimes due to memory corruption/race 2321 stack: &stackFmt{ 2322 parts: []*regexp.Regexp{ 2323 linuxCallTrace, 2324 parseStackTrace, 2325 }, 2326 }, 2327 }, 2328 { 2329 title: compile("kernel BUG at (.*)"), 2330 fmt: "kernel BUG in %[2]v", 2331 stack: &stackFmt{ 2332 parts: []*regexp.Regexp{ 2333 linuxRipFrame, 2334 linuxCallTrace, 2335 parseStackTrace, 2336 }, 2337 // Lots of skb wrappers contain BUG_ON, but the bug is almost always in the caller. 2338 skip: []string{"^skb_"}, 2339 }, 2340 }, 2341 }, 2342 []*regexp.Regexp{}, 2343 }, 2344 { 2345 []byte("Kernel BUG"), 2346 []oopsFormat{ 2347 { 2348 title: compile("Kernel BUG (.*)"), 2349 fmt: "kernel BUG %[1]v", 2350 }, 2351 }, 2352 []*regexp.Regexp{}, 2353 }, 2354 { 2355 []byte("BUG kmalloc-"), 2356 []oopsFormat{ 2357 { 2358 title: compile("BUG kmalloc-.*: Object already free"), 2359 fmt: "BUG: Object already free", 2360 }, 2361 }, 2362 []*regexp.Regexp{}, 2363 }, 2364 { 2365 []byte("divide error:"), 2366 []oopsFormat{ 2367 { 2368 title: compile("divide error: "), 2369 fmt: "divide error in %[1]v", 2370 stack: &stackFmt{ 2371 parts: []*regexp.Regexp{ 2372 linuxRipFrame, 2373 }, 2374 }, 2375 }, 2376 }, 2377 []*regexp.Regexp{}, 2378 }, 2379 { 2380 // A misspelling of the above introduced in 9d06c4027f21 ("x86/entry: Convert Divide Error to IDTENTRY"). 2381 []byte("divide_error:"), 2382 []oopsFormat{ 2383 { 2384 title: compile("divide_error: "), 2385 fmt: "divide error in %[1]v", 2386 stack: &stackFmt{ 2387 parts: []*regexp.Regexp{ 2388 linuxRipFrame, 2389 }, 2390 }, 2391 }, 2392 }, 2393 []*regexp.Regexp{}, 2394 }, 2395 { 2396 []byte("invalid opcode:"), 2397 []oopsFormat{ 2398 { 2399 title: compile("invalid opcode: "), 2400 fmt: "invalid opcode in %[1]v", 2401 stack: &stackFmt{ 2402 parts: []*regexp.Regexp{ 2403 linuxRipFrame, 2404 }, 2405 }, 2406 }, 2407 }, 2408 []*regexp.Regexp{}, 2409 }, 2410 { 2411 []byte("UBSAN:"), 2412 []oopsFormat{ 2413 { 2414 title: compile("UBSAN:"), 2415 report: compile("UBSAN: Undefined behaviour in"), 2416 fmt: "UBSAN: undefined-behaviour in %[1]v", 2417 stack: &stackFmt{ 2418 parts: []*regexp.Regexp{ 2419 linuxCallTrace, 2420 parseStackTrace, 2421 }, 2422 skip: []string{"ubsan", "overflow"}, 2423 }, 2424 }, 2425 { 2426 title: compile("UBSAN: array-index-out-of-bounds in"), 2427 fmt: "UBSAN: array-index-out-of-bounds in %[1]v", 2428 alt: []string{"bad-access in %[1]v"}, 2429 stack: &stackFmt{ 2430 parts: []*regexp.Regexp{ 2431 linuxCallTrace, 2432 parseStackTrace, 2433 }, 2434 skip: []string{"ubsan", "overflow"}, 2435 }, 2436 }, 2437 { 2438 title: compile("UBSAN:"), 2439 report: compile("UBSAN: (.*?) in"), 2440 fmt: "UBSAN: %[1]v in %[2]v", 2441 stack: &stackFmt{ 2442 parts: []*regexp.Regexp{ 2443 linuxCallTrace, 2444 parseStackTrace, 2445 }, 2446 skip: []string{"ubsan", "overflow"}, 2447 }, 2448 }, 2449 }, 2450 []*regexp.Regexp{}, 2451 }, 2452 { 2453 []byte("Booting the kernel."), 2454 []oopsFormat{ 2455 { 2456 title: compile("^Booting the kernel"), 2457 fmt: "unexpected kernel reboot", 2458 noStackTrace: true, 2459 }, 2460 }, 2461 []*regexp.Regexp{ 2462 // These may appear on the same line when the fuzzer reads from the console the existing 2463 // boot message and then pass it as mount option, kernel then prints it back 2464 // as an invalid mount option and we detect false reboot. 2465 compile("Parsing ELF|Decompressing Linux|Unknown parameter '"), 2466 }, 2467 }, 2468 { 2469 []byte("unregister_netdevice: waiting for"), 2470 []oopsFormat{ 2471 { 2472 title: compile("unregister_netdevice: waiting for (?:.*) to become free"), 2473 fmt: "unregister_netdevice: waiting for DEV to become free", 2474 noStackTrace: true, 2475 }, 2476 }, 2477 []*regexp.Regexp{}, 2478 }, 2479 { 2480 // Custom vfs error printed by older versions of the kernel, see #3621. 2481 []byte("VFS: Close: file count is 0"), 2482 []oopsFormat{ 2483 { 2484 title: compile("VFS: Close: file count is 0"), 2485 fmt: "VFS: Close: file count is zero (use-after-free)", 2486 noStackTrace: true, 2487 }, 2488 }, 2489 []*regexp.Regexp{}, 2490 }, 2491 { 2492 // Custom vfs error printed by older versions of the kernel, see #3621. 2493 []byte("VFS: Busy inodes after unmount"), 2494 []oopsFormat{ 2495 { 2496 title: compile("VFS: Busy inodes after unmount"), 2497 fmt: "VFS: Busy inodes after unmount (use-after-free)", 2498 noStackTrace: true, 2499 }, 2500 }, 2501 []*regexp.Regexp{}, 2502 }, 2503 { 2504 []byte("Internal error:"), 2505 []oopsFormat{ 2506 { 2507 title: compile("Internal error:"), 2508 fmt: "Internal error in %[1]v", 2509 // arm64 shows some crashes as "Internal error: synchronous external abort", 2510 // while arm shows the same crash as "Unable to handle kernel paging request", 2511 // so we need to merge them. 2512 alt: []string{"bad-access in %[1]v"}, 2513 stack: &stackFmt{ 2514 parts: []*regexp.Regexp{ 2515 linuxRipFrame, 2516 linuxCallTrace, 2517 parseStackTrace, 2518 }, 2519 }, 2520 }, 2521 }, 2522 []*regexp.Regexp{}, 2523 }, 2524 { 2525 []byte("Unhandled fault:"), 2526 []oopsFormat{ 2527 { 2528 title: compile("Unhandled fault:"), 2529 fmt: "Unhandled fault in %[1]v", 2530 // x86_64 shows NULL derefs as "general protection fault", 2531 // while arm shows the same crash as "Unhandled fault: page domain fault". 2532 alt: []string{"bad-access in %[1]v"}, 2533 stack: &stackFmt{ 2534 parts: []*regexp.Regexp{ 2535 linuxRipFrame, 2536 linuxCallTrace, 2537 parseStackTrace, 2538 }, 2539 }, 2540 }, 2541 }, 2542 []*regexp.Regexp{}, 2543 }, 2544 { 2545 []byte("Alignment trap:"), 2546 []oopsFormat{ 2547 { 2548 title: compile("Alignment trap:"), 2549 fmt: "Alignment trap in %[1]v", 2550 stack: &stackFmt{ 2551 parts: []*regexp.Regexp{ 2552 linuxRipFrame, 2553 linuxCallTrace, 2554 parseStackTrace, 2555 }, 2556 }, 2557 }, 2558 }, 2559 []*regexp.Regexp{}, 2560 }, 2561 { 2562 []byte("trusty: panic"), 2563 []oopsFormat{ 2564 { 2565 title: compile("trusty: panic.* ASSERT FAILED"), 2566 report: compile("trusty: panic \\(.*?\\):(?: DEBUG)? ASSERT FAILED at \\(.*?\\): (.+)"), 2567 fmt: "trusty: ASSERT FAILED: %[1]v", 2568 noStackTrace: true, 2569 }, 2570 { 2571 title: compile("trusty: panic.* ASSERT FAILED.*: *(.*)"), 2572 fmt: "trusty: ASSERT FAILED: %[1]v", 2573 corrupted: true, 2574 }, 2575 { 2576 title: compile("trusty: panic"), 2577 report: compile("trusty: panic \\(.*?\\): (.+)"), 2578 fmt: "trusty: panic: %[1]v", 2579 noStackTrace: true, 2580 }, 2581 }, 2582 []*regexp.Regexp{}, 2583 }, 2584 &groupGoRuntimeErrors, 2585 }, commonOopses...)