providers/redhat/package_feed.go (64 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package redhat import ( "sort" "github.com/facebookincubator/flog" "github.com/facebookincubator/nvdtools/providers/redhat/schema" "github.com/facebookincubator/nvdtools/rpm" "github.com/facebookincubator/nvdtools/wfn" "github.com/pkg/errors" ) // packageFeed is an association between package names and the list of CVEs, // fixed or not, that have been recording against that package. // Packages are identified by their base package names without any epoch, // version, release. type packageFeed map[string][]*schema.CVE // addPackage adds pkg to the list of packages only if not already there. func addPackage(pkgs []string, pkg string) []string { for _, p := range pkgs { if p == pkg { return pkgs } } return append(pkgs, pkg) } // packageFeed transforms a Feed into a packageFeed. func (feed *Feed) packageFeed() packageFeed { if feed.pkg2CVE != nil { return feed.pkg2CVE } pkgFeed := packageFeed{} for _, cve := range feed.Data { var pkgs []string // 1. look at AffectedRelease. for _, ar := range cve.AffectedRelease { if ar.Package == "" { continue } // Failing to parse a package isn't fatal, but we want to surface the error rpmPkg, err := rpm.Parse(ar.Package) if err != nil { flog.Errorf("feed: failed to parse package: %q", ar.Package) continue } pkgs = addPackage(pkgs, rpmPkg.Name) } // 2. look at PackageState. for _, ps := range cve.PackageState { if ps.PackageName == "" { continue } pkgs = addPackage(pkgs, ps.PackageName) } for _, pkg := range pkgs { pkgFeed[pkg] = append(pkgFeed[pkg], cve) } } feed.pkg2CVE = pkgFeed return pkgFeed } // ListFixedCVEs will return the list of CVEs that aren't applicable for the // given (distro, package). Those CVEs could be not applicable for various // reasons. For instance for packaged version isn't vulnerable or a fix has // been backported. // distro is a CPE identifying a distribution. // pkg is the full package name as reported, for instance by rpm -qa. func (feed *Feed) ListFixedCVEs(d *wfn.Attributes, p *rpm.Package) ([]string, error) { pkgFeed := feed.packageFeed() checker, err := feed.Checker() if err != nil { return nil, errors.Wrapf(err, "list") } var cves []string for _, cve := range pkgFeed[p.Name] { if checker.Check(p, d, cve.Name) { cves = append(cves, cve.Name) } } // Sort for deterministic output. sort.Strings(cves) return cves, nil }