From 3c9f0482c172a445a80545c10165229fb3eed4b4 Mon Sep 17 00:00:00 2001 From: Zvonimir Pavlinovic Date: Fri, 15 Dec 2023 20:21:37 +0000 Subject: [PATCH] internal/sarif: add stacks Location information will be added later. Updates golang/go#61347 Change-Id: Ibd6a2f7f6dfd4ac6e333c5de070b76a68e8e462c Reviewed-on: https://go-review.googlesource.com/c/vuln/+/550735 TryBot-Result: Gopher Robot LUCI-TryBot-Result: Go LUCI Reviewed-by: Maceo Thompson Run-TryBot: Zvonimir Pavlinovic --- .../source-call/source_call_sarif.ct | 133 +++++++++++++++++- internal/sarif/handler.go | 44 +++++- 2 files changed, 173 insertions(+), 4 deletions(-) diff --git a/cmd/govulncheck/testdata/testfiles/source-call/source_call_sarif.ct b/cmd/govulncheck/testdata/testfiles/source-call/source_call_sarif.ct index e395dee2..6c79399a 100644 --- a/cmd/govulncheck/testdata/testfiles/source-call/source_call_sarif.ct +++ b/cmd/govulncheck/testdata/testfiles/source-call/source_call_sarif.ct @@ -135,21 +135,148 @@ $ govulncheck -C ${moddir}/vuln -format sarif ./... "level": "error", "message": { "text": "Your code calls vulnerable functions in 1 package (github.com/tidwall/gjson)." - } + }, + "stacks": [ + { + "message": { + "text": "A call stack for vulnerable function github.com/tidwall/gjson.Result.ForEach" + }, + "frames": [ + { + "module": "golang.org/vuln", + "location": { + "physicalLocation": { + "artifactLocation": {}, + "region": {} + }, + "message": {} + } + }, + { + "module": "github.com/tidwall/gjson", + "location": { + "physicalLocation": { + "artifactLocation": {}, + "region": {} + }, + "message": {} + } + }, + { + "module": "github.com/tidwall/gjson", + "location": { + "physicalLocation": { + "artifactLocation": {}, + "region": {} + }, + "message": {} + } + }, + { + "module": "github.com/tidwall/gjson", + "location": { + "physicalLocation": { + "artifactLocation": {}, + "region": {} + }, + "message": {} + } + }, + { + "module": "github.com/tidwall/gjson", + "location": { + "physicalLocation": { + "artifactLocation": {}, + "region": {} + }, + "message": {} + } + }, + { + "module": "github.com/tidwall/gjson", + "location": { + "physicalLocation": { + "artifactLocation": {}, + "region": {} + }, + "message": {} + } + } + ] + } + ] }, { "ruleId": "GO-2021-0113", "level": "error", "message": { "text": "Your code calls vulnerable functions in 1 package (golang.org/x/text/language)." - } + }, + "stacks": [ + { + "message": { + "text": "A call stack for vulnerable function golang.org/x/text/language.Parse" + }, + "frames": [ + { + "module": "golang.org/vuln", + "location": { + "physicalLocation": { + "artifactLocation": {}, + "region": {} + }, + "message": {} + } + }, + { + "module": "golang.org/x/text", + "location": { + "physicalLocation": { + "artifactLocation": {}, + "region": {} + }, + "message": {} + } + } + ] + } + ] }, { "ruleId": "GO-2021-0265", "level": "error", "message": { "text": "Your code calls vulnerable functions in 1 package (github.com/tidwall/gjson)." - } + }, + "stacks": [ + { + "message": { + "text": "A call stack for vulnerable function github.com/tidwall/gjson.Result.Get" + }, + "frames": [ + { + "module": "golang.org/vuln", + "location": { + "physicalLocation": { + "artifactLocation": {}, + "region": {} + }, + "message": {} + } + }, + { + "module": "github.com/tidwall/gjson", + "location": { + "physicalLocation": { + "artifactLocation": {}, + "region": {} + }, + "message": {} + } + } + ] + } + ] }, { "ruleId": "GO-2022-0969", diff --git a/internal/sarif/handler.go b/internal/sarif/handler.go index 253a5add..d6546891 100644 --- a/internal/sarif/handler.go +++ b/internal/sarif/handler.go @@ -163,7 +163,8 @@ func results(h *handler) []Result { RuleID: fs[0].OSV, Level: level(fs[0], h.cfg), Message: Description{Text: resultMessage(fs, h.cfg)}, - // TODO: add location, code flows, and stacks + // TODO: add location and code flows + Stacks: stacks(fs), } results = append(results, res) } @@ -236,3 +237,44 @@ func level(f *govulncheck.Finding, cfg *govulncheck.Config) string { return errorLevel } } + +func stacks(fs []*govulncheck.Finding) []Stack { + if fs[0].Trace[0].Function == "" { // not call level findings + return nil + } + + var stacks []Stack + for _, f := range fs { + stacks = append(stacks, stack(f)) + } + // Sort stacks for deterministic output. We sort by message + // which is effectively sorting by full symbol name. The + // performance should not be an issue here. + sort.SliceStable(stacks, func(i, j int) bool { return stacks[i].Message.Text < stacks[j].Message.Text }) + return stacks +} + +// stack transforms call stack in f to a sarif stack. +func stack(f *govulncheck.Finding) Stack { + trace := f.Trace + + var frames []Frame + for i := len(trace) - 1; i >= 0; i-- { // vulnerable symbol is at the top frame + frame := trace[i] + frames = append(frames, Frame{ + Module: frame.Module, + // TODO: add location + }) + } + + vuln := trace[0] + vulnSym := vuln.Function + if vuln.Receiver != "" { + vulnSym = vuln.Receiver + "." + vulnSym + } + vulnSym = vuln.Package + "." + vulnSym + return Stack{ + Frames: frames, + Message: Description{Text: fmt.Sprintf("A call stack for vulnerable function %s", vulnSym)}, + } +}