From 8fb9097dbd6b0a342bdae84a3ada30958db70c7f Mon Sep 17 00:00:00 2001 From: Eric Sim Date: Tue, 11 Dec 2018 14:39:08 -0800 Subject: [PATCH 1/7] Add updaters for Amazon Linux 2018.03 and Amazon Linux 2 We get vulnerabilities from ALAS (Amazon Linux Security Advisories) data, which can be found in updateinfo.xml from the repos. --- cmd/clair/main.go | 1 + ext/vulnsrc/amzn/amzn.go | 319 ++++++++++++++++++ ext/vulnsrc/amzn/amzn_test.go | 213 ++++++++++++ ext/vulnsrc/amzn/repomd.go | 28 ++ .../testdata/amazon_linux_1_description_0.txt | 1 + .../testdata/amazon_linux_1_description_1.txt | 1 + .../testdata/amazon_linux_1_updateinfo.xml | 104 ++++++ .../testdata/amazon_linux_2_description_0.txt | 1 + .../testdata/amazon_linux_2_description_1.txt | 1 + .../testdata/amazon_linux_2_updateinfo.xml | 104 ++++++ ext/vulnsrc/amzn/updateinfo.go | 38 +++ 11 files changed, 811 insertions(+) create mode 100644 ext/vulnsrc/amzn/amzn.go create mode 100644 ext/vulnsrc/amzn/amzn_test.go create mode 100644 ext/vulnsrc/amzn/repomd.go create mode 100644 ext/vulnsrc/amzn/testdata/amazon_linux_1_description_0.txt create mode 100644 ext/vulnsrc/amzn/testdata/amazon_linux_1_description_1.txt create mode 100644 ext/vulnsrc/amzn/testdata/amazon_linux_1_updateinfo.xml create mode 100644 ext/vulnsrc/amzn/testdata/amazon_linux_2_description_0.txt create mode 100644 ext/vulnsrc/amzn/testdata/amazon_linux_2_description_1.txt create mode 100644 ext/vulnsrc/amzn/testdata/amazon_linux_2_updateinfo.xml create mode 100644 ext/vulnsrc/amzn/updateinfo.go diff --git a/cmd/clair/main.go b/cmd/clair/main.go index 221489f3..3803c02e 100644 --- a/cmd/clair/main.go +++ b/cmd/clair/main.go @@ -52,6 +52,7 @@ import ( _ "github.com/coreos/clair/ext/notification/webhook" _ "github.com/coreos/clair/ext/vulnmdsrc/nvd" _ "github.com/coreos/clair/ext/vulnsrc/alpine" + _ "github.com/coreos/clair/ext/vulnsrc/amzn" _ "github.com/coreos/clair/ext/vulnsrc/debian" _ "github.com/coreos/clair/ext/vulnsrc/oracle" _ "github.com/coreos/clair/ext/vulnsrc/rhel" diff --git a/ext/vulnsrc/amzn/amzn.go b/ext/vulnsrc/amzn/amzn.go new file mode 100644 index 00000000..7c110b38 --- /dev/null +++ b/ext/vulnsrc/amzn/amzn.go @@ -0,0 +1,319 @@ +// Copyright 2017 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 amzn implements a vulnerability source updater using +// ALAS (Amazon Linux Security Advisories). +package amzn + +import ( + "bufio" + "compress/gzip" + "encoding/xml" + "io" + "regexp" + "strings" + + log "github.com/sirupsen/logrus" + + "github.com/coreos/clair/database" + "github.com/coreos/clair/ext/versionfmt" + "github.com/coreos/clair/ext/versionfmt/rpm" + "github.com/coreos/clair/ext/vulnsrc" + "github.com/coreos/clair/pkg/commonerr" + "github.com/coreos/clair/pkg/httputil" +) + +const ( + amazonLinux1Name = "Amazon Linux 2018.03" + amazonLinux1Namespace = "amzn:2018.03" + amazonLinux1UpdaterFlag = "amazonLinux1Updater" + amazonLinux1MirrorListURI = "http://repo.us-west-2.amazonaws.com/2018.03/updates/x86_64/mirror.list" + amazonLinux2Name = "Amazon Linux 2" + amazonLinux2Namespace = "amzn:2" + amazonLinux2UpdaterFlag = "amazonLinux2Updater" + amazonLinux2MirrorListURI = "https://cdn.amazonlinux.com/2/core/latest/x86_64/mirror.list" +) + +type updater struct { + Name string + Namespace string + UpdaterFlag string + MirrorListURI string +} + +func init() { + // Register updater for Amazon Linux 2018.03. + amazonLinux1Updater := updater { + Name: amazonLinux1Name, + Namespace: amazonLinux1Namespace, + UpdaterFlag: amazonLinux1UpdaterFlag, + MirrorListURI: amazonLinux1MirrorListURI, + } + vulnsrc.RegisterUpdater("amzn", &amazonLinux1Updater) + + // Register updater for Amazon Linux 2. + amazonLinux2Updater := updater { + Name: amazonLinux2Name, + Namespace: amazonLinux2Namespace, + UpdaterFlag: amazonLinux2UpdaterFlag, + MirrorListURI: amazonLinux2MirrorListURI, + } + vulnsrc.RegisterUpdater("amzn2", &amazonLinux2Updater) +} + +func (u *updater) Update(datastore database.Datastore) (response vulnsrc.UpdateResponse, err error) { + log.WithField("package", u.Name).Info("Start fetching vulnerabilities") + + // Get the flag value (the timestamp of the latest ALAS of the previous update). + flagValue, found, err := database.FindKeyValueAndRollback(datastore, u.UpdaterFlag) + if err != nil { + return response, err + } + + if !found { + flagValue = ""; + } + + var timestamp string + + // Get the ALASs from updateinfo.xml.gz from the repos. + updateInfo, err := u.getUpdateInfo() + if err != nil { + return response, err + } + + // Get the ALASs which were issued/updated since the previous update. + var alasList []ALAS + for _, alas := range updateInfo.ALASList { + if compareTimestamp(alas.Updated.Date, flagValue) > 0 { + alasList = append(alasList, alas) + + if compareTimestamp(alas.Updated.Date, timestamp) > 0 { + timestamp = alas.Updated.Date + } + } + } + + // Get the vulnerabilities. + response.Vulnerabilities, err = u.alasListToVulnerabilities(alasList) + if err != nil { + return response, err + } + + // Set the flag value. + if timestamp != "" { + response.FlagName = u.UpdaterFlag + response.FlagValue = timestamp + } else { + log.WithField("package", u.Name).Debug("no update") + } + + return response, err +} + +func (u *updater) Clean() { + +} + +func (u *updater) getUpdateInfo() (updateInfo UpdateInfo, err error) { + // Get the URI of updateinfo.xml.gz. + updateInfoURI, err := u.getUpdateInfoURI() + if err != nil { + return updateInfo, err + } + + // Download updateinfo.xml.gz. + updateInfoResponse, err := httputil.GetWithUserAgent(updateInfoURI) + if err != nil { + log.WithError(err).Error("could not download updateinfo.xml.gz") + return updateInfo, commonerr.ErrCouldNotDownload + } + defer updateInfoResponse.Body.Close() + + if !httputil.Status2xx(updateInfoResponse) { + log.WithField("StatusCode", updateInfoResponse.StatusCode).Error("could not download updateinfo.xml.gz") + return updateInfo, commonerr.ErrCouldNotDownload + } + + // Decompress updateinfo.xml.gz. + updateInfoXml, err := gzip.NewReader(updateInfoResponse.Body) + if err != nil { + log.WithError(err).Error("could not decompress updateinfo.xml.gz") + return updateInfo, commonerr.ErrCouldNotDownload + } + defer updateInfoXml.Close() + + // Decode updateinfo.xml. + updateInfo, err = decodeUpdateInfo(updateInfoXml) + if err != nil { + log.WithError(err).Error("could not decode updateinfo.xml") + return updateInfo, err + } + + return +} + +func (u *updater) getUpdateInfoURI() (updateInfoURI string, err error) { + // Download mirror.list + mirrorListResponse, err := httputil.GetWithUserAgent(u.MirrorListURI) + if err != nil { + log.WithError(err).Error("could not download mirror list") + return updateInfoURI, commonerr.ErrCouldNotDownload + } + defer mirrorListResponse.Body.Close() + + // Parse the URI of the first mirror. + scanner := bufio.NewScanner(mirrorListResponse.Body) + success := scanner.Scan() + if success != true { + log.WithError(err).Error("could not parse mirror list") + } + mirrorURI := scanner.Text() + + // Download repomd.xml. + repoMdURI := mirrorURI + "/repodata/repomd.xml" + repoMdResponse, err := httputil.GetWithUserAgent(repoMdURI) + if err != nil { + log.WithError(err).Error("could not download repomd.xml") + return updateInfoURI, commonerr.ErrCouldNotDownload + } + defer repoMdResponse.Body.Close() + + // Decode repomd.xml. + var repoMd RepoMd + err = xml.NewDecoder(repoMdResponse.Body).Decode(&repoMd) + if err != nil { + log.WithError(err).Error("could not decode repomd.xml") + return updateInfoURI, commonerr.ErrCouldNotDownload + } + + // Parse the URI of updateinfo.xml.gz. + for _, repo := range repoMd.RepoList { + if repo.Type == "updateinfo" { + updateInfoURI = mirrorURI + "/" + repo.Location.Href + break + } + } + if updateInfoURI == "" { + log.Error("could not find updateinfo in repomd.xml") + return updateInfoURI, commonerr.ErrCouldNotDownload + } + + return +} + +func decodeUpdateInfo(updateInfoReader io.Reader) (updateInfo UpdateInfo, err error) { + err = xml.NewDecoder(updateInfoReader).Decode(&updateInfo) + if err != nil { + return updateInfo, err + } + + return +} + +func (u *updater) alasListToVulnerabilities(alasList []ALAS) (vulnerabilities []database.VulnerabilityWithAffected, err error) { + for _, alas := range alasList { + featureVersions := u.alasToFeatureVersions(alas) + if len(featureVersions) > 0 { + vulnerability := database.VulnerabilityWithAffected{ + Vulnerability: database.Vulnerability{ + Name: u.alasToName(alas), + Link: u.alasToLink(alas), + Severity: u.alasToSeverity(alas), + Description: u.alasToDescription(alas), + }, + Affected: featureVersions, + } + vulnerabilities = append(vulnerabilities, vulnerability) + } + } + + return +} + +func (u *updater) alasToName(alas ALAS) string { + return alas.Id +} + +func (u *updater) alasToLink(alas ALAS) string { + if u.Name == amazonLinux1Name { + return "https://alas.aws.amazon.com/" + alas.Id + ".html" + } + + // "ALAS2-2018-1097" becomes "https://alas.aws.amazon.com/AL2/ALAS-2018-1097.html". + re := regexp.MustCompile(`^ALAS2-(.+)$`) + return "https://alas.aws.amazon.com/AL2/ALAS-" + re.FindStringSubmatch(alas.Id)[1] + ".html" +} + +func (u *updater) alasToSeverity(alas ALAS) database.Severity { + switch alas.Severity { + case "low": + return database.LowSeverity + case "medium": + return database.MediumSeverity + case "important": + return database.HighSeverity + case "critical": + return database.CriticalSeverity + default: + log.WithField("severity", alas.Severity).Warning("could not determine vulnerability severity") + return database.UnknownSeverity + } +} + +func (u *updater) alasToDescription(alas ALAS) string { + re := regexp.MustCompile(`\s+`) + return re.ReplaceAllString(strings.TrimSpace(alas.Description), " ") +} + +func (u *updater) alasToFeatureVersions(alas ALAS) (featureVersions []database.AffectedFeature) { + for _, p := range alas.Packages { + var version string + if p.Epoch == "0" { + version = p.Version + "-" + p.Release + } else { + version = p.Epoch + ":" + p.Version + "-" + p.Release + } + err := versionfmt.Valid(rpm.ParserName, version) + if err != nil { + log.WithError(err).WithField("version", version).Warning("could not parse package version. skipping") + continue + } + + var featureVersion database.AffectedFeature + featureVersion.Namespace.Name = u.Namespace + featureVersion.Namespace.VersionFormat = rpm.ParserName + featureVersion.FeatureName = p.Name + featureVersion.AffectedVersion = version + if version != versionfmt.MaxVersion { + featureVersion.FixedInVersion = version + } + featureVersion.AffectedType = database.AffectBinaryPackage + + featureVersions = append(featureVersions, featureVersion) + } + + return +} + +func compareTimestamp(date0 string, date1 string) int { + // format: YYYY-MM-DD hh:mm + if date0 < date1 { + return -1 + } else if date0 > date1 { + return 1 + } else { + return 0 + } +} \ No newline at end of file diff --git a/ext/vulnsrc/amzn/amzn_test.go b/ext/vulnsrc/amzn/amzn_test.go new file mode 100644 index 00000000..93a49139 --- /dev/null +++ b/ext/vulnsrc/amzn/amzn_test.go @@ -0,0 +1,213 @@ +// Copyright 2017 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 amzn + +import ( + "io/ioutil" + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/coreos/clair/database" + "github.com/coreos/clair/ext/versionfmt/rpm" + "github.com/stretchr/testify/assert" +) + +func TestAmazonLinux1(t *testing.T) { + amazonLinux1Updater := updater{ + Name: "Amazon Linux 2018.03", + Namespace: "amzn:2018.03", + UpdaterFlag: "amazonLinux1Updater", + MirrorListURI: "http://repo.us-west-2.amazonaws.com/2018.03/updates/x86_64/mirror.list", + } + + _, filename, _, _ := runtime.Caller(0) + path := filepath.Join(filepath.Dir(filename)) + + expectedDescription0Bytes, err := ioutil.ReadFile(path + "/testdata/amazon_linux_1_description_0.txt") + expectedDescription0 := string(expectedDescription0Bytes) + + expectedDescription1Bytes, _ := ioutil.ReadFile(path + "/testdata/amazon_linux_1_description_1.txt") + expectedDescription1 := string(expectedDescription1Bytes) + + updateInfoXml, _ := os.Open(path + "/testdata/amazon_linux_1_updateinfo.xml") + defer updateInfoXml.Close() + + updateInfo, err := decodeUpdateInfo(updateInfoXml) + assert.Nil(t, err) + + vulnerabilities, err := amazonLinux1Updater.alasListToVulnerabilities(updateInfo.ALASList) + assert.Nil(t, err) + + assert.Equal(t, "ALAS-2011-1", vulnerabilities[0].Name) + assert.Equal(t, "https://alas.aws.amazon.com/ALAS-2011-1.html", vulnerabilities[0].Link) + assert.Equal(t, database.MediumSeverity, vulnerabilities[0].Severity) + assert.Equal(t, expectedDescription0, vulnerabilities[0].Description) + assert.Equal(t, 11, len(vulnerabilities[0].Affected)) + + expectedFeatureVersions0 := []database.AffectedFeature{ + { + Namespace: database.Namespace{ + Name: "amzn:2018.03", + VersionFormat: rpm.ParserName, + }, + FeatureName: "httpd-devel", + AffectedVersion: "2.2.21-1.18.amzn1", + FixedInVersion: "2.2.21-1.18.amzn1", + AffectedType: database.AffectBinaryPackage, + }, + { + Namespace: database.Namespace{ + Name: "amzn:2018.03", + VersionFormat: rpm.ParserName, + }, + FeatureName: "httpd-debuginfo", + AffectedVersion: "2.2.21-1.18.amzn1", + FixedInVersion: "2.2.21-1.18.amzn1", + AffectedType: database.AffectBinaryPackage, + }, + } + + for _, expectedFeatureVersion := range expectedFeatureVersions0 { + assert.Contains(t, vulnerabilities[0].Affected, expectedFeatureVersion) + } + + assert.Equal(t, "ALAS-2011-2", vulnerabilities[1].Name) + assert.Equal(t, "https://alas.aws.amazon.com/ALAS-2011-2.html", vulnerabilities[1].Link) + assert.Equal(t, database.HighSeverity, vulnerabilities[1].Severity) + assert.Equal(t, expectedDescription1, vulnerabilities[1].Description) + assert.Equal(t, 8, len(vulnerabilities[1].Affected)) + + expectedFeatureVersions1 := []database.AffectedFeature{ + { + Namespace: database.Namespace{ + Name: "amzn:2018.03", + VersionFormat: rpm.ParserName, + }, + FeatureName: "cyrus-imapd-debuginfo", + AffectedVersion: "2.3.16-6.4.amzn1", + FixedInVersion: "2.3.16-6.4.amzn1", + AffectedType: database.AffectBinaryPackage, + }, + { + Namespace: database.Namespace{ + Name: "amzn:2018.03", + VersionFormat: rpm.ParserName, + }, + FeatureName: "cyrus-imapd-utils", + AffectedVersion: "2.3.16-6.4.amzn1", + FixedInVersion: "2.3.16-6.4.amzn1", + AffectedType: database.AffectBinaryPackage, + }, + } + + for _, expectedFeatureVersion := range expectedFeatureVersions1 { + assert.Contains(t, vulnerabilities[1].Affected, expectedFeatureVersion) + } +} + +func TestAmazonLinux2(t *testing.T) { + amazonLinux2Updater := updater { + Name: "Amazon Linux 2", + Namespace: "amzn:2", + UpdaterFlag: "amazonLinux2Updater", + MirrorListURI: "https://cdn.amazonlinux.com/2/core/latest/x86_64/mirror.list", + } + + _, filename, _, _ := runtime.Caller(0) + path := filepath.Join(filepath.Dir(filename)) + + description0Bytes, _ := ioutil.ReadFile(path + "/testdata/amazon_linux_2_description_0.txt") + expectedDescription0 := string(description0Bytes) + + description1Bytes, _ := ioutil.ReadFile(path + "/testdata/amazon_linux_2_description_1.txt") + expectedDescription1 := string(description1Bytes) + + updateInfoXml, _ := os.Open(path + "/testdata/amazon_linux_2_updateinfo.xml") + defer updateInfoXml.Close() + + updateInfo, err := decodeUpdateInfo(updateInfoXml) + assert.Nil(t, err) + + vulnerabilities, err := amazonLinux2Updater.alasListToVulnerabilities(updateInfo.ALASList) + assert.Nil(t, err) + + assert.Equal(t, "ALAS2-2018-939", vulnerabilities[0].Name) + assert.Equal(t, "https://alas.aws.amazon.com/AL2/ALAS-2018-939.html", vulnerabilities[0].Link) + assert.Equal(t, database.CriticalSeverity, vulnerabilities[0].Severity) + assert.Equal(t, expectedDescription0, vulnerabilities[0].Description) + assert.Equal(t, 13, len(vulnerabilities[0].Affected)) + + expectedFeatureVersions0 := []database.AffectedFeature{ + { + Namespace: database.Namespace{ + Name: "amzn:2", + VersionFormat: rpm.ParserName, + }, + FeatureName: "kernel", + AffectedVersion: "4.9.76-38.79.amzn2", + FixedInVersion: "4.9.76-38.79.amzn2", + AffectedType: database.AffectBinaryPackage, + }, + { + Namespace: database.Namespace{ + Name: "amzn:2", + VersionFormat: rpm.ParserName, + }, + FeatureName: "kernel-headers", + AffectedVersion: "4.9.76-38.79.amzn2", + FixedInVersion: "4.9.76-38.79.amzn2", + AffectedType: database.AffectBinaryPackage, + }, + } + + for _, expectedFeatureVersion := range expectedFeatureVersions0 { + assert.Contains(t, vulnerabilities[0].Affected, expectedFeatureVersion) + } + + assert.Equal(t, "ALAS2-2018-942", vulnerabilities[1].Name) + assert.Equal(t, "https://alas.aws.amazon.com/AL2/ALAS-2018-942.html", vulnerabilities[1].Link) + assert.Equal(t, database.HighSeverity, vulnerabilities[1].Severity) + assert.Equal(t, expectedDescription1, vulnerabilities[1].Description) + assert.Equal(t, 5, len(vulnerabilities[1].Affected)) + + expectedFeatureVersions1 := []database.AffectedFeature{ + { + Namespace: database.Namespace{ + Name: "amzn:2", + VersionFormat: rpm.ParserName, + }, + FeatureName: "qemu-kvm", + AffectedVersion: "10:1.5.3-141.amzn2.5.3", + FixedInVersion: "10:1.5.3-141.amzn2.5.3", + AffectedType: database.AffectBinaryPackage, + }, + { + Namespace: database.Namespace{ + Name: "amzn:2", + VersionFormat: rpm.ParserName, + }, + FeatureName: "qemu-img", + AffectedVersion: "10:1.5.3-141.amzn2.5.3", + FixedInVersion: "10:1.5.3-141.amzn2.5.3", + AffectedType: database.AffectBinaryPackage, + }, + } + + for _, expectedFeatureVersion := range expectedFeatureVersions1 { + assert.Contains(t, vulnerabilities[1].Affected, expectedFeatureVersion) + } +} diff --git a/ext/vulnsrc/amzn/repomd.go b/ext/vulnsrc/amzn/repomd.go new file mode 100644 index 00000000..093d2182 --- /dev/null +++ b/ext/vulnsrc/amzn/repomd.go @@ -0,0 +1,28 @@ +// Copyright 2017 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 amzn + +type RepoMd struct { + RepoList []Repo `xml:"data"` +} + +type Repo struct { + Type string `xml:"type,attr"` + Location Location `xml:"location"` +} + +type Location struct { + Href string `xml:"href,attr"` +} \ No newline at end of file diff --git a/ext/vulnsrc/amzn/testdata/amazon_linux_1_description_0.txt b/ext/vulnsrc/amzn/testdata/amazon_linux_1_description_0.txt new file mode 100644 index 00000000..f7c8a198 --- /dev/null +++ b/ext/vulnsrc/amzn/testdata/amazon_linux_1_description_0.txt @@ -0,0 +1 @@ +Package updates are available for Amazon Linux AMI that fix the following vulnerabilities: CVE-2011-3192: A flaw was found in the way the Apache HTTP Server handled Range HTTP headers. A remote attacker could use this flaw to cause httpd to use an excessive amount of memory and CPU time via HTTP requests with a specially-crafted Range header. The byterange filter in the Apache HTTP Server 1.3.x, 2.0.x through 2.0.64, and 2.2.x through 2.2.19 allows remote attackers to cause a denial of service (memory and CPU consumption) via a Range header that expresses multiple overlapping ranges, as exploited in the wild in August 2011, a different vulnerability than CVE-2007-0086. \ No newline at end of file diff --git a/ext/vulnsrc/amzn/testdata/amazon_linux_1_description_1.txt b/ext/vulnsrc/amzn/testdata/amazon_linux_1_description_1.txt new file mode 100644 index 00000000..d058071f --- /dev/null +++ b/ext/vulnsrc/amzn/testdata/amazon_linux_1_description_1.txt @@ -0,0 +1 @@ +Package updates are available for Amazon Linux that fix the following vulnerabilities: CVE-2011-3208: Stack-based buffer overflow in the split_wildmats function in nntpd.c in nntpd in Cyrus IMAP Server before 2.3.17 and 2.4.x before 2.4.11 allows remote attackers to execute arbitrary code via a crafted NNTP command. A buffer overflow flaw was found in the cyrus-imapd NNTP server, nntpd. A remote user able to use the nntpd service could use this flaw to crash the nntpd child process or, possibly, execute arbitrary code with the privileges of the cyrus user. \ No newline at end of file diff --git a/ext/vulnsrc/amzn/testdata/amazon_linux_1_updateinfo.xml b/ext/vulnsrc/amzn/testdata/amazon_linux_1_updateinfo.xml new file mode 100644 index 00000000..94c21e7c --- /dev/null +++ b/ext/vulnsrc/amzn/testdata/amazon_linux_1_updateinfo.xml @@ -0,0 +1,104 @@ + + + + ALAS-2011-1 + Amazon Linux AMI 2011.09 - ALAS-2011-1: medium priority package update for httpd + + + medium + + Package updates are available for Amazon Linux AMI that fix the following vulnerabilities: + CVE-2011-3192: + A flaw was found in the way the Apache HTTP Server handled Range HTTP headers. A remote attacker could use this flaw to cause httpd to use an excessive amount of memory and CPU time via HTTP requests with a specially-crafted Range header. + The byterange filter in the Apache HTTP Server 1.3.x, 2.0.x through 2.0.64, and 2.2.x through 2.2.19 allows remote attackers to cause a denial of service (memory and CPU consumption) via a Range header that expresses multiple overlapping ranges, as exploited in the wild in August 2011, a different vulnerability than CVE-2007-0086. + + + + + + + + Amazon Linux AMI + + Packages/httpd-devel-2.2.21-1.18.amzn1.i686.rpm + + + Packages/httpd-debuginfo-2.2.21-1.18.amzn1.i686.rpm + + + Packages/httpd-2.2.21-1.18.amzn1.i686.rpm + + + Packages/httpd-tools-2.2.21-1.18.amzn1.i686.rpm + + + Packages/mod_ssl-2.2.21-1.18.amzn1.i686.rpm + + + Packages/mod_ssl-2.2.21-1.18.amzn1.x86_64.rpm + + + Packages/httpd-tools-2.2.21-1.18.amzn1.x86_64.rpm + + + Packages/httpd-2.2.21-1.18.amzn1.x86_64.rpm + + + Packages/httpd-devel-2.2.21-1.18.amzn1.x86_64.rpm + + + Packages/httpd-debuginfo-2.2.21-1.18.amzn1.x86_64.rpm + + + Packages/httpd-manual-2.2.21-1.18.amzn1.noarch.rpm + + + + + + ALAS-2011-2 + Amazon Linux - ALAS-2011-2: important priority package update for cyrus-imapd + + + important + + Package updates are available for Amazon Linux that fix the following vulnerabilities: + CVE-2011-3208: + Stack-based buffer overflow in the split_wildmats function in nntpd.c in nntpd in Cyrus IMAP Server before 2.3.17 and 2.4.x before 2.4.11 allows remote attackers to execute arbitrary code via a crafted NNTP command. + A buffer overflow flaw was found in the cyrus-imapd NNTP server, nntpd. A remote user able to use the nntpd service could use this flaw to crash the nntpd child process or, possibly, execute arbitrary code with the privileges of the cyrus user. + + + + + + + + Amazon Linux + + Packages/cyrus-imapd-debuginfo-2.3.16-6.4.amzn1.i686.rpm + + + Packages/cyrus-imapd-utils-2.3.16-6.4.amzn1.i686.rpm + + + Packages/cyrus-imapd-devel-2.3.16-6.4.amzn1.i686.rpm + + + Packages/cyrus-imapd-2.3.16-6.4.amzn1.i686.rpm + + + Packages/cyrus-imapd-debuginfo-2.3.16-6.4.amzn1.x86_64.rpm + + + Packages/cyrus-imapd-devel-2.3.16-6.4.amzn1.x86_64.rpm + + + Packages/cyrus-imapd-2.3.16-6.4.amzn1.x86_64.rpm + + + Packages/cyrus-imapd-utils-2.3.16-6.4.amzn1.x86_64.rpm + + + + + \ No newline at end of file diff --git a/ext/vulnsrc/amzn/testdata/amazon_linux_2_description_0.txt b/ext/vulnsrc/amzn/testdata/amazon_linux_2_description_0.txt new file mode 100644 index 00000000..b5e97d5b --- /dev/null +++ b/ext/vulnsrc/amzn/testdata/amazon_linux_2_description_0.txt @@ -0,0 +1 @@ +Package updates are available for Amazon Linux 2 that fix the following vulnerabilities: CVE-2017-5754: 1519781: CVE-2017-5754 hw: cpu: speculative execution permission faults handling An industry-wide issue was found in the way many modern microprocessor designs have implemented speculative execution of instructions (a commonly used performance optimization). There are three primary variants of the issue which differ in the way the speculative execution can be exploited. Variant CVE-2017-5754 relies on the fact that, on impacted microprocessors, during speculative execution of instruction permission faults, exception generation triggered by a faulting access is suppressed until the retirement of the whole instruction block. In a combination with the fact that memory accesses may populate the cache even when the block is being dropped and never committed (executed), an unprivileged local attacker could use this flaw to read privileged (kernel space) memory by conducting targeted cache side-channel attacks. Note: CVE-2017-5754 affects Intel x86-64 microprocessors. AMD x86-64 microprocessors are not affected by this issue. CVE-2017-5715: An industry-wide issue was found in the way many modern microprocessor designs have implemented speculative execution of instructions (a commonly used performance optimization). There are three primary variants of the issue which differ in the way the speculative execution can be exploited. Variant CVE-2017-5715 triggers the speculative execution by utilizing branch target injection. It relies on the presence of a precisely-defined instruction sequence in the privileged code as well as the fact that memory accesses may cause allocation into the microprocessor's data cache even for speculatively executed instructions that never actually commit (retire). As a result, an unprivileged attacker could use this flaw to cross the syscall and guest/host boundaries and read privileged memory by conducting targeted cache side-channel attacks. 1519780: CVE-2017-5715 hw: cpu: speculative execution branch target injection \ No newline at end of file diff --git a/ext/vulnsrc/amzn/testdata/amazon_linux_2_description_1.txt b/ext/vulnsrc/amzn/testdata/amazon_linux_2_description_1.txt new file mode 100644 index 00000000..037e8fa9 --- /dev/null +++ b/ext/vulnsrc/amzn/testdata/amazon_linux_2_description_1.txt @@ -0,0 +1 @@ +Package updates are available for Amazon Linux 2 that fix the following vulnerabilities: CVE-2017-5715: An industry-wide issue was found in the way many modern microprocessor designs have implemented speculative execution of instructions (a commonly used performance optimization). There are three primary variants of the issue which differ in the way the speculative execution can be exploited. Variant CVE-2017-5715 triggers the speculative execution by utilizing branch target injection. It relies on the presence of a precisely-defined instruction sequence in the privileged code as well as the fact that memory accesses may cause allocation into the microprocessor's data cache even for speculatively executed instructions that never actually commit (retire). As a result, an unprivileged attacker could use this flaw to cross the syscall and guest/host boundaries and read privileged memory by conducting targeted cache side-channel attacks. 1519780: CVE-2017-5715 hw: cpu: speculative execution branch target injection \ No newline at end of file diff --git a/ext/vulnsrc/amzn/testdata/amazon_linux_2_updateinfo.xml b/ext/vulnsrc/amzn/testdata/amazon_linux_2_updateinfo.xml new file mode 100644 index 00000000..f8631979 --- /dev/null +++ b/ext/vulnsrc/amzn/testdata/amazon_linux_2_updateinfo.xml @@ -0,0 +1,104 @@ + + + + ALAS2-2018-939 + Amazon Linux 2 2017.12 - ALAS2-2018-939: critical priority package update for kernel + + + critical + + Package updates are available for Amazon Linux 2 that fix the following vulnerabilities: + CVE-2017-5754: + 1519781: + CVE-2017-5754 hw: cpu: speculative execution permission faults handling + An industry-wide issue was found in the way many modern microprocessor designs have implemented speculative execution of instructions (a commonly used performance optimization). There are three primary variants of the issue which differ in the way the speculative execution can be exploited. Variant CVE-2017-5754 relies on the fact that, on impacted microprocessors, during speculative execution of instruction permission faults, exception generation triggered by a faulting access is suppressed until the retirement of the whole instruction block. In a combination with the fact that memory accesses may populate the cache even when the block is being dropped and never committed (executed), an unprivileged local attacker could use this flaw to read privileged (kernel space) memory by conducting targeted cache side-channel attacks. Note: CVE-2017-5754 affects Intel x86-64 microprocessors. AMD x86-64 microprocessors are not affected by this issue. + + CVE-2017-5715: + An industry-wide issue was found in the way many modern microprocessor designs have implemented speculative execution of instructions (a commonly used performance optimization). There are three primary variants of the issue which differ in the way the speculative execution can be exploited. Variant CVE-2017-5715 triggers the speculative execution by utilizing branch target injection. It relies on the presence of a precisely-defined instruction sequence in the privileged code as well as the fact that memory accesses may cause allocation into the microprocessor&#039;s data cache even for speculatively executed instructions that never actually commit (retire). As a result, an unprivileged attacker could use this flaw to cross the syscall and guest/host boundaries and read privileged memory by conducting targeted cache side-channel attacks. + 1519780: + CVE-2017-5715 hw: cpu: speculative execution branch target injection + + + + + + + + Amazon Linux 2 + + Packages/kernel-4.9.76-38.79.amzn2.x86_64.rpm + + + Packages/kernel-headers-4.9.76-38.79.amzn2.x86_64.rpm + + + Packages/kernel-debuginfo-common-x86_64-4.9.76-38.79.amzn2.x86_64.rpm + + Packages/perf-4.9.76-38.79.amzn2.x86_64.rpm + + Packages/perf-debuginfo-4.9.76-38.79.amzn2.x86_64.rpm + + + Packages/python-perf-4.9.76-38.79.amzn2.x86_64.rpm + + + Packages/python-perf-debuginfo-4.9.76-38.79.amzn2.x86_64.rpm + + + Packages/kernel-tools-4.9.76-38.79.amzn2.x86_64.rpm + + + Packages/kernel-tools-devel-4.9.76-38.79.amzn2.x86_64.rpm + + + Packages/kernel-tools-debuginfo-4.9.76-38.79.amzn2.x86_64.rpm + + + Packages/kernel-devel-4.9.76-38.79.amzn2.x86_64.rpm + + + Packages/kernel-debuginfo-4.9.76-38.79.amzn2.x86_64.rpm + + + Packages/kernel-doc-4.9.76-38.79.amzn2.noarch.rpm + + + + + + ALAS2-2018-942 + Amazon Linux 2 2017.12 - ALAS2-2018-942: important priority package update for qemu-kvm + + important + + Package updates are available for Amazon Linux 2 that fix the following vulnerabilities: + CVE-2017-5715: + An industry-wide issue was found in the way many modern microprocessor designs have implemented speculative execution of instructions (a commonly used performance optimization). There are three primary variants of the issue which differ in the way the speculative execution can be exploited. Variant CVE-2017-5715 triggers the speculative execution by utilizing branch target injection. It relies on the presence of a precisely-defined instruction sequence in the privileged code as well as the fact that memory accesses may cause allocation into the microprocessor&#039;s data cache even for speculatively executed instructions that never actually commit (retire). As a result, an unprivileged attacker could use this flaw to cross the syscall and guest/host boundaries and read privileged memory by conducting targeted cache side-channel attacks. + 1519780: + CVE-2017-5715 hw: cpu: speculative execution branch target injection + + + + + + + Amazon Linux 2 + + Packages/qemu-kvm-1.5.3-141.amzn2.5.3.x86_64.rpm + + + Packages/qemu-img-1.5.3-141.amzn2.5.3.x86_64.rpm + + + Packages/qemu-kvm-common-1.5.3-141.amzn2.5.3.x86_64.rpm + + + Packages/qemu-kvm-tools-1.5.3-141.amzn2.5.3.x86_64.rpm + + + Packages/qemu-kvm-debuginfo-1.5.3-141.amzn2.5.3.x86_64.rpm + + + + + \ No newline at end of file diff --git a/ext/vulnsrc/amzn/updateinfo.go b/ext/vulnsrc/amzn/updateinfo.go new file mode 100644 index 00000000..e73a8209 --- /dev/null +++ b/ext/vulnsrc/amzn/updateinfo.go @@ -0,0 +1,38 @@ +// Copyright 2017 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 amzn + +type UpdateInfo struct { + ALASList []ALAS `xml:"update"` +} + +type ALAS struct { + Id string `xml:"id"` + Updated Updated `xml:"updated"` + Severity string `xml:"severity"` + Description string `xml:"description"` + Packages []Package `xml:"pkglist>collection>package"` +} + +type Updated struct { + Date string `xml:"date,attr"` +} + +type Package struct { + Name string `xml:"name,attr"` + Epoch string `xml:"epoch,attr"` + Version string `xml:"version,attr"` + Release string `xml:"release,attr"` +} \ No newline at end of file From 803cf4a29e1ddd59c177ccc73924822c45d9c316 Mon Sep 17 00:00:00 2001 From: Eric Sim Date: Tue, 11 Dec 2018 16:11:04 -0800 Subject: [PATCH 2/7] gofmt --- ext/vulnsrc/amzn/amzn.go | 24 ++++++++-------- ext/vulnsrc/amzn/amzn_test.go | 50 +++++++++++++++++----------------- ext/vulnsrc/amzn/repomd.go | 2 +- ext/vulnsrc/amzn/updateinfo.go | 2 +- 4 files changed, 39 insertions(+), 39 deletions(-) diff --git a/ext/vulnsrc/amzn/amzn.go b/ext/vulnsrc/amzn/amzn.go index 7c110b38..678737f3 100644 --- a/ext/vulnsrc/amzn/amzn.go +++ b/ext/vulnsrc/amzn/amzn.go @@ -35,14 +35,14 @@ import ( ) const ( - amazonLinux1Name = "Amazon Linux 2018.03" - amazonLinux1Namespace = "amzn:2018.03" - amazonLinux1UpdaterFlag = "amazonLinux1Updater" - amazonLinux1MirrorListURI = "http://repo.us-west-2.amazonaws.com/2018.03/updates/x86_64/mirror.list" - amazonLinux2Name = "Amazon Linux 2" - amazonLinux2Namespace = "amzn:2" - amazonLinux2UpdaterFlag = "amazonLinux2Updater" - amazonLinux2MirrorListURI = "https://cdn.amazonlinux.com/2/core/latest/x86_64/mirror.list" + amazonLinux1Name = "Amazon Linux 2018.03" + amazonLinux1Namespace = "amzn:2018.03" + amazonLinux1UpdaterFlag = "amazonLinux1Updater" + amazonLinux1MirrorListURI = "http://repo.us-west-2.amazonaws.com/2018.03/updates/x86_64/mirror.list" + amazonLinux2Name = "Amazon Linux 2" + amazonLinux2Namespace = "amzn:2" + amazonLinux2UpdaterFlag = "amazonLinux2Updater" + amazonLinux2MirrorListURI = "https://cdn.amazonlinux.com/2/core/latest/x86_64/mirror.list" ) type updater struct { @@ -54,7 +54,7 @@ type updater struct { func init() { // Register updater for Amazon Linux 2018.03. - amazonLinux1Updater := updater { + amazonLinux1Updater := updater{ Name: amazonLinux1Name, Namespace: amazonLinux1Namespace, UpdaterFlag: amazonLinux1UpdaterFlag, @@ -63,7 +63,7 @@ func init() { vulnsrc.RegisterUpdater("amzn", &amazonLinux1Updater) // Register updater for Amazon Linux 2. - amazonLinux2Updater := updater { + amazonLinux2Updater := updater{ Name: amazonLinux2Name, Namespace: amazonLinux2Namespace, UpdaterFlag: amazonLinux2UpdaterFlag, @@ -82,7 +82,7 @@ func (u *updater) Update(datastore database.Datastore) (response vulnsrc.UpdateR } if !found { - flagValue = ""; + flagValue = "" } var timestamp string @@ -316,4 +316,4 @@ func compareTimestamp(date0 string, date1 string) int { } else { return 0 } -} \ No newline at end of file +} diff --git a/ext/vulnsrc/amzn/amzn_test.go b/ext/vulnsrc/amzn/amzn_test.go index 93a49139..4e5f8cf6 100644 --- a/ext/vulnsrc/amzn/amzn_test.go +++ b/ext/vulnsrc/amzn/amzn_test.go @@ -64,20 +64,20 @@ func TestAmazonLinux1(t *testing.T) { Name: "amzn:2018.03", VersionFormat: rpm.ParserName, }, - FeatureName: "httpd-devel", + FeatureName: "httpd-devel", AffectedVersion: "2.2.21-1.18.amzn1", - FixedInVersion: "2.2.21-1.18.amzn1", - AffectedType: database.AffectBinaryPackage, + FixedInVersion: "2.2.21-1.18.amzn1", + AffectedType: database.AffectBinaryPackage, }, { Namespace: database.Namespace{ Name: "amzn:2018.03", VersionFormat: rpm.ParserName, }, - FeatureName: "httpd-debuginfo", + FeatureName: "httpd-debuginfo", AffectedVersion: "2.2.21-1.18.amzn1", - FixedInVersion: "2.2.21-1.18.amzn1", - AffectedType: database.AffectBinaryPackage, + FixedInVersion: "2.2.21-1.18.amzn1", + AffectedType: database.AffectBinaryPackage, }, } @@ -97,20 +97,20 @@ func TestAmazonLinux1(t *testing.T) { Name: "amzn:2018.03", VersionFormat: rpm.ParserName, }, - FeatureName: "cyrus-imapd-debuginfo", + FeatureName: "cyrus-imapd-debuginfo", AffectedVersion: "2.3.16-6.4.amzn1", - FixedInVersion: "2.3.16-6.4.amzn1", - AffectedType: database.AffectBinaryPackage, + FixedInVersion: "2.3.16-6.4.amzn1", + AffectedType: database.AffectBinaryPackage, }, { Namespace: database.Namespace{ Name: "amzn:2018.03", VersionFormat: rpm.ParserName, }, - FeatureName: "cyrus-imapd-utils", + FeatureName: "cyrus-imapd-utils", AffectedVersion: "2.3.16-6.4.amzn1", - FixedInVersion: "2.3.16-6.4.amzn1", - AffectedType: database.AffectBinaryPackage, + FixedInVersion: "2.3.16-6.4.amzn1", + AffectedType: database.AffectBinaryPackage, }, } @@ -120,7 +120,7 @@ func TestAmazonLinux1(t *testing.T) { } func TestAmazonLinux2(t *testing.T) { - amazonLinux2Updater := updater { + amazonLinux2Updater := updater{ Name: "Amazon Linux 2", Namespace: "amzn:2", UpdaterFlag: "amazonLinux2Updater", @@ -157,20 +157,20 @@ func TestAmazonLinux2(t *testing.T) { Name: "amzn:2", VersionFormat: rpm.ParserName, }, - FeatureName: "kernel", + FeatureName: "kernel", AffectedVersion: "4.9.76-38.79.amzn2", - FixedInVersion: "4.9.76-38.79.amzn2", - AffectedType: database.AffectBinaryPackage, + FixedInVersion: "4.9.76-38.79.amzn2", + AffectedType: database.AffectBinaryPackage, }, { Namespace: database.Namespace{ Name: "amzn:2", VersionFormat: rpm.ParserName, }, - FeatureName: "kernel-headers", + FeatureName: "kernel-headers", AffectedVersion: "4.9.76-38.79.amzn2", - FixedInVersion: "4.9.76-38.79.amzn2", - AffectedType: database.AffectBinaryPackage, + FixedInVersion: "4.9.76-38.79.amzn2", + AffectedType: database.AffectBinaryPackage, }, } @@ -190,20 +190,20 @@ func TestAmazonLinux2(t *testing.T) { Name: "amzn:2", VersionFormat: rpm.ParserName, }, - FeatureName: "qemu-kvm", + FeatureName: "qemu-kvm", AffectedVersion: "10:1.5.3-141.amzn2.5.3", - FixedInVersion: "10:1.5.3-141.amzn2.5.3", - AffectedType: database.AffectBinaryPackage, + FixedInVersion: "10:1.5.3-141.amzn2.5.3", + AffectedType: database.AffectBinaryPackage, }, { Namespace: database.Namespace{ Name: "amzn:2", VersionFormat: rpm.ParserName, }, - FeatureName: "qemu-img", + FeatureName: "qemu-img", AffectedVersion: "10:1.5.3-141.amzn2.5.3", - FixedInVersion: "10:1.5.3-141.amzn2.5.3", - AffectedType: database.AffectBinaryPackage, + FixedInVersion: "10:1.5.3-141.amzn2.5.3", + AffectedType: database.AffectBinaryPackage, }, } diff --git a/ext/vulnsrc/amzn/repomd.go b/ext/vulnsrc/amzn/repomd.go index 093d2182..a9fe8322 100644 --- a/ext/vulnsrc/amzn/repomd.go +++ b/ext/vulnsrc/amzn/repomd.go @@ -25,4 +25,4 @@ type Repo struct { type Location struct { Href string `xml:"href,attr"` -} \ No newline at end of file +} diff --git a/ext/vulnsrc/amzn/updateinfo.go b/ext/vulnsrc/amzn/updateinfo.go index e73a8209..160dee6b 100644 --- a/ext/vulnsrc/amzn/updateinfo.go +++ b/ext/vulnsrc/amzn/updateinfo.go @@ -35,4 +35,4 @@ type Package struct { Epoch string `xml:"epoch,attr"` Version string `xml:"version,attr"` Release string `xml:"release,attr"` -} \ No newline at end of file +} From 8e98ee878ac324888855c35597fb6bea2ba84369 Mon Sep 17 00:00:00 2001 From: Eric Sim Date: Tue, 11 Dec 2018 17:11:56 -0800 Subject: [PATCH 3/7] Add 2xx checks for mirror.list and repomd.xml --- ext/vulnsrc/amzn/amzn.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ext/vulnsrc/amzn/amzn.go b/ext/vulnsrc/amzn/amzn.go index 678737f3..b458d9c3 100644 --- a/ext/vulnsrc/amzn/amzn.go +++ b/ext/vulnsrc/amzn/amzn.go @@ -173,6 +173,11 @@ func (u *updater) getUpdateInfoURI() (updateInfoURI string, err error) { } defer mirrorListResponse.Body.Close() + if !httputil.Status2xx(mirrorListResponse) { + log.WithField("StatusCode", mirrorListResponse.StatusCode).Error("could not download mirror list") + return updateInfoURI, commonerr.ErrCouldNotDownload + } + // Parse the URI of the first mirror. scanner := bufio.NewScanner(mirrorListResponse.Body) success := scanner.Scan() @@ -190,6 +195,11 @@ func (u *updater) getUpdateInfoURI() (updateInfoURI string, err error) { } defer repoMdResponse.Body.Close() + if !httputil.Status2xx(repoMdResponse) { + log.WithField("StatusCode", repoMdResponse.StatusCode).Error("could not download repomd.xml") + return updateInfoURI, commonerr.ErrCouldNotDownload + } + // Decode repomd.xml. var repoMd RepoMd err = xml.NewDecoder(repoMdResponse.Body).Decode(&repoMd) From 684ae2be1dd312d6f5f859bb88ae3e4f9342001a Mon Sep 17 00:00:00 2001 From: Eric Sim Date: Mon, 17 Dec 2018 14:36:04 -0800 Subject: [PATCH 4/7] Refactoring (minor) --- ext/vulnsrc/amzn/amzn.go | 119 ++++++++++++++++++++-------------- ext/vulnsrc/amzn/amzn_test.go | 12 ++-- 2 files changed, 75 insertions(+), 56 deletions(-) diff --git a/ext/vulnsrc/amzn/amzn.go b/ext/vulnsrc/amzn/amzn.go index b458d9c3..6a1fd465 100644 --- a/ext/vulnsrc/amzn/amzn.go +++ b/ext/vulnsrc/amzn/amzn.go @@ -26,6 +26,7 @@ import ( log "github.com/sirupsen/logrus" + "fmt" "github.com/coreos/clair/database" "github.com/coreos/clair/ext/versionfmt" "github.com/coreos/clair/ext/versionfmt/rpm" @@ -35,50 +36,55 @@ import ( ) const ( - amazonLinux1Name = "Amazon Linux 2018.03" - amazonLinux1Namespace = "amzn:2018.03" amazonLinux1UpdaterFlag = "amazonLinux1Updater" amazonLinux1MirrorListURI = "http://repo.us-west-2.amazonaws.com/2018.03/updates/x86_64/mirror.list" - amazonLinux2Name = "Amazon Linux 2" - amazonLinux2Namespace = "amzn:2" + amazonLinux1Name = "Amazon Linux 2018.03" + amazonLinux1Namespace = "amzn:2018.03" + amazonLinux1LinkFormat = "https://alas.aws.amazon.com/%s.html" amazonLinux2UpdaterFlag = "amazonLinux2Updater" amazonLinux2MirrorListURI = "https://cdn.amazonlinux.com/2/core/latest/x86_64/mirror.list" + amazonLinux2Name = "Amazon Linux 2" + amazonLinux2Namespace = "amzn:2" + amazonLinux2LinkFormat = "https://alas.aws.amazon.com/AL2/%s.html" ) type updater struct { - Name string - Namespace string UpdaterFlag string MirrorListURI string + Name string + Namespace string + LinkFormat string } func init() { // Register updater for Amazon Linux 2018.03. amazonLinux1Updater := updater{ - Name: amazonLinux1Name, - Namespace: amazonLinux1Namespace, UpdaterFlag: amazonLinux1UpdaterFlag, MirrorListURI: amazonLinux1MirrorListURI, + Name: amazonLinux1Name, + Namespace: amazonLinux1Namespace, + LinkFormat: amazonLinux1LinkFormat, } - vulnsrc.RegisterUpdater("amzn", &amazonLinux1Updater) + vulnsrc.RegisterUpdater("amzn1", &amazonLinux1Updater) // Register updater for Amazon Linux 2. amazonLinux2Updater := updater{ - Name: amazonLinux2Name, - Namespace: amazonLinux2Namespace, UpdaterFlag: amazonLinux2UpdaterFlag, MirrorListURI: amazonLinux2MirrorListURI, + Name: amazonLinux2Name, + Namespace: amazonLinux2Namespace, + LinkFormat: amazonLinux2LinkFormat, } vulnsrc.RegisterUpdater("amzn2", &amazonLinux2Updater) } -func (u *updater) Update(datastore database.Datastore) (response vulnsrc.UpdateResponse, err error) { +func (u *updater) Update(datastore database.Datastore) (vulnsrc.UpdateResponse, error) { log.WithField("package", u.Name).Info("Start fetching vulnerabilities") // Get the flag value (the timestamp of the latest ALAS of the previous update). flagValue, found, err := database.FindKeyValueAndRollback(datastore, u.UpdaterFlag) if err != nil { - return response, err + return vulnsrc.UpdateResponse{}, err } if !found { @@ -90,7 +96,7 @@ func (u *updater) Update(datastore database.Datastore) (response vulnsrc.UpdateR // Get the ALASs from updateinfo.xml.gz from the repos. updateInfo, err := u.getUpdateInfo() if err != nil { - return response, err + return vulnsrc.UpdateResponse{}, err } // Get the ALASs which were issued/updated since the previous update. @@ -106,9 +112,10 @@ func (u *updater) Update(datastore database.Datastore) (response vulnsrc.UpdateR } // Get the vulnerabilities. - response.Vulnerabilities, err = u.alasListToVulnerabilities(alasList) - if err != nil { - return response, err + vulnerabilities := u.alasListToVulnerabilities(alasList) + + response := vulnsrc.UpdateResponse{ + Vulnerabilities: vulnerabilities, } // Set the flag value. @@ -126,56 +133,56 @@ func (u *updater) Clean() { } -func (u *updater) getUpdateInfo() (updateInfo UpdateInfo, err error) { +func (u *updater) getUpdateInfo() (UpdateInfo, error) { // Get the URI of updateinfo.xml.gz. updateInfoURI, err := u.getUpdateInfoURI() if err != nil { - return updateInfo, err + return UpdateInfo{}, err } // Download updateinfo.xml.gz. updateInfoResponse, err := httputil.GetWithUserAgent(updateInfoURI) if err != nil { log.WithError(err).Error("could not download updateinfo.xml.gz") - return updateInfo, commonerr.ErrCouldNotDownload + return UpdateInfo{}, commonerr.ErrCouldNotDownload } defer updateInfoResponse.Body.Close() if !httputil.Status2xx(updateInfoResponse) { log.WithField("StatusCode", updateInfoResponse.StatusCode).Error("could not download updateinfo.xml.gz") - return updateInfo, commonerr.ErrCouldNotDownload + return UpdateInfo{}, commonerr.ErrCouldNotDownload } // Decompress updateinfo.xml.gz. updateInfoXml, err := gzip.NewReader(updateInfoResponse.Body) if err != nil { log.WithError(err).Error("could not decompress updateinfo.xml.gz") - return updateInfo, commonerr.ErrCouldNotDownload + return UpdateInfo{}, commonerr.ErrCouldNotParse } defer updateInfoXml.Close() // Decode updateinfo.xml. - updateInfo, err = decodeUpdateInfo(updateInfoXml) + updateInfo, err := decodeUpdateInfo(updateInfoXml) if err != nil { log.WithError(err).Error("could not decode updateinfo.xml") - return updateInfo, err + return UpdateInfo{}, commonerr.ErrCouldNotParse } - return + return updateInfo, nil } -func (u *updater) getUpdateInfoURI() (updateInfoURI string, err error) { +func (u *updater) getUpdateInfoURI() (string, error) { // Download mirror.list mirrorListResponse, err := httputil.GetWithUserAgent(u.MirrorListURI) if err != nil { log.WithError(err).Error("could not download mirror list") - return updateInfoURI, commonerr.ErrCouldNotDownload + return "", commonerr.ErrCouldNotDownload } defer mirrorListResponse.Body.Close() if !httputil.Status2xx(mirrorListResponse) { log.WithField("StatusCode", mirrorListResponse.StatusCode).Error("could not download mirror list") - return updateInfoURI, commonerr.ErrCouldNotDownload + return "", commonerr.ErrCouldNotDownload } // Parse the URI of the first mirror. @@ -191,13 +198,13 @@ func (u *updater) getUpdateInfoURI() (updateInfoURI string, err error) { repoMdResponse, err := httputil.GetWithUserAgent(repoMdURI) if err != nil { log.WithError(err).Error("could not download repomd.xml") - return updateInfoURI, commonerr.ErrCouldNotDownload + return "", commonerr.ErrCouldNotDownload } defer repoMdResponse.Body.Close() if !httputil.Status2xx(repoMdResponse) { log.WithField("StatusCode", repoMdResponse.StatusCode).Error("could not download repomd.xml") - return updateInfoURI, commonerr.ErrCouldNotDownload + return "", commonerr.ErrCouldNotDownload } // Decode repomd.xml. @@ -205,10 +212,11 @@ func (u *updater) getUpdateInfoURI() (updateInfoURI string, err error) { err = xml.NewDecoder(repoMdResponse.Body).Decode(&repoMd) if err != nil { log.WithError(err).Error("could not decode repomd.xml") - return updateInfoURI, commonerr.ErrCouldNotDownload + return "", commonerr.ErrCouldNotDownload } // Parse the URI of updateinfo.xml.gz. + var updateInfoURI string for _, repo := range repoMd.RepoList { if repo.Type == "updateinfo" { updateInfoURI = mirrorURI + "/" + repo.Location.Href @@ -217,22 +225,24 @@ func (u *updater) getUpdateInfoURI() (updateInfoURI string, err error) { } if updateInfoURI == "" { log.Error("could not find updateinfo in repomd.xml") - return updateInfoURI, commonerr.ErrCouldNotDownload + return "", commonerr.ErrCouldNotDownload } - return + return updateInfoURI, nil } -func decodeUpdateInfo(updateInfoReader io.Reader) (updateInfo UpdateInfo, err error) { - err = xml.NewDecoder(updateInfoReader).Decode(&updateInfo) +func decodeUpdateInfo(updateInfoReader io.Reader) (UpdateInfo, error) { + var updateInfo UpdateInfo + err := xml.NewDecoder(updateInfoReader).Decode(&updateInfo) if err != nil { return updateInfo, err } - return + return updateInfo, nil } -func (u *updater) alasListToVulnerabilities(alasList []ALAS) (vulnerabilities []database.VulnerabilityWithAffected, err error) { +func (u *updater) alasListToVulnerabilities(alasList []ALAS) []database.VulnerabilityWithAffected { + var vulnerabilities []database.VulnerabilityWithAffected for _, alas := range alasList { featureVersions := u.alasToFeatureVersions(alas) if len(featureVersions) > 0 { @@ -249,7 +259,7 @@ func (u *updater) alasListToVulnerabilities(alasList []ALAS) (vulnerabilities [] } } - return + return vulnerabilities } func (u *updater) alasToName(alas ALAS) string { @@ -258,12 +268,16 @@ func (u *updater) alasToName(alas ALAS) string { func (u *updater) alasToLink(alas ALAS) string { if u.Name == amazonLinux1Name { - return "https://alas.aws.amazon.com/" + alas.Id + ".html" + return fmt.Sprintf(u.LinkFormat, alas.Id) } - // "ALAS2-2018-1097" becomes "https://alas.aws.amazon.com/AL2/ALAS-2018-1097.html". - re := regexp.MustCompile(`^ALAS2-(.+)$`) - return "https://alas.aws.amazon.com/AL2/ALAS-" + re.FindStringSubmatch(alas.Id)[1] + ".html" + if u.Name == amazonLinux2Name { + // "ALAS2-2018-1097" becomes "https://alas.aws.amazon.com/AL2/ALAS-2018-1097.html". + re := regexp.MustCompile(`^ALAS2-(.+)$`) + return fmt.Sprintf(u.LinkFormat, "ALAS-"+re.FindStringSubmatch(alas.Id)[1]) + } + + return "" } func (u *updater) alasToSeverity(alas ALAS) database.Severity { @@ -287,7 +301,8 @@ func (u *updater) alasToDescription(alas ALAS) string { return re.ReplaceAllString(strings.TrimSpace(alas.Description), " ") } -func (u *updater) alasToFeatureVersions(alas ALAS) (featureVersions []database.AffectedFeature) { +func (u *updater) alasToFeatureVersions(alas ALAS) []database.AffectedFeature { + var featureVersions []database.AffectedFeature for _, p := range alas.Packages { var version string if p.Epoch == "0" { @@ -301,20 +316,24 @@ func (u *updater) alasToFeatureVersions(alas ALAS) (featureVersions []database.A continue } - var featureVersion database.AffectedFeature - featureVersion.Namespace.Name = u.Namespace - featureVersion.Namespace.VersionFormat = rpm.ParserName - featureVersion.FeatureName = p.Name - featureVersion.AffectedVersion = version + featureVersion := database.AffectedFeature{ + Namespace: database.Namespace{ + Name: u.Namespace, + VersionFormat: rpm.ParserName, + }, + FeatureName: p.Name, + AffectedVersion: version, + AffectedType: database.AffectBinaryPackage, + } + if version != versionfmt.MaxVersion { featureVersion.FixedInVersion = version } - featureVersion.AffectedType = database.AffectBinaryPackage featureVersions = append(featureVersions, featureVersion) } - return + return featureVersions } func compareTimestamp(date0 string, date1 string) int { diff --git a/ext/vulnsrc/amzn/amzn_test.go b/ext/vulnsrc/amzn/amzn_test.go index 4e5f8cf6..9076730c 100644 --- a/ext/vulnsrc/amzn/amzn_test.go +++ b/ext/vulnsrc/amzn/amzn_test.go @@ -28,10 +28,11 @@ import ( func TestAmazonLinux1(t *testing.T) { amazonLinux1Updater := updater{ + MirrorListURI: "http://repo.us-west-2.amazonaws.com/2018.03/updates/x86_64/mirror.list", Name: "Amazon Linux 2018.03", Namespace: "amzn:2018.03", UpdaterFlag: "amazonLinux1Updater", - MirrorListURI: "http://repo.us-west-2.amazonaws.com/2018.03/updates/x86_64/mirror.list", + LinkFormat: "https://alas.aws.amazon.com/%s.html", } _, filename, _, _ := runtime.Caller(0) @@ -49,8 +50,7 @@ func TestAmazonLinux1(t *testing.T) { updateInfo, err := decodeUpdateInfo(updateInfoXml) assert.Nil(t, err) - vulnerabilities, err := amazonLinux1Updater.alasListToVulnerabilities(updateInfo.ALASList) - assert.Nil(t, err) + vulnerabilities := amazonLinux1Updater.alasListToVulnerabilities(updateInfo.ALASList) assert.Equal(t, "ALAS-2011-1", vulnerabilities[0].Name) assert.Equal(t, "https://alas.aws.amazon.com/ALAS-2011-1.html", vulnerabilities[0].Link) @@ -121,10 +121,11 @@ func TestAmazonLinux1(t *testing.T) { func TestAmazonLinux2(t *testing.T) { amazonLinux2Updater := updater{ + MirrorListURI: "https://cdn.amazonlinux.com/2/core/latest/x86_64/mirror.list", Name: "Amazon Linux 2", Namespace: "amzn:2", UpdaterFlag: "amazonLinux2Updater", - MirrorListURI: "https://cdn.amazonlinux.com/2/core/latest/x86_64/mirror.list", + LinkFormat: "https://alas.aws.amazon.com/AL2/%s.html", } _, filename, _, _ := runtime.Caller(0) @@ -142,8 +143,7 @@ func TestAmazonLinux2(t *testing.T) { updateInfo, err := decodeUpdateInfo(updateInfoXml) assert.Nil(t, err) - vulnerabilities, err := amazonLinux2Updater.alasListToVulnerabilities(updateInfo.ALASList) - assert.Nil(t, err) + vulnerabilities := amazonLinux2Updater.alasListToVulnerabilities(updateInfo.ALASList) assert.Equal(t, "ALAS2-2018-939", vulnerabilities[0].Name) assert.Equal(t, "https://alas.aws.amazon.com/AL2/ALAS-2018-939.html", vulnerabilities[0].Link) From adde75975f42f9e116829c1d5b875f35e788e169 Mon Sep 17 00:00:00 2001 From: Eric Sim Date: Thu, 11 Apr 2019 12:32:08 -0700 Subject: [PATCH 5/7] Fix style issues --- ext/vulnsrc/amzn/amzn.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ext/vulnsrc/amzn/amzn.go b/ext/vulnsrc/amzn/amzn.go index 6a1fd465..d188c971 100644 --- a/ext/vulnsrc/amzn/amzn.go +++ b/ext/vulnsrc/amzn/amzn.go @@ -1,4 +1,4 @@ -// Copyright 2017 clair authors +// Copyright 2019 clair authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -20,13 +20,14 @@ import ( "bufio" "compress/gzip" "encoding/xml" + "fmt" "io" "regexp" "strings" log "github.com/sirupsen/logrus" - "fmt" + "github.com/coreos/clair/database" "github.com/coreos/clair/ext/versionfmt" "github.com/coreos/clair/ext/versionfmt/rpm" @@ -41,6 +42,7 @@ const ( amazonLinux1Name = "Amazon Linux 2018.03" amazonLinux1Namespace = "amzn:2018.03" amazonLinux1LinkFormat = "https://alas.aws.amazon.com/%s.html" + amazonLinux2UpdaterFlag = "amazonLinux2Updater" amazonLinux2MirrorListURI = "https://cdn.amazonlinux.com/2/core/latest/x86_64/mirror.list" amazonLinux2Name = "Amazon Linux 2" From 6617f560cc9ce90eece08aca29841827c72ca5c2 Mon Sep 17 00:00:00 2001 From: Eric Sim Date: Thu, 11 Apr 2019 13:14:32 -0700 Subject: [PATCH 6/7] database: Rename affected type to feature type (for Amazon Linux updater) --- ext/vulnsrc/amzn/amzn.go | 3 +-- ext/vulnsrc/amzn/amzn_test.go | 16 ++++++++-------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/ext/vulnsrc/amzn/amzn.go b/ext/vulnsrc/amzn/amzn.go index d188c971..232ebe2e 100644 --- a/ext/vulnsrc/amzn/amzn.go +++ b/ext/vulnsrc/amzn/amzn.go @@ -27,7 +27,6 @@ import ( log "github.com/sirupsen/logrus" - "github.com/coreos/clair/database" "github.com/coreos/clair/ext/versionfmt" "github.com/coreos/clair/ext/versionfmt/rpm" @@ -325,7 +324,7 @@ func (u *updater) alasToFeatureVersions(alas ALAS) []database.AffectedFeature { }, FeatureName: p.Name, AffectedVersion: version, - AffectedType: database.AffectBinaryPackage, + FeatureType: database.BinaryPackage, } if version != versionfmt.MaxVersion { diff --git a/ext/vulnsrc/amzn/amzn_test.go b/ext/vulnsrc/amzn/amzn_test.go index 9076730c..0ecad6b8 100644 --- a/ext/vulnsrc/amzn/amzn_test.go +++ b/ext/vulnsrc/amzn/amzn_test.go @@ -67,7 +67,7 @@ func TestAmazonLinux1(t *testing.T) { FeatureName: "httpd-devel", AffectedVersion: "2.2.21-1.18.amzn1", FixedInVersion: "2.2.21-1.18.amzn1", - AffectedType: database.AffectBinaryPackage, + FeatureType: database.BinaryPackage, }, { Namespace: database.Namespace{ @@ -77,7 +77,7 @@ func TestAmazonLinux1(t *testing.T) { FeatureName: "httpd-debuginfo", AffectedVersion: "2.2.21-1.18.amzn1", FixedInVersion: "2.2.21-1.18.amzn1", - AffectedType: database.AffectBinaryPackage, + FeatureType: database.BinaryPackage, }, } @@ -100,7 +100,7 @@ func TestAmazonLinux1(t *testing.T) { FeatureName: "cyrus-imapd-debuginfo", AffectedVersion: "2.3.16-6.4.amzn1", FixedInVersion: "2.3.16-6.4.amzn1", - AffectedType: database.AffectBinaryPackage, + FeatureType: database.BinaryPackage, }, { Namespace: database.Namespace{ @@ -110,7 +110,7 @@ func TestAmazonLinux1(t *testing.T) { FeatureName: "cyrus-imapd-utils", AffectedVersion: "2.3.16-6.4.amzn1", FixedInVersion: "2.3.16-6.4.amzn1", - AffectedType: database.AffectBinaryPackage, + FeatureType: database.BinaryPackage, }, } @@ -160,7 +160,7 @@ func TestAmazonLinux2(t *testing.T) { FeatureName: "kernel", AffectedVersion: "4.9.76-38.79.amzn2", FixedInVersion: "4.9.76-38.79.amzn2", - AffectedType: database.AffectBinaryPackage, + FeatureType: database.BinaryPackage, }, { Namespace: database.Namespace{ @@ -170,7 +170,7 @@ func TestAmazonLinux2(t *testing.T) { FeatureName: "kernel-headers", AffectedVersion: "4.9.76-38.79.amzn2", FixedInVersion: "4.9.76-38.79.amzn2", - AffectedType: database.AffectBinaryPackage, + FeatureType: database.BinaryPackage, }, } @@ -193,7 +193,7 @@ func TestAmazonLinux2(t *testing.T) { FeatureName: "qemu-kvm", AffectedVersion: "10:1.5.3-141.amzn2.5.3", FixedInVersion: "10:1.5.3-141.amzn2.5.3", - AffectedType: database.AffectBinaryPackage, + FeatureType: database.BinaryPackage, }, { Namespace: database.Namespace{ @@ -203,7 +203,7 @@ func TestAmazonLinux2(t *testing.T) { FeatureName: "qemu-img", AffectedVersion: "10:1.5.3-141.amzn2.5.3", FixedInVersion: "10:1.5.3-141.amzn2.5.3", - AffectedType: database.AffectBinaryPackage, + FeatureType: database.BinaryPackage, }, } From 32cd4f1ec3ffa0abe5807d6bb34eebea5792311e Mon Sep 17 00:00:00 2001 From: Eric Sim Date: Tue, 23 Apr 2019 10:38:48 -0700 Subject: [PATCH 7/7] Add Amazon Linux to drivers and data sources doc --- Documentation/drivers-and-data-sources.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Documentation/drivers-and-data-sources.md b/Documentation/drivers-and-data-sources.md index ddbfcce4..11c06795 100644 --- a/Documentation/drivers-and-data-sources.md +++ b/Documentation/drivers-and-data-sources.md @@ -17,21 +17,23 @@ All of these components can be found in the `ext/` directory. ## Data Sources for the built-in drivers -| Data Source | Data Collected | Format | License | -|-------------------------------|--------------------------------------------------------------------------|--------|-----------------| -| [Debian Security Bug Tracker] | Debian 6, 7, 8, unstable namespaces | [dpkg] | [Debian] | -| [Ubuntu CVE Tracker] | Ubuntu 12.04, 12.10, 13.04, 14.04, 14.10, 15.04, 15.10, 16.04 namespaces | [dpkg] | [GPLv2] | -| [Red Hat Security Data] | CentOS 5, 6, 7 namespaces | [rpm] | [CVRF] | -| [Oracle Linux Security Data] | Oracle Linux 5, 6, 7 namespaces | [rpm] | [CVRF] | -| [SUSE OVAL Descriptions] | openSUSE, SUSE Linux Enterprise namespaces | [rpm] | [CC-BY-NC-4.0] | -| [Alpine SecDB] | Alpine 3.3, Alpine 3.4, Alpine 3.5 namespaces | [apk] | [MIT] | -| [NIST NVD] | Generic Vulnerability Metadata | N/A | [Public Domain] | +| Data Source | Data Collected | Format | License | +|------------------------------------|--------------------------------------------------------------------------|--------|-----------------| +| [Debian Security Bug Tracker] | Debian 6, 7, 8, unstable namespaces | [dpkg] | [Debian] | +| [Ubuntu CVE Tracker] | Ubuntu 12.04, 12.10, 13.04, 14.04, 14.10, 15.04, 15.10, 16.04 namespaces | [dpkg] | [GPLv2] | +| [Red Hat Security Data] | CentOS 5, 6, 7 namespaces | [rpm] | [CVRF] | +| [Oracle Linux Security Data] | Oracle Linux 5, 6, 7 namespaces | [rpm] | [CVRF] | +| [Amazon Linux Security Advisories] | Amazon Linux 2018.03, 2 namespaces | [rpm] | [MIT-0] | +| [SUSE OVAL Descriptions] | openSUSE, SUSE Linux Enterprise namespaces | [rpm] | [CC-BY-NC-4.0] | +| [Alpine SecDB] | Alpine 3.3, Alpine 3.4, Alpine 3.5 namespaces | [apk] | [MIT] | +| [NIST NVD] | Generic Vulnerability Metadata | N/A | [Public Domain] | [Debian Security Bug Tracker]: https://security-tracker.debian.org/tracker [Ubuntu CVE Tracker]: https://launchpad.net/ubuntu-cve-tracker [Red Hat Security Data]: https://www.redhat.com/security/data/metrics [Oracle Linux Security Data]: https://linux.oracle.com/security/ [SUSE OVAL Descriptions]: https://www.suse.com/de-de/support/security/oval/ +[Amazon Linux Security Advisories]: https://alas.aws.amazon.com/ [NIST NVD]: https://nvd.nist.gov [dpkg]: https://en.wikipedia.org/wiki/dpkg [rpm]: http://www.rpm.org @@ -42,6 +44,7 @@ All of these components can be found in the `ext/` directory. [Alpine SecDB]: http://git.alpinelinux.org/cgit/alpine-secdb/ [apk]: http://git.alpinelinux.org/cgit/apk-tools/ [MIT]: https://gist.github.com/jzelinskie/6da1e2da728424d88518be2adbd76979 +[MIT-0]: https://spdx.org/licenses/MIT-0.html [CC-BY-NC-4.0]: https://creativecommons.org/licenses/by-nc/4.0/] ## Adding new drivers