Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(fedora): support fedora #1616

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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, AlmaLinux, Rocky Linux, CBL-Mariner, 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, Fedora, CBL-Mariner, 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**
Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -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, Rocky Linux, CBL-Mariner, 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, Fedora, CBL-Mariner, 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**:
Expand Down
2 changes: 2 additions & 0 deletions docs/vulnerability/detection/data-source.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
| | [Security Data][rhel-api] |
| AlmaLinux | [AlmaLinux Product Errata][alma] |
| Rocky Linux | [Rocky Linux UpdateInfo][rocky] |
| Fedora | [Fedora UpdateInfo][fedora] |
| Oracle Linux | [OVAL][oracle] |
| CBL-Mariner | [OVAL][mariner] |
| OpenSUSE/SLES | [CVRF][suse] |
Expand Down Expand Up @@ -56,6 +57,7 @@
[rhel-api]: https://www.redhat.com/security/data/metrics/
[alma]: https://errata.almalinux.org/
[rocky]: https://download.rockylinux.org/pub/rocky/
[fedora]: https://dl.fedoraproject.org/pub/fedora/linux/updates/
[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/
Expand Down
1 change: 1 addition & 0 deletions docs/vulnerability/detection/os.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The unfixed/unfixable vulnerabilities mean that the patch has not yet been provi
| CentOS | 6, 7, 8 | Installed by yum/rpm | YES |
| AlmaLinux | 8 | Installed by yum/rpm | NO |
| Rocky Linux | 8 | Installed by yum/rpm | NO |
| Fedora | 32, 33, 34, 35 | Installed by dnf/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 |
Expand Down
2 changes: 2 additions & 0 deletions pkg/detector/ospkg/detect.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/aquasecurity/trivy/pkg/detector/ospkg/alpine"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/amazon"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/debian"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/fedora"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/mariner"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/oracle"
"github.com/aquasecurity/trivy/pkg/detector/ospkg/photon"
Expand Down Expand Up @@ -44,6 +45,7 @@ var (
fos.CentOS: redhat.NewScanner(),
fos.Rocky: rocky.NewScanner(),
fos.Oracle: oracle.NewScanner(),
fos.Fedora: fedora.NewScanner(),
fos.OpenSUSELeap: suse.NewScanner(suse.OpenSUSE),
fos.SLES: suse.NewScanner(suse.SUSEEnterpriseLinux),
fos.Photon: photon.NewScanner(),
Expand Down
125 changes: 125 additions & 0 deletions pkg/detector/ospkg/fedora/fedora.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package fedora

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/fedora"
"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{
"32": time.Date(2021, 5, 25, 23, 59, 59, 0, time.UTC),
"33": time.Date(2021, 11, 16, 23, 59, 59, 0, time.UTC),
"34": time.Date(2022, 5, 17, 23, 59, 59, 0, time.UTC),
"35": time.Date(2022, 11, 30, 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 Fedora scanner
type Scanner struct {
vs fedora.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: fedora.NewVulnSrc(),
options: o,
}
}

// Detect vulnerabilities in package using Fedora scanner
func (s *Scanner) Detect(osVer string, pkgs []ftypes.Package) ([]types.DetectedVulnerability, error) {
log.Logger.Info("Detecting Fedora vulnerabilities...")
if strings.Count(osVer, ".") > 0 {
osVer = osVer[:strings.Index(osVer, ".")]
}
log.Logger.Debugf("Fedora: os version: %s", osVer)
log.Logger.Debugf("Fedora: the number of packages: %d", len(pkgs))

var vulns []types.DetectedVulnerability
for _, pkg := range pkgs {
pkgName := addModularNamespace(pkg.Name, pkg.Modularitylabel)
advisories, err := s.vs.Get(osVer, pkgName)
if err != nil {
return nil, xerrors.Errorf("failed to get Fedora 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)
}
}
}

return vulns, nil
}

// IsSupportedVersion checks the OSFamily can be scanned using Fedora 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
}
143 changes: 143 additions & 0 deletions pkg/detector/ospkg/fedora/fedora_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package fedora_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/fedora"
"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/fedora.yaml"},
args: args{
osVer: "35",
pkgs: []ftypes.Package{
{
Name: "vim-minimal",
Epoch: 2,
Version: "8.2.3642",
Release: "1.fc35",
Arch: "x86_64",
SrcName: "vim",
SrcEpoch: 2,
SrcVersion: "8.2.3642",
SrcRelease: "1.fc35",
Modularitylabel: "",
License: "Vim and MIT",
Layer: ftypes.Layer{},
},
},
},
want: []types.DetectedVulnerability{
{
PkgName: "vim-minimal",
VulnerabilityID: "CVE-2022-0158",
InstalledVersion: "2:8.2.3642-1.fc35",
FixedVersion: "2:8.2.4068-1.fc35",
Layer: ftypes.Layer{},
},
},
},
{
name: "Get returns an error",
fixtures: []string{"testdata/fixtures/invalid.yaml"},
args: args{
osVer: "35",
pkgs: []ftypes.Package{
{
Name: "jq",
Version: "1.5-12",
SrcName: "jq",
SrcVersion: "1.5-12",
},
},
},
wantErr: "failed to get Fedora advisories",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_ = dbtest.InitDB(t, tt.fixtures)
defer db.Close()

s := fedora.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: "fedora 35",
now: time.Date(2019, 3, 2, 23, 59, 59, 0, time.UTC),
args: args{
osFamily: "fedora",
osVer: "35",
},
want: true,
},
{
name: "fedora 35 with EOL",
now: time.Date(2022, 12, 1, 0, 0, 0, 0, time.UTC),
args: args{
osFamily: "rocky",
osVer: "35",
},
want: false,
},
{
name: "unknown",
now: time.Date(2019, 5, 2, 23, 59, 59, 0, time.UTC),
args: args{
osFamily: "fedora",
osVer: "unknown",
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := fedora.NewScanner(fedora.WithClock(fake.NewFakeClock(tt.now)))
got := s.IsSupportedVersion(tt.args.osFamily, tt.args.osVer)
assert.Equal(t, tt.want, got)
})
}
}
7 changes: 7 additions & 0 deletions pkg/detector/ospkg/fedora/testdata/fixtures/fedora.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
- bucket: fedora 35
pairs:
- bucket: vim-minimal
pairs:
- key: CVE-2022-0158
value:
FixedVersion: "2:8.2.4068-1.fc35"
9 changes: 9 additions & 0 deletions pkg/detector/ospkg/fedora/testdata/fixtures/invalid.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
- bucket: fedora 35
pairs:
- bucket: jq
pairs:
- key: CVE-2020-8177
value:
FixedVersion:
- foo
- bar