diff --git a/ext/vulnsrc/oracle/oracle.go b/ext/vulnsrc/oracle/oracle.go index 8c03977e..6fe35c95 100644 --- a/ext/vulnsrc/oracle/oracle.go +++ b/ext/vulnsrc/oracle/oracle.go @@ -63,11 +63,19 @@ type definition struct { References []reference `xml:"metadata>reference"` Criteria criteria `xml:"criteria"` Severity string `xml:"metadata>advisory>severity"` + CVEs []cve `xml:"metadata>advisory>cve"` } type reference struct { Source string `xml:"source,attr"` URI string `xml:"ref_url,attr"` + ID string `xml:"ref_id,attr"` +} + +type cve struct { + Impact string `xml:"impact,attr"` + Href string `xml:"href,attr"` + ID string `xml:",chardata"` } type criteria struct { @@ -227,14 +235,31 @@ func parseELSA(ovalReader io.Reader) (vulnerabilities []database.VulnerabilityWi Vulnerability: database.Vulnerability{ Name: name(definition), Link: link(definition), - Severity: severity(definition), + Severity: severity(definition.Severity), Description: description(definition), }, } for _, p := range pkgs { vulnerability.Affected = append(vulnerability.Affected, p) } - vulnerabilities = append(vulnerabilities, vulnerability) + + // Only ELSA is present + if len(definition.CVEs) == 0 { + vulnerabilities = append(vulnerabilities, vulnerability) + continue + } + + // Create one vulnerability per CVE + for _, currentCVE := range definition.CVEs { + vulnerability.Name = currentCVE.ID + vulnerability.Link = currentCVE.Href + if currentCVE.Impact != "" { + vulnerability.Severity = severity(currentCVE.Impact) + } else { + vulnerability.Severity = severity(definition.Severity) + } + vulnerabilities = append(vulnerabilities, vulnerability) + } } } @@ -396,20 +421,20 @@ func link(def definition) (link string) { return } -func severity(def definition) database.Severity { - switch strings.ToLower(def.Severity) { +func severity(sev string) database.Severity { + switch strings.ToLower(sev) { case "n/a": return database.NegligibleSeverity case "low": return database.LowSeverity case "moderate": return database.MediumSeverity - case "important": + case "important", "high": // some ELSAs have "high" instead of "important" return database.HighSeverity case "critical": return database.CriticalSeverity default: - log.WithField("severity", def.Severity).Warning("could not determine vulnerability severity") + log.WithField("severity", sev).Warning("could not determine vulnerability severity") return database.UnknownSeverity } } diff --git a/ext/vulnsrc/oracle/oracle_test.go b/ext/vulnsrc/oracle/oracle_test.go index bba2d6ef..a7071b94 100644 --- a/ext/vulnsrc/oracle/oracle_test.go +++ b/ext/vulnsrc/oracle/oracle_test.go @@ -15,6 +15,7 @@ package oracle import ( + "fmt" "os" "path/filepath" "runtime" @@ -25,7 +26,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestOracleParser(t *testing.T) { +func TestOracleParserOneCve(t *testing.T) { _, filename, _, _ := runtime.Caller(0) path := filepath.Join(filepath.Dir(filename)) @@ -35,8 +36,8 @@ func TestOracleParser(t *testing.T) { vulnerabilities, err := parseELSA(testFile) if assert.Nil(t, err) && assert.Len(t, vulnerabilities, 1) { - assert.Equal(t, "ELSA-2015-1193", vulnerabilities[0].Name) - assert.Equal(t, "http://linux.oracle.com/errata/ELSA-2015-1193.html", vulnerabilities[0].Link) + assert.Equal(t, "CVE-2015-0252", vulnerabilities[0].Name) + assert.Equal(t, "http://linux.oracle.com/cve/CVE-2015-0252.html", vulnerabilities[0].Link) assert.Equal(t, database.MediumSeverity, vulnerabilities[0].Severity) assert.Equal(t, ` [3.1.1-7] Resolves: rhbz#1217104 CVE-2015-0252 `, vulnerabilities[0].Description) @@ -77,41 +78,30 @@ func TestOracleParser(t *testing.T) { assert.Contains(t, vulnerabilities[0].Affected, expectedFeature) } } +} - testFile2, _ := os.Open(filepath.Join(path, "/testdata/fetcher_oracle_test.2.xml")) - defer testFile2.Close() +func TestELSAParserMultipleCVE(t *testing.T) { + testFile, _ := os.Open("testdata/fetcher_oracle_test.2.xml") + defer testFile.Close() - vulnerabilities, err = parseELSA(testFile2) - if assert.Nil(t, err) && assert.Len(t, vulnerabilities, 1) { - assert.Equal(t, "ELSA-2015-1207", vulnerabilities[0].Name) - assert.Equal(t, "http://linux.oracle.com/errata/ELSA-2015-1207.html", vulnerabilities[0].Link) - assert.Equal(t, database.CriticalSeverity, vulnerabilities[0].Severity) - assert.Equal(t, ` [38.1.0-1.0.1.el7_1] - Add firefox-oracle-default-prefs.js and remove the corresponding Red Hat file [38.1.0-1] - Update to 38.1.0 ESR [38.0.1-2] - Fixed rhbz#1222807 by removing preun section `, vulnerabilities[0].Description) - expectedFeatures := []database.AffectedFeature{ - { - AffectedType: affectedType, - Namespace: database.Namespace{ - Name: "oracle:6", - VersionFormat: rpm.ParserName, - }, - FeatureName: "firefox", - FixedInVersion: "0:38.1.0-1.0.1.el6_6", - AffectedVersion: "0:38.1.0-1.0.1.el6_6", - }, - { - AffectedType: affectedType, - Namespace: database.Namespace{ - Name: "oracle:7", - VersionFormat: rpm.ParserName, - }, - FeatureName: "firefox", - FixedInVersion: "0:38.1.0-1.0.1.el7_1", - AffectedVersion: "0:38.1.0-1.0.1.el7_1", - }, - } + vulnerabilities, err := parseELSA(testFile) - for _, expectedFeature := range expectedFeatures { - assert.Contains(t, vulnerabilities[0].Affected, expectedFeature) + // Expected + expectedCve := []string{"CVE-2015-2722", "CVE-2015-2724", "CVE-2015-2725", "CVE-2015-2727", + "CVE-2015-2728", "CVE-2015-2729", "CVE-2015-2731", "CVE-2015-2733", "CVE-2015-2734", + "CVE-2015-2735", "CVE-2015-2736", "CVE-2015-2737", "CVE-2015-2738", "CVE-2015-2739", + "CVE-2015-2740", "CVE-2015-2741", "CVE-2015-2743"} + expectedSeverity := []string{"Negligible", "Low", "Medium", "High", + "Critical", "Unknown", "Critical", "Critical", "Critical", + "Critical", "Critical", "Critical", "Critical", "Critical", + "Critical", "Critical", "Critical"} + + if assert.Nil(t, err) && assert.Len(t, vulnerabilities, len(expectedCve)) { + for i, vulnerability := range vulnerabilities { + assert.Equal(t, expectedCve[i], vulnerability.Name) + assert.Equal(t, fmt.Sprintf("http://linux.oracle.com/cve/%s.html", expectedCve[i]), vulnerability.Link) + assert.Equal(t, database.Severity(expectedSeverity[i]), vulnerability.Severity) + assert.Equal(t, ` [38.1.0-1.0.1.el7_1] - Add firefox-oracle-default-prefs.js and remove the corresponding Red Hat file [38.1.0-1] - Update to 38.1.0 ESR [38.0.1-2] - Fixed rhbz#1222807 by removing preun section `, vulnerability.Description) } } } diff --git a/ext/vulnsrc/oracle/testdata/fetcher_oracle_test.2.xml b/ext/vulnsrc/oracle/testdata/fetcher_oracle_test.2.xml index 89b290e6..371aea93 100644 --- a/ext/vulnsrc/oracle/testdata/fetcher_oracle_test.2.xml +++ b/ext/vulnsrc/oracle/testdata/fetcher_oracle_test.2.xml @@ -47,18 +47,18 @@ ELSA-2015-1207: firefox security update (CRITICAL) - Fixed rhbz#1222807 by removing preun section CRITICAL Copyright 2015 Oracle, Inc. -CVE-2015-2722 -CVE-2015-2724 -CVE-2015-2725 -CVE-2015-2727 -CVE-2015-2728 -CVE-2015-2729 +CVE-2015-2722 +CVE-2015-2724 +CVE-2015-2725 +CVE-2015-2727 +CVE-2015-2728 +CVE-2015-2729 CVE-2015-2731 CVE-2015-2733 CVE-2015-2734 @@ -99,7 +99,7 @@ ELSA-2015-1207: firefox security update (CRITICAL) @@ -141,7 +141,7 @@ ELSA-2015-1207: firefox security update (CRITICAL) @@ -154,7 +154,7 @@ ELSA-2015-1207: firefox security update (CRITICAL) 66ced3de1e5e0159