Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(oracle): Improve handling and reporting of vulnerabilities between normal, FIPS, and ksplice package variants #2273

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 40 additions & 17 deletions pkg/detector/ospkg/oracle/oracle.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package oracle

import (
ustrings "github.com/aquasecurity/trivy-db/pkg/utils/strings"
"sort"
"strings"
"time"

version "github.com/knqyf263/go-rpm-version"
"golang.org/x/exp/maps"
"golang.org/x/xerrors"
"k8s.io/utils/clock"

Expand Down Expand Up @@ -44,16 +47,6 @@ func NewScanner() *Scanner {
}
}

func extractKsplice(v string) string {
subs := strings.Split(strings.ToLower(v), ".")
for _, s := range subs {
if strings.HasPrefix(s, "ksplice") {
return s
}
}
return ""
}

// Detect scans and return vulnerability in Oracle scanner
func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting Oracle Linux vulnerabilities...")
Expand All @@ -74,15 +67,14 @@ func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Packa

installed := utils.FormatVersion(pkg)
installedVersion := version.NewVersion(installed)

uniqVulns := map[string]types.DetectedVulnerability{}
for _, adv := range advisories {
// when one of them doesn't have ksplice, we'll also skip it
// extract kspliceX and compare it with kspliceY in advisories
// if kspliceX and kspliceY are different, we will skip the advisory
if extractKsplice(adv.FixedVersion) != extractKsplice(pkg.Release) {
if oracleoval.GetPackageFlavor(adv.FixedVersion) != oracleoval.GetPackageFlavor(pkg.Release) {
continue
}

fixedVersion := version.NewVersion(adv.FixedVersion)
vulnID := adv.VulnerabilityID
vuln := types.DetectedVulnerability{
VulnerabilityID: adv.VulnerabilityID,
PkgName: pkg.Name,
Expand All @@ -91,12 +83,43 @@ func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Packa
Layer: pkg.Layer,
Custom: adv.Custom,
DataSource: adv.DataSource,
VendorIDs: adv.VendorIDs,
}

// unpatched vulnerabilities
if adv.FixedVersion == "" {
// To avoid overwriting the fixed version by mistake, we should skip unpatched vulnerabilities if they were added earlier
if _, ok := uniqVulns[vulnID]; !ok {
uniqVulns[vulnID] = vuln
}
continue
}
// patched vulnerabilities
fixedVersion := version.NewVersion(adv.FixedVersion)
if installedVersion.LessThan(fixedVersion) {
vuln.FixedVersion = adv.FixedVersion
vulns = append(vulns, vuln)
vuln.VendorIDs = adv.VendorIDs
vuln.FixedVersion = fixedVersion.String()

if v, ok := uniqVulns[vulnID]; ok {
// In case two advisories resolve the same CVE-ID.
// e.g. The first fix might be incomplete.
v.VendorIDs = ustrings.Unique(append(v.VendorIDs, vuln.VendorIDs...))

// The newer fixed version should be taken.
if version.NewVersion(v.FixedVersion).LessThan(fixedVersion) {
v.FixedVersion = vuln.FixedVersion
}
uniqVulns[vulnID] = v
} else {
uniqVulns[vulnID] = vuln
}
}
}

vulns = append(vulns, maps.Values(uniqVulns)...)
sort.Slice(vulns, func(i, j int) bool {
return vulns[i].VulnerabilityID < vulns[j].VulnerabilityID
})
}
return vulns, nil
}
Expand Down
220 changes: 201 additions & 19 deletions pkg/detector/ospkg/oracle/oracle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ func TestScanner_Detect(t *testing.T) {
PkgName: "curl",
InstalledVersion: "7.29.0-59.0.1.el7",
FixedVersion: "7.29.0-59.0.1.el7_9.1",
VendorIDs: []string{"ELSA-2020-5002"},
DataSource: &dbTypes.DataSource{
ID: vulnerability.OracleOVAL,
Name: "Oracle Linux OVAL definitions",
Expand Down Expand Up @@ -159,51 +160,65 @@ func TestScanner_Detect(t *testing.T) {
want: nil,
},
{
name: "the installed version has ksplice2",
name: "with ksplice",
fixtures: []string{"testdata/fixtures/oracle7.yaml", "testdata/fixtures/data-source.yaml"},
args: args{
osVer: "7",
pkgs: []ftypes.Package{
{
Name: "glibc",
Epoch: 2,
Version: "2.28",
Release: "151.0.1.ksplice2.el8",
Version: "2.17",
Release: "156.ksplice1.el7",
Arch: "x86_64",
SrcEpoch: 2,
SrcName: "glibc",
SrcVersion: "2.28",
SrcRelease: "151.0.1.ksplice2.el8",
SrcVersion: "2.17",
SrcRelease: "156.ksplice1.el7",
},
},
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2017-1000364",
PkgName: "glibc",
InstalledVersion: "2:2.17-156.ksplice1.el7",
FixedVersion: "2:2.17-157.ksplice1.el7_3.4",
VendorIDs: []string{"ELSA-2017-3582"},
DataSource: &dbTypes.DataSource{
ID: vulnerability.OracleOVAL,
Name: "Oracle Linux OVAL definitions",
URL: "https://linux.oracle.com/security/oval/",
},
},
},
want: nil,
},
{
name: "with ksplice",
name: "ksplice2",
fixtures: []string{"testdata/fixtures/oracle7.yaml", "testdata/fixtures/data-source.yaml"},
args: args{
osVer: "7",
pkgs: []ftypes.Package{
{
Name: "glibc",
Epoch: 2,
Version: "2.17",
Release: "156.ksplice1.el7",
Name: "glibcx",
Epoch: 0,
Version: "0.1",
Release: "123.ksplice1.el7_3.4",
Arch: "x86_64",
SrcEpoch: 2,
SrcEpoch: 0,
SrcName: "glibc",
SrcVersion: "2.17",
SrcRelease: "156.ksplice1.el7",
SrcVersion: "0.1",
SrcRelease: "123.ksplice1.el7_3.4",
},
},
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2017-1000364",
PkgName: "glibc",
InstalledVersion: "2:2.17-156.ksplice1.el7",
FixedVersion: "2:2.17-157.ksplice1.el7_3.4",
VulnerabilityID: "CVE-2001-10001",
PkgName: "glibcx",
InstalledVersion: "0.1-123.ksplice1.el7_3.4",
FixedVersion: "0.1-123.ksplice2.el7_3.4",
VendorIDs: []string{"ELSA-2001-1001"},
DataSource: &dbTypes.DataSource{
ID: vulnerability.OracleOVAL,
Name: "Oracle Linux OVAL definitions",
Expand Down Expand Up @@ -231,6 +246,173 @@ func TestScanner_Detect(t *testing.T) {
},
wantErr: "failed to unmarshal advisory JSON",
},
{
name: "unpatched without fips",
fixtures: []string{"testdata/fixtures/oracle7.yaml", "testdata/fixtures/data-source.yaml"},
args: args{
osVer: "7",
pkgs: []ftypes.Package{
{
Name: "gnutls",
Version: "3.6.3",
Release: "1.el8",
Arch: "x86_64",
SrcName: "gnutls",
SrcVersion: "3.6.3",
SrcRelease: "1.el8",
},
},
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2021-20231",
PkgName: "gnutls",
InstalledVersion: "3.6.3-1.el8",
FixedVersion: "3.6.16-4.el8",
VendorIDs: []string{"ELSA-2021-4451"},
DataSource: &dbTypes.DataSource{
ID: vulnerability.OracleOVAL,
Name: "Oracle Linux OVAL definitions",
URL: "https://linux.oracle.com/security/oval/",
},
},
{
VulnerabilityID: "CVE-2021-20232",
PkgName: "gnutls",
InstalledVersion: "3.6.3-1.el8",
FixedVersion: "3.6.16-4.el8",
VendorIDs: []string{"ELSA-2021-4451"},
DataSource: &dbTypes.DataSource{
ID: vulnerability.OracleOVAL,
Name: "Oracle Linux OVAL definitions",
URL: "https://linux.oracle.com/security/oval/",
},
},
{
VulnerabilityID: "CVE-2021-3580",
PkgName: "gnutls",
InstalledVersion: "3.6.3-1.el8",
FixedVersion: "3.6.16-4.el8",
VendorIDs: []string{"ELSA-2021-4451"},
DataSource: &dbTypes.DataSource{
ID: vulnerability.OracleOVAL,
Name: "Oracle Linux OVAL definitions",
URL: "https://linux.oracle.com/security/oval/",
},
},
},
},
{
name: "patched without fips",
fixtures: []string{"testdata/fixtures/oracle7.yaml", "testdata/fixtures/data-source.yaml"},
args: args{
osVer: "7",
pkgs: []ftypes.Package{
{
Name: "gnutls",
Version: "3.6.16",
Release: "4.el8",
Arch: "x86_64",
SrcName: "gnutls",
SrcVersion: "3.6.16",
SrcRelease: "4.el8",
},
},
},
want: nil,
},
{
name: "unpatched with fips",
fixtures: []string{"testdata/fixtures/oracle7.yaml", "testdata/fixtures/data-source.yaml"},
args: args{
osVer: "7",
pkgs: []ftypes.Package{
{
Name: "gnutls",
Epoch: 10,
Version: "3.6.16",
Release: "4.el8_fips",
Arch: "x86_64",
SrcEpoch: 10,
SrcName: "gnutls",
SrcVersion: "3.6.16_fips",
SrcRelease: "4.el8",
},
},
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2021-20231",
PkgName: "gnutls",
InstalledVersion: "10:3.6.16-4.el8_fips",
FixedVersion: "10:3.6.16-4.0.1.el8_fips",
VendorIDs: []string{"ELSA-2022-9221"},
DataSource: &dbTypes.DataSource{
ID: vulnerability.OracleOVAL,
Name: "Oracle Linux OVAL definitions",
URL: "https://linux.oracle.com/security/oval/",
},
},
{
VulnerabilityID: "CVE-2021-20232",
PkgName: "gnutls",
InstalledVersion: "10:3.6.16-4.el8_fips",
FixedVersion: "10:3.6.16-4.0.1.el8_fips",
VendorIDs: []string{"ELSA-2022-9221"},
DataSource: &dbTypes.DataSource{
ID: vulnerability.OracleOVAL,
Name: "Oracle Linux OVAL definitions",
URL: "https://linux.oracle.com/security/oval/",
},
},
{
VulnerabilityID: "CVE-2021-3580",
PkgName: "gnutls",
InstalledVersion: "10:3.6.16-4.el8_fips",
FixedVersion: "10:3.6.16-4.0.1.el8_fips",
VendorIDs: []string{"ELSA-2022-9221"},
DataSource: &dbTypes.DataSource{
ID: vulnerability.OracleOVAL,
Name: "Oracle Linux OVAL definitions",
URL: "https://linux.oracle.com/security/oval/",
},
},
},
},
{
name: "multiple advisories",
fixtures: []string{"testdata/fixtures/multiple-advisories.yaml", "testdata/fixtures/data-source.yaml"},
args: args{
osVer: "7",
pkgs: []ftypes.Package{
{
Name: "kernel-uek",
Version: "5.4.17",
Release: "2102.201.1.el8",
SrcName: "kernel-uek",
SrcVersion: "5.4.17",
SrcRelease: "2102.201.1.el8",
},
},
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2021-23133",
PkgName: "kernel-uek",
InstalledVersion: "5.4.17-2102.201.1.el8",
FixedVersion: "5.4.17-2102.203.5.el8",
VendorIDs: []string{
"ELSA-2021-9306",
"ELSA-2021-9362",
},
DataSource: &dbTypes.DataSource{
ID: vulnerability.OracleOVAL,
Name: "Oracle Linux OVAL definitions",
URL: "https://linux.oracle.com/security/oval/",
},
},
},
},
}

for _, tt := range tests {
Expand All @@ -248,7 +430,7 @@ func TestScanner_Detect(t *testing.T) {
assert.NoError(t, err)
}

assert.Equal(t, tt.want, got)
assert.ElementsMatch(t, tt.want, got)
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
pairs:
- key: CVE-2020-8177
value:
FixedVersion:
- foo
- bar
Entries:
- FixedVersion:
- foo
- bar
Loading