refactor: don't use global Config in private func (#1197)
* refactor: cve_client.go * refactor: don't use global Config in private func * remove import alias for config * refactor: dbclient * refactor: resultDir * refactor: resultsDir * refactor * refactor: gost * refactor: db client * refactor: cveDB * refactor: cvedb * refactor: exploitDB * refactor: remove detector/dbclient.go * refactor: writer * refactor: syslog writer * refactor: ips * refactor: ensureResultDir * refactor: proxy * fix(db): call CloseDB * add integration test * feat(report): sort array in json * sort func for json diff * add build-int to makefile * add int-rds-redis to makefile * fix: test case, makefile * fix makefile * show cve count after diff * make diff * diff -c * sort exploits in json for diff * sort metasploit, exploit
This commit is contained in:
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/future-architect/vuls/constant"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/kotakanbe/goval-dictionary/db"
|
||||
)
|
||||
|
||||
// Alpine is the struct of Alpine Linux
|
||||
@@ -16,22 +15,33 @@ type Alpine struct {
|
||||
}
|
||||
|
||||
// NewAlpine creates OVAL client for SUSE
|
||||
func NewAlpine() Alpine {
|
||||
func NewAlpine(cnf config.VulnDictInterface) Alpine {
|
||||
return Alpine{
|
||||
Base{
|
||||
family: constant.Alpine,
|
||||
Cnf: cnf,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FillWithOval returns scan result after updating CVE info by OVAL
|
||||
func (o Alpine) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
|
||||
func (o Alpine) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
|
||||
var relatedDefs ovalResult
|
||||
if config.Conf.OvalDict.IsFetchViaHTTP() {
|
||||
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
|
||||
if o.Cnf.IsFetchViaHTTP() {
|
||||
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
driver, err := newOvalDB(o.Cnf, r.Family)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() {
|
||||
if err := driver.CloseDB(); err != nil {
|
||||
logging.Log.Errorf("Failed to close DB. err: %+v")
|
||||
}
|
||||
}()
|
||||
|
||||
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
"github.com/kotakanbe/goval-dictionary/db"
|
||||
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
|
||||
)
|
||||
|
||||
@@ -111,18 +110,19 @@ type Debian struct {
|
||||
}
|
||||
|
||||
// NewDebian creates OVAL client for Debian
|
||||
func NewDebian() Debian {
|
||||
func NewDebian(cnf config.VulnDictInterface) Debian {
|
||||
return Debian{
|
||||
DebianBase{
|
||||
Base{
|
||||
family: constant.Debian,
|
||||
Cnf: cnf,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FillWithOval returns scan result after updating CVE info by OVAL
|
||||
func (o Debian) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
|
||||
func (o Debian) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
|
||||
|
||||
//Debian's uname gives both of kernel release(uname -r), version(kernel-image version)
|
||||
linuxImage := "linux-image-" + r.RunningKernel.Release
|
||||
@@ -141,19 +141,29 @@ func (o Debian) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err
|
||||
}
|
||||
|
||||
var relatedDefs ovalResult
|
||||
if config.Conf.OvalDict.IsFetchViaHTTP() {
|
||||
if o.Cnf.IsFetchViaHTTP() {
|
||||
if r.Family != constant.Raspbian {
|
||||
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
|
||||
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
// OVAL does not support Package for Raspbian, so skip it.
|
||||
result := r.RemoveRaspbianPackFromResult()
|
||||
if relatedDefs, err = getDefsByPackNameViaHTTP(&result); err != nil {
|
||||
if relatedDefs, err = getDefsByPackNameViaHTTP(&result, o.Cnf.GetURL()); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
driver, err := newOvalDB(o.Cnf, r.Family)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() {
|
||||
if err := driver.CloseDB(); err != nil {
|
||||
logging.Log.Errorf("Failed to close DB. err: %+v")
|
||||
}
|
||||
}()
|
||||
|
||||
if r.Family != constant.Raspbian {
|
||||
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
|
||||
return 0, err
|
||||
@@ -201,18 +211,19 @@ type Ubuntu struct {
|
||||
}
|
||||
|
||||
// NewUbuntu creates OVAL client for Debian
|
||||
func NewUbuntu() Ubuntu {
|
||||
func NewUbuntu(cnf config.VulnDictInterface) Ubuntu {
|
||||
return Ubuntu{
|
||||
DebianBase{
|
||||
Base{
|
||||
family: constant.Ubuntu,
|
||||
Cnf: cnf,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FillWithOval returns scan result after updating CVE info by OVAL
|
||||
func (o Ubuntu) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
|
||||
func (o Ubuntu) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
|
||||
switch util.Major(r.Release) {
|
||||
case "14":
|
||||
kernelNamesInOval := []string{
|
||||
@@ -228,7 +239,7 @@ func (o Ubuntu) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err
|
||||
"linux-signed-lts-xenial",
|
||||
"linux",
|
||||
}
|
||||
return o.fillWithOval(driver, r, kernelNamesInOval)
|
||||
return o.fillWithOval(r, kernelNamesInOval)
|
||||
case "16":
|
||||
kernelNamesInOval := []string{
|
||||
"linux-aws",
|
||||
@@ -263,7 +274,7 @@ func (o Ubuntu) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err
|
||||
"linux-snapdragon",
|
||||
"linux",
|
||||
}
|
||||
return o.fillWithOval(driver, r, kernelNamesInOval)
|
||||
return o.fillWithOval(r, kernelNamesInOval)
|
||||
case "18":
|
||||
kernelNamesInOval := []string{
|
||||
"linux-aws",
|
||||
@@ -318,7 +329,7 @@ func (o Ubuntu) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err
|
||||
"linux-snapdragon",
|
||||
"linux",
|
||||
}
|
||||
return o.fillWithOval(driver, r, kernelNamesInOval)
|
||||
return o.fillWithOval(r, kernelNamesInOval)
|
||||
case "20":
|
||||
kernelNamesInOval := []string{
|
||||
"linux-aws",
|
||||
@@ -346,12 +357,12 @@ func (o Ubuntu) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err
|
||||
"linux-signed-oracle",
|
||||
"linux",
|
||||
}
|
||||
return o.fillWithOval(driver, r, kernelNamesInOval)
|
||||
return o.fillWithOval(r, kernelNamesInOval)
|
||||
}
|
||||
return 0, fmt.Errorf("Ubuntu %s is not support for now", r.Release)
|
||||
}
|
||||
|
||||
func (o Ubuntu) fillWithOval(driver db.DB, r *models.ScanResult, kernelNamesInOval []string) (nCVEs int, err error) {
|
||||
func (o Ubuntu) fillWithOval(r *models.ScanResult, kernelNamesInOval []string) (nCVEs int, err error) {
|
||||
linuxImage := "linux-image-" + r.RunningKernel.Release
|
||||
runningKernelVersion := ""
|
||||
kernelPkgInOVAL := ""
|
||||
@@ -417,11 +428,21 @@ func (o Ubuntu) fillWithOval(driver db.DB, r *models.ScanResult, kernelNamesInOv
|
||||
}
|
||||
|
||||
var relatedDefs ovalResult
|
||||
if config.Conf.OvalDict.IsFetchViaHTTP() {
|
||||
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
|
||||
if o.Cnf.IsFetchViaHTTP() {
|
||||
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
driver, err := newOvalDB(o.Cnf, r.Family)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() {
|
||||
if err := driver.CloseDB(); err != nil {
|
||||
logging.Log.Errorf("Failed to close DB. err: %+v")
|
||||
}
|
||||
}()
|
||||
|
||||
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
87
oval/oval.go
87
oval/oval.go
@@ -6,7 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
cnf "github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/config"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/future-architect/vuls/util"
|
||||
@@ -17,29 +17,43 @@ import (
|
||||
|
||||
// Client is the interface of OVAL client.
|
||||
type Client interface {
|
||||
FillWithOval(db.DB, *models.ScanResult) (int, error)
|
||||
|
||||
// CheckIfOvalFetched checks if oval entries are in DB by family, release.
|
||||
CheckIfOvalFetched(db.DB, string, string) (bool, error)
|
||||
CheckIfOvalFresh(db.DB, string, string) (bool, error)
|
||||
FillWithOval(*models.ScanResult) (int, error)
|
||||
CheckIfOvalFetched(string, string) (bool, error)
|
||||
CheckIfOvalFresh(string, string) (bool, error)
|
||||
}
|
||||
|
||||
// Base is a base struct
|
||||
type Base struct {
|
||||
family string
|
||||
Cnf config.VulnDictInterface
|
||||
}
|
||||
|
||||
// CheckIfOvalFetched checks if oval entries are in DB by family, release.
|
||||
func (b Base) CheckIfOvalFetched(driver db.DB, osFamily, release string) (fetched bool, err error) {
|
||||
if !cnf.Conf.OvalDict.IsFetchViaHTTP() {
|
||||
count, err := driver.CountDefs(osFamily, release)
|
||||
func (b Base) CheckIfOvalFetched(osFamily, release string) (fetched bool, err error) {
|
||||
ovalFamily, err := GetFamilyInOval(osFamily)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !b.Cnf.IsFetchViaHTTP() {
|
||||
driver, err := newOvalDB(b.Cnf, ovalFamily)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("Failed to count OVAL defs: %s, %s, %w", osFamily, release, err)
|
||||
return false, err
|
||||
}
|
||||
defer func() {
|
||||
if err := driver.CloseDB(); err != nil {
|
||||
logging.Log.Errorf("Failed to close DB. err: %+v")
|
||||
}
|
||||
}()
|
||||
|
||||
count, err := driver.CountDefs(ovalFamily, release)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("Failed to count OVAL defs: %s, %s, %w", ovalFamily, release, err)
|
||||
}
|
||||
logging.Log.Infof("OVAL %s %s found. defs: %d", osFamily, release, count)
|
||||
return 0 < count, nil
|
||||
}
|
||||
|
||||
url, _ := util.URLPathJoin(cnf.Conf.OvalDict.URL, "count", osFamily, release)
|
||||
url, _ := util.URLPathJoin(config.Conf.OvalDict.URL, "count", ovalFamily, release)
|
||||
resp, body, errs := gorequest.New().Timeout(10 * time.Second).Get(url).End()
|
||||
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
|
||||
return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %+v", url, resp, errs)
|
||||
@@ -48,16 +62,30 @@ func (b Base) CheckIfOvalFetched(driver db.DB, osFamily, release string) (fetche
|
||||
if err := json.Unmarshal([]byte(body), &count); err != nil {
|
||||
return false, xerrors.Errorf("Failed to Unmarshal. body: %s, err: %w", body, err)
|
||||
}
|
||||
logging.Log.Infof("OVAL %s %s is fresh. defs: %d", osFamily, release, count)
|
||||
return 0 < count, nil
|
||||
}
|
||||
|
||||
// CheckIfOvalFresh checks if oval entries are fresh enough
|
||||
func (b Base) CheckIfOvalFresh(driver db.DB, osFamily, release string) (ok bool, err error) {
|
||||
func (b Base) CheckIfOvalFresh(osFamily, release string) (ok bool, err error) {
|
||||
ovalFamily, err := GetFamilyInOval(osFamily)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
var lastModified time.Time
|
||||
if !cnf.Conf.OvalDict.IsFetchViaHTTP() {
|
||||
lastModified = driver.GetLastModified(osFamily, release)
|
||||
if !b.Cnf.IsFetchViaHTTP() {
|
||||
driver, err := newOvalDB(b.Cnf, ovalFamily)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer func() {
|
||||
if err := driver.CloseDB(); err != nil {
|
||||
logging.Log.Errorf("Failed to close DB. err: %+v")
|
||||
}
|
||||
}()
|
||||
lastModified = driver.GetLastModified(ovalFamily, release)
|
||||
} else {
|
||||
url, _ := util.URLPathJoin(cnf.Conf.OvalDict.URL, "lastmodified", osFamily, release)
|
||||
url, _ := util.URLPathJoin(config.Conf.OvalDict.URL, "lastmodified", ovalFamily, release)
|
||||
resp, body, errs := gorequest.New().Timeout(10 * time.Second).Get(url).End()
|
||||
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
|
||||
return false, xerrors.Errorf("HTTP GET error, url: %s, resp: %v, err: %+v", url, resp, errs)
|
||||
@@ -75,6 +103,33 @@ func (b Base) CheckIfOvalFresh(driver db.DB, osFamily, release string) (ok bool,
|
||||
osFamily, release, lastModified)
|
||||
return false, nil
|
||||
}
|
||||
logging.Log.Infof("OVAL is fresh: %s %s ", osFamily, release)
|
||||
logging.Log.Infof("OVAL %s %s is fresh. lastModified: %s", osFamily, release, lastModified.Format(time.RFC3339))
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// NewOvalDB returns oval db client
|
||||
func newOvalDB(cnf config.VulnDictInterface, familyInScanResult string) (driver db.DB, err error) {
|
||||
if cnf.IsFetchViaHTTP() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
path := cnf.GetURL()
|
||||
if cnf.GetType() == "sqlite3" {
|
||||
path = cnf.GetSQLite3Path()
|
||||
}
|
||||
|
||||
ovalFamily, err := GetFamilyInOval(familyInScanResult)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
driver, locked, err := db.NewDB(ovalFamily, cnf.GetType(), path, cnf.GetDebugSQL())
|
||||
if err != nil {
|
||||
if locked {
|
||||
err = xerrors.Errorf("SQLite3: %s is locked. err: %w", cnf.GetSQLite3Path(), err)
|
||||
}
|
||||
err = xerrors.Errorf("Failed to new OVAL DB. err: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
return driver, nil
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/future-architect/vuls/constant"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/kotakanbe/goval-dictionary/db"
|
||||
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
|
||||
)
|
||||
|
||||
@@ -21,18 +20,29 @@ type RedHatBase struct {
|
||||
}
|
||||
|
||||
// FillWithOval returns scan result after updating CVE info by OVAL
|
||||
func (o RedHatBase) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
|
||||
func (o RedHatBase) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
|
||||
var relatedDefs ovalResult
|
||||
if config.Conf.OvalDict.IsFetchViaHTTP() {
|
||||
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
|
||||
if o.Cnf.IsFetchViaHTTP() {
|
||||
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
driver, err := newOvalDB(o.Cnf, r.Family)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() {
|
||||
if err := driver.CloseDB(); err != nil {
|
||||
logging.Log.Errorf("Failed to close DB. err: %+v")
|
||||
}
|
||||
}()
|
||||
|
||||
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
|
||||
relatedDefs.Sort()
|
||||
for _, defPacks := range relatedDefs.entries {
|
||||
nCVEs += o.update(r, defPacks)
|
||||
}
|
||||
@@ -92,7 +102,7 @@ func (o RedHatBase) update(r *models.ScanResult, defPacks defPacks) (nCVEs int)
|
||||
ovalContent := *o.convertToModel(cve.CveID, &defPacks.def)
|
||||
vinfo, ok := r.ScannedCves[cve.CveID]
|
||||
if !ok {
|
||||
logging.Log.Debugf("%s is newly detected by OVAL", cve.CveID)
|
||||
logging.Log.Debugf("%s is newly detected by OVAL: DefID: %s", cve.CveID, defPacks.def.DefinitionID)
|
||||
vinfo = models.VulnInfo{
|
||||
CveID: cve.CveID,
|
||||
Confidences: models.Confidences{models.OvalMatch},
|
||||
@@ -103,13 +113,12 @@ func (o RedHatBase) update(r *models.ScanResult, defPacks defPacks) (nCVEs int)
|
||||
cveContents := vinfo.CveContents
|
||||
if v, ok := vinfo.CveContents[ctype]; ok {
|
||||
if v.LastModified.After(ovalContent.LastModified) {
|
||||
logging.Log.Debugf("%s, OvalID: %d ignored: ",
|
||||
cve.CveID, defPacks.def.ID)
|
||||
logging.Log.Debugf("%s ignored. DefID: %s ", cve.CveID, defPacks.def.DefinitionID)
|
||||
} else {
|
||||
logging.Log.Debugf("%s OVAL will be overwritten", cve.CveID)
|
||||
logging.Log.Debugf("%s OVAL will be overwritten. DefID: %s", cve.CveID, defPacks.def.DefinitionID)
|
||||
}
|
||||
} else {
|
||||
logging.Log.Debugf("%s also detected by OVAL", cve.CveID)
|
||||
logging.Log.Debugf("%s also detected by OVAL. DefID: %s", cve.CveID, defPacks.def.DefinitionID)
|
||||
cveContents = models.CveContents{}
|
||||
}
|
||||
|
||||
@@ -247,11 +256,12 @@ type RedHat struct {
|
||||
}
|
||||
|
||||
// NewRedhat creates OVAL client for Redhat
|
||||
func NewRedhat() RedHat {
|
||||
func NewRedhat(cnf config.VulnDictInterface) RedHat {
|
||||
return RedHat{
|
||||
RedHatBase{
|
||||
Base{
|
||||
family: constant.RedHat,
|
||||
Cnf: cnf,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -263,11 +273,12 @@ type CentOS struct {
|
||||
}
|
||||
|
||||
// NewCentOS creates OVAL client for CentOS
|
||||
func NewCentOS() CentOS {
|
||||
func NewCentOS(cnf config.VulnDictInterface) CentOS {
|
||||
return CentOS{
|
||||
RedHatBase{
|
||||
Base{
|
||||
family: constant.CentOS,
|
||||
Cnf: cnf,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -279,11 +290,12 @@ type Oracle struct {
|
||||
}
|
||||
|
||||
// NewOracle creates OVAL client for Oracle
|
||||
func NewOracle() Oracle {
|
||||
func NewOracle(cnf config.VulnDictInterface) Oracle {
|
||||
return Oracle{
|
||||
RedHatBase{
|
||||
Base{
|
||||
family: constant.Oracle,
|
||||
Cnf: cnf,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -296,11 +308,12 @@ type Amazon struct {
|
||||
}
|
||||
|
||||
// NewAmazon creates OVAL client for Amazon Linux
|
||||
func NewAmazon() Amazon {
|
||||
func NewAmazon(cnf config.VulnDictInterface) Amazon {
|
||||
return Amazon{
|
||||
RedHatBase{
|
||||
Base{
|
||||
family: constant.Amazon,
|
||||
Cnf: cnf,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
20
oval/suse.go
20
oval/suse.go
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/future-architect/vuls/constant"
|
||||
"github.com/future-architect/vuls/logging"
|
||||
"github.com/future-architect/vuls/models"
|
||||
"github.com/kotakanbe/goval-dictionary/db"
|
||||
ovalmodels "github.com/kotakanbe/goval-dictionary/models"
|
||||
)
|
||||
|
||||
@@ -17,23 +16,34 @@ type SUSE struct {
|
||||
}
|
||||
|
||||
// NewSUSE creates OVAL client for SUSE
|
||||
func NewSUSE() SUSE {
|
||||
func NewSUSE(cnf config.VulnDictInterface) SUSE {
|
||||
// TODO implement other family
|
||||
return SUSE{
|
||||
Base{
|
||||
family: constant.SUSEEnterpriseServer,
|
||||
Cnf: cnf,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// FillWithOval returns scan result after updating CVE info by OVAL
|
||||
func (o SUSE) FillWithOval(driver db.DB, r *models.ScanResult) (nCVEs int, err error) {
|
||||
func (o SUSE) FillWithOval(r *models.ScanResult) (nCVEs int, err error) {
|
||||
var relatedDefs ovalResult
|
||||
if config.Conf.OvalDict.IsFetchViaHTTP() {
|
||||
if relatedDefs, err = getDefsByPackNameViaHTTP(r); err != nil {
|
||||
if o.Cnf.IsFetchViaHTTP() {
|
||||
if relatedDefs, err = getDefsByPackNameViaHTTP(r, o.Cnf.GetURL()); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
} else {
|
||||
driver, err := newOvalDB(o.Cnf, r.Family)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer func() {
|
||||
if err := driver.CloseDB(); err != nil {
|
||||
logging.Log.Errorf("Failed to close DB. err: %+v")
|
||||
}
|
||||
}()
|
||||
|
||||
if relatedDefs, err = getDefsByPackNameFromOvalDB(driver, r); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
90
oval/util.go
90
oval/util.go
@@ -6,6 +6,7 @@ import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff"
|
||||
@@ -72,6 +73,12 @@ func (e *ovalResult) upsert(def ovalmodels.Definition, packName string, fstat fi
|
||||
return false
|
||||
}
|
||||
|
||||
func (e *ovalResult) Sort() {
|
||||
sort.SliceStable(e.entries, func(i, j int) bool {
|
||||
return e.entries[i].def.DefinitionID < e.entries[j].def.DefinitionID
|
||||
})
|
||||
}
|
||||
|
||||
type request struct {
|
||||
packName string
|
||||
versionRelease string
|
||||
@@ -88,8 +95,7 @@ type response struct {
|
||||
}
|
||||
|
||||
// getDefsByPackNameViaHTTP fetches OVAL information via HTTP
|
||||
func getDefsByPackNameViaHTTP(r *models.ScanResult) (
|
||||
relatedDefs ovalResult, err error) {
|
||||
func getDefsByPackNameViaHTTP(r *models.ScanResult, url string) (relatedDefs ovalResult, err error) {
|
||||
|
||||
nReq := len(r.Packages) + len(r.SrcPackages)
|
||||
reqChan := make(chan request, nReq)
|
||||
@@ -127,7 +133,7 @@ func getDefsByPackNameViaHTTP(r *models.ScanResult) (
|
||||
select {
|
||||
case req := <-reqChan:
|
||||
url, err := util.URLPathJoin(
|
||||
config.Conf.OvalDict.URL,
|
||||
url,
|
||||
"packs",
|
||||
r.Family,
|
||||
r.Release,
|
||||
@@ -190,7 +196,6 @@ func httpGet(url string, req request, resChan chan<- response, errChan chan<- er
|
||||
var resp *http.Response
|
||||
count, retryMax := 0, 3
|
||||
f := func() (err error) {
|
||||
// resp, body, errs = gorequest.New().SetDebug(config.Conf.Debug).Get(url).End()
|
||||
resp, body, errs = gorequest.New().Timeout(10 * time.Second).Get(url).End()
|
||||
if 0 < len(errs) || resp == nil || resp.StatusCode != 200 {
|
||||
count++
|
||||
@@ -246,13 +251,18 @@ func getDefsByPackNameFromOvalDB(driver db.DB, r *models.ScanResult) (relatedDef
|
||||
})
|
||||
}
|
||||
|
||||
ovalFamily, err := GetFamilyInOval(r.Family)
|
||||
if err != nil {
|
||||
return relatedDefs, err
|
||||
}
|
||||
|
||||
for _, req := range requests {
|
||||
definitions, err := driver.GetByPackName(r.Family, r.Release, req.packName, req.arch)
|
||||
definitions, err := driver.GetByPackName(ovalFamily, r.Release, req.packName, req.arch)
|
||||
if err != nil {
|
||||
return relatedDefs, xerrors.Errorf("Failed to get %s OVAL info by package: %#v, err: %w", r.Family, req, err)
|
||||
}
|
||||
for _, def := range definitions {
|
||||
affected, notFixedYet, fixedIn := isOvalDefAffected(def, req, r.Family, r.RunningKernel, r.EnabledDnfModules)
|
||||
affected, notFixedYet, fixedIn := isOvalDefAffected(def, req, ovalFamily, r.RunningKernel, r.EnabledDnfModules)
|
||||
if !affected {
|
||||
continue
|
||||
}
|
||||
@@ -414,3 +424,71 @@ var centosVerPattern = regexp.MustCompile(`\.[es]l(\d+)(?:_\d+)?(?:\.centos)?`)
|
||||
func centOSVersionToRHEL(ver string) string {
|
||||
return centosVerPattern.ReplaceAllString(ver, ".el$1")
|
||||
}
|
||||
|
||||
// NewOVALClient returns a client for OVAL database
|
||||
func NewOVALClient(family string, cnf config.GovalDictConf) (Client, error) {
|
||||
switch family {
|
||||
case constant.Debian, constant.Raspbian:
|
||||
return NewDebian(&cnf), nil
|
||||
case constant.Ubuntu:
|
||||
return NewUbuntu(&cnf), nil
|
||||
case constant.RedHat:
|
||||
return NewRedhat(&cnf), nil
|
||||
case constant.CentOS:
|
||||
//use RedHat's OVAL
|
||||
return NewCentOS(&cnf), nil
|
||||
case constant.Oracle:
|
||||
return NewOracle(&cnf), nil
|
||||
case constant.SUSEEnterpriseServer:
|
||||
// TODO other suse family
|
||||
return NewSUSE(&cnf), nil
|
||||
case constant.Alpine:
|
||||
return NewAlpine(&cnf), nil
|
||||
case constant.Amazon:
|
||||
return NewAmazon(&cnf), nil
|
||||
case constant.FreeBSD, constant.Windows:
|
||||
return nil, nil
|
||||
case constant.ServerTypePseudo:
|
||||
return nil, nil
|
||||
default:
|
||||
if family == "" {
|
||||
return nil, xerrors.New("Probably an error occurred during scanning. Check the error message")
|
||||
}
|
||||
return nil, xerrors.Errorf("OVAL for %s is not implemented yet", family)
|
||||
}
|
||||
}
|
||||
|
||||
// GetFamilyInOval returns the OS family name in OVAL
|
||||
// For example, CentOS uses Red Hat's OVAL, so return 'redhat'
|
||||
func GetFamilyInOval(familyInScanResult string) (string, error) {
|
||||
switch familyInScanResult {
|
||||
case constant.Debian, constant.Raspbian:
|
||||
return constant.Debian, nil
|
||||
case constant.Ubuntu:
|
||||
return constant.Ubuntu, nil
|
||||
case constant.RedHat:
|
||||
return constant.RedHat, nil
|
||||
case constant.CentOS:
|
||||
//use RedHat's OVAL
|
||||
return constant.RedHat, nil
|
||||
case constant.Oracle:
|
||||
return constant.Oracle, nil
|
||||
case constant.SUSEEnterpriseServer:
|
||||
// TODO other suse family
|
||||
return constant.SUSEEnterpriseServer, nil
|
||||
case constant.Alpine:
|
||||
return constant.Alpine, nil
|
||||
case constant.Amazon:
|
||||
return constant.Amazon, nil
|
||||
case constant.FreeBSD, constant.Windows:
|
||||
return "", nil
|
||||
case constant.ServerTypePseudo:
|
||||
return "", nil
|
||||
default:
|
||||
if familyInScanResult == "" {
|
||||
return "", xerrors.New("Probably an error occurred during scanning. Check the error message")
|
||||
}
|
||||
return "", xerrors.Errorf("OVAL for %s is not implemented yet", familyInScanResult)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1281,3 +1281,57 @@ func Test_lessThan(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ovalResult_Sort(t *testing.T) {
|
||||
type fields struct {
|
||||
entries []defPacks
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want fields
|
||||
}{
|
||||
{
|
||||
name: "already sorted",
|
||||
fields: fields{
|
||||
entries: []defPacks{
|
||||
{def: ovalmodels.Definition{DefinitionID: "0"}},
|
||||
{def: ovalmodels.Definition{DefinitionID: "1"}},
|
||||
},
|
||||
},
|
||||
want: fields{
|
||||
entries: []defPacks{
|
||||
{def: ovalmodels.Definition{DefinitionID: "0"}},
|
||||
{def: ovalmodels.Definition{DefinitionID: "1"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sort",
|
||||
fields: fields{
|
||||
entries: []defPacks{
|
||||
{def: ovalmodels.Definition{DefinitionID: "1"}},
|
||||
{def: ovalmodels.Definition{DefinitionID: "0"}},
|
||||
},
|
||||
},
|
||||
want: fields{
|
||||
entries: []defPacks{
|
||||
{def: ovalmodels.Definition{DefinitionID: "0"}},
|
||||
{def: ovalmodels.Definition{DefinitionID: "1"}},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
o := &ovalResult{
|
||||
entries: tt.fields.entries,
|
||||
}
|
||||
o.Sort()
|
||||
|
||||
if !reflect.DeepEqual(o.entries, tt.want.entries) {
|
||||
t.Errorf("act %#v, want %#v", o.entries, tt.want.entries)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user