forked from aquasecurity/trivy-db
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(wrlinux): Add Wind River Linux support (aquasecurity#259)
Signed-off-by: Sakib Sajal <sakib.sajal@windriver.com>
- Loading branch information
Showing
7 changed files
with
336 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
pkg/vulnsrc/wrlinux/testdata/vuln-list/wrlinux/CVE-2020-24241.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
{ | ||
"Candidate": "CVE-2020-24241", | ||
"PublicDate": "2020-08-25T00:00:00Z", | ||
"Description": "In Netwide Assembler (NASM) 2.15rc10, there is heap use-after-free in saa_wbytes in nasmlib/saa.c.", | ||
"Notes": null, | ||
"Priority": "medium", | ||
"Bugs": [ | ||
"LINCD-2974", | ||
"LIN1019-5289", | ||
"LIN1018-6614", | ||
"LIN10-7689" | ||
], | ||
"Patches": { | ||
"nasm": { | ||
"10.18.44.1": { | ||
"Status": "pending", | ||
"Note": "" | ||
}, | ||
"10.19.45.1": { | ||
"Status": "released", | ||
"Note": "10.19.45.11" | ||
}, | ||
"10.20.6.0": { | ||
"Status": "not-affected", | ||
"Note": "" | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package wrlinux | ||
|
||
type WRLinuxCVE struct { | ||
Description string `json:"description"` | ||
Candidate string | ||
Priority string | ||
Patches map[PackageName]Patch | ||
References []string | ||
} | ||
|
||
type PackageName string | ||
type Release string | ||
type Patch map[Release]Status | ||
|
||
type Status struct { | ||
Status string | ||
Note string | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
/* | ||
* Copyright (c) 2022 Wind River Systems, Inc. | ||
* | ||
* The right to copy, distribute, modify, or otherwise make use | ||
* of this software may be licensed only pursuant to the terms | ||
* of an applicable Wind River license agreement. | ||
*/ | ||
|
||
package wrlinux | ||
|
||
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" | ||
ustrings "github.com/aquasecurity/trivy-db/pkg/utils/strings" | ||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability" | ||
) | ||
|
||
const ( | ||
wrlinuxDir = "wrlinux" | ||
platformFormat = "WRLinux OS %s" | ||
) | ||
|
||
var ( | ||
targetStatuses = []string{"pending", "released"} | ||
|
||
source = types.DataSource{ | ||
ID: vulnerability.WRLinux, | ||
Name: "WRLinux OS CVE metadata", | ||
URL: "https://support2.windriver.com", | ||
} | ||
) | ||
|
||
type Option func(src *VulnSrc) | ||
|
||
func WithCustomPut(put db.CustomPut) Option { | ||
return func(src *VulnSrc) { | ||
src.put = put | ||
} | ||
} | ||
|
||
type VulnSrc struct { | ||
put db.CustomPut | ||
dbc db.Operation | ||
} | ||
|
||
func NewVulnSrc(opts ...Option) VulnSrc { | ||
src := VulnSrc{ | ||
put: defaultPut, | ||
dbc: db.Config{}, | ||
} | ||
|
||
for _, o := range opts { | ||
o(&src) | ||
} | ||
|
||
return src | ||
} | ||
|
||
func (vs VulnSrc) Name() types.SourceID { | ||
return source.ID | ||
} | ||
|
||
func (vs VulnSrc) Update(dir string) error { | ||
rootDir := filepath.Join(dir, "vuln-list", wrlinuxDir) | ||
var cves []WRLinuxCVE | ||
err := utils.FileWalk(rootDir, func(r io.Reader, path string) error { | ||
var cve WRLinuxCVE | ||
if err := json.NewDecoder(r).Decode(&cve); err != nil { | ||
return xerrors.Errorf("failed to decode WRLinux JSON: %w", err) | ||
} | ||
cves = append(cves, cve) | ||
return nil | ||
}) | ||
if err != nil { | ||
return xerrors.Errorf("error in wrlinux walk: %w", err) | ||
} | ||
|
||
if err = vs.save(cves); err != nil { | ||
return xerrors.Errorf("error in wrlinux save: %w", err) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (vs VulnSrc) save(cves []WRLinuxCVE) error { | ||
log.Println("Saving wrlinux DB") | ||
err := vs.dbc.BatchUpdate(func(tx *bolt.Tx) error { | ||
err := vs.commit(tx, cves) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
}) | ||
if err != nil { | ||
return xerrors.Errorf("error in batch update: %w", err) | ||
} | ||
return nil | ||
} | ||
|
||
func (vs VulnSrc) commit(tx *bolt.Tx, cves []WRLinuxCVE) error { | ||
for _, cve := range cves { | ||
if err := vs.put(vs.dbc, tx, cve); err != nil { | ||
return xerrors.Errorf("put error: %w", err) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (vs VulnSrc) Get(osVer string, pkgName string) ([]types.Advisory, error) { | ||
bucket := fmt.Sprintf(platformFormat, OsVerToRelease(osVer)) | ||
advisories, err := vs.dbc.GetAdvisories(bucket, pkgName) | ||
if err != nil { | ||
return nil, xerrors.Errorf("failed to get wrlinux advisories: %w", err) | ||
} | ||
return advisories, nil | ||
} | ||
|
||
func defaultPut(dbc db.Operation, tx *bolt.Tx, advisory interface{}) error { | ||
cve, ok := advisory.(WRLinuxCVE) | ||
if !ok { | ||
return xerrors.New("unknown type") | ||
} | ||
for packageName, patch := range cve.Patches { | ||
pkgName := string(packageName) | ||
for osVer, status := range patch { | ||
if !ustrings.InSlice(status.Status, targetStatuses) { | ||
continue | ||
} | ||
release := OsVerToRelease(string(osVer)) | ||
platformName := fmt.Sprintf(platformFormat, release) | ||
if err := dbc.PutDataSource(tx, platformName, source); err != nil { | ||
return xerrors.Errorf("failed to put data source: %w", err) | ||
} | ||
|
||
adv := types.Advisory{} | ||
if status.Status == "released" { | ||
adv.FixedVersion = status.Note | ||
} | ||
if err := dbc.PutAdvisoryDetail(tx, cve.Candidate, pkgName, []string{platformName}, adv); err != nil { | ||
return xerrors.Errorf("failed to save wrlinux advisory: %w", err) | ||
} | ||
|
||
vuln := types.VulnerabilityDetail{ | ||
Severity: SeverityFromPriority(cve.Priority), | ||
References: cve.References, | ||
Description: cve.Description, | ||
} | ||
if err := dbc.PutVulnerabilityDetail(tx, cve.Candidate, source.ID, vuln); err != nil { | ||
return xerrors.Errorf("failed to save wrlinux vulnerability: %w", err) | ||
} | ||
|
||
// for optimization | ||
if err := dbc.PutVulnerabilityID(tx, cve.Candidate); err != nil { | ||
return xerrors.Errorf("failed to save the vulnerability ID: %w", err) | ||
} | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// SeverityFromPriority converts wrlinux priority into Trivy severity | ||
func SeverityFromPriority(priority string) types.Severity { | ||
switch priority { | ||
case "new": | ||
return types.SeverityUnknown | ||
case "negligible", "low": | ||
return types.SeverityLow | ||
case "medium": | ||
return types.SeverityMedium | ||
case "high": | ||
return types.SeverityHigh | ||
case "critical": | ||
return types.SeverityCritical | ||
default: | ||
return types.SeverityUnknown | ||
} | ||
} | ||
|
||
// gets the release from the osVersion | ||
// "w.x.y.z" -> "w.x" | ||
func OsVerToRelease(osVer string) string { | ||
s := strings.Split(osVer, ".") | ||
if s[len(s)-1] == "0" { | ||
return "LINCD" | ||
} | ||
return strings.Join(s[:2], ".") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/* | ||
* Copyright (c) 2022 Wind River Systems, Inc. | ||
* | ||
* The right to copy, distribute, modify, or otherwise make use | ||
* of this software may be licensed only pursuant to the terms | ||
* of an applicable Wind River license agreement. | ||
*/ | ||
|
||
package wrlinux_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/aquasecurity/trivy-db/pkg/db" | ||
"github.com/aquasecurity/trivy-db/pkg/dbtest" | ||
"github.com/aquasecurity/trivy-db/pkg/types" | ||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/wrlinux" | ||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability" | ||
) | ||
|
||
func TestVulnSrc_Update(t *testing.T) { | ||
type wantKV struct { | ||
key []string | ||
value interface{} | ||
} | ||
tests := []struct { | ||
name string | ||
statuses []string | ||
wantValues []wantKV | ||
noBuckets [][]string | ||
wantErr string | ||
}{ | ||
{ | ||
name: "happy path", | ||
wantValues: []wantKV{ | ||
{ | ||
key: []string{"data-source", "WRLinux OS 10.19"}, | ||
value: types.DataSource{ | ||
ID: vulnerability.WRLinux, | ||
Name: "WRLinux OS CVE metadata", | ||
URL: "https://support2.windriver.com", | ||
}, | ||
}, | ||
{ | ||
key: []string{"advisory-detail", "CVE-2020-24241", "WRLinux OS 10.19", "nasm"}, | ||
value: types.Advisory{ | ||
FixedVersion: "10.19.45.11", | ||
}, | ||
}, | ||
{ | ||
key: []string{"vulnerability-detail", "CVE-2020-24241", "wrlinux"}, | ||
value: types.VulnerabilityDetail{ | ||
Description: "In Netwide Assembler (NASM) 2.15rc10, there is heap use-after-free in saa_wbytes in nasmlib/saa.c.", | ||
Severity: 2, | ||
References: []string{}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
cacheDir := dbtest.InitDB(t, nil) | ||
|
||
src := wrlinux.NewVulnSrc() | ||
err := src.Update("testdata") | ||
if tt.wantErr != "" { | ||
require.Error(t, err) | ||
assert.Contains(t, err.Error(), tt.wantErr, tt.name) | ||
return | ||
} | ||
|
||
require.NoError(t, err, tt.name) | ||
|
||
// Compare DB entries | ||
require.NoError(t, err, db.Close()) | ||
dbPath := db.Path(cacheDir) | ||
for _, want := range tt.wantValues { | ||
dbtest.JSONEq(t, dbPath, want.key, want.value) | ||
} | ||
}) | ||
} | ||
} |