Skip to content

Commit

Permalink
feat(fedora): support fedora
Browse files Browse the repository at this point in the history
  • Loading branch information
MaineK00n committed Jan 21, 2022
1 parent 3e43e9a commit f4041d2
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 1 deletion.
230 changes: 230 additions & 0 deletions pkg/vulnsrc/fedora/fedora.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
package fedora

import (
"encoding/json"
"fmt"
"io"
"log"
"path/filepath"
"strings"

bolt "go.etcd.io/bbolt"
"golang.org/x/xerrors"

"github.com/aquasecurity/trivy-db/pkg/db"
"github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy-db/pkg/utils"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
)

const (
fedoraDir = "fedora"
)

var (
platformFormat = map[string]string{
"fedora": "fedora %s",
"epel": "epel %s",
}
targetMode = []string{"fedora", "epel"}
targetFedoraRelease = []string{"32", "33", "34", "35"}
targetEPELRelease = []string{"7", "8", "9"}
targetRepository = []string{"Everything", "Modular"}
targetArches = []string{"x86_64"}
)

type VulnSrc struct {
dbc db.Operation
}

func NewVulnSrc() VulnSrc {
return VulnSrc{
dbc: db.Config{},
}
}

func (vs VulnSrc) Name() string {
return vulnerability.Fedora
}

func (vs VulnSrc) Update(dir string) error {
rootDir := filepath.Join(dir, "vuln-list", fedoraDir)
errata := map[string]map[string][]FSA{}
for _, mode := range targetMode {
errata[mode] = map[string][]FSA{}
}
err := utils.FileWalk(rootDir, func(r io.Reader, path string) error {
var erratum FSA
if err := json.NewDecoder(r).Decode(&erratum); err != nil {
return xerrors.Errorf("failed to decode Fedora erratum: %w", err)
}

dirs := strings.Split(strings.TrimPrefix(path, rootDir), string(filepath.Separator))[1:]
mode := dirs[0]
if !utils.StringInSlice(mode, targetMode) {
log.Printf("unsupported Fedora mode: %s\n", mode)
return nil
}
majorVer := dirs[1]
if mode == "fedora" {
if !utils.StringInSlice(majorVer, targetFedoraRelease) {
log.Printf("unsupported Fedora version: %s\n", majorVer)
return nil
}

repo := dirs[2]
if !utils.StringInSlice(repo, targetRepository) {
log.Printf("unsupported Fedora Repository: %s\n", repo)
return nil
}

arch := dirs[3]
if !utils.StringInSlice(arch, targetArches) {
switch arch {
case "aarch64":
default:
log.Printf("unsupported Fedora arch: %s\n", arch)
}
return nil
}
} else {
if !utils.StringInSlice(majorVer, targetEPELRelease) {
log.Printf("unsupported EPEL version: %s\n", majorVer)
return nil
}

if majorVer == "7" {
arch := dirs[2]
if !utils.StringInSlice(arch, targetArches) {
switch arch {
case "aarch64":
default:
log.Printf("unsupported EPEL arch: %s\n", arch)
}
return nil
}
} else {
repo := dirs[2]
if !utils.StringInSlice(repo, targetRepository) {
log.Printf("unsupported EPEL Repository: %s\n", repo)
return nil
}

arch := dirs[3]
if !utils.StringInSlice(arch, targetArches) {
switch arch {
case "aarch64":
default:
log.Printf("unsupported EPEL arch: %s\n", arch)
}
return nil
}
}
}
errata[mode][majorVer] = append(errata[mode][majorVer], erratum)
return nil
})
if err != nil {
return xerrors.Errorf("error in Fedora walk: %w", err)
}

if err := vs.save(errata); err != nil {
return xerrors.Errorf("error in Fedora save: %w", err)
}

return nil
}

func (vs VulnSrc) save(errataMode map[string]map[string][]FSA) error {
err := vs.dbc.BatchUpdate(func(tx *bolt.Tx) error {
for mode, errataVer := range errataMode {
for majorVer, errata := range errataVer {
platformName := fmt.Sprintf(platformFormat[mode], majorVer)
if err := vs.commit(tx, platformName, errata); err != nil {
return xerrors.Errorf("error in save Fedora %s: %w", majorVer, err)
}
}
}
return nil
})
if err != nil {
return xerrors.Errorf("error in db batch update: %w", err)
}
return nil
}

func (vs VulnSrc) commit(tx *bolt.Tx, platformName string, errata []FSA) error {
for _, erratum := range errata {
for _, cveID := range erratum.CveIDs {
for _, pkg := range erratum.Packages {
advisory := types.Advisory{
FixedVersion: constructVersion(pkg.Epoch, pkg.Version, pkg.Release),
}
if err := vs.dbc.PutAdvisoryDetail(tx, cveID, platformName, pkg.Name, advisory); err != nil {
return xerrors.Errorf("failed to save Fedora/EPEL advisory: %w", err)
}

}
var references []string
for _, ref := range erratum.References {
references = append(references, ref.Href)
}

vuln := types.VulnerabilityDetail{
Severity: generalizeSeverity(erratum.Severity),
References: references,
Title: erratum.Title,
Description: erratum.Description,
}
if err := vs.dbc.PutVulnerabilityDetail(tx, cveID, vulnerability.Fedora, vuln); err != nil {
return xerrors.Errorf("failed to save Fedora/EPEL vulnerability: %w", err)
}

if err := vs.dbc.PutVulnerabilityID(tx, cveID); err != nil {
return xerrors.Errorf("failed to save the vulnerability ID: %w", err)
}
}
}
return nil
}

func (vs VulnSrc) Get(mode, release, pkgName string) ([]types.Advisory, error) {
format, ok := platformFormat[mode]
if !ok {
return nil, xerrors.Errorf("failed to get Fedora advisories: mode(%s) is not support", mode)
}
bucket := fmt.Sprintf(format, release)
advisories, err := vs.dbc.GetAdvisories(bucket, pkgName)
if err != nil {
return nil, xerrors.Errorf("failed to get Fedora advisories: %w", err)
}
return advisories, nil
}

func constructVersion(epoch, version, release string) string {
verStr := ""
if epoch != "0" && epoch != "" {
verStr += fmt.Sprintf("%s:", epoch)
}
verStr += version

if release != "" {
verStr += fmt.Sprintf("-%s", release)

}
return verStr
}

func generalizeSeverity(severity string) types.Severity {
switch strings.ToLower(severity) {
case "low":
return types.SeverityLow
case "moderate":
return types.SeverityMedium
case "important":
return types.SeverityHigh
case "critical":
return types.SeverityCritical
}
return types.SeverityUnknown
}
48 changes: 48 additions & 0 deletions pkg/vulnsrc/fedora/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package fedora

// FSA has detailed data of Fedora Security Advisory
type FSA struct {
ID string `xml:"id" json:"id,omitempty"`
Title string `xml:"title" json:"title,omitempty"`
Type string `xml:"type,attr" json:"type,omitempty"`
Issued Date `xml:"issued" json:"issued,omitempty"`
Updated Date `xml:"updated" json:"updated,omitempty"`
Severity string `xml:"severity" json:"severity,omitempty"`
Description string `xml:"description" json:"description,omitempty"`
Packages []Package `xml:"pkglist>collection>package" json:"packages,omitempty"`
Module Module `json:"module,omitempty"`
References []Reference `xml:"references>reference" json:"references,omitempty"`
CveIDs []string `json:"cveids,omitempty"`
}

// Updated has updated at
type Date struct {
Date string `xml:"date,attr" json:"date,omitempty"`
}

// Reference has reference information
type Reference struct {
Href string `xml:"href,attr" json:"href,omitempty"`
ID string `xml:"id,attr" json:"id,omitempty"`
Title string `xml:"title,attr" json:"title,omitempty"`
Type string `xml:"type,attr" json:"type,omitempty"`
}

// Package has affected package information
type Package struct {
Name string `xml:"name,attr" json:"name,omitempty"`
Epoch string `xml:"epoch,attr" json:"epoch,omitempty"`
Version string `xml:"version,attr" json:"version,omitempty"`
Release string `xml:"release,attr" json:"release,omitempty"`
Arch string `xml:"arch,attr" json:"arch,omitempty"`
Filename string `xml:"filename" json:"filename,omitempty"`
}

// Module has modular package information
type Module struct {
Stream string `json:"stream,omitempty"`
Name string `json:"name,omitempty"`
Version int64 `json:"version,omitempty"`
Arch string `json:"arch,omitempty"`
Context string `json:"context,omitempty"`
}
2 changes: 1 addition & 1 deletion pkg/vulnsrc/vulnerability/vulnerability.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const (
)

var (
sources = []string{NVD, RedHat, Debian, DebianOVAL, Ubuntu, Alpine, Amazon, OracleOVAL, SuseCVRF, Photon, ArchLinux, Alma, Rocky,
sources = []string{NVD, RedHat, Debian, DebianOVAL, Ubuntu, Alpine, Amazon, OracleOVAL, SuseCVRF, Photon, ArchLinux, Alma, Rocky, Fedora,
RubySec, PhpSecurityAdvisories, NodejsSecurityWg,
GHSAComposer, GHSAMaven, GHSANpm, GHSANuget, GHSAPip, GHSARubygems, GLAD, OSVPyPI, OSVGo, OSVCratesio,
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/vulnsrc/vulnsrc.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/bundler"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/composer"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/debian"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/fedora"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/ghsa"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/glad"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/govulndb"
Expand Down Expand Up @@ -40,6 +41,7 @@ var (
archlinux.NewVulnSrc(),
redhat.NewVulnSrc(),
redhatoval.NewVulnSrc(),
fedora.NewVulnSrc(),
debian.NewVulnSrc(),
ubuntu.NewVulnSrc(),
amazon.NewVulnSrc(),
Expand Down

0 comments on commit f4041d2

Please sign in to comment.