Skip to content

Commit

Permalink
feat(alpine): support apk repositories (#1987)
Browse files Browse the repository at this point in the history
  • Loading branch information
knqyf263 authored Apr 14, 2022
1 parent d9bddb9 commit 6fdb554
Show file tree
Hide file tree
Showing 39 changed files with 618 additions and 298 deletions.
34 changes: 17 additions & 17 deletions docs/docs/vulnerability/detection/os.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@

The unfixed/unfixable vulnerabilities mean that the patch has not yet been provided on their distribution. Trivy doesn't support self-compiled packages/binaries, but official packages provided by vendors such as Red Hat and Debian.

| OS | Supported Versions | Target Packages | Detection of unfixed vulnerabilities |
| -------------------------------- | ---------------------------------------- | ----------------------------- | :----------------------------------: |
| Alpine Linux | 2.2 - 2.7, 3.0 - 3.15 | Installed by apk | NO |
| Red Hat Universal Base Image[^1] | 7, 8 | Installed by yum/rpm | YES |
| 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 |
| CBL-Mariner | 1.0, 2.0 | Installed by yum/rpm | YES |
| Amazon Linux | 1, 2 | Installed by yum/rpm | NO |
| openSUSE Leap | 42, 15 | Installed by zypper/rpm | NO |
| SUSE Enterprise Linux | 11, 12, 15 | Installed by zypper/rpm | NO |
| Photon OS | 1.0, 2.0, 3.0, 4.0 | Installed by tdnf/yum/rpm | NO |
| Debian GNU/Linux | wheezy, jessie, stretch, buster, bullseye| Installed by apt/apt-get/dpkg | YES |
| Ubuntu | All versions supported by Canonical | Installed by apt/apt-get/dpkg | YES |
| Distroless[^2] | Any | Installed by apt/apt-get/dpkg | YES |
| OS | Supported Versions | Target Packages | Detection of unfixed vulnerabilities |
| -------------------------------- |-------------------------------------------| ----------------------------- | :----------------------------------: |
| Alpine Linux | 2.2 - 2.7, 3.0 - 3.15, edge | Installed by apk | NO |
| Red Hat Universal Base Image[^1] | 7, 8 | Installed by yum/rpm | YES |
| 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 |
| CBL-Mariner | 1.0, 2.0 | Installed by yum/rpm | YES |
| Amazon Linux | 1, 2 | Installed by yum/rpm | NO |
| openSUSE Leap | 42, 15 | Installed by zypper/rpm | NO |
| SUSE Enterprise Linux | 11, 12, 15 | Installed by zypper/rpm | NO |
| Photon OS | 1.0, 2.0, 3.0, 4.0 | Installed by tdnf/yum/rpm | NO |
| Debian GNU/Linux | wheezy, jessie, stretch, buster, bullseye | Installed by apt/apt-get/dpkg | YES |
| Ubuntu | All versions supported by Canonical | Installed by apt/apt-get/dpkg | YES |
| Distroless[^2] | Any | Installed by apt/apt-get/dpkg | YES |

[^1]: https://developers.redhat.com/products/rhel/ubi
[^2]: https://github.com/GoogleContainerTools/distroless
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ require (
github.com/Masterminds/sprig/v3 v3.2.2
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986
github.com/aquasecurity/fanal v0.0.0-20220413103552-a2db5fcf54ed
github.com/aquasecurity/fanal v0.0.0-20220413153130-ae71d24c572b
github.com/aquasecurity/go-dep-parser v0.0.0-20220412145205-d0501f906d90
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8=
github.com/aquasecurity/defsec v0.28.4 h1:O0ukf2uMEqRRX3EHfu+9J0EyD39v50NDjwtf96nES8E=
github.com/aquasecurity/defsec v0.28.4/go.mod h1:vUdThwusBM7y1gJ7CVX3+h3bsPvpmOIEp3NEdzTDkhA=
github.com/aquasecurity/fanal v0.0.0-20220413103552-a2db5fcf54ed h1:8eCdv9koYS04ib1jVfyYGcUjkn9DcEF+W1WAigZmd4s=
github.com/aquasecurity/fanal v0.0.0-20220413103552-a2db5fcf54ed/go.mod h1:P+PBmaNRkj5kBiRSM5vKtKviKxEm3kK179Mu9BVx1AQ=
github.com/aquasecurity/fanal v0.0.0-20220413153130-ae71d24c572b h1:T4jWSwpQ6Ll1cEHOLiLfvk2bsc3T2meUujct43suSEo=
github.com/aquasecurity/fanal v0.0.0-20220413153130-ae71d24c572b/go.mod h1:7VRXBnhuTlJBjb0ZSQxKrVi+eSpNHnXb2hbfjEG7opw=
github.com/aquasecurity/go-dep-parser v0.0.0-20220412145205-d0501f906d90 h1:uZcI5qV7J1pzOc6W49l7iEey/KtEVlaqsNU5l65vZLk=
github.com/aquasecurity/go-dep-parser v0.0.0-20220412145205-d0501f906d90/go.mod h1:rK/5BoRt8/D7xXydoVVeBaQuk6zDJ6W+FWz/RqFuJxI=
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM=
Expand Down
7 changes: 7 additions & 0 deletions integration/client_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ func TestClientServer(t *testing.T) {
},
golden: "testdata/alpine-310.json.golden",
},
{
name: "alpine distroless",
args: csArgs{
Input: "testdata/fixtures/images/alpine-distroless.tar.gz",
},
golden: "testdata/alpine-distroless.json.golden",
},
{
name: "debian buster/10",
args: csArgs{
Expand Down
8 changes: 8 additions & 0 deletions integration/standalone_tar_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ func TestTar(t *testing.T) {
},
golden: "testdata/alpine-310.json.golden",
},
{
name: "alpine distroless",
testArgs: args{
Format: "json",
Input: "testdata/fixtures/images/alpine-distroless.tar.gz",
},
golden: "testdata/alpine-distroless.json.golden",
},
{
name: "amazon linux 1",
testArgs: args{
Expand Down
85 changes: 85 additions & 0 deletions integration/testdata/alpine-distroless.json.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{
"SchemaVersion": 2,
"ArtifactName": "testdata/fixtures/images/alpine-distroless.tar.gz",
"ArtifactType": "container_image",
"Metadata": {
"OS": {
"Family": "alpine",
"Name": "edge"
},
"ImageID": "sha256:22848737c0d272ad5d7c7369d8ca830a62929e63e38edcb22085139a6ae0688d",
"DiffIDs": [
"sha256:89da7cc836da4b53ab1ceb572576458c005e7e444b8bb79abda196668a2f0c92"
],
"ImageConfig": {
"architecture": "amd64",
"author": "github.com/chainguard-dev/apko",
"created": "1970-01-01T00:00:00Z",
"history": [
{
"author": "apko",
"created": "1970-01-01T00:00:00Z",
"created_by": "apko",
"comment": "This is an apko single-layer image"
}
],
"os": "linux",
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:89da7cc836da4b53ab1ceb572576458c005e7e444b8bb79abda196668a2f0c92"
]
},
"config": {
"Entrypoint": [
"/usr/bin/git"
],
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt"
],
"User": "65532"
}
}
},
"Results": [
{
"Target": "testdata/fixtures/images/alpine-distroless.tar.gz (alpine edge)",
"Class": "os-pkgs",
"Type": "alpine",
"Vulnerabilities": [
{
"VulnerabilityID": "CVE-2022-24765",
"PkgName": "git",
"InstalledVersion": "2.35.1-r2",
"FixedVersion": "2.35.2-r0",
"Layer": {
"DiffID": "sha256:89da7cc836da4b53ab1ceb572576458c005e7e444b8bb79abda196668a2f0c92"
},
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2022-24765",
"Title": "Git for Windows is a fork of Git containing Windows-specific patches. ...",
"Description": "Git for Windows is a fork of Git containing Windows-specific patches.",
"Severity": "MEDIUM",
"CweIDs": [
"CWE-427"
],
"References": [
"http://www.openwall.com/lists/oss-security/2022/04/12/7",
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24765",
"https://git-scm.com/book/en/v2/Appendix-A%3A-Git-in-Other-Environments-Git-in-Bash",
"https://git-scm.com/docs/git#Documentation/git.txt-codeGITCEILINGDIRECTORIEScode",
"https://github.com/git-for-windows/git/security/advisories/GHSA-vw2c-22j4-2fh2",
"https://ubuntu.com/security/notices/USN-5376-1"
],
"PublishedDate": "2022-04-12T18:15:00Z",
"LastModifiedDate": "2022-04-12T21:15:00Z"
}
]
},
{
"Target": "usr/bin/git-lfs",
"Class": "lang-pkgs",
"Type": "gobinary"
}
]
}
9 changes: 8 additions & 1 deletion integration/testdata/fixtures/db/alpine.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,11 @@
pairs:
- key: CVE-2019-14697
value:
FixedVersion: 1.1.20-r5
FixedVersion: 1.1.20-r5
- bucket: alpine edge
pairs:
- bucket: git
pairs:
- key: CVE-2022-24765
value:
FixedVersion: 2.35.2-r0
18 changes: 18 additions & 0 deletions integration/testdata/fixtures/db/vulnerability.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1119,3 +1119,21 @@
Title: Security update for openssl-1_1
VendorSeverity:
suse-cvrf: 2.0
- key: CVE-2022-24765
value:
Title: "Git for Windows is a fork of Git containing Windows-specific patches. ..."
Description: "Git for Windows is a fork of Git containing Windows-specific patches."
CweIDs:
- CWE-427
References:
- http://www.openwall.com/lists/oss-security/2022/04/12/7
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-24765
- https://git-scm.com/book/en/v2/Appendix-A%3A-Git-in-Other-Environments-Git-in-Bash
- https://git-scm.com/docs/git#Documentation/git.txt-codeGITCEILINGDIRECTORIEScode
- https://github.com/git-for-windows/git/security/advisories/GHSA-vw2c-22j4-2fh2
- https://ubuntu.com/security/notices/USN-5376-1
Severity: MEDIUM
VendorSeverity:
ubuntu: 2
LastModifiedDate: 2022-04-12T21:15:00Z
PublishedDate: 2022-04-12T18:15:00Z
2 changes: 1 addition & 1 deletion pkg/detector/ospkg/alma/alma.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func NewScanner(opts ...option) *Scanner {
}

// Detect vulnerabilities in package using AlmaLinux scanner
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting AlmaLinux vulnerabilities...")
if strings.Count(osVer, ".") > 0 {
osVer = osVer[:strings.Index(osVer, ".")]
Expand Down
2 changes: 1 addition & 1 deletion pkg/detector/ospkg/alma/alma_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func TestScanner_Detect(t *testing.T) {
defer db.Close()

s := alma.NewScanner()
got, err := s.Detect(tt.args.osVer, tt.args.pkgs)
got, err := s.Detect(tt.args.osVer, nil, tt.args.pkgs)
if tt.wantErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
Expand Down
28 changes: 25 additions & 3 deletions pkg/detector/ospkg/alpine/alpine.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ var (
"3.13": time.Date(2022, 11, 1, 23, 59, 59, 0, time.UTC),
"3.14": time.Date(2023, 5, 1, 23, 59, 59, 0, time.UTC),
"3.15": time.Date(2023, 11, 1, 23, 59, 59, 0, time.UTC),
"edge": time.Date(9999, 1, 1, 0, 0, 0, 0, time.UTC),
}
)

Expand Down Expand Up @@ -79,17 +80,27 @@ func NewScanner(opts ...option) *Scanner {
}

// Detect vulnerabilities in package using Alpine scanner
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
func (s *Scanner) Detect(osVer string, repo *ftypes.Repository, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting Alpine vulnerabilities...")
if strings.Count(osVer, ".") > 1 {
osVer = osVer[:strings.LastIndex(osVer, ".")]
}
repoRelease := s.repoRelease(repo)

log.Logger.Debugf("alpine: os version: %s", osVer)
log.Logger.Debugf("alpine: package repository: %s", repoRelease)
log.Logger.Debugf("alpine: the number of packages: %d", len(pkgs))

stream := osVer
if repoRelease != "" && osVer != repoRelease {
// Prefer the repository release. Use OS version only when the repository is not detected.
stream = repoRelease
log.Logger.Infof("Use the repository release '%s' for vulnerability detection, instead of OS version '%s'", repoRelease, osVer)
}

var vulns []types.DetectedVulnerability
for _, pkg := range pkgs {
advisories, err := s.vs.Get(osVer, pkg.SrcName)
advisories, err := s.vs.Get(stream, pkg.SrcName)
if err != nil {
return nil, xerrors.Errorf("failed to get alpine advisories: %w", err)
}
Expand Down Expand Up @@ -161,8 +172,19 @@ func (s *Scanner) IsSupportedVersion(osFamily, osVer string) bool {
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 true // may be the latest version
}

return s.clock.Now().Before(eol)
}

func (s *Scanner) repoRelease(repo *ftypes.Repository) string {
if repo == nil {
return ""
}
release := repo.Release
if strings.Count(release, ".") > 1 {
release = release[:strings.LastIndex(release, ".")]
}
return release
}
39 changes: 37 additions & 2 deletions pkg/detector/ospkg/alpine/alpine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"testing"
"time"

"github.com/aquasecurity/fanal/analyzer/os"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
fake "k8s.io/utils/clock/testing"
Expand All @@ -21,6 +23,7 @@ import (
func TestScanner_Detect(t *testing.T) {
type args struct {
osVer string
repo *ftypes.Repository
pkgs []ftypes.Package
}
tests := []struct {
Expand Down Expand Up @@ -146,6 +149,38 @@ func TestScanner_Detect(t *testing.T) {
},
},
},
{
name: "repository is newer than OS version",
fixtures: []string{"testdata/fixtures/alpine.yaml", "testdata/fixtures/data-source.yaml"},
args: args{
osVer: "3.9.3",
repo: &ftypes.Repository{
Family: os.Alpine,
Release: "3.10",
},
pkgs: []ftypes.Package{
{
Name: "jq",
Version: "1.6-r0",
SrcName: "jq",
SrcVersion: "1.6-r0",
},
},
},
want: []types.DetectedVulnerability{
{
PkgName: "jq",
VulnerabilityID: "CVE-2020-1234",
InstalledVersion: "1.6-r0",
FixedVersion: "1.6-r1",
DataSource: &dbTypes.DataSource{
ID: vulnerability.Alpine,
Name: "Alpine Secdb",
URL: "https://secdb.alpinelinux.org/",
},
},
},
},
{
name: "Get returns an error",
fixtures: []string{"testdata/fixtures/invalid.yaml", "testdata/fixtures/data-source.yaml"},
Expand All @@ -169,7 +204,7 @@ func TestScanner_Detect(t *testing.T) {
defer db.Close()

s := alpine.NewScanner()
got, err := s.Detect(tt.args.osVer, tt.args.pkgs)
got, err := s.Detect(tt.args.osVer, tt.args.repo, tt.args.pkgs)
if tt.wantErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
Expand Down Expand Up @@ -239,7 +274,7 @@ func TestScanner_IsSupportedVersion(t *testing.T) {
osFamily: "alpine",
osVer: "unknown",
},
want: false,
want: true,
},
}
for _, tt := range tests {
Expand Down
2 changes: 1 addition & 1 deletion pkg/detector/ospkg/amazon/amazon.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func NewScanner(opts ...option) *Scanner {
}

// Detect scans the packages using amazon scanner
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting Amazon Linux vulnerabilities...")

osVer = strings.Fields(osVer)[0]
Expand Down
2 changes: 1 addition & 1 deletion pkg/detector/ospkg/amazon/amazon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func TestScanner_Detect(t *testing.T) {
defer db.Close()

s := amazon.NewScanner()
got, err := s.Detect(tt.args.osVer, tt.args.pkgs)
got, err := s.Detect(tt.args.osVer, nil, tt.args.pkgs)
if tt.wantErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
Expand Down
2 changes: 1 addition & 1 deletion pkg/detector/ospkg/debian/debian.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func NewScanner(opts ...option) *Scanner {
}

// Detect scans and return vulnerabilities using Debian scanner
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting Debian vulnerabilities...")

if strings.Count(osVer, ".") > 0 {
Expand Down
2 changes: 1 addition & 1 deletion pkg/detector/ospkg/debian/debian_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func TestScanner_Detect(t *testing.T) {
defer db.Close()

s := debian.NewScanner()
got, err := s.Detect(tt.args.osVer, tt.args.pkgs)
got, err := s.Detect(tt.args.osVer, nil, tt.args.pkgs)
if tt.wantErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
Expand Down
Loading

0 comments on commit 6fdb554

Please sign in to comment.