aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--syz-cluster/dashboard/handler.go14
-rw-r--r--syz-cluster/dashboard/templates/series.html6
-rw-r--r--syz-cluster/pkg/api/api.go13
-rw-r--r--syz-cluster/pkg/controller/api_test.go11
-rw-r--r--syz-cluster/pkg/db/entities.go15
-rw-r--r--syz-cluster/pkg/db/migrations/1_initialize.up.sql5
-rw-r--r--syz-cluster/pkg/service/finding.go29
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.