From 8cd7de276e337f2753c72374ab972d6d8e6b1925 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Thu, 16 Sep 2021 22:20:59 +0300 Subject: [PATCH] feat(alpine): support unfixed vulnerabilities (#1235) --- pkg/detector/ospkg/alpine/alpine.go | 56 ++++++++++++++----- pkg/detector/ospkg/alpine/alpine_test.go | 20 ++++++- .../fixtures/{alpine310.yaml => alpine.yaml} | 7 +++ 3 files changed, 67 insertions(+), 16 deletions(-) rename pkg/detector/ospkg/alpine/testdata/fixtures/{alpine310.yaml => alpine.yaml} (81%) diff --git a/pkg/detector/ospkg/alpine/alpine.go b/pkg/detector/ospkg/alpine/alpine.go index ae22c44c3989..98357b9bd04b 100644 --- a/pkg/detector/ospkg/alpine/alpine.go +++ b/pkg/detector/ospkg/alpine/alpine.go @@ -9,6 +9,7 @@ import ( "k8s.io/utils/clock" ftypes "github.com/aquasecurity/fanal/types" + dbTypes "github.com/aquasecurity/trivy-db/pkg/types" "github.com/aquasecurity/trivy-db/pkg/vulnsrc/alpine" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/scanner/utils" @@ -100,26 +101,55 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV } for _, adv := range advisories { - fixedVersion, err := version.NewVersion(adv.FixedVersion) - if err != nil { - log.Logger.Debugf("failed to parse Alpine Linux fixed version: %s", err) + if !s.isVulnerable(installedVersion, adv) { continue } - if installedVersion.LessThan(fixedVersion) { - vuln := types.DetectedVulnerability{ - VulnerabilityID: adv.VulnerabilityID, - PkgName: pkg.Name, - InstalledVersion: installed, - FixedVersion: adv.FixedVersion, - Layer: pkg.Layer, - } - vulns = append(vulns, vuln) - } + vulns = append(vulns, types.DetectedVulnerability{ + VulnerabilityID: adv.VulnerabilityID, + PkgName: pkg.Name, + InstalledVersion: installed, + FixedVersion: adv.FixedVersion, + Layer: pkg.Layer, + }) + } } return vulns, nil } +func (s *Scanner) isVulnerable(installedVersion version.Version, adv dbTypes.Advisory) bool { + // This logic is for unfixed vulnerabilities, but Trivy DB doesn't have advisories for unfixed vulnerabilities for now + // because Alpine just provides potentially vulnerable packages. It will cause a lot of false positives. + // This is for Aqua commercial products. + if adv.AffectedVersion != "" { + // AffectedVersion means which version introduced this vulnerability. + affectedVersion, err := version.NewVersion(adv.AffectedVersion) + if err != nil { + log.Logger.Debugf("failed to parse Alpine Linux affected package version: %s", err) + return false + } + if affectedVersion.GreaterThan(installedVersion) { + return false + } + } + + // This logic is also for unfixed vulnerabilities. + if adv.FixedVersion == "" { + // It means the unfixed vulnerability + return true + } + + // Compare versions for fixed vulnerabilities + fixedVersion, err := version.NewVersion(adv.FixedVersion) + if err != nil { + log.Logger.Debugf("failed to parse Alpine Linux fixed version: %s", err) + return false + } + + // It means the fixed vulnerability + return installedVersion.LessThan(fixedVersion) +} + // IsSupportedVersion checks the OSFamily can be scanned using Alpine scanner func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool { if strings.Count(osVer, ".") > 1 { diff --git a/pkg/detector/ospkg/alpine/alpine_test.go b/pkg/detector/ospkg/alpine/alpine_test.go index e2d5eadcc295..06f7b701343c 100644 --- a/pkg/detector/ospkg/alpine/alpine_test.go +++ b/pkg/detector/ospkg/alpine/alpine_test.go @@ -1,6 +1,7 @@ package alpine_test import ( + "sort" "testing" "time" @@ -29,7 +30,7 @@ func TestScanner_Detect(t *testing.T) { }{ { name: "happy path", - fixtures: []string{"testdata/fixtures/alpine310.yaml"}, + fixtures: []string{"testdata/fixtures/alpine.yaml"}, args: args{ osVer: "3.10.2", pkgs: []ftypes.Package{ @@ -60,11 +61,20 @@ func TestScanner_Detect(t *testing.T) { DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", }, }, + { + PkgName: "ansible", + VulnerabilityID: "CVE-2021-20191", + InstalledVersion: "2.6.4", + FixedVersion: "", + Layer: ftypes.Layer{ + DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", + }, + }, }, }, { name: "contain rc", - fixtures: []string{"testdata/fixtures/alpine310.yaml"}, + fixtures: []string{"testdata/fixtures/alpine.yaml"}, args: args{ osVer: "3.10", pkgs: []ftypes.Package{ @@ -87,7 +97,7 @@ func TestScanner_Detect(t *testing.T) { }, { name: "contain pre", - fixtures: []string{"testdata/fixtures/alpine310.yaml"}, + fixtures: []string{"testdata/fixtures/alpine.yaml"}, args: args{ osVer: "3.10", pkgs: []ftypes.Package{ @@ -143,6 +153,10 @@ func TestScanner_Detect(t *testing.T) { assert.Contains(t, err.Error(), tt.wantErr) return } + + sort.Slice(got, func(i, j int) bool { + return got[i].VulnerabilityID < got[j].VulnerabilityID + }) assert.NoError(t, err) assert.Equal(t, tt.want, got) }) diff --git a/pkg/detector/ospkg/alpine/testdata/fixtures/alpine310.yaml b/pkg/detector/ospkg/alpine/testdata/fixtures/alpine.yaml similarity index 81% rename from pkg/detector/ospkg/alpine/testdata/fixtures/alpine310.yaml rename to pkg/detector/ospkg/alpine/testdata/fixtures/alpine.yaml index 1d56e4c066ea..810578368790 100644 --- a/pkg/detector/ospkg/alpine/testdata/fixtures/alpine310.yaml +++ b/pkg/detector/ospkg/alpine/testdata/fixtures/alpine.yaml @@ -8,6 +8,13 @@ - key: CVE-2019-10217 value: FixedVersion: "2.8.4-r0" + - key: CVE-2020-1740 + value: + FixedVersion: "" + AffectedVersion: "2.6.5" + - key: CVE-2021-20191 + value: + FixedVersion: "" - key: CVE-2019-INVALID value: FixedVersion: "invalid"