1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package govulncheck
import (
"strings"
"golang.org/x/mod/semver"
"golang.org/x/vuln/internal"
isem "golang.org/x/vuln/internal/semver"
"golang.org/x/vuln/osv"
"golang.org/x/vuln/vulncheck"
)
// latestFixed returns the latest fixed version in the list of affected ranges,
// or the empty string if there are no fixed versions.
func latestFixed(as []osv.Affected) string {
v := ""
for _, a := range as {
for _, r := range a.Ranges {
if r.Type == osv.TypeSemver {
for _, e := range r.Events {
if e.Fixed != "" && (v == "" ||
semver.Compare(isem.CanonicalizeSemverPrefix(e.Fixed), isem.CanonicalizeSemverPrefix(v)) > 0) {
v = e.Fixed
}
}
}
}
}
return v
}
func foundVersion(modulePath string, moduleVersions map[string]string) string {
var found string
if v := moduleVersions[modulePath]; v != "" {
found = versionString(modulePath, v[1:])
}
return found
}
func fixedVersion(modulePath string, affected []osv.Affected) string {
fixed := latestFixed(affected)
if fixed != "" {
fixed = versionString(modulePath, fixed)
}
return fixed
}
// versionString prepends a version string prefix (`v` or `go`
// depending on the modulePath) to the given semver-style version string.
func versionString(modulePath, version string) string {
if version == "" {
return ""
}
v := "v" + version
if modulePath == internal.GoStdModulePath || modulePath == internal.GoCmdModulePath {
return semverToGoTag(v)
}
return v
}
// highest returns the highest (one with the smallest index) entry in the call
// stack for which f returns true.
func highest(cs []*StackFrame, f func(e *StackFrame) bool) int {
for i := 0; i < len(cs); i++ {
if f(cs[i]) {
return i
}
}
return -1
}
// lowest returns the lowest (one with the largest index) entry in the call
// stack for which f returns true.
func lowest(cs []*StackFrame, f func(e *StackFrame) bool) int {
for i := len(cs) - 1; i >= 0; i-- {
if f(cs[i]) {
return i
}
}
return -1
}
// pkgPath returns the package path from fn.
func pkgPath(fn *vulncheck.FuncNode) string {
if fn.PkgPath != "" {
return fn.PkgPath
}
s := strings.TrimPrefix(fn.RecvType, "*")
if i := strings.LastIndexByte(s, '.'); i > 0 {
s = s[:i]
}
return s
}
// moduleVersionMap builds a map from module paths to versions.
func moduleVersionMap(mods []*vulncheck.Module) map[string]string {
moduleVersions := map[string]string{}
for _, m := range mods {
v := m.Version
if m.Replace != nil {
v = m.Replace.Version
}
moduleVersions[m.Path] = v
}
return moduleVersions
}
// pkgMap creates a map from package paths to packages for all pkgs
// and their transitive imports.
func pkgMap(pkgs []*vulncheck.Package) map[string]*vulncheck.Package {
m := make(map[string]*vulncheck.Package)
var visit func(*vulncheck.Package)
visit = func(p *vulncheck.Package) {
if _, ok := m[p.PkgPath]; ok {
return
}
m[p.PkgPath] = p
for _, i := range p.Imports {
visit(i)
}
}
for _, p := range pkgs {
visit(p)
}
return m
}
|