From f5c5573936e7226a22f327e8ff7578d9b619d5e9 Mon Sep 17 00:00:00 2001 From: MaineK00n Date: Thu, 20 Jan 2022 18:43:43 +0900 Subject: [PATCH] feat(rocky): support Rocky Linux (#1570) Co-authored-by: knqyf263 --- README.md | 2 +- docs/getting-started/overview.md | 2 +- docs/vulnerability/detection/data-source.md | 4 +- docs/vulnerability/detection/os.md | 1 + go.mod | 2 +- go.sum | 2 + integration/client_server_test.go | 7 + integration/docker_engine_test.go | 6 + integration/standalone_tar_test.go | 8 + integration/testdata/almalinux-8.json.golden | 3 +- .../testdata/fixtures/db/rockylinux.yaml | 7 + .../testdata/fixtures/db/vulnerability.yaml | 2 + integration/testdata/rockylinux-8.json.golden | 118 +++++++++++++ pkg/detector/ospkg/detect.go | 3 + pkg/detector/ospkg/rocky/rocky.go | 132 ++++++++++++++ pkg/detector/ospkg/rocky/rocky_test.go | 167 ++++++++++++++++++ .../rocky/testdata/fixtures/invalid.yaml | 9 + .../rocky/testdata/fixtures/modular.yaml | 7 + .../ospkg/rocky/testdata/fixtures/rocky.yaml | 10 ++ pkg/result/result.go | 2 +- 20 files changed, 488 insertions(+), 6 deletions(-) create mode 100644 integration/testdata/fixtures/db/rockylinux.yaml create mode 100644 integration/testdata/rockylinux-8.json.golden create mode 100644 pkg/detector/ospkg/rocky/rocky.go create mode 100644 pkg/detector/ospkg/rocky/rocky_test.go create mode 100644 pkg/detector/ospkg/rocky/testdata/fixtures/invalid.yaml create mode 100644 pkg/detector/ospkg/rocky/testdata/fixtures/modular.yaml create mode 100644 pkg/detector/ospkg/rocky/testdata/fixtures/rocky.yaml diff --git a/README.md b/README.md index 8984e62c9a..323d3cf429 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0) # Features - Comprehensive vulnerability detection - - OS packages (Alpine Linux, Red Hat Universal Base Image, Red Hat Enterprise Linux, CentOS, Oracle Linux, Debian, Ubuntu, Amazon Linux, openSUSE Leap, SUSE Enterprise Linux, Photon OS and Distroless) + - OS packages (Alpine Linux, Red Hat Universal Base Image, Red Hat Enterprise Linux, CentOS, AlmaLinux, Rocky Linux, Oracle Linux, Debian, Ubuntu, Amazon Linux, openSUSE Leap, SUSE Enterprise Linux, Photon OS and Distroless) - **Language-specific packages** (Bundler, Composer, Pipenv, Poetry, npm, yarn, Cargo, NuGet, Maven, and Go) - Misconfiguration detection (IaC scanning) - A wide variety of built-in policies are provided **out of the box** diff --git a/docs/getting-started/overview.md b/docs/getting-started/overview.md index 42c5cc379b..26e25bc1f9 100644 --- a/docs/getting-started/overview.md +++ b/docs/getting-started/overview.md @@ -22,7 +22,7 @@ See [Integrations][integrations] for details. ## Features - Comprehensive vulnerability detection - - [OS packages][os] (Alpine, Red Hat Universal Base Image, Red Hat Enterprise Linux, CentOS, AlmaLinux, Oracle Linux, Debian, Ubuntu, Amazon Linux, openSUSE Leap, SUSE Enterprise Linux, Photon OS and Distroless) + - [OS packages][os] (Alpine, Red Hat Universal Base Image, Red Hat Enterprise Linux, CentOS, AlmaLinux, Rocky Linux, Oracle Linux, Debian, Ubuntu, Amazon Linux, openSUSE Leap, SUSE Enterprise Linux, Photon OS and Distroless) - [**Language-specific packages**][lang] (Bundler, Composer, Pipenv, Poetry, npm, yarn, Cargo, NuGet, Maven, and Go) - Detect IaC misconfigurations - A wide variety of [built-in policies][builtin] are provided **out of the box**: diff --git a/docs/vulnerability/detection/data-source.md b/docs/vulnerability/detection/data-source.md index fae7aad62e..1793a080aa 100644 --- a/docs/vulnerability/detection/data-source.md +++ b/docs/vulnerability/detection/data-source.md @@ -11,7 +11,8 @@ | Ubuntu | [Ubuntu CVE Tracker][ubuntu] | | RHEL/CentOS | [OVAL][rhel-oval] | | | [Security Data][rhel-api] | -| AlmaLinux | [AlmaLinux Product Errata][alma] | +| AlmaLinux | [AlmaLinux Product Errata][alma] | +| Rocky Linux | [Rocky Linux UpdateInfo][rocky] | | Oracle Linux | [OVAL][oracle] | | OpenSUSE/SLES | [CVRF][suse] | | Photon OS | [Photon Security Advisory][photon] | @@ -53,6 +54,7 @@ [rhel-oval]: https://www.redhat.com/security/data/oval/v2/ [rhel-api]: https://www.redhat.com/security/data/metrics/ [alma]: https://errata.almalinux.org/ +[rocky]: https://download.rockylinux.org/pub/rocky/ [oracle]: https://linux.oracle.com/security/oval/ [suse]: http://ftp.suse.com/pub/projects/security/cvrf/ [photon]: https://packages.vmware.com/photon/photon_cve_metadata/ diff --git a/docs/vulnerability/detection/os.md b/docs/vulnerability/detection/os.md index 6dc8dd6bfb..9f7595dcf0 100644 --- a/docs/vulnerability/detection/os.md +++ b/docs/vulnerability/detection/os.md @@ -9,6 +9,7 @@ The unfixed/unfixable vulnerabilities mean that the patch has not yet been provi | Red Hat Enterprise Linux | 6, 7, 8 | Installed by yum/rpm | YES | | CentOS | 6, 7, 8 | Installed by yum/rpm | YES | | AlmaLinux | 8 | Installed by yum/rpm | NO | +| Rocky Linux | 8 | Installed by yum/rpm | NO | | Oracle Linux | 5, 6, 7, 8 | Installed by yum/rpm | NO | | Amazon Linux | 1, 2 | Installed by yum/rpm | NO | | openSUSE Leap | 42, 15 | Installed by zypper/rpm | NO | diff --git a/go.mod b/go.mod index f8de4cb998..bb48638350 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492 - github.com/aquasecurity/trivy-db v0.0.0-20220116182821-1a83ba8d44cf + github.com/aquasecurity/trivy-db v0.0.0-20220119092408-3e43e9ac6def github.com/caarlos0/env/v6 v6.0.0 github.com/cenkalti/backoff v2.2.1+incompatible github.com/cheggaaa/pb/v3 v3.0.3 diff --git a/go.sum b/go.sum index c2ad0f84b9..5effb5e812 100644 --- a/go.sum +++ b/go.sum @@ -243,6 +243,8 @@ github.com/aquasecurity/tfsec v0.63.1 h1:KH63HTcUoab7d3PKtqFO6T8K5AY7bzLw7Kiu+EY github.com/aquasecurity/tfsec v0.63.1/go.mod h1:g5ZWmsfqW1FsCaPb9ux8Pzjcyss/WUB2XuRd5slqvnc= github.com/aquasecurity/trivy-db v0.0.0-20220116182821-1a83ba8d44cf h1:STzhFjoXPmE+HQzjydti5w5KNvQpUYwaH4y878jq+II= github.com/aquasecurity/trivy-db v0.0.0-20220116182821-1a83ba8d44cf/go.mod h1:rnojVJTK+RySsfLW7xMqmQRSjQpm5fEjS+/N4kf3fcc= +github.com/aquasecurity/trivy-db v0.0.0-20220119092408-3e43e9ac6def h1:2E1Fj1ouevZG/2ii+XgZitDf3h5fyvNeUKduHbpDZr0= +github.com/aquasecurity/trivy-db v0.0.0-20220119092408-3e43e9ac6def/go.mod h1:rnojVJTK+RySsfLW7xMqmQRSjQpm5fEjS+/N4kf3fcc= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= diff --git a/integration/client_server_test.go b/integration/client_server_test.go index a98df130b6..406155f4b5 100644 --- a/integration/client_server_test.go +++ b/integration/client_server_test.go @@ -148,6 +148,13 @@ func TestClientServer(t *testing.T) { }, golden: "testdata/almalinux-8.json.golden", }, + { + name: "rocky linux 8", + args: csArgs{ + Input: "testdata/fixtures/images/rockylinux-8.tar.gz", + }, + golden: "testdata/rockylinux-8.json.golden", + }, { name: "distroless base", args: csArgs{ diff --git a/integration/docker_engine_test.go b/integration/docker_engine_test.go index cf1a11a141..41be1cf432 100644 --- a/integration/docker_engine_test.go +++ b/integration/docker_engine_test.go @@ -109,6 +109,12 @@ func TestDockerEngine(t *testing.T) { wantOutputFile: "testdata/almalinux-8.json.golden", testfile: "testdata/fixtures/images/almalinux-8.tar.gz", }, + { + name: "rocky linux 8", + imageTag: "rockylinux:8", + testfile: "testdata/fixtures/images/rockylinux-8.tar.gz", + wantOutputFile: "testdata/rockylinux-8.json.golden", + }, { name: "debian buster/10", imageTag: "debian:buster", diff --git a/integration/standalone_tar_test.go b/integration/standalone_tar_test.go index ba79943a4c..f816b57e70 100644 --- a/integration/standalone_tar_test.go +++ b/integration/standalone_tar_test.go @@ -181,6 +181,14 @@ func TestTar(t *testing.T) { }, golden: "testdata/almalinux-8.json.golden", }, + { + name: "rocky linux 8", + testArgs: args{ + Format: "json", + Input: "testdata/fixtures/images/rockylinux-8.tar.gz", + }, + golden: "testdata/rockylinux-8.json.golden", + }, { name: "distroless base", testArgs: args{ diff --git a/integration/testdata/almalinux-8.json.golden b/integration/testdata/almalinux-8.json.golden index 5ae4f991cf..c9d4dfc4fb 100644 --- a/integration/testdata/almalinux-8.json.golden +++ b/integration/testdata/almalinux-8.json.golden @@ -101,7 +101,8 @@ "https://www.openssl.org/news/secadv/20210824.txt", "https://www.oracle.com/security-alerts/cpuoct2021.html", "https://www.tenable.com/security/tns-2021-16", - "https://www.tenable.com/security/tns-2022-02" + "https://www.tenable.com/security/tns-2022-02", + "https://access.redhat.com/hydra/rest/securitydata/cve/CVE-2021-3712.json" ], "PublishedDate": "2021-08-24T15:15:00Z", "LastModifiedDate": "2022-01-06T09:15:00Z" diff --git a/integration/testdata/fixtures/db/rockylinux.yaml b/integration/testdata/fixtures/db/rockylinux.yaml new file mode 100644 index 0000000000..e24aa9d764 --- /dev/null +++ b/integration/testdata/fixtures/db/rockylinux.yaml @@ -0,0 +1,7 @@ +- bucket: rocky 8 + pairs: + - bucket: openssl-libs + pairs: + - key: CVE-2021-3712 + value: + FixedVersion: 1:1.1.1k-5.el8_5 \ No newline at end of file diff --git a/integration/testdata/fixtures/db/vulnerability.yaml b/integration/testdata/fixtures/db/vulnerability.yaml index b11633aaa4..c397ab59be 100644 --- a/integration/testdata/fixtures/db/vulnerability.yaml +++ b/integration/testdata/fixtures/db/vulnerability.yaml @@ -745,6 +745,7 @@ - https://www.oracle.com/security-alerts/cpuoct2021.html - https://www.tenable.com/security/tns-2021-16 - https://www.tenable.com/security/tns-2022-02 + - https://access.redhat.com/hydra/rest/securitydata/cve/CVE-2021-3712.json Severity: HIGH Title: "openssl: Read buffer overruns processing ASN.1 strings" VendorSeverity: @@ -755,6 +756,7 @@ oracle-oval: 2.0 photon: 3.0 redhat: 2.0 + rocky: 2.0 ubuntu: 2.0 - key: RUSTSEC-2019-0001 value: diff --git a/integration/testdata/rockylinux-8.json.golden b/integration/testdata/rockylinux-8.json.golden new file mode 100644 index 0000000000..31a6373284 --- /dev/null +++ b/integration/testdata/rockylinux-8.json.golden @@ -0,0 +1,118 @@ +{ + "SchemaVersion": 2, + "ArtifactName": "testdata/fixtures/images/rockylinux-8.tar.gz", + "ArtifactType": "container_image", + "Metadata": { + "OS": { + "Family": "rocky", + "Name": "8.5" + }, + "ImageID": "sha256:210996f98b856d7cd00496ddbe9412e73f1c714c95de09661e07b4e43648f9ab", + "DiffIDs": [ + "sha256:65dbea0a4b39709e0a2cc8624fd99478e9f302c0a5661d7676d6d3bd3cb6d181" + ], + "ImageConfig": { + "architecture": "amd64", + "container": "16458df10693f731fae0492f791a5e4b725245c35cf28c7fca00982219d7bdf3", + "created": "2021-12-15T20:22:37.180885096Z", + "docker_version": "20.10.7", + "history": [ + { + "created": "2021-12-15T20:22:36Z", + "created_by": "/bin/sh -c #(nop) ADD file:790b4c6a174560d4701baf59e884e7d07f50f0e193e545d6d5ed1d7390979d1a in / " + }, + { + "created": "2021-12-15T20:22:37Z", + "created_by": "/bin/sh -c #(nop) CMD [\"/bin/bash\"]", + "empty_layer": true + } + ], + "os": "linux", + "rootfs": { + "type": "layers", + "diff_ids": [ + "sha256:65dbea0a4b39709e0a2cc8624fd99478e9f302c0a5661d7676d6d3bd3cb6d181" + ] + }, + "config": { + "Cmd": [ + "/bin/bash" + ], + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ], + "Image": "sha256:b3d7893772a2427ad53224d9db4c70be399de0a28c09804ac0c5cb203ab0244e" + } + } + }, + "Results": [ + { + "Target": "testdata/fixtures/images/rockylinux-8.tar.gz (rocky 8.5)", + "Class": "os-pkgs", + "Type": "rocky", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2021-3712", + "PkgName": "openssl-libs", + "InstalledVersion": "1:1.1.1k-4.el8", + "FixedVersion": "1:1.1.1k-5.el8_5", + "Layer": { + "DiffID": "sha256:65dbea0a4b39709e0a2cc8624fd99478e9f302c0a5661d7676d6d3bd3cb6d181" + }, + "SeveritySource": "rocky", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2021-3712", + "Title": "openssl: Read buffer overruns processing ASN.1 strings", + "Description": "ASN.1 strings are represented internally within OpenSSL as an ASN1_STRING structure which contains a buffer holding the string data and a field holding the buffer length. This contrasts with normal C strings which are repesented as a buffer for the string data which is terminated with a NUL (0) byte. Although not a strict requirement, ASN.1 strings that are parsed using OpenSSL's own \"d2i\" functions (and other similar parsing functions) as well as any string whose value has been set with the ASN1_STRING_set() function will additionally NUL terminate the byte array in the ASN1_STRING structure. However, it is possible for applications to directly construct valid ASN1_STRING structures which do not NUL terminate the byte array by directly setting the \"data\" and \"length\" fields in the ASN1_STRING array. This can also happen by using the ASN1_STRING_set0() function. Numerous OpenSSL functions that print ASN.1 data have been found to assume that the ASN1_STRING byte array will be NUL terminated, even though this is not guaranteed for strings that have been directly constructed. Where an application requests an ASN.1 structure to be printed, and where that ASN.1 structure contains ASN1_STRINGs that have been directly constructed by the application without NUL terminating the \"data\" field, then a read buffer overrun can occur. The same thing can also occur during name constraints processing of certificates (for example if a certificate has been directly constructed by the application instead of loading it via the OpenSSL parsing functions, and the certificate contains non NUL terminated ASN1_STRING structures). It can also occur in the X509_get1_email(), X509_REQ_get1_email() and X509_get1_ocsp() functions. If a malicious actor can cause an application to directly construct an ASN1_STRING and then process it through one of the affected OpenSSL functions then this issue could be hit. This might result in a crash (causing a Denial of Service attack). It could also result in the disclosure of private memory contents (such as private keys, or sensitive plaintext). Fixed in OpenSSL 1.1.1l (Affected 1.1.1-1.1.1k). Fixed in OpenSSL 1.0.2za (Affected 1.0.2-1.0.2y).", + "Severity": "MEDIUM", + "CweIDs": [ + "CWE-125" + ], + "CVSS": { + "nvd": { + "V2Vector": "AV:N/AC:M/Au:N/C:P/I:N/A:P", + "V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:H", + "V2Score": 5.8, + "V3Score": 7.4 + }, + "redhat": { + "V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:H", + "V3Score": 7.4 + } + }, + "References": [ + "http://www.openwall.com/lists/oss-security/2021/08/26/2", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-3712", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=94d23fcff9b2a7a8368dfe52214d5c2569882c11", + "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=ccb0a11145ee72b042d10593a64eaf9e8a55ec12", + "https://kc.mcafee.com/corporate/index?page=content\u0026id=SB10366", + "https://linux.oracle.com/cve/CVE-2021-3712.html", + "https://linux.oracle.com/errata/ELSA-2021-9632.html", + "https://lists.apache.org/thread.html/r18995de860f0e63635f3008fd2a6aca82394249476d21691e7c59c9e@%3Cdev.tomcat.apache.org%3E", + "https://lists.apache.org/thread.html/rad5d9f83f0d11fb3f8bb148d179b8a9ad7c6a17f18d70e5805a713d1@%3Cdev.tomcat.apache.org%3E", + "https://lists.debian.org/debian-lts-announce/2021/09/msg00014.html", + "https://lists.debian.org/debian-lts-announce/2021/09/msg00021.html", + "https://security.netapp.com/advisory/ntap-20210827-0010/", + "https://ubuntu.com/security/notices/USN-5051-1", + "https://ubuntu.com/security/notices/USN-5051-2", + "https://ubuntu.com/security/notices/USN-5051-3", + "https://ubuntu.com/security/notices/USN-5051-4 (regression only in trusty/esm)", + "https://ubuntu.com/security/notices/USN-5088-1", + "https://www.debian.org/security/2021/dsa-4963", + "https://www.openssl.org/news/secadv/20210824.txt", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://www.tenable.com/security/tns-2021-16", + "https://www.tenable.com/security/tns-2022-02", + "https://access.redhat.com/hydra/rest/securitydata/cve/CVE-2021-3712.json" + ], + "PublishedDate": "2021-08-24T15:15:00Z", + "LastModifiedDate": "2022-01-06T09:15:00Z" + } + ] + }, + { + "Target": "Python", + "Class": "lang-pkgs", + "Type": "python-pkg" + } + ] +} \ No newline at end of file diff --git a/pkg/detector/ospkg/detect.go b/pkg/detector/ospkg/detect.go index 3a8176b421..4f122a208c 100644 --- a/pkg/detector/ospkg/detect.go +++ b/pkg/detector/ospkg/detect.go @@ -15,6 +15,7 @@ import ( "github.com/aquasecurity/trivy/pkg/detector/ospkg/oracle" "github.com/aquasecurity/trivy/pkg/detector/ospkg/photon" "github.com/aquasecurity/trivy/pkg/detector/ospkg/redhat" + "github.com/aquasecurity/trivy/pkg/detector/ospkg/rocky" "github.com/aquasecurity/trivy/pkg/detector/ospkg/suse" "github.com/aquasecurity/trivy/pkg/detector/ospkg/ubuntu" "github.com/aquasecurity/trivy/pkg/log" @@ -76,6 +77,8 @@ func newDriver(osFamily, osName string) Driver { return ubuntu.NewScanner() case fos.RedHat, fos.CentOS: return redhat.NewScanner() + case fos.Rocky: + return rocky.NewScanner() case fos.Amazon: return amazon.NewScanner() case fos.Oracle: diff --git a/pkg/detector/ospkg/rocky/rocky.go b/pkg/detector/ospkg/rocky/rocky.go new file mode 100644 index 0000000000..86a3cd10b6 --- /dev/null +++ b/pkg/detector/ospkg/rocky/rocky.go @@ -0,0 +1,132 @@ +package rocky + +import ( + "strings" + "time" + + version "github.com/knqyf263/go-rpm-version" + "golang.org/x/xerrors" + "k8s.io/utils/clock" + + ftypes "github.com/aquasecurity/fanal/types" + "github.com/aquasecurity/trivy-db/pkg/vulnsrc/rocky" + "github.com/aquasecurity/trivy/pkg/log" + "github.com/aquasecurity/trivy/pkg/scanner/utils" + "github.com/aquasecurity/trivy/pkg/types" +) + +var ( + eolDates = map[string]time.Time{ + // Source: + // https://endoflife.date/rocky-linux + "8": time.Date(2029, 5, 31, 23, 59, 59, 0, time.UTC), + } +) + +type options struct { + clock clock.Clock +} + +type option func(*options) + +func WithClock(clock clock.Clock) option { + return func(opts *options) { + opts.clock = clock + } +} + +// Scanner implements the Rocky Linux scanner +type Scanner struct { + vs rocky.VulnSrc + *options +} + +// NewScanner is the factory method for Scanner +func NewScanner(opts ...option) *Scanner { + o := &options{ + clock: clock.RealClock{}, + } + + for _, opt := range opts { + opt(o) + } + return &Scanner{ + vs: rocky.NewVulnSrc(), + options: o, + } +} + +// Detect vulnerabilities in package using Rocky Linux scanner +func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) { + log.Logger.Info("Detecting Rocky Linux vulnerabilities...") + if strings.Count(osVer, ".") > 0 { + osVer = osVer[:strings.Index(osVer, ".")] + } + log.Logger.Debugf("Rocky Linux: os version: %s", osVer) + log.Logger.Debugf("Rocky Linux: the number of packages: %d", len(pkgs)) + + var vulns []types.DetectedVulnerability + var skipPkgs []string + for _, pkg := range pkgs { + if pkg.Modularitylabel != "" { + skipPkgs = append(skipPkgs, pkg.Name) + continue + } + pkgName := addModularNamespace(pkg.Name, pkg.Modularitylabel) + advisories, err := s.vs.Get(osVer, pkgName) + if err != nil { + return nil, xerrors.Errorf("failed to get Rocky Linux advisories: %w", err) + } + + installed := utils.FormatVersion(pkg) + installedVersion := version.NewVersion(installed) + + for _, adv := range advisories { + fixedVersion := version.NewVersion(adv.FixedVersion) + if installedVersion.LessThan(fixedVersion) { + vuln := types.DetectedVulnerability{ + VulnerabilityID: adv.VulnerabilityID, + PkgName: pkg.Name, + InstalledVersion: installed, + FixedVersion: fixedVersion.String(), + Layer: pkg.Layer, + } + vulns = append(vulns, vuln) + } + } + } + if len(skipPkgs) > 0 { + log.Logger.Infof("Skipped detection of these packages: %q because modular packages cannot be detected correctly due to a bug in Rocky Linux Errata. See also: https://forums.rockylinux.org/t/some-errata-missing-in-comparison-with-rhel-and-almalinux/3843", skipPkgs) + } + + return vulns, nil +} + +// IsSupportedVersion checks the OSFamily can be scanned using Rocky Linux scanner +func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool { + if strings.Count(osVer, ".") > 0 { + osVer = osVer[:strings.Index(osVer, ".")] + } + + eol, ok := eolDates[osVer] + if !ok { + log.Logger.Warnf("This OS version is not on the EOL list: %s %s", osFamily, osVer) + return false + } + + return s.clock.Now().Before(eol) +} + +func addModularNamespace(name, label string) string { + // e.g. npm, nodejs:12:8030020201124152102:229f0a1c => nodejs:12::npm + var count int + for i, r := range label { + if r == ':' { + count++ + } + if count == 2 { + return label[:i] + "::" + name + } + } + return name +} diff --git a/pkg/detector/ospkg/rocky/rocky_test.go b/pkg/detector/ospkg/rocky/rocky_test.go new file mode 100644 index 0000000000..81fd207112 --- /dev/null +++ b/pkg/detector/ospkg/rocky/rocky_test.go @@ -0,0 +1,167 @@ +package rocky_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + fake "k8s.io/utils/clock/testing" + + ftypes "github.com/aquasecurity/fanal/types" + "github.com/aquasecurity/trivy-db/pkg/db" + "github.com/aquasecurity/trivy/pkg/dbtest" + "github.com/aquasecurity/trivy/pkg/detector/ospkg/rocky" + "github.com/aquasecurity/trivy/pkg/types" +) + +func TestScanner_Detect(t *testing.T) { + type args struct { + osVer string + pkgs []ftypes.Package + } + tests := []struct { + name string + args args + fixtures []string + want []types.DetectedVulnerability + wantErr string + }{ + { + name: "happy path", + fixtures: []string{"testdata/fixtures/rocky.yaml"}, + args: args{ + osVer: "8.5", + pkgs: []ftypes.Package{ + { + Name: "bpftool", + Epoch: 0, + Version: "4.18.0", + Release: "348.el8.0.3", + Arch: "x86_64", + SrcName: "kernel", + SrcEpoch: 0, + SrcVersion: "4.18.0", + SrcRelease: "348.el8.0.3", + Modularitylabel: "", + License: "GPLv2", + Layer: ftypes.Layer{}, + }, + }, + }, + want: []types.DetectedVulnerability{ + { + PkgName: "bpftool", + VulnerabilityID: "CVE-2021-20317", + InstalledVersion: "4.18.0-348.el8.0.3", + FixedVersion: "4.18.0-348.2.1.el8_5", + Layer: ftypes.Layer{}, + }, + }, + }, + { + name: "skip modular package", + fixtures: []string{"testdata/fixtures/modular.yaml"}, + args: args{ + osVer: "8.5", + pkgs: []ftypes.Package{ + { + Name: "nginx", + Epoch: 1, + Version: "1.16.1", + Release: "2.module+el8.4.0+543+efbf198b.0", + Arch: "x86_64", + SrcName: "nginx", + SrcEpoch: 1, + SrcVersion: "1.16.1", + SrcRelease: "2.module+el8.4.0+543+efbf198b.0", + Modularitylabel: "nginx:1.16:8040020210610090125:9f9e2e7e", + License: "BSD", + Layer: ftypes.Layer{}, + }, + }, + }, + want: nil, + }, + { + name: "Get returns an error", + fixtures: []string{"testdata/fixtures/invalid.yaml"}, + args: args{ + osVer: "8.5", + pkgs: []ftypes.Package{ + { + Name: "jq", + Version: "1.5-12", + SrcName: "jq", + SrcVersion: "1.5-12", + }, + }, + }, + wantErr: "failed to get Rocky Linux advisories", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _ = dbtest.InitDB(t, tt.fixtures) + defer db.Close() + + s := rocky.NewScanner() + got, err := s.Detect(tt.args.osVer, tt.args.pkgs) + if tt.wantErr != "" { + require.Error(t, err) + assert.Contains(t, err.Error(), tt.wantErr) + return + } + assert.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} + +func TestScanner_IsSupportedVersion(t *testing.T) { + type args struct { + osFamily string + osVer string + } + tests := []struct { + name string + now time.Time + args args + want bool + }{ + { + name: "rocky 8.5", + now: time.Date(2019, 3, 2, 23, 59, 59, 0, time.UTC), + args: args{ + osFamily: "rocky", + osVer: "8.5", + }, + want: true, + }, + { + name: "rocky 8.5 with EOL", + now: time.Date(2029, 6, 1, 0, 0, 0, 0, time.UTC), + args: args{ + osFamily: "rocky", + osVer: "8.5", + }, + want: false, + }, + { + name: "unknown", + now: time.Date(2019, 5, 2, 23, 59, 59, 0, time.UTC), + args: args{ + osFamily: "rocky", + osVer: "unknown", + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := rocky.NewScanner(rocky.WithClock(fake.NewFakeClock(tt.now))) + got := s.IsSupportedVersion(tt.args.osFamily, tt.args.osVer) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/pkg/detector/ospkg/rocky/testdata/fixtures/invalid.yaml b/pkg/detector/ospkg/rocky/testdata/fixtures/invalid.yaml new file mode 100644 index 0000000000..883c443e85 --- /dev/null +++ b/pkg/detector/ospkg/rocky/testdata/fixtures/invalid.yaml @@ -0,0 +1,9 @@ +- bucket: rocky 8 + pairs: + - bucket: jq + pairs: + - key: CVE-2020-8177 + value: + FixedVersion: + - foo + - bar \ No newline at end of file diff --git a/pkg/detector/ospkg/rocky/testdata/fixtures/modular.yaml b/pkg/detector/ospkg/rocky/testdata/fixtures/modular.yaml new file mode 100644 index 0000000000..32858f14d6 --- /dev/null +++ b/pkg/detector/ospkg/rocky/testdata/fixtures/modular.yaml @@ -0,0 +1,7 @@ +- bucket: rocky 8 + pairs: + - bucket: nginx:1.16::nginx # actual: bucket of modular package is not created. ref: https://github.com/aquasecurity/trivy-db/pull/154 + pairs: + - key: CVE-2021-23017 + value: + FixedVersion: "1:1.16.1-2.module+el8.4.0+543+efbf198b.1" \ No newline at end of file diff --git a/pkg/detector/ospkg/rocky/testdata/fixtures/rocky.yaml b/pkg/detector/ospkg/rocky/testdata/fixtures/rocky.yaml new file mode 100644 index 0000000000..b66e5b20ac --- /dev/null +++ b/pkg/detector/ospkg/rocky/testdata/fixtures/rocky.yaml @@ -0,0 +1,10 @@ +- bucket: rocky 8 + pairs: + - bucket: bpftool + pairs: + - key: CVE-2021-0129 + value: + FixedVersion: "4.18.0-348.el8.0.2" + - key: CVE-2021-20317 + value: + FixedVersion: "4.18.0-348.2.1.el8_5" \ No newline at end of file diff --git a/pkg/result/result.go b/pkg/result/result.go index 5eab84dedf..2ef9c35619 100644 --- a/pkg/result/result.go +++ b/pkg/result/result.go @@ -94,7 +94,7 @@ func (c Client) detectSource(reportType string) []string { switch reportType { case vulnerability.Ubuntu, vulnerability.Alpine, vulnerability.RedHat, vulnerability.RedHatOVAL, vulnerability.Debian, vulnerability.DebianOVAL, vulnerability.Fedora, vulnerability.Amazon, - vulnerability.OracleOVAL, vulnerability.SuseCVRF, vulnerability.OpenSuseCVRF, vulnerability.Photon, vulnerability.Alma: + vulnerability.OracleOVAL, vulnerability.SuseCVRF, vulnerability.OpenSuseCVRF, vulnerability.Photon, vulnerability.Alma, vulnerability.Rocky: sources = []string{reportType} case vulnerability.CentOS: // CentOS doesn't have its own so we use RedHat sources = []string{vulnerability.RedHat}