diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-09-26 12:02:43 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-09-26 12:02:43 +0200 |
| commit | db716d6653d073b0abfb51186cd4ac2d5418c9c6 (patch) | |
| tree | 3441a3d043c0ef52cbb5241ad283ffaeb6fb968a /pkg | |
| parent | 455b6354e8fc3c74fbbc436cc611f113d884f7a3 (diff) | |
pkg/report: fix guilty file extraction
Account for the case that some file names can appear _before_ crash report starts.
Start extracting guilty file starting from StartPos.
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/report/linux.go | 47 | ||||
| -rw-r--r-- | pkg/report/report.go | 15 | ||||
| -rw-r--r-- | pkg/report/report_test.go | 22 | ||||
| -rw-r--r-- | pkg/report/testdata/linux/guilty/20 | 1 | ||||
| -rw-r--r-- | pkg/report/testdata/linux/guilty/39 | 77 |
5 files changed, 124 insertions, 38 deletions
diff --git a/pkg/report/linux.go b/pkg/report/linux.go index e23f7e32c..1880298b6 100644 --- a/pkg/report/linux.go +++ b/pkg/report/linux.go @@ -27,7 +27,7 @@ type linux struct { consoleOutputRe *regexp.Regexp questionableRe *regexp.Regexp guiltyFileBlacklist []*regexp.Regexp - reportStartIgnores [][]byte + reportStartIgnores []*regexp.Regexp infoMessagesWithStack [][]byte eoi []byte } @@ -82,10 +82,10 @@ func ctorLinux(kernelSrc, kernelObj string, ignores []*regexp.Regexp) (Reporter, regexp.MustCompile(`^fs/proc/generic.c`), } // These pattern do _not_ start a new report, i.e. can be in a middle of another report. - ctx.reportStartIgnores = [][]byte{ - []byte("invalid opcode: 0000"), - []byte("Kernel panic - not syncing: panic_on_warn set"), - []byte("unregister_netdevice: waiting for"), + ctx.reportStartIgnores = []*regexp.Regexp{ + compile(`invalid opcode: 0000`), + compile(`Kernel panic - not syncing: panic_on_warn set`), + compile(`unregister_netdevice: waiting for`), } // These pattern math kernel reports which are not bugs in itself but contain stack traces. // If we see them in the middle of another report, we know that the report is potentially corrupted. @@ -200,14 +200,7 @@ func (ctx *linux) parseOutput(output []byte) ( startPos = pos break } else if secondReportPos == 0 { - ignored := false - for _, ignore := range ctx.reportStartIgnores { - if bytes.Contains(line, ignore) { - ignored = true - break - } - } - if !ignored { + if !matchesAny(line, ctx.reportStartIgnores) { secondReportPos = pos } } @@ -274,20 +267,22 @@ func (ctx *linux) parseOutput(output []byte) ( } func (ctx *linux) Symbolize(rep *Report) error { - if ctx.vmlinux == "" { - return nil - } - symbolized, err := ctx.symbolize(rep.Report) - if err != nil { - return err + if ctx.vmlinux != "" { + symbolized, err := ctx.symbolize(rep.Report) + if err != nil { + return err + } + rep.Report = symbolized } - rep.Report = symbolized - guiltyFile := ctx.extractGuiltyFile(rep.Report) - if guiltyFile != "" { - rep.Maintainers, err = ctx.getMaintainers(guiltyFile) + // We still do this even if we did not symbolize, + // because tests pass in already symbolized input. + rep.guiltyFile = ctx.extractGuiltyFile(rep) + if rep.guiltyFile != "" { + maintainers, err := ctx.getMaintainers(rep.guiltyFile) if err != nil { return err } + rep.Maintainers = maintainers } return nil } @@ -381,7 +376,8 @@ func symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, err return symbolized } -func (ctx *linux) extractGuiltyFile(report []byte) string { +func (ctx *linux) extractGuiltyFile(rep *Report) string { + report := rep.Report[rep.StartPos:] if linuxRcuStall.Match(report) { // Special case for rcu stalls. // There are too many frames that we want to skip before actual guilty frames, @@ -412,6 +408,9 @@ nextFile: } func (ctx *linux) getMaintainers(file string) ([]string, error) { + if ctx.kernelSrc == "" { + return nil, nil + } mtrs, err := ctx.getMaintainersImpl(file, false) if err != nil { return nil, err diff --git a/pkg/report/report.go b/pkg/report/report.go index 27a71e937..e97930fe0 100644 --- a/pkg/report/report.go +++ b/pkg/report/report.go @@ -43,8 +43,10 @@ type Report struct { Corrupted bool // CorruptedReason contains reason why the report is marked as corrupted. CorruptedReason string - // Maintainers is list of maintainer emails. + // Maintainers is list of maintainer emails (filled in by Symbolize). Maintainers []string + // guiltyFile is the source file that we think is to blame for the crash (filled in by Symbolize). + guiltyFile string } // NewReporter creates reporter for the specified OS/Type. @@ -189,17 +191,6 @@ func sanitizeTitle(title string) string { return strings.TrimSpace(string(res)) } -type guilter interface { - extractGuiltyFile([]byte) string -} - -func (wrap reporterWrapper) extractGuiltyFile(report []byte) string { - if g, ok := wrap.Reporter.(guilter); ok { - return g.extractGuiltyFile(report) - } - panic("not implemented") -} - type oops struct { header []byte formats []oopsFormat diff --git a/pkg/report/report_test.go b/pkg/report/report_test.go index 7012b54f2..2eaf54fa6 100644 --- a/pkg/report/report_test.go +++ b/pkg/report/report_test.go @@ -220,8 +220,26 @@ func testGuiltyFile(t *testing.T, reporter Reporter, fn string) { } file := string(data[len(prefix) : len(prefix)+nlnl]) report := data[len(prefix)+nlnl:] - if guilty := reporter.(guilter).extractGuiltyFile(report); guilty != file { - t.Fatalf("got guilty %q, want %q", guilty, file) + rep := reporter.Parse(report) + if rep == nil { + t.Fatalf("did not find crash in the input") + } + // Parse doesn't generally run on already symbolized output, + // but here we run it on symbolized output because we can't symbolize in tests. + // The problem is with duplicated lines due to inlined frames, + // Parse can strip such report after first title line because it thinks + // that the duplicated title line is beginning on another report. + // In such case we restore whole report, but still keep StartPos that + // Parse produces at least in some cases. + if !bytes.HasSuffix(report, rep.Report) { + rep.Report = report + rep.StartPos = 0 + } + if err := reporter.Symbolize(rep); err != nil { + t.Fatalf("failed to symbolize report: %v", err) + } + if rep.guiltyFile != file { + t.Fatalf("got guilty %q, want %q", rep.guiltyFile, file) } } diff --git a/pkg/report/testdata/linux/guilty/20 b/pkg/report/testdata/linux/guilty/20 index 0fc073699..b95a5b74d 100644 --- a/pkg/report/testdata/linux/guilty/20 +++ b/pkg/report/testdata/linux/guilty/20 @@ -1,3 +1,4 @@ FILE: driver/foo/lib/foo.c +WARNING: CPU: 2 PID: 24023 at kernel/locking/lockdep.c:3344 __lock_acquire+0x10e5/0x3690 kernel/locking/lockdep.c:3344 driver/foo/lib/foo.c:10 diff --git a/pkg/report/testdata/linux/guilty/39 b/pkg/report/testdata/linux/guilty/39 new file mode 100644 index 000000000..79bbf1223 --- /dev/null +++ b/pkg/report/testdata/linux/guilty/39 @@ -0,0 +1,77 @@ +FILE: security/apparmor/policy_ns.c + + sock_common_setsockopt+0x9a/0xe0 net/core/sock.c:3038 + __sys_setsockopt+0x1ba/0x3c0 net/socket.c:1902 + __do_sys_setsockopt net/socket.c:1913 [inline] + __se_sys_setsockopt net/socket.c:1910 [inline] + __x64_sys_setsockopt+0xbe/0x150 net/socket.c:1910 + do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290 +================================================================== +BUG: KASAN: global-out-of-bounds in memcmp+0xe3/0x160 lib/string.c:861 +Read of size 1 at addr ffffffff88000008 by task syz-executor0/10914 + + entry_SYSCALL_64_after_hwframe+0x49/0xbe +RIP: 0033:0x457579 +Code: 1d b4 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 eb b3 fb ff c3 66 2e 0f 1f 84 00 00 00 00 +RSP: 002b:00007f4c14533c78 EFLAGS: 00000246 ORIG_RAX: 0000000000000036 +RAX: ffffffffffffffda RBX: 00007f4c14533c90 RCX: 0000000000457579 +RDX: 0000000000000040 RSI: 0000000000000000 RDI: 0000000000000003 +RBP: 000000000072bf00 R08: 0000000000000004 R09: 0000000000000000 +R10: 0000000020000080 R11: 0000000000000246 R12: 00007f4c145346d4 +R13: 00000000004c3ed9 R14: 00000000004d6260 R15: 0000000000000004 +CPU: 0 PID: 10914 Comm: syz-executor0 Not tainted 4.19.0-rc5+ #252 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 +Call Trace: + __dump_stack lib/dump_stack.c:77 [inline] + dump_stack+0x1c4/0x2b4 lib/dump_stack.c:113 + print_address_description.cold.8+0x58/0x1ff mm/kasan/report.c:256 + kasan_report_error mm/kasan/report.c:354 [inline] + kasan_report.cold.9+0x242/0x309 mm/kasan/report.c:412 + __asan_report_load1_noabort+0x14/0x20 mm/kasan/report.c:430 + memcmp+0xe3/0x160 lib/string.c:861 + strnstr+0x4b/0x70 lib/string.c:934 + __aa_lookupn_ns+0xc1/0x570 security/apparmor/policy_ns.c:209 + aa_lookupn_ns+0x88/0x1e0 security/apparmor/policy_ns.c:240 + aa_fqlookupn_profile+0x1b9/0x1010 security/apparmor/policy.c:468 + fqlookupn_profile+0x80/0xc0 security/apparmor/label.c:1844 + aa_label_strn_parse+0xa3a/0x1230 security/apparmor/label.c:1908 + aa_label_parse+0x42/0x50 security/apparmor/label.c:1943 + aa_change_profile+0x513/0x3510 security/apparmor/domain.c:1362 + apparmor_setprocattr+0xa8b/0x1150 security/apparmor/lsm.c:656 + security_setprocattr+0x66/0xc0 security/security.c:1298 + proc_pid_attr_write+0x301/0x540 fs/proc/base.c:2555 + __vfs_write+0x119/0x9f0 fs/read_write.c:485 + vfs_write+0x1fc/0x560 fs/read_write.c:549 + ksys_write+0x101/0x260 fs/read_write.c:598 + __do_sys_write fs/read_write.c:610 [inline] + __se_sys_write fs/read_write.c:607 [inline] + __x64_sys_write+0x73/0xb0 fs/read_write.c:607 + do_syscall_64+0x1b9/0x820 arch/x86/entry/common.c:290 + entry_SYSCALL_64_after_hwframe+0x49/0xbe +RIP: 0033:0x457579 +Code: 1d b4 fb ff c3 66 2e 0f 1f 84 00 00 00 00 00 66 90 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 0f 83 eb b3 fb ff c3 66 2e 0f 1f 84 00 00 00 00 +RSP: 002b:00007f5a92ec2c78 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 +RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 0000000000457579 +RDX: 000000000000002c RSI: 00000000200000c0 RDI: 0000000000000004 +RBP: 000000000072bf00 R08: 0000000000000000 R09: 0000000000000000 +R10: 0000000000000000 R11: 0000000000000246 R12: 00007f5a92ec36d4 +R13: 00000000004c5454 R14: 00000000004d8c78 R15: 00000000ffffffff + +CPU: 1 PID: 10921 Comm: syz-executor3 Not tainted 4.19.0-rc5+ #252 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 +The buggy address belongs to the variable: + __start_rodata+0x8/0x1000 +Call Trace: + __dump_stack lib/dump_stack.c:77 [inline] + dump_stack+0x1c4/0x2b4 lib/dump_stack.c:113 + +Memory state around the buggy address: + ffffffff87ffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + ffffffff87ffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + fail_dump lib/fault-inject.c:51 [inline] + should_fail.cold.4+0xa/0x17 lib/fault-inject.c:149 +ffffffff88000000: 00 fa fa fa fa fa fa fa 00 01 fa fa fa fa fa fa + ^ + ffffffff88000080: 00 00 00 07 fa fa fa fa 00 04 fa fa fa fa fa fa + ffffffff88000100: 05 fa fa fa fa fa fa fa 00 00 00 00 05 fa fa fa +================================================================== |
