diff options
| -rw-r--r-- | syz-cluster/dashboard/handler.go | 14 | ||||
| -rw-r--r-- | syz-cluster/dashboard/templates/series.html | 6 | ||||
| -rw-r--r-- | syz-cluster/pkg/api/api.go | 13 | ||||
| -rw-r--r-- | syz-cluster/pkg/controller/api_test.go | 11 | ||||
| -rw-r--r-- | syz-cluster/pkg/db/entities.go | 15 | ||||
| -rw-r--r-- | syz-cluster/pkg/db/migrations/1_initialize.up.sql | 5 | ||||
| -rw-r--r-- | syz-cluster/pkg/service/finding.go | 29 |
7 files changed, 67 insertions, 26 deletions
diff --git a/syz-cluster/dashboard/handler.go b/syz-cluster/dashboard/handler.go index 8799b1550..9b8503df3 100644 --- a/syz-cluster/dashboard/handler.go +++ b/syz-cluster/dashboard/handler.go @@ -258,6 +258,20 @@ func (h *dashboardHandler) findingInfo(w http.ResponseWriter, r *http.Request) e return h.streamBlob(w, finding.ReportURI) case "log": return h.streamBlob(w, finding.LogURI) + case "syz_repro": + opts, err := blob.ReadAllBytes(h.blobStorage, finding.SyzReproOptsURI) + if err != nil { + return err + } + repro, err := blob.ReadAllBytes(h.blobStorage, finding.SyzReproURI) + if err != nil { + return err + } + fmt.Fprintf(w, "# %s\n", opts) + _, err = w.Write(repro) + return err + case "c_repro": + return h.streamBlob(w, finding.CReproURI) default: return fmt.Errorf("%w: unknown key value", errBadRequest) } diff --git a/syz-cluster/dashboard/templates/series.html b/syz-cluster/dashboard/templates/series.html index 9a71e0053..6e01360b1 100644 --- a/syz-cluster/dashboard/templates/series.html +++ b/syz-cluster/dashboard/templates/series.html @@ -154,7 +154,11 @@ {{.Title}} {{end}} </td> - <td><a href="/findings/{{.ID}}/log" class="modal-link-raw">[Log]</a></td> + <td> + {{if .LogURI}}<a href="/findings/{{.ID}}/log" class="modal-link-raw">[Log]</a>{{end}} + {{if .SyzReproURI}}<a href="/findings/{{.ID}}/syz_repro" class="modal-link-raw">[Syz Repro]</a>{{end}} + {{if .CReproURI}}<a href="/findings/{{.ID}}/c_repro" class="modal-link-raw">[C Repro]</a>{{end}} + </td> </tr> {{end}} </tbody> diff --git a/syz-cluster/pkg/api/api.go b/syz-cluster/pkg/api/api.go index 33da0e5ff..3f3a6b089 100644 --- a/syz-cluster/pkg/api/api.go +++ b/syz-cluster/pkg/api/api.go @@ -82,11 +82,14 @@ type BootResult struct { // NewFinding is a kernel crash, boot error, etc. found during a test. type NewFinding struct { - SessionID string `json:"session_id"` - TestName string `json:"test_name"` - Title string `json:"title"` - Report []byte `json:"report"` - Log []byte `json:"log"` + SessionID string `json:"session_id"` + TestName string `json:"test_name"` + Title string `json:"title"` + Report []byte `json:"report"` + Log []byte `json:"log"` + SyzRepro []byte `json:"syz_repro"` + SyzReproOpts []byte `json:"syz_repro_opts"` + CRepro []byte `json:"c_repro"` } type Series struct { diff --git a/syz-cluster/pkg/controller/api_test.go b/syz-cluster/pkg/controller/api_test.go index fa8491208..621be5686 100644 --- a/syz-cluster/pkg/controller/api_test.go +++ b/syz-cluster/pkg/controller/api_test.go @@ -68,10 +68,13 @@ func TestAPISaveFinding(t *testing.T) { t.Run("must succeed", func(t *testing.T) { finding := &api.NewFinding{ - SessionID: sessionID, - TestName: "test", - Report: []byte("report"), - Log: []byte("log"), + SessionID: sessionID, + TestName: "test", + Report: []byte("report"), + Log: []byte("log"), + SyzRepro: []byte("syz repro"), + SyzReproOpts: []byte("syz_repro_opts"), + CRepro: []byte("C repro"), } err = client.UploadFinding(ctx, finding) assert.NoError(t, err) diff --git a/syz-cluster/pkg/db/entities.go b/syz-cluster/pkg/db/entities.go index c6c469131..13c440926 100644 --- a/syz-cluster/pkg/db/entities.go +++ b/syz-cluster/pkg/db/entities.go @@ -121,12 +121,15 @@ type SessionTest struct { } type Finding struct { - ID string `spanner:"ID"` - SessionID string `spanner:"SessionID"` - TestName string `spanner:"TestName"` - Title string `spanner:"Title"` - ReportURI string `spanner:"ReportURI"` - LogURI string `spanner:"LogURI"` + ID string `spanner:"ID"` + SessionID string `spanner:"SessionID"` + TestName string `spanner:"TestName"` + Title string `spanner:"Title"` + ReportURI string `spanner:"ReportURI"` + LogURI string `spanner:"LogURI"` + SyzReproURI string `spanner:"SyzReproURI"` + SyzReproOptsURI string `spanner:"SyzReproOptsURI"` + CReproURI string `spanner:"CReproURI"` } type SessionReport struct { diff --git a/syz-cluster/pkg/db/migrations/1_initialize.up.sql b/syz-cluster/pkg/db/migrations/1_initialize.up.sql index 3100c9bb2..baec817cb 100644 --- a/syz-cluster/pkg/db/migrations/1_initialize.up.sql +++ b/syz-cluster/pkg/db/migrations/1_initialize.up.sql @@ -90,8 +90,11 @@ CREATE TABLE Findings ( SessionID STRING(36) NOT NULL, TestName STRING(256) NOT NULL, Title STRING(256) NOT NULL, - ReportURI STRING(256) NOT NULL, LogURI STRING(256) NOT NULL, + ReportURI STRING(256) NOT NULL, + SyzReproURI STRING(256) NOT NULL, + SyzReproOptsURI STRING(256) NOT NULL, + CReproURI STRING(256) NOT NULL, CONSTRAINT FK_SessionCrashes FOREIGN KEY (SessionID) REFERENCES Sessions (ID), CONSTRAINT FK_TestCrashes FOREIGN KEY (SessionID, TestName) REFERENCES SessionTests (SessionID, TestName), ) PRIMARY KEY (ID); diff --git a/syz-cluster/pkg/service/finding.go b/syz-cluster/pkg/service/finding.go index b668dc798..fb6e2e22e 100644 --- a/syz-cluster/pkg/service/finding.go +++ b/syz-cluster/pkg/service/finding.go @@ -35,19 +35,30 @@ func (s *FindingService) Save(ctx context.Context, req *api.NewFinding) error { Title: req.Title, } var err error - if len(req.Log) > 0 { - finding.LogURI, err = s.blobStorage.Write(bytes.NewReader(req.Log), "Finding", finding.ID, "log") - if err != nil { - return fmt.Errorf("failed to save the log: %w", err) - } + + type saveAsset struct { + saveTo *string + value []byte + name string } - if len(req.Report) > 0 { - finding.ReportURI, err = s.blobStorage.Write(bytes.NewReader(req.Report), "Finding", finding.ID, "report") + + for _, asset := range []saveAsset{ + {&finding.LogURI, req.Log, "log"}, + {&finding.ReportURI, req.Report, "report"}, + {&finding.SyzReproURI, req.SyzRepro, "syz_repro"}, + {&finding.SyzReproOptsURI, req.SyzReproOpts, "syz_repro_opts"}, + {&finding.CReproURI, req.CRepro, "c_repro"}, + } { + if len(asset.value) == 0 { + continue + } + *asset.saveTo, err = s.blobStorage.Write(bytes.NewReader(asset.value), "Finding", finding.ID, asset.name) if err != nil { - return fmt.Errorf("failed to save the report: %w", err) + return fmt.Errorf("failed to save %s: %w", asset.name, err) } } - // TODO: if it's not actually addded, the blob records will be orphaned. + + // TODO: if it's not actually addded, the blobs above will be orphaned. err = s.findingRepo.Save(ctx, finding) if err == db.ErrFindingExists { // It's ok, just ignore. |
