| // Copyright 2017 syzkaller project authors. All rights reserved. |
| // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. |
| |
| // +build aetest |
| |
| package dash |
| |
| import ( |
| "fmt" |
| "strings" |
| "testing" |
| |
| "github.com/google/syzkaller/pkg/email" |
| ) |
| |
| func TestEmailReport(t *testing.T) { |
| c := NewCtx(t) |
| defer c.Close() |
| |
| build := testBuild(1) |
| c.client2.UploadBuild(build) |
| |
| crash := testCrash(build, 1) |
| crash.Maintainers = []string{`"Foo Bar" <foo@bar.com>`, `bar@foo.com`} |
| c.client2.ReportCrash(crash) |
| |
| // Report the crash over email and check all fields. |
| var sender0, extBugID0, body0 string |
| { |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 1) |
| msg := <-c.emailSink |
| sender0 = msg.Sender |
| body0 = msg.Body |
| sender, extBugID, err := email.RemoveAddrContext(msg.Sender) |
| if err != nil { |
| t.Fatalf("failed to remove sender context: %v", err) |
| } |
| extBugID0 = extBugID |
| _, dbCrash, dbBuild := c.loadBug(extBugID0) |
| crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log) |
| kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) |
| c.expectEQ(sender, fromAddr(c.ctx)) |
| to := config.Namespaces["test2"].Reporting[0].Config.(*EmailConfig).Email |
| c.expectEQ(msg.To, []string{to}) |
| c.expectEQ(msg.Subject, crash.Title) |
| c.expectEQ(len(msg.Attachments), 0) |
| body := fmt.Sprintf(`Hello, |
| |
| syzbot found the following crash on: |
| |
| HEAD commit: 111111111111 kernel_commit_title1 |
| git tree: repo1/branch1 |
| console output: %[2]v |
| kernel config: %[3]v |
| dashboard link: https://testapp.appspot.com/bug?extid=%[1]v |
| compiler: compiler1 |
| CC: [bar@foo.com foo@bar.com] |
| |
| Unfortunately, I don't have any reproducer for this crash yet. |
| |
| IMPORTANT: if you fix the bug, please add the following tag to the commit: |
| Reported-by: syzbot+%[1]v@testapp.appspotmail.com |
| |
| report1 |
| |
| --- |
| This bug is generated by a bot. It may contain errors. |
| See https://goo.gl/tpsmEJ for more information about syzbot. |
| syzbot engineers can be reached at syzkaller@googlegroups.com. |
| |
| syzbot will keep track of this bug report. See: |
| https://goo.gl/tpsmEJ#bug-status-tracking for how to communicate with syzbot.`, |
| extBugID0, crashLogLink, kernelConfigLink) |
| if msg.Body != body { |
| t.Fatalf("got email body:\n%s\n\nwant:\n%s", msg.Body, body) |
| } |
| c.checkURLContents(crashLogLink, crash.Log) |
| c.checkURLContents(kernelConfigLink, build.KernelConfig) |
| } |
| |
| // Emulate receive of the report from a mailing list. |
| // This should update the bug with the link/Message-ID. |
| // nolint: lll |
| incoming1 := fmt.Sprintf(`Sender: syzkaller@googlegroups.com |
| Date: Tue, 15 Aug 2017 14:59:00 -0700 |
| Message-ID: <1234> |
| Subject: crash1 |
| From: %v |
| To: foo@bar.com |
| Content-Type: text/plain |
| |
| Hello |
| |
| syzbot will keep track of this bug report. |
| If you forgot to add the Reported-by tag, once the fix for this bug is merged |
| into any tree, please reply to this email with: |
| #syz fix: exact-commit-title |
| To mark this as a duplicate of another syzbot report, please reply with: |
| #syz dup: exact-subject-of-another-report |
| If it's a one-off invalid bug report, please reply with: |
| #syz invalid |
| |
| -- |
| You received this message because you are subscribed to the Google Groups "syzkaller" group. |
| To unsubscribe from this group and stop receiving emails from it, send an email to syzkaller+unsubscribe@googlegroups.com. |
| To post to this group, send email to syzkaller@googlegroups.com. |
| To view this discussion on the web visit https://groups.google.com/d/msgid/syzkaller/1234@google.com. |
| For more options, visit https://groups.google.com/d/optout. |
| `, sender0) |
| |
| c.expectOK(c.POST("/_ah/mail/", incoming1)) |
| |
| // Emulate that somebody sends us our own email back without quoting. |
| // We used to extract "#syz fix: exact-commit-title" from it. |
| c.incomingEmail(sender0, body0) |
| |
| // Now report syz reproducer and check updated email. |
| crash.ReproOpts = []byte("repro opts") |
| crash.ReproSyz = []byte("getpid()") |
| syzRepro := []byte(fmt.Sprintf("%s#%s\n%s", syzReproPrefix, crash.ReproOpts, crash.ReproSyz)) |
| c.client2.ReportCrash(crash) |
| |
| { |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 1) |
| msg := <-c.emailSink |
| c.expectEQ(msg.Sender, sender0) |
| sender, _, err := email.RemoveAddrContext(msg.Sender) |
| if err != nil { |
| t.Fatalf("failed to remove sender context: %v", err) |
| } |
| _, dbCrash, dbBuild := c.loadBug(extBugID0) |
| reproSyzLink := externalLink(c.ctx, textReproSyz, dbCrash.ReproSyz) |
| crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log) |
| kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) |
| c.expectEQ(sender, fromAddr(c.ctx)) |
| to := []string{ |
| "bugs@syzkaller.com", |
| "default@sender.com", // This is from incomingEmail. |
| "foo@bar.com", |
| config.Namespaces["test2"].Reporting[0].Config.(*EmailConfig).Email, |
| } |
| c.expectEQ(msg.To, to) |
| c.expectEQ(msg.Subject, "Re: "+crash.Title) |
| c.expectEQ(len(msg.Attachments), 0) |
| c.expectEQ(msg.Headers["In-Reply-To"], []string{"<1234>"}) |
| body := fmt.Sprintf(`syzbot has found a reproducer for the following crash on: |
| |
| HEAD commit: 111111111111 kernel_commit_title1 |
| git tree: repo1/branch1 |
| console output: %[3]v |
| kernel config: %[4]v |
| dashboard link: https://testapp.appspot.com/bug?extid=%[1]v |
| compiler: compiler1 |
| syzkaller repro:%[2]v |
| CC: [bar@foo.com foo@bar.com] |
| |
| IMPORTANT: if you fix the bug, please add the following tag to the commit: |
| Reported-by: syzbot+%[1]v@testapp.appspotmail.com |
| |
| report1 |
| `, extBugID0, reproSyzLink, crashLogLink, kernelConfigLink) |
| if msg.Body != body { |
| t.Fatalf("got email body:\n%s\n\nwant:\n%s", msg.Body, body) |
| } |
| c.checkURLContents(reproSyzLink, syzRepro) |
| c.checkURLContents(crashLogLink, crash.Log) |
| c.checkURLContents(kernelConfigLink, build.KernelConfig) |
| } |
| |
| // Now upstream the bug and check that it reaches the next reporting. |
| c.incomingEmail(sender0, "#syz upstream") |
| |
| sender1, extBugID1 := "", "" |
| { |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 1) |
| msg := <-c.emailSink |
| sender1 = msg.Sender |
| if sender1 == sender0 { |
| t.Fatalf("same ID in different reporting") |
| } |
| sender, extBugID, err := email.RemoveAddrContext(msg.Sender) |
| if err != nil { |
| t.Fatalf("failed to remove sender context: %v", err) |
| } |
| extBugID1 = extBugID |
| _, dbCrash, dbBuild := c.loadBug(extBugID1) |
| reproSyzLink := externalLink(c.ctx, textReproSyz, dbCrash.ReproSyz) |
| crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log) |
| kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) |
| c.expectEQ(sender, fromAddr(c.ctx)) |
| c.expectEQ(msg.To, []string{"bar@foo.com", "bugs@syzkaller.com", |
| "default@maintainers.com", "foo@bar.com"}) |
| c.expectEQ(msg.Subject, crash.Title) |
| c.expectEQ(len(msg.Attachments), 0) |
| body := fmt.Sprintf(`Hello, |
| |
| syzbot found the following crash on: |
| |
| HEAD commit: 111111111111 kernel_commit_title1 |
| git tree: repo1/branch1 |
| console output: %[3]v |
| kernel config: %[4]v |
| dashboard link: https://testapp.appspot.com/bug?extid=%[1]v |
| compiler: compiler1 |
| syzkaller repro:%[2]v |
| |
| IMPORTANT: if you fix the bug, please add the following tag to the commit: |
| Reported-by: syzbot+%[1]v@testapp.appspotmail.com |
| |
| report1 |
| |
| --- |
| This bug is generated by a bot. It may contain errors. |
| See https://goo.gl/tpsmEJ for more information about syzbot. |
| syzbot engineers can be reached at syzkaller@googlegroups.com. |
| |
| syzbot will keep track of this bug report. See: |
| https://goo.gl/tpsmEJ#bug-status-tracking for how to communicate with syzbot. |
| syzbot can test patches for this bug, for details see: |
| https://goo.gl/tpsmEJ#testing-patches`, |
| extBugID1, reproSyzLink, crashLogLink, kernelConfigLink) |
| if msg.Body != body { |
| t.Fatalf("got email body:\n%s\n\nwant:\n%s", msg.Body, body) |
| } |
| c.checkURLContents(reproSyzLink, syzRepro) |
| c.checkURLContents(crashLogLink, crash.Log) |
| c.checkURLContents(kernelConfigLink, build.KernelConfig) |
| } |
| |
| // Model that somebody adds more emails to CC list. |
| incoming3 := fmt.Sprintf(`Sender: syzkaller@googlegroups.com |
| Date: Tue, 15 Aug 2017 14:59:00 -0700 |
| Message-ID: <1234> |
| Subject: crash1 |
| From: foo@bar.com |
| To: %v |
| CC: new@new.com, "another" <another@another.com>, bar@foo.com, bugs@syzkaller.com, foo@bar.com |
| Content-Type: text/plain |
| |
| +more people |
| `, sender1) |
| |
| c.expectOK(c.POST("/_ah/mail/", incoming3)) |
| |
| // Now upload a C reproducer. |
| build2 := testBuild(2) |
| build2.KernelCommitTitle = "a really long title, longer than 80 chars, really long-long-long-long-long-long title" |
| c.client2.UploadBuild(build2) |
| crash.BuildID = build2.ID |
| crash.ReproC = []byte("int main() {}") |
| crash.Maintainers = []string{"\"qux\" <qux@qux.com>"} |
| c.client2.ReportCrash(crash) |
| |
| { |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 1) |
| msg := <-c.emailSink |
| c.expectEQ(msg.Sender, sender1) |
| sender, _, err := email.RemoveAddrContext(msg.Sender) |
| if err != nil { |
| t.Fatalf("failed to remove sender context: %v", err) |
| } |
| _, dbCrash, dbBuild := c.loadBug(extBugID1) |
| reproCLink := externalLink(c.ctx, textReproC, dbCrash.ReproC) |
| reproSyzLink := externalLink(c.ctx, textReproSyz, dbCrash.ReproSyz) |
| crashLogLink := externalLink(c.ctx, textCrashLog, dbCrash.Log) |
| kernelConfigLink := externalLink(c.ctx, textKernelConfig, dbBuild.KernelConfig) |
| c.expectEQ(sender, fromAddr(c.ctx)) |
| c.expectEQ(msg.To, []string{"another@another.com", "bar@foo.com", "bugs@syzkaller.com", |
| "default@maintainers.com", "foo@bar.com", "new@new.com", "qux@qux.com"}) |
| c.expectEQ(msg.Subject, "Re: "+crash.Title) |
| c.expectEQ(len(msg.Attachments), 0) |
| body := fmt.Sprintf(`syzbot has found a reproducer for the following crash on: |
| |
| HEAD commit: 222222222222 a really long title, longer than 80 chars, re.. |
| git tree: repo2/branch2 |
| console output: %[4]v |
| kernel config: %[5]v |
| dashboard link: https://testapp.appspot.com/bug?extid=%[1]v |
| compiler: compiler2 |
| syzkaller repro:%[3]v |
| C reproducer: %[2]v |
| |
| IMPORTANT: if you fix the bug, please add the following tag to the commit: |
| Reported-by: syzbot+%[1]v@testapp.appspotmail.com |
| |
| report1 |
| `, extBugID1, reproCLink, reproSyzLink, crashLogLink, kernelConfigLink) |
| if msg.Body != body { |
| t.Fatalf("got email body:\n%s\n\nwant:\n%s", msg.Body, body) |
| } |
| c.checkURLContents(reproCLink, crash.ReproC) |
| c.checkURLContents(reproSyzLink, syzRepro) |
| c.checkURLContents(crashLogLink, crash.Log) |
| c.checkURLContents(kernelConfigLink, build2.KernelConfig) |
| } |
| |
| // Send an invalid command. |
| incoming4 := fmt.Sprintf(`Sender: syzkaller@googlegroups.com |
| Date: Tue, 15 Aug 2017 14:59:00 -0700 |
| Message-ID: <abcdef> |
| Subject: title1 |
| From: foo@bar.com |
| To: %v |
| Content-Type: text/plain |
| |
| #syz bad-command |
| `, sender1) |
| |
| c.expectOK(c.POST("/_ah/mail/", incoming4)) |
| |
| { |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 1) |
| msg := <-c.emailSink |
| c.expectEQ(msg.To, []string{"<foo@bar.com>"}) |
| c.expectEQ(msg.Subject, "Re: title1") |
| c.expectEQ(msg.Headers["In-Reply-To"], []string{"<abcdef>"}) |
| if !strings.Contains(msg.Body, `> #syz bad-command |
| |
| unknown command "bad-command" |
| `) { |
| t.Fatal("no unknown command reply for bad command") |
| } |
| } |
| |
| // Now mark the bug as fixed. |
| c.incomingEmail(sender1, "#syz fix: some: commit title") |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 0) |
| |
| // Check that the commit is now passed to builders. |
| builderPollResp, _ := c.client2.BuilderPoll(build.Manager) |
| c.expectEQ(len(builderPollResp.PendingCommits), 1) |
| c.expectEQ(builderPollResp.PendingCommits[0], "some: commit title") |
| |
| build3 := testBuild(3) |
| build3.Manager = build.Manager |
| build3.Commits = []string{"some: commit title"} |
| c.client2.UploadBuild(build3) |
| |
| build4 := testBuild(4) |
| build4.Manager = build2.Manager |
| build4.Commits = []string{"some: commit title"} |
| c.client2.UploadBuild(build4) |
| |
| // New crash must produce new bug in the first reporting. |
| c.client2.ReportCrash(crash) |
| { |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 1) |
| msg := <-c.emailSink |
| c.expectEQ(msg.Subject, crash.Title+" (2)") |
| if msg.Sender == sender0 { |
| t.Fatalf("same reporting ID for new bug") |
| } |
| } |
| } |
| |
| // Bug must not be mailed to maintainers if maintainers list is empty. |
| func TestEmailNoMaintainers(t *testing.T) { |
| c := NewCtx(t) |
| defer c.Close() |
| |
| build := testBuild(1) |
| c.client2.UploadBuild(build) |
| |
| crash := testCrash(build, 1) |
| c.client2.ReportCrash(crash) |
| |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 1) |
| sender := (<-c.emailSink).Sender |
| |
| incoming1 := fmt.Sprintf(`Sender: syzkaller@googlegroups.com |
| Date: Tue, 15 Aug 2017 14:59:00 -0700 |
| Message-ID: <1234> |
| Subject: crash1 |
| From: %v |
| To: foo@bar.com |
| Content-Type: text/plain |
| |
| #syz upstream |
| `, sender) |
| c.expectOK(c.POST("/_ah/mail/", incoming1)) |
| |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 0) |
| } |
| |
| // Basic dup scenario: mark one bug as dup of another. |
| func TestEmailDup(t *testing.T) { |
| c := NewCtx(t) |
| defer c.Close() |
| |
| build := testBuild(1) |
| c.client2.UploadBuild(build) |
| |
| crash1 := testCrash(build, 1) |
| crash1.Title = "BUG: slightly more elaborate title" |
| c.client2.ReportCrash(crash1) |
| |
| crash2 := testCrash(build, 2) |
| crash1.Title = "KASAN: another title" |
| c.client2.ReportCrash(crash2) |
| |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 2) |
| msg1 := <-c.emailSink |
| msg2 := <-c.emailSink |
| |
| // Dup crash2 to crash1. |
| c.incomingEmail(msg2.Sender, "#syz dup: BUG: slightly more elaborate title") |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 0) |
| |
| // Second crash happens again |
| crash2.ReproC = []byte("int main() {}") |
| c.client2.ReportCrash(crash2) |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 0) |
| |
| // Now close the original bug, and check that new bugs for dup are now created. |
| c.incomingEmail(msg1.Sender, "#syz invalid") |
| |
| // New crash must produce new bug in the first reporting. |
| c.client2.ReportCrash(crash2) |
| { |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 1) |
| msg := <-c.emailSink |
| c.expectEQ(msg.Subject, crash2.Title+" (2)") |
| } |
| } |
| |
| func TestEmailUndup(t *testing.T) { |
| c := NewCtx(t) |
| defer c.Close() |
| |
| build := testBuild(1) |
| c.client2.UploadBuild(build) |
| |
| crash1 := testCrash(build, 1) |
| crash1.Title = "BUG: slightly more elaborate title" |
| c.client2.ReportCrash(crash1) |
| |
| crash2 := testCrash(build, 2) |
| crash1.Title = "KASAN: another title" |
| c.client2.ReportCrash(crash2) |
| |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 2) |
| msg1 := <-c.emailSink |
| msg2 := <-c.emailSink |
| |
| // Dup crash2 to crash1. |
| c.incomingEmail(msg2.Sender, "#syz dup: BUG: slightly more elaborate title") |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 0) |
| |
| // Undup crash2. |
| c.incomingEmail(msg2.Sender, "#syz undup") |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 0) |
| |
| // Now close the original bug, and check that new crashes for the dup does not create bugs. |
| c.incomingEmail(msg1.Sender, "#syz invalid") |
| c.client2.ReportCrash(crash2) |
| c.expectOK(c.GET("/email_poll")) |
| c.expectEQ(len(c.emailSink), 0) |
| } |