Skip to content

Commit eee64c5

Browse files
committed
internal/report: improve cve5ToReport
- Consider all "affected" blocks instead of just the first one. - More cleverly account for vendor/product/package data. For example, ignore it if it is "n/a", or if it is merely a suffix of the module path we already have. - Attempt to populate version data. Skip the test that checks if v4 and v5 are handled equivalently, as we are now taking into account data that is only available in v5. Change-Id: Ibf46c2ad77bad6d72b50ed21b136e5ee014a99f8 Reviewed-on: https://go-review.googlesource.com/c/vulndb/+/548057 Reviewed-by: Sarawut Wansee <[email protected]> Reviewed-by: Damien Neil <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 625c3c9 commit eee64c5

12 files changed

+236
-39
lines changed

internal/cveschema5/cveschema5.go

+3
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@ type VersionRange struct {
9595
Fixed Version `json:"lessThan"`
9696
Status VersionStatus `json:"status"`
9797
VersionType string `json:"versionType"`
98+
99+
// Not used in Go CVEs, but supported in the schema.
100+
LessThanOrEqual Version `json:"lessThanOrEqual,omitempty"`
98101
}
99102

100103
type VersionStatus string

internal/report/cve.go

+129-30
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@
55
package report
66

77
import (
8+
"fmt"
89
"regexp"
910
"strings"
1011

1112
"golang.org/x/vulndb/internal/cveschema"
1213
"golang.org/x/vulndb/internal/cveschema5"
1314
"golang.org/x/vulndb/internal/proxy"
1415
"golang.org/x/vulndb/internal/stdlib"
16+
"golang.org/x/vulndb/internal/version"
1517
)
1618

1719
func vendor(modulePath string) string {
@@ -133,38 +135,9 @@ func cve5ToReport(c *cveschema5.CVERecord, id, modulePath string) *Report {
133135
refs = append(refs, referenceFromUrl(ref.URL))
134136
}
135137

136-
// For now, use the first product name as the package path.
137-
// TODO(tatianabradley): Make this more sophisticated, to consider
138-
// all the blocks in cna.Affected, versions, etc.
139-
var pkgPath string
140-
if affected := cna.Affected; len(affected) > 0 {
141-
pkgPath = affected[0].Product
142-
}
143-
if stdlib.Contains(modulePath) {
144-
pkgPath = modulePath
145-
modulePath = stdlib.ModulePath
146-
}
147-
if modulePath == "" {
148-
modulePath = "TODO"
149-
}
150-
if pkgPath == "" {
151-
pkgPath = modulePath
152-
}
153-
modules := []*Module{
154-
{
155-
Module: modulePath,
156-
Versions: nil,
157-
Packages: []*Package{
158-
{
159-
Package: pkgPath,
160-
},
161-
},
162-
},
163-
}
164-
165138
r := &Report{
166139
ID: id,
167-
Modules: modules,
140+
Modules: affectedToModules(cna.Affected, modulePath),
168141
Summary: Summary(cna.Title),
169142
Description: description,
170143
Credits: credits,
@@ -185,3 +158,129 @@ func getCWE5(c *cveschema5.CNAPublishedContainer) string {
185158
func isGoCNA5(c *cveschema5.CNAPublishedContainer) bool {
186159
return c.ProviderMetadata.OrgID == GoOrgUUID
187160
}
161+
162+
func affectedToModules(as []cveschema5.Affected, modulePath string) []*Module {
163+
// Use a placeholder module if there is no information on
164+
// modules/packages in the CVE.
165+
if len(as) == 0 {
166+
return []*Module{{
167+
Module: modulePath,
168+
}}
169+
}
170+
171+
var modules []*Module
172+
for _, a := range as {
173+
modules = append(modules, affectedToModule(&a, modulePath))
174+
}
175+
176+
return modules
177+
}
178+
179+
func affectedToModule(a *cveschema5.Affected, modulePath string) *Module {
180+
var pkgPath string
181+
isSet := func(s string) bool {
182+
const na = "n/a"
183+
return s != "" && s != na
184+
}
185+
switch {
186+
case isSet(a.PackageName):
187+
pkgPath = a.PackageName
188+
case isSet(a.Product):
189+
pkgPath = a.Product
190+
case isSet(a.Vendor):
191+
pkgPath = a.Vendor
192+
default:
193+
pkgPath = modulePath
194+
}
195+
196+
// If the package path is just a suffix of the modulePath,
197+
// it is probably not useful.
198+
if strings.HasSuffix(modulePath, pkgPath) {
199+
pkgPath = modulePath
200+
}
201+
202+
if stdlib.Contains(pkgPath) {
203+
if strings.HasPrefix(pkgPath, stdlib.ToolchainModulePath) {
204+
modulePath = stdlib.ToolchainModulePath
205+
} else {
206+
modulePath = stdlib.ModulePath
207+
}
208+
}
209+
210+
var symbols []string
211+
for _, s := range a.ProgramRoutines {
212+
symbols = append(symbols, s.Name)
213+
}
214+
215+
vs, uvs := convertVersions(a.Versions, a.DefaultStatus)
216+
217+
return &Module{
218+
Module: modulePath,
219+
Versions: vs,
220+
UnsupportedVersions: uvs,
221+
Packages: []*Package{
222+
{
223+
Package: pkgPath,
224+
Symbols: symbols,
225+
GOOS: a.Platforms,
226+
},
227+
},
228+
}
229+
}
230+
231+
func convertVersions(vrs []cveschema5.VersionRange, defaultStatus cveschema5.VersionStatus) (vs []VersionRange, uvs []UnsupportedVersion) {
232+
for _, vr := range vrs {
233+
// Version ranges starting with "n/a" don't have any meaningful data.
234+
if vr.Introduced == "n/a" {
235+
continue
236+
}
237+
v, ok := toVersionRange(&vr, defaultStatus)
238+
if ok {
239+
vs = append(vs, *v)
240+
continue
241+
}
242+
uvs = append(uvs, toUnsupported(&vr, defaultStatus))
243+
}
244+
return vs, uvs
245+
}
246+
247+
func toVersionRange(cvr *cveschema5.VersionRange, defaultStatus cveschema5.VersionStatus) (*VersionRange, bool) {
248+
// For now, we only support version ranges that are easy to convert to our format.
249+
if cvr.VersionType != typeSemver ||
250+
cvr.LessThanOrEqual != "" ||
251+
!version.IsValid(string(cvr.Introduced)) ||
252+
!version.IsValid(string(cvr.Fixed)) ||
253+
cvr.Status != cveschema5.StatusAffected ||
254+
defaultStatus != cveschema5.StatusUnaffected {
255+
return nil, false
256+
}
257+
258+
introduced := string(cvr.Introduced)
259+
if introduced == "0" {
260+
introduced = ""
261+
}
262+
263+
return &VersionRange{
264+
Introduced: introduced,
265+
Fixed: string(cvr.Fixed),
266+
}, true
267+
}
268+
269+
func toUnsupported(cvr *cveschema5.VersionRange, defaultStatus cveschema5.VersionStatus) UnsupportedVersion {
270+
var version string
271+
switch {
272+
case cvr.Fixed != "":
273+
version = fmt.Sprintf("%s from %s before %s", cvr.Status, cvr.Introduced, cvr.Fixed)
274+
case cvr.LessThanOrEqual != "":
275+
version = fmt.Sprintf("%s from %s to %s", cvr.Status, cvr.Introduced, cvr.Fixed)
276+
default:
277+
version = fmt.Sprintf("%s at %s", cvr.Status, cvr.Introduced)
278+
}
279+
if defaultStatus != "" {
280+
version = fmt.Sprintf("%s (default: %s)", version, defaultStatus)
281+
}
282+
return UnsupportedVersion{
283+
Version: version,
284+
Type: "cve_version_range",
285+
}
286+
}

internal/report/cve_test.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,12 @@ func TestCVE5ToReport(t *testing.T) {
104104
}
105105
}
106106

107-
// Check that the created report is the same for v4 and v5.
108-
// This is a transitional test that will be removed once we are OK
109-
// with divergence between v4 and v5, or if we remove support for v4 entirely.
110107
func TestV4V5Equivalence(t *testing.T) {
108+
// Skip, but leave the test in case it is needed in the course of
109+
// the transition.
110+
// TODO(tatianabradley): Delete this test once we have completed the
111+
// transition to V5.
112+
t.Skip("V4 and V5 are no longer required to be equivalent.")
111113
if err := filepath.WalkDir(filepath.Join(testdata, "TestCVE5ToReport"), func(path string, d fs.DirEntry, err error) error {
112114
if err != nil {
113115
return err

internal/report/testdata/cve/TestCVE5ToReport/CVE-2020-9283.txtar

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ id: PLACEHOLDER-ID
99
modules:
1010
- module: golang.org/x/crypto
1111
packages:
12-
- package: n/a
12+
- package: golang.org/x/crypto
1313
description: |
1414
golang.org/x/crypto before v0.0.0-20200220183623-bac4c82f6975 for Go allows a panic during signature verification in the golang.org/x/crypto/ssh package. A client can attack an SSH server that accepts public keys. Also, a server can attack any SSH client.
1515
cves:

internal/report/testdata/cve/TestCVE5ToReport/CVE-2021-3115.txtar

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Expected output of TestCVE5ToReport/CVE-2021-3115.
77
-- CVE-2021-3115 --
88
id: PLACEHOLDER-ID
99
modules:
10-
- module: std
10+
- module: cmd
1111
packages:
1212
- package: cmd/go
1313
description: |

internal/report/testdata/cve/TestCVE5ToReport/CVE-2022-39213.txtar

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ Expected output of TestCVE5ToReport/CVE-2022-39213.
88
id: PLACEHOLDER-ID
99
modules:
1010
- module: github.com/pandatix/go-cvss
11+
unsupported_versions:
12+
- version: affected at >= 0.2.0, < 0.4.0
13+
type: cve_version_range
1114
packages:
12-
- package: go-cvss
15+
- package: github.com/pandatix/go-cvss
1316
summary: Out-of-bounds Read in go-cvss
1417
description: |
1518
go-cvss is a Go module to manipulate Common Vulnerability Scoring System (CVSS). In affected versions when a full CVSS v2.0 vector string is parsed using `ParseVector`, an Out-of-Bounds Read is possible due to a lack of tests. The Go module will then panic. The problem is patched in tag `v0.4.0`, by the commit `d9d478ff0c13b8b09ace030db9262f3c2fe031f4`. Users are advised to upgrade. Users unable to upgrade may avoid this issue by parsing only CVSS v2.0 vector strings that do not have all attributes defined (e.g. `AV:N/AC:L/Au:N/C:P/I:P/A:C/E:U/RL:OF/RC:C/CDP:MH/TD:H/CR:M/IR:M/AR:M`). As stated in [SECURITY.md](https://github.com/pandatix/go-cvss/blob/master/SECURITY.md), the CPE v2.3 to refer to this Go module is `cpe:2.3:a:pandatix:go_cvss:*:*:*:*:*:*:*:*`. The entry has already been requested to the NVD CPE dictionary.

internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-29407.txtar

+6
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,14 @@ Expected output of TestCVE5ToReport/CVE-2023-29407.
88
id: PLACEHOLDER-ID
99
modules:
1010
- module: golang.org/x/image
11+
versions:
12+
- fixed: 0.10.0
1113
packages:
1214
- package: golang.org/x/image/tiff
15+
symbols:
16+
- newDecoder
17+
- Decode
18+
- DecodeConfig
1319
summary: Excessive CPU consumption when decoding 0-height images in golang.org/x/image/tiff
1420
description: |
1521
A maliciously-crafted image can cause excessive CPU consumption in decoding. A tiled image with a height of 0 and a very large width can cause excessive CPU consumption, despite the image size (width * height) appearing to be zero.

internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-44378.txtar

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ Expected output of TestCVE5ToReport/CVE-2023-44378.
88
id: PLACEHOLDER-ID
99
modules:
1010
- module: github.com/Consensys/gnark
11+
unsupported_versions:
12+
- version: affected at < 0.9.0
13+
type: cve_version_range
1114
packages:
12-
- package: gnark
15+
- package: github.com/Consensys/gnark
1316
summary: gnark vulnerable to unsoundness in variable comparison/non-unique binary decomposition
1417
description: |
1518
gnark is a zk-SNARK library that offers a high-level API to design circuits. Prior to version 0.9.0, for some in-circuit values, it is possible to construct two valid decomposition to bits. In addition to the canonical decomposition of `a`, for small values there exists a second decomposition for `a+r` (where `r` is the modulus the values are being reduced by). The second decomposition was possible due to overflowing the field where the values are defined. Upgrading to version 0.9.0 should fix the issue without needing to change the calls to value comparison methods.

internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45141.txtar

+4-1
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ Expected output of TestCVE5ToReport/CVE-2023-45141.
88
id: PLACEHOLDER-ID
99
modules:
1010
- module: github.com/gofiber/fiber
11+
unsupported_versions:
12+
- version: affected at < 2.50.0
13+
type: cve_version_range
1114
packages:
12-
- package: fiber
15+
- package: github.com/gofiber/fiber
1316
summary: CSRF Token Validation Vulnerability in fiber
1417
description: |
1518
Fiber is an express inspired web framework written in Go. A Cross-Site Request Forgery (CSRF) vulnerability has been identified in the application, which allows an attacker to obtain tokens and forge malicious requests on behalf of a user. This can lead to unauthorized actions being taken on the user's behalf, potentially compromising the security and integrity of the application. The vulnerability is caused by improper validation and enforcement of CSRF tokens within the application. This vulnerability has been addressed in version 2.50.0 and users are advised to upgrade. Users should take additional security measures like captchas or Two-Factor Authentication (2FA) and set Session cookies with SameSite=Lax or SameSite=Secure, and the Secure and HttpOnly attributes.

internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45283.txtar

+59
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,67 @@ Expected output of TestCVE5ToReport/CVE-2023-45283.
88
id: PLACEHOLDER-ID
99
modules:
1010
- module: std
11+
versions:
12+
- fixed: 1.20.11
13+
- introduced: 1.21.0-0
14+
fixed: 1.21.4
1115
packages:
1216
- package: path/filepath
17+
goos:
18+
- windows
19+
symbols:
20+
- Clean
21+
- volumeNameLen
22+
- join
23+
- Abs
24+
- Base
25+
- Dir
26+
- EvalSymlinks
27+
- Glob
28+
- IsLocal
29+
- Join
30+
- Rel
31+
- Split
32+
- VolumeName
33+
- Walk
34+
- WalkDir
35+
- module: std
36+
versions:
37+
- fixed: 1.20.11
38+
- introduced: 1.21.0-0
39+
fixed: 1.21.4
40+
packages:
41+
- package: internal/safefilepath
42+
goos:
43+
- windows
44+
symbols:
45+
- fromFS
46+
- FromFS
47+
- module: std
48+
versions:
49+
- introduced: 1.20.11
50+
fixed: 1.20.12
51+
- introduced: 1.21.4
52+
fixed: 1.21.5
53+
packages:
54+
- package: path/filepath
55+
goos:
56+
- windows
57+
symbols:
58+
- volumeNameLen
59+
- Abs
60+
- Base
61+
- Clean
62+
- Dir
63+
- EvalSymlinks
64+
- Glob
65+
- IsLocal
66+
- Join
67+
- Rel
68+
- Split
69+
- VolumeName
70+
- Walk
71+
- WalkDir
1372
summary: Insecure parsing of Windows paths with a \??\ prefix in path/filepath
1473
description: |
1574
The filepath package does not recognize paths with a \??\ prefix as special. On Windows, a path beginning with \??\ is a Root Local Device path equivalent to a path beginning with \\?\. Paths with a \??\ prefix may be used to access arbitrary locations on the system. For example, the path \??\c:\x is equivalent to the more common path c:\x. Before fix, Clean could convert a rooted path such as \a\..\??\b into the root local device path \??\b. Clean will now convert this to .\??\b. Similarly, Join(\, ??, b) could convert a seemingly innocent sequence of path elements into the root local device path \??\b. Join will now convert this to \.\??\b. In addition, with fix, IsAbs now correctly reports paths beginning with \??\ as absolute, and VolumeName correctly reports the \??\ prefix as a volume name. UPDATE: Go 1.20.11 and Go 1.21.4 inadvertently changed the definition of the volume name in Windows paths starting with \?, resulting in filepath.Clean(\?\c:) returning \?\c: rather than \?\c:\ (among other effects). The previous behavior has been restored.

internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45285.txtar

+5-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ Expected output of TestCVE5ToReport/CVE-2023-45285.
77
-- CVE-2023-45285 --
88
id: PLACEHOLDER-ID
99
modules:
10-
- module: std
10+
- module: cmd
11+
versions:
12+
- fixed: 1.20.12
13+
- introduced: 1.21.0-0
14+
fixed: 1.21.5
1115
packages:
1216
- package: cmd/go
1317
summary: Command 'go get' may unexpectedly fallback to insecure git in cmd/go

internal/report/testdata/cve/TestCVE5ToReport/CVE-2023-45286.txtar

+15
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,23 @@ Expected output of TestCVE5ToReport/CVE-2023-45286.
88
id: PLACEHOLDER-ID
99
modules:
1010
- module: github.com/go-resty/resty/v2
11+
unsupported_versions:
12+
- version: 'unaffected from 0 before 2.10.0 (default: affected)'
13+
type: cve_version_range
1114
packages:
1215
- package: github.com/go-resty/resty/v2
16+
symbols:
17+
- handleRequestBody
18+
- Backoff
19+
- Request.Delete
20+
- Request.Execute
21+
- Request.Get
22+
- Request.Head
23+
- Request.Options
24+
- Request.Patch
25+
- Request.Post
26+
- Request.Put
27+
- Request.Send
1328
summary: HTTP request body disclosure in github.com/go-resty/resty/v2
1429
description: |
1530
A race condition in go-resty can result in HTTP request body disclosure across requests. This condition can be triggered by calling sync.Pool.Put with the same *bytes.Buffer more than once, when request retries are enabled and a retry occurs. The call to sync.Pool.Get will then return a bytes.Buffer that hasn't had bytes.Buffer.Reset called on it. This dirty buffer will contain the HTTP request body from an unrelated request, and go-resty will append the current HTTP request body to it, sending two bodies in one request. The sync.Pool in question is defined at package level scope, so a completely unrelated server could receive the request body.

0 commit comments

Comments
 (0)