From 00fadfc3e3da8c25b6c0c3f13d48017173a45a93 Mon Sep 17 00:00:00 2001 From: Sida Chen Date: Thu, 18 Oct 2018 14:32:54 -0400 Subject: [PATCH 1/2] database: Add affected feature type Affected feature type is for determining either the source feature or the binary feature that an vulnerability affects. --- database/affected_feature_type.go | 26 ++++++++++++++++++++++++++ database/models.go | 8 +++++--- 2 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 database/affected_feature_type.go diff --git a/database/affected_feature_type.go b/database/affected_feature_type.go new file mode 100644 index 00000000..950ddeae --- /dev/null +++ b/database/affected_feature_type.go @@ -0,0 +1,26 @@ +// Copyright 2018 clair authors +// +// 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 database + +// AffectedFeatureType indicates the type of feature that a vulnerability +// affects. +type AffectedFeatureType string + +const ( + // AffectSourcePackage indicates the vulnerability affects a source package. + AffectSourcePackage AffectedFeatureType = "source" + // AffectBinaryPackage indicates the vulnerability affects a binary package. + AffectBinaryPackage AffectedFeatureType = "binary" +) diff --git a/database/models.go b/database/models.go index e448f31b..5f63cbc1 100644 --- a/database/models.go +++ b/database/models.go @@ -199,8 +199,10 @@ type VulnerabilityWithFixedIn struct { // by a Vulnerability. Namespace and Feature Name is unique. Affected Feature is // bound to vulnerability. type AffectedFeature struct { - Namespace Namespace - FeatureName string + // AffectedType determines which type of package it affects. + AffectedType AffectedFeatureType + Namespace Namespace + FeatureName string // FixedInVersion is known next feature version that's not affected by the // vulnerability. Empty FixedInVersion means the unaffected version is // unknown. @@ -229,7 +231,7 @@ type Vulnerability struct { Metadata MetadataMap } -// VulnerabilityWithAffected is an vulnerability with all known affected +// VulnerabilityWithAffected is a vulnerability with all known affected // features. type VulnerabilityWithAffected struct { Vulnerability From 2236b0a5c9a094bde2b7979417b9538cb944e726 Mon Sep 17 00:00:00 2001 From: Sida Chen Date: Thu, 18 Oct 2018 14:52:50 -0400 Subject: [PATCH 2/2] updater: Add vulnsrc affected feature type Each vulnerability source has a specific type of feature that it affects We assume the following: * Alpine: Binary Package * Debian: Source Package * Ubuntu: Source Package * Oracle OVAL: Binary Package * RHEL OVAL: Binary Package --- ext/vulnsrc/alpine/alpine.go | 4 ++++ ext/vulnsrc/debian/debian.go | 2 ++ ext/vulnsrc/debian/debian_test.go | 5 +++++ ext/vulnsrc/oracle/oracle.go | 2 ++ ext/vulnsrc/oracle/oracle_test.go | 5 +++++ ext/vulnsrc/rhel/rhel.go | 2 ++ ext/vulnsrc/rhel/rhel_test.go | 5 +++++ ext/vulnsrc/ubuntu/ubuntu.go | 8 +++++--- ext/vulnsrc/ubuntu/ubuntu_test.go | 3 +++ updater.go | 2 +- updater_test.go | 9 ++++++--- 11 files changed, 40 insertions(+), 7 deletions(-) diff --git a/ext/vulnsrc/alpine/alpine.go b/ext/vulnsrc/alpine/alpine.go index a12e358b..890ffc26 100644 --- a/ext/vulnsrc/alpine/alpine.go +++ b/ext/vulnsrc/alpine/alpine.go @@ -37,6 +37,9 @@ const ( secdbGitURL = "https://github.com/alpinelinux/alpine-secdb" updaterFlag = "alpine-secdbUpdater" nvdURLPrefix = "https://cve.mitre.org/cgi-bin/cvename.cgi?name=" + // affected type indicates if the affected feature hint is for binary or + // source package. + affectedType = database.AffectBinaryPackage ) func init() { @@ -226,6 +229,7 @@ func parseYAML(r io.Reader) (vulns []database.VulnerabilityWithAffected, err err } vuln.Affected = []database.AffectedFeature{ { + AffectedType: affectedType, FeatureName: pkg.Name, AffectedVersion: version, FixedInVersion: fixedInVersion, diff --git a/ext/vulnsrc/debian/debian.go b/ext/vulnsrc/debian/debian.go index 31154dfb..2d265f8a 100644 --- a/ext/vulnsrc/debian/debian.go +++ b/ext/vulnsrc/debian/debian.go @@ -38,6 +38,7 @@ const ( url = "https://security-tracker.debian.org/tracker/data/json" cveURLPrefix = "https://security-tracker.debian.org/tracker" updaterFlag = "debianUpdater" + affectedType = database.AffectSourcePackage ) type jsonData map[string]map[string]jsonVuln @@ -227,6 +228,7 @@ func parseDebianJSON(data *jsonData) (vulnerabilities []database.VulnerabilityWi // Create and add the feature version. pkg := database.AffectedFeature{ + AffectedType: affectedType, FeatureName: pkgName, AffectedVersion: version, FixedInVersion: fixedInVersion, diff --git a/ext/vulnsrc/debian/debian_test.go b/ext/vulnsrc/debian/debian_test.go index 3a6f9ace..e304e028 100644 --- a/ext/vulnsrc/debian/debian_test.go +++ b/ext/vulnsrc/debian/debian_test.go @@ -41,6 +41,7 @@ func TestDebianParser(t *testing.T) { expectedFeatures := []database.AffectedFeature{ { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "debian:8", VersionFormat: dpkg.ParserName, @@ -49,6 +50,7 @@ func TestDebianParser(t *testing.T) { AffectedVersion: versionfmt.MaxVersion, }, { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "debian:unstable", VersionFormat: dpkg.ParserName, @@ -69,6 +71,7 @@ func TestDebianParser(t *testing.T) { expectedFeatures := []database.AffectedFeature{ { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "debian:8", VersionFormat: dpkg.ParserName, @@ -78,6 +81,7 @@ func TestDebianParser(t *testing.T) { AffectedVersion: "0.7.0", }, { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "debian:unstable", VersionFormat: dpkg.ParserName, @@ -87,6 +91,7 @@ func TestDebianParser(t *testing.T) { AffectedVersion: "0.7.0", }, { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "debian:8", VersionFormat: dpkg.ParserName, diff --git a/ext/vulnsrc/oracle/oracle.go b/ext/vulnsrc/oracle/oracle.go index 16df151b..b5ab5e96 100644 --- a/ext/vulnsrc/oracle/oracle.go +++ b/ext/vulnsrc/oracle/oracle.go @@ -41,6 +41,7 @@ const ( ovalURI = "https://linux.oracle.com/oval/" elsaFilePrefix = "com.oracle.elsa-" updaterFlag = "oracleUpdater" + affectedType = database.AffectBinaryPackage ) var ( @@ -345,6 +346,7 @@ func toFeatures(criteria criteria) []database.AffectedFeature { } else if strings.Contains(c.Comment, " is earlier than ") { const prefixLen = len(" is earlier than ") featureVersion.FeatureName = strings.TrimSpace(c.Comment[:strings.Index(c.Comment, " is earlier than ")]) + featureVersion.AffectedType = affectedType version := c.Comment[strings.Index(c.Comment, " is earlier than ")+prefixLen:] err := versionfmt.Valid(rpm.ParserName, version) if err != nil { diff --git a/ext/vulnsrc/oracle/oracle_test.go b/ext/vulnsrc/oracle/oracle_test.go index a9348d48..0af8d02a 100644 --- a/ext/vulnsrc/oracle/oracle_test.go +++ b/ext/vulnsrc/oracle/oracle_test.go @@ -42,6 +42,7 @@ func TestOracleParser(t *testing.T) { expectedFeatures := []database.AffectedFeature{ { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "oracle:7", VersionFormat: rpm.ParserName, @@ -51,6 +52,7 @@ func TestOracleParser(t *testing.T) { AffectedVersion: "0:3.1.1-7.el7_1", }, { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "oracle:7", VersionFormat: rpm.ParserName, @@ -60,6 +62,7 @@ func TestOracleParser(t *testing.T) { AffectedVersion: "0:3.1.1-7.el7_1", }, { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "oracle:7", VersionFormat: rpm.ParserName, @@ -86,6 +89,7 @@ func TestOracleParser(t *testing.T) { 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, @@ -95,6 +99,7 @@ func TestOracleParser(t *testing.T) { AffectedVersion: "0:38.1.0-1.0.1.el6_6", }, { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "oracle:7", VersionFormat: rpm.ParserName, diff --git a/ext/vulnsrc/rhel/rhel.go b/ext/vulnsrc/rhel/rhel.go index b35f5639..79bfb7cc 100644 --- a/ext/vulnsrc/rhel/rhel.go +++ b/ext/vulnsrc/rhel/rhel.go @@ -43,6 +43,7 @@ const ( ovalURI = "https://www.redhat.com/security/data/oval/" rhsaFilePrefix = "com.redhat.rhsa-" updaterFlag = "rhelUpdater" + affectedType = database.AffectBinaryPackage ) var ( @@ -341,6 +342,7 @@ func toFeatures(criteria criteria) []database.AffectedFeature { } else if strings.Contains(c.Comment, " is earlier than ") { const prefixLen = len(" is earlier than ") featureVersion.FeatureName = strings.TrimSpace(c.Comment[:strings.Index(c.Comment, " is earlier than ")]) + featureVersion.AffectedType = affectedType version := c.Comment[strings.Index(c.Comment, " is earlier than ")+prefixLen:] err := versionfmt.Valid(rpm.ParserName, version) if err != nil { diff --git a/ext/vulnsrc/rhel/rhel_test.go b/ext/vulnsrc/rhel/rhel_test.go index 5ac3e108..41f9a778 100644 --- a/ext/vulnsrc/rhel/rhel_test.go +++ b/ext/vulnsrc/rhel/rhel_test.go @@ -46,6 +46,7 @@ func TestRHELParserMultipleCVE(t *testing.T) { database.MediumSeverity, database.MediumSeverity} expectedFeatures := []database.AffectedFeature{ { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "centos:6", VersionFormat: rpm.ParserName, @@ -55,6 +56,7 @@ func TestRHELParserMultipleCVE(t *testing.T) { AffectedVersion: "0:38.1.0-1.el6_6", }, { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "centos:7", VersionFormat: rpm.ParserName, @@ -94,6 +96,7 @@ func TestRHELParserOneCVE(t *testing.T) { expectedFeatures := []database.AffectedFeature{ { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "centos:7", VersionFormat: rpm.ParserName, @@ -103,6 +106,7 @@ func TestRHELParserOneCVE(t *testing.T) { FixedInVersion: "0:3.1.1-7.el7_1", }, { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "centos:7", VersionFormat: rpm.ParserName, @@ -112,6 +116,7 @@ func TestRHELParserOneCVE(t *testing.T) { FixedInVersion: "0:3.1.1-7.el7_1", }, { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "centos:7", VersionFormat: rpm.ParserName, diff --git a/ext/vulnsrc/ubuntu/ubuntu.go b/ext/vulnsrc/ubuntu/ubuntu.go index ba3a9ac5..4dd79226 100644 --- a/ext/vulnsrc/ubuntu/ubuntu.go +++ b/ext/vulnsrc/ubuntu/ubuntu.go @@ -35,9 +35,10 @@ import ( ) const ( - trackerURI = "https://git.launchpad.net/ubuntu-cve-tracker" - updaterFlag = "ubuntuUpdater" - cveURL = "http://people.ubuntu.com/~ubuntu-security/cve/%s" + trackerURI = "https://git.launchpad.net/ubuntu-cve-tracker" + updaterFlag = "ubuntuUpdater" + cveURL = "http://people.ubuntu.com/~ubuntu-security/cve/%s" + affectedType = database.AffectSourcePackage ) var ( @@ -334,6 +335,7 @@ func parseUbuntuCVE(fileContent io.Reader) (vulnerability database.Vulnerability // Create and add the new package. featureVersion := database.AffectedFeature{ + AffectedType: affectedType, Namespace: database.Namespace{ Name: releaseName, VersionFormat: dpkg.ParserName, diff --git a/ext/vulnsrc/ubuntu/ubuntu_test.go b/ext/vulnsrc/ubuntu/ubuntu_test.go index a4bd8afd..7e593859 100644 --- a/ext/vulnsrc/ubuntu/ubuntu_test.go +++ b/ext/vulnsrc/ubuntu/ubuntu_test.go @@ -46,6 +46,7 @@ func TestUbuntuParser(t *testing.T) { expectedFeatures := []database.AffectedFeature{ { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "ubuntu:14.04", VersionFormat: dpkg.ParserName, @@ -54,6 +55,7 @@ func TestUbuntuParser(t *testing.T) { AffectedVersion: versionfmt.MaxVersion, }, { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "ubuntu:15.04", VersionFormat: dpkg.ParserName, @@ -63,6 +65,7 @@ func TestUbuntuParser(t *testing.T) { AffectedVersion: "0.4-3", }, { + AffectedType: affectedType, Namespace: database.Namespace{ Name: "ubuntu:15.10", VersionFormat: dpkg.ParserName, diff --git a/updater.go b/updater.go index 567db2c2..bd092a9b 100644 --- a/updater.go +++ b/updater.go @@ -425,7 +425,7 @@ func doVulnerabilitiesNamespacing(vulnerabilities []database.VulnerabilityWithAf for _, fv := range namespacedFeatures { // validate vulnerabilities, throw out the invalid vulnerabilities - if fv.AffectedVersion == "" || fv.FeatureName == "" || fv.Namespace.Name == "" || fv.Namespace.VersionFormat == "" { + if fv.AffectedType == "" || fv.AffectedVersion == "" || fv.FeatureName == "" || fv.Namespace.Name == "" || fv.Namespace.VersionFormat == "" { log.WithFields(log.Fields{ "Name": fv.FeatureName, "Affected Version": fv.AffectedVersion, diff --git a/updater_test.go b/updater_test.go index c1a623d9..93ad2ecd 100644 --- a/updater_test.go +++ b/updater_test.go @@ -183,6 +183,7 @@ func newmockUpdaterDatastore() *mockUpdaterDatastore { func TestDoVulnerabilitiesNamespacing(t *testing.T) { fv1 := database.AffectedFeature{ + AffectedType: database.AffectSourcePackage, Namespace: database.Namespace{Name: "Namespace1"}, FeatureName: "Feature1", FixedInVersion: "0.1", @@ -190,6 +191,7 @@ func TestDoVulnerabilitiesNamespacing(t *testing.T) { } fv2 := database.AffectedFeature{ + AffectedType: database.AffectSourcePackage, Namespace: database.Namespace{Name: "Namespace2"}, FeatureName: "Feature1", FixedInVersion: "0.2", @@ -197,7 +199,7 @@ func TestDoVulnerabilitiesNamespacing(t *testing.T) { } fv3 := database.AffectedFeature{ - + AffectedType: database.AffectSourcePackage, Namespace: database.Namespace{Name: "Namespace2"}, FeatureName: "Feature2", FixedInVersion: "0.3", @@ -235,8 +237,9 @@ func TestCreatVulnerabilityNotification(t *testing.T) { VersionFormat: vf1, } af1 := database.AffectedFeature{ - Namespace: ns1, - FeatureName: "feature 1", + AffectedType: database.AffectSourcePackage, + Namespace: ns1, + FeatureName: "feature 1", } v1 := database.VulnerabilityWithAffected{