From 386a13a4f6d4108b9269dad59211a60b229bc35c Mon Sep 17 00:00:00 2001 From: Alex Goodman Date: Mon, 1 Jun 2020 07:18:17 -0400 Subject: [PATCH] replace dummy matcher with os matcher --- vulnscan/matcher/controller.go | 33 ++++++++++------- vulnscan/matcher/dummy/matcher.go | 27 -------------- vulnscan/matcher/os/matcher.go | 61 +++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 40 deletions(-) delete mode 100644 vulnscan/matcher/dummy/matcher.go create mode 100644 vulnscan/matcher/os/matcher.go diff --git a/vulnscan/matcher/controller.go b/vulnscan/matcher/controller.go index 50d24208..f4a5a1c3 100644 --- a/vulnscan/matcher/controller.go +++ b/vulnscan/matcher/controller.go @@ -1,11 +1,12 @@ package matcher import ( + imgbomOS "github.com/anchore/imgbom/imgbom/os" "github.com/anchore/imgbom/imgbom/pkg" "github.com/anchore/vulnscan/internal/log" - "github.com/anchore/vulnscan/vulnscan/match" - "github.com/anchore/vulnscan/vulnscan/matcher/dummy" + "github.com/anchore/vulnscan/vulnscan/matcher/os" "github.com/anchore/vulnscan/vulnscan/result" + "github.com/anchore/vulnscan/vulnscan/vulnerability" ) var controllerInstance controller @@ -14,7 +15,7 @@ func init() { controllerInstance = controller{ matchers: make(map[pkg.Type][]Matcher), } - controllerInstance.add(&dummy.Matcher{}) + controllerInstance.add(&os.Matcher{}) } type controller struct { @@ -23,28 +24,34 @@ type controller struct { func (c *controller) add(matchers ...Matcher) { for _, m := range matchers { - if _, ok := c.matchers[m.Type()]; ok { - c.matchers[m.Type()] = make([]Matcher, 0) - } + for _, t := range m.Types() { + if _, ok := c.matchers[t]; ok { + c.matchers[t] = make([]Matcher, 0) + } - c.matchers[m.Type()] = append(c.matchers[m.Type()], m) - log.Debugf("adding matcher: %+v", m.Type()) + c.matchers[t] = append(c.matchers[t], m) + log.Debugf("adding matcher: %+v", t) + } } } -// TODO: do we need to pass the entire store? or just a reader interface subset? -func (c *controller) findMatches(s match.Store, packages ...pkg.Package) result.Result { +func (c *controller) findMatches(s vulnerability.Provider, o imgbomOS.OS, packages ...*pkg.Package) result.Result { res := result.NewResult() for _, p := range packages { for _, matchers := range c.matchers { for _, m := range matchers { - res.Add(p, m.Match(s, p)...) + matches, err := m.Match(s, o, p) + if err != nil { + log.Errorf("matcher failed for pkg=%s: %w", p, err) + } else { + res.Add(p, matches...) + } } } } return res } -func FindMatches(s match.Store, packages ...pkg.Package) result.Result { - return controllerInstance.findMatches(s, packages...) +func FindMatches(s vulnerability.Provider, o imgbomOS.OS, packages ...*pkg.Package) result.Result { + return controllerInstance.findMatches(s, o, packages...) } diff --git a/vulnscan/matcher/dummy/matcher.go b/vulnscan/matcher/dummy/matcher.go deleted file mode 100644 index 17cfb457..00000000 --- a/vulnscan/matcher/dummy/matcher.go +++ /dev/null @@ -1,27 +0,0 @@ -package dummy - -import ( - "github.com/anchore/imgbom/imgbom/pkg" - "github.com/anchore/vulnscan-db/pkg/vulnerability" - "github.com/anchore/vulnscan/vulnscan/match" -) - -// TODO: delete me... - -type Matcher struct { -} - -func (m *Matcher) Type() pkg.Type { - return pkg.DebPkg -} - -func (m *Matcher) Match(match.Store, pkg.Package) []match.Match { - return []match.Match{ - { - Confidence: 42, - Vulnerability: vulnerability.Vulnerability{}, - Package: pkg.Package{}, - SearchKey: "the key", - }, - } -} diff --git a/vulnscan/matcher/os/matcher.go b/vulnscan/matcher/os/matcher.go new file mode 100644 index 00000000..5e0a44f5 --- /dev/null +++ b/vulnscan/matcher/os/matcher.go @@ -0,0 +1,61 @@ +package os + +import ( + "fmt" + + "github.com/anchore/imgbom/imgbom/os" + "github.com/anchore/imgbom/imgbom/pkg" + "github.com/anchore/vulnscan/vulnscan/match" + "github.com/anchore/vulnscan/vulnscan/version" + "github.com/anchore/vulnscan/vulnscan/vulnerability" +) + +// TODO: consider renaming this package to DISTRO for easier importing... + +type Matcher struct { +} + +func (m *Matcher) Types() []pkg.Type { + return []pkg.Type{pkg.DebPkg} +} + +func (m *Matcher) Match(store vulnerability.Provider, o os.OS, p *pkg.Package) ([]match.Match, error) { + // TODO: add other kinds of matches? fuzzy matches, etc... + return m.exactPackageNameMatch(store, o, p) +} + +func (m *Matcher) exactPackageNameMatch(store vulnerability.Provider, o os.OS, p *pkg.Package) ([]match.Match, error) { + + matches := make([]match.Match, 0) + + // TODO: there should be a vulnerability object in the vulnscan-db/db/vulnerability for mondel serialization and one here in vulnerability for rich objects + + allPkgVulns, err := store.GetByOs(o, p) + if err != nil { + return nil, fmt.Errorf("matcher failed to fetch os=%s pkg=%s: %w", o, p.Name, err) + } + + verObj, err := version.NewVersionFromPkg(p) + if err != nil { + return nil, fmt.Errorf("matcher failed to parse version pkg=%s ver=%s: %w", p.Name, p.Version, err) + } + + for _, vuln := range allPkgVulns { + // if the constraint it met, then the given package has the vulnerability + satisfied, err := vuln.Constraint.Satisfied(verObj) + if err != nil { + // TODO: not enough information (cannot back track constraint object) + return nil, fmt.Errorf("matcher failed to check constraint=%s version=%s: %w", vuln.Constraint, verObj, err) + } + + if satisfied { + matches = append(matches, match.Match{ + Confidence: 1.0, // TODO: this is hard coded for now + Vulnerability: *vuln, + Package: p, + SearchKey: fmt.Sprintf("%s:%s", p.Name, p.Version), // TODO: better way to signify exact match? + }) + } + } + return matches, nil +}