Repository: aquasecurity/trivy (Go)

Issue:
Can trivy filter false positive vulnerabilities for centos 7 (epel, remi)?
Hi, Trivy team
I use Trivy to scan centos:7 based image. However, I get many false positives in result.

Trivy version: 0.11.0
Base image: centos:7 (centos 7.8.2003)
Trivy command: trivy --timeout 5m0s --vuln-type os -f json -q $image-name

<details>
<summary>Click to toggle contents of 'Dockerfile'</summary>

```
FROM centos:7
RUN yum upgrade -y

RUN yum install -y \
        https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \
        https://rpms.remirepo.net/enterprise/remi-release-7.rpm \
    && \
    rpm --import \
        /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 \
        /etc/pki/rpm-gpg/RPM-GPG-KEY-remi \
        /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 \
    && \
    yum-config-manager --enable remi,remi-php73 && \
    yum install -y \
        php
```
</details>


The result will contain the following:
<details>
<summary>Click to toggle contents of 'Result'</summary>

```json
...
{
        "VulnerabilityID": "CVE-2015-5589",
        "PkgName": "php",
        "InstalledVersion": "7.3.22-1.el7.remi",
        "Layer": {
          "DiffID": "sha256:2c1f6971c560d8970f6f247d0040c4a48752eb8b9166aae0dc885dd9b7c732e9"
        },
        "SeveritySource": "redhat",
        "Title": "php: segmentation fault in Phar::convertToData on invalid file",
        "Description": "The phar_convert_to_other function in ext/phar/phar_object.c in PHP before 5.4.43, 5.5.x before 5.5.27, and 5.6.x before 5.6.11 does not validate a file pointer before a close operation, which allows remote attackers to cause a denial of service (segmentation fault) or possibly have unspecified other impact via a crafted TAR archive that is mishandled in a Phar::convertToData call.",
        "Severity": "MEDIUM",
        "CweIDs": [
          "CWE-20"
        ],
        "VendorVectors": {
          "nvd": {
            "v2": "AV:N/AC:L/Au:N/C:C/I:C/A:C",
            "v3": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
          },
          "redhat": {
            "v2": "AV:N/AC:M/Au:N/C:N/I:N/A:P"
          }
        },
        "CVSS": {
          "nvd": {
            "V2Vector": "AV:N/AC:L/Au:N/C:C/I:C/A:C",
            "V3Vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
            "V2Score": 10,
            "V3Score": 9.8
          },
          "redhat": {
            "V2Vector": "AV:N/AC:M/Au:N/C:N/I:N/A:P",
            "V2Score": 4.3
          }
        },
        "References": [
          "http://git.php.net/?p=php-src.git;a=commit;h=bf58162ddf970f63502837f366930e44d6a992cf",
          "http://openwall.com/lists/oss-security/2015/07/18/1",
          "http://php.net/ChangeLog-5.php",
          "http://seclists.org/oss-sec/2015/q3/141",
          "http://www.debian.org/security/2015/dsa-3344",
          "http://www.securityfocus.com/bid/75974",
          "https://bugs.php.net/bug.php?id=69958",
          "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-5589",
          "https://usn.ubuntu.com/usn/usn-2758-1"
        ],
        "PublishedDate": "2016-05-16T10:59:00Z",
        "LastModifiedDate": "2017-11-04T01:29:00Z"
      }
...
```
</details>

Based on the Description and References, the vulnerability does not affect the installed 7.3.22-1.el7.remi PHP version. I have attached only one vulnerability for PHP, but there are 156 false positive vulnerabilities in total. Many false positive vulnerabilities for another packages also, but I chose PHP for example.

Why are many false positive for centos? Could I change configuration to filter false positive?




Discussion:
Thanks for the report @ar1em – we're taking a look and will get back to you.
It looks like this issue is caused by `remi` repository. `yum install php` usually installs php 5.x, but `remi-php73` installs php 7.x. `remi` repository doesn't seem to provide security advisories and we can't detect vulnerabilities. We should skip the version with `.remi` suffix for now. I think we can insert the process here.
https://github.com/aquasecurity/trivy/blob/329f2452835b241c85659abcebc3dd80bacefa33/pkg/detector/ospkg/redhat/redhat.go#L66
We can fix this issue shortly, but let me keep it for the first contributor.
@knqyf263 

I was trying to contribute by fixing this issue. But unable to reproduce the issue.

Created the image with the given  Dockerfile.

./trivy --timeout 5m0s --vuln-type os -f json -q testimage
[
  {
    "Target": "testimage (centos 7.8.2003)",
    "Type": "centos",
    "Vulnerabilities": null
  }
]

Same here. Can't reproduce with trivy built from `master` branch and provided Dockerfile:
```
./trivy --timeout 5m0s --vuln-type os -f json -q test_image:v1
[
  {
    "Target": "test_image:v1 (centos 7.8.2003)",
    "Type": "centos",
    "Vulnerabilities": null
  }
]
```
@rahul2393 Can you help them reproduce it?
> @rahul2393 Can you help them reproduce it?
Checking
reproduced
@pippo @KrishKayc
```
#!/bin/bash 

# build trivy version 0.11.0
git clone https://github.com/aquasecurity/trivy 
cd trivy 
git checkout v0.11.0
make build 

# make image
mkdir testimage 
cat <<EOF > testimage/Dockerfile
FROM centos:7
RUN yum upgrade -y
RUN yum install -y \
        https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm \
        https://rpms.remirepo.net/enterprise/remi-release-7.rpm \
    && \
    rpm --import \
        /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 \
        /etc/pki/rpm-gpg/RPM-GPG-KEY-remi \
        /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 \
    && \
    yum-config-manager --enable remi,remi-php73 && \
    yum install -y php
EOF
cd testimage 
docker build -t testimage-649 .

# scan image
cd ../
./trivy testimage-649

```
<img width="1440" alt="Screenshot 2020-10-14 at 5 08 10 PM" src="https://user-images.githubusercontent.com/18293335/95983783-d8ebe980-0e3f-11eb-84a2-267e846bc490.png">
Interestingly  at my end also it's not replicated
@masahiro331  thanks, but still no.

Runnunig the shell script you provided ends up with a successful run:
```
[...]

Installed:
  php.x86_64 0:7.3.23-1.el7.remi

Dependency Installed:
  apr.x86_64 0:1.4.8-5.el7
  apr-util.x86_64 0:1.5.2-6.el7
  centos-logos.noarch 0:70.0.6-3.el7.centos
  httpd.x86_64 0:2.4.6-93.el7.centos
  httpd-tools.x86_64 0:2.4.6-93.el7.centos
  libargon2.x86_64 0:20161029-3.el7
  libedit.x86_64 0:3.0-12.20121213cvs.el7
  mailcap.noarch 0:2.1.41-2.el7
  php-cli.x86_64 0:7.3.23-1.el7.remi
  php-common.x86_64 0:7.3.23-1.el7.remi
  php-json.x86_64 0:7.3.23-1.el7.remi

Complete!
Removing intermediate container 2042235bf295
 ---> 896e823e5043
Successfully built 896e823e5043
Successfully tagged testimage-649:latest
2020-10-14T13:28:34.469+0200    WARN    You should avoid using the :latest tag as it is cached. You need to specify '--clear-cache' option when :latest image is changed
2020-10-14T13:28:34.513+0200    INFO    Need to update DB
2020-10-14T13:28:34.513+0200    INFO    Downloading DB...
18.82 MiB / 18.82 MiB [---------------------------------------------------------------------------------------------------------------------------------------------------------] 100.00% 373.67 KiB p/s 52s
2020-10-14T13:29:42.449+0200    WARN    No OS package is detected. Make sure you haven't deleted any files that contain information about the installed packages.
2020-10-14T13:29:42.449+0200    WARN    e.g. files under "/lib/apk/db/", "/var/lib/dpkg/" and "/var/lib/rpm"
2020-10-14T13:29:42.449+0200    INFO    Detecting RHEL/CentOS vulnerabilities...

testimage-649 (centos 7.8.2003)
===============================
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
```

My env:
```
# uname -a
Darwin xxxxxxxx 19.6.0 Darwin Kernel Version 19.6.0: Mon Aug 31 22:12:52 PDT 2020; root:xnu-6153.141.2~1/RELEASE_X86_64 x86_64
# docker version
Client: Docker Engine - Community
 Cloud integration  0.1.18
 Version:           19.03.13
 API version:       1.40
 Go version:        go1.13.15
 Git commit:        4484c46d9d
 Built:             Wed Sep 16 16:58:31 2020
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.13
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       4484c46d9d
  Built:            Wed Sep 16 17:07:04 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.3.7
  GitCommit:        8fba4e9a7d01810a393d5d25a3621dc101981175
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683
```
@pippo Do you have `rpm` command in your local env? If no, you have to install it.
https://github.com/aquasecurity/trivy#binary
Thanks for the hint, @knqyf263. I didn't have it installed, indeed.
However, installing it didn't change anything.
```
# ./trivy testimage-649
2020-10-14T16:33:51.065+0200    WARN    You should avoid using the :latest tag as it is cached. You need to specify '--clear-cache' option when :latest image is changed
2020-10-14T16:33:51.097+0200    WARN    No OS package is detected. Make sure you haven't deleted any files that contain information about the installed packages.
2020-10-14T16:33:51.097+0200    WARN    e.g. files under "/lib/apk/db/", "/var/lib/dpkg/" and "/var/lib/rpm"
2020-10-14T16:33:51.097+0200    INFO    Detecting RHEL/CentOS vulnerabilities...

testimage-649 (centos 7.8.2003)
===============================
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)

# rpm --version
RPM version 4.15.1
```

Also, isn't it a defect by itself, that missing mandatory(?) dependency wasn't reported by `trivy`, eventually resulting in a false positive?
Did you clear the cache?
Nope, I hadn't and that was the issue for me. 🤦 
Now I can reproduce it both with the shell script provided & manually. Thanks.

I can try working on the fix later today.
This look like, like most vulnerability scanner, this project is just "broken by design"

Package from my repository (PHP 7.2, 7.3 and 7.4) provides upstream versions, so have same fixes than official PHP sources
Older versions (5.6, 7.0, 7.1) have security backports, and this is documented in RPM changelog and NEWS file

```
* rpm -q --changelog php70-php-cli | grep CVE
  CVE-2020-7070
  CVE-2020-7068
  CVE-2019-11048
  CVE-2020-7067
  CVE-2020-7066
  CVE-2020-7064
  CVE-2020-7063
  CVE-2020-7062
  CVE-2020-7060
  CVE-2020-7059
  CVE-2019-11046
  ...
```

And
```
$ cat /usr/share/doc/php-common/NEWS
Backported from 7.2.34

- Core:
  . Fixed bug #79699 (PHP parses encoded cookie names so malicious `__Host-`
    cookies can be sent). (CVE-2020-7070) (Stas)

Backported from 7.2.33

- Core:
  . Fixed bug #79877 (getimagesize function silently truncates after a null 
    byte) (cmb)

- Phar:
  . Fixed bug #79797 (Use of freed hash key in the phar_parse_zipfile
    function). (CVE-2020-7068) (cmb)

...
```

I understand you probably cannot take care of every existing distribution, and every existing 3rd party repository, which explain why I say "broken by design"




Patch:
diff --git a/pkg/detector/ospkg/redhat/redhat.go b/pkg/detector/ospkg/redhat/redhat.go
index 9c7d79e658f3..72677784b81c 100644
--- a/pkg/detector/ospkg/redhat/redhat.go
+++ b/pkg/detector/ospkg/redhat/redhat.go
@@ -35,6 +35,9 @@ var (
 		// N/A
 		"8": time.Date(3000, 6, 30, 23, 59, 59, 0, time.UTC),
 	}
+	excludedVendorsSuffix = []string{
+		".remi",
+	}
 )
 
 type Scanner struct {
@@ -57,6 +60,11 @@ func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedV
 
 	var vulns []types.DetectedVulnerability
 	for _, pkg := range pkgs {
+		if !s.isFromSupportedVendor(pkg) {
+			log.Logger.Debugf("Skipping %s: unsupported vendor", pkg.SrcName)
+			continue
+		}
+
 		// For Red Hat Security Data API containing only source package names
 		advisories, err := s.vs.Get(osVer, pkg.SrcName)
 		if err != nil {
@@ -125,3 +133,12 @@ func (s *Scanner) isSupportedVersion(now time.Time, osFamily, osVer string) bool
 	}
 	return now.Before(eolDate)
 }
+
+func (s *Scanner) isFromSupportedVendor(pkg ftypes.Package) bool {
+	for _, s := range excludedVendorsSuffix {
+		if strings.HasSuffix(pkg.Release, s) {
+			return false
+		}
+	}
+	return true
+}


Test patch:
diff --git a/pkg/detector/ospkg/redhat/redhat_test.go b/pkg/detector/ospkg/redhat/redhat_test.go
index c120079280cf..6d58edb33ffb 100644
--- a/pkg/detector/ospkg/redhat/redhat_test.go
+++ b/pkg/detector/ospkg/redhat/redhat_test.go
@@ -208,6 +208,45 @@ func TestScanner_Detect(t *testing.T) {
 			},
 			wantErr: true,
 		},
+		{
+			name: "happy path: packages from remi repository are skipped",
+			args: args{
+				osVer: "7.6",
+				pkgs: []ftypes.Package{
+					{
+						Name:       "php",
+						Version:    "7.3.23",
+						Release:    "1.el7.remi",
+						Arch:       "x86_64",
+						Epoch:      0,
+						SrcName:    "php",
+						SrcVersion: "7.3.23",
+						SrcRelease: "1.el7.remi",
+						SrcEpoch:   0,
+						Layer: ftypes.Layer{
+							DiffID: "sha256:c27b3cf4d516baf5932d5df3a573c6a571ddace3ee2a577492292d2e849c112b",
+						},
+					},
+				},
+			},
+			get: []dbTypes.GetExpectation{
+				{
+					Args: dbTypes.GetArgs{
+						Release: "7",
+						PkgName: "php",
+					},
+					Returns: dbTypes.GetReturns{
+						Advisories: []dbTypes.Advisory{
+							{
+								VulnerabilityID: "CVE-2011-4718",
+								FixedVersion:    "",
+							},
+						},
+					},
+				},
+			},
+			want: []types.DetectedVulnerability(nil),
+		},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {