2020-06-24 14:38:42 -05:00
|
|
|
package cveinfo
|
|
|
|
|
|
|
|
import (
|
2021-04-05 19:40:33 -05:00
|
|
|
"fmt"
|
2022-09-28 13:39:54 -05:00
|
|
|
|
|
|
|
v1 "github.com/google/go-containerregistry/pkg/v1"
|
|
|
|
"github.com/opencontainers/go-digest"
|
2022-01-19 10:57:10 -05:00
|
|
|
ispec "github.com/opencontainers/image-spec/specs-go/v1"
|
2021-12-03 22:50:58 -05:00
|
|
|
"zotregistry.io/zot/pkg/extensions/search/common"
|
2022-09-28 13:39:54 -05:00
|
|
|
cvemodel "zotregistry.io/zot/pkg/extensions/search/cve/model"
|
|
|
|
"zotregistry.io/zot/pkg/extensions/search/cve/trivy"
|
2021-12-03 22:50:58 -05:00
|
|
|
"zotregistry.io/zot/pkg/log"
|
|
|
|
"zotregistry.io/zot/pkg/storage"
|
2020-06-24 14:38:42 -05:00
|
|
|
)
|
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
type CveInfo interface {
|
|
|
|
GetImageListForCVE(repo, cveID string) ([]ImageInfoByCVE, error)
|
|
|
|
GetImageListWithCVEFixed(repo, cveID string) ([]common.TagInfo, error)
|
|
|
|
GetCVEListForImage(image string) (map[string]cvemodel.CVE, error)
|
|
|
|
GetCVESummaryForImage(image string) (ImageCVESummary, error)
|
|
|
|
UpdateDB() error
|
2020-06-24 14:38:42 -05:00
|
|
|
}
|
2020-06-26 14:09:10 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
type Scanner interface {
|
|
|
|
ScanImage(image string) (map[string]cvemodel.CVE, error)
|
|
|
|
IsImageFormatScannable(image string) (bool, error)
|
|
|
|
CompareSeverities(severity1, severity2 string) int
|
|
|
|
UpdateDB() error
|
2021-10-04 16:27:26 -05:00
|
|
|
}
|
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
type ImageInfoByCVE struct {
|
|
|
|
Tag string
|
|
|
|
Digest digest.Digest
|
|
|
|
Manifest v1.Manifest
|
|
|
|
}
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
type ImageCVESummary struct {
|
|
|
|
Count int
|
|
|
|
MaxSeverity string
|
|
|
|
}
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
type BaseCveInfo struct {
|
|
|
|
Log log.Logger
|
|
|
|
Scanner Scanner
|
|
|
|
LayoutUtils common.OciLayoutUtils
|
|
|
|
}
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
func NewCVEInfo(storeController storage.StoreController, log log.Logger) *BaseCveInfo {
|
|
|
|
layoutUtils := common.NewBaseOciLayoutUtils(storeController, log)
|
|
|
|
scanner := trivy.NewScanner(storeController, layoutUtils, log)
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
return &BaseCveInfo{Log: log, Scanner: scanner, LayoutUtils: layoutUtils}
|
|
|
|
}
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
func (cveinfo BaseCveInfo) GetImageListForCVE(repo, cveID string) ([]ImageInfoByCVE, error) {
|
|
|
|
imgList := make([]ImageInfoByCVE, 0)
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
manifests, err := cveinfo.LayoutUtils.GetImageManifests(repo)
|
|
|
|
if err != nil {
|
|
|
|
cveinfo.Log.Error().Err(err).Str("repo", repo).Msg("unable to get list of tags from repo")
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
return imgList, err
|
|
|
|
}
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
for _, manifest := range manifests {
|
|
|
|
tag := manifest.Annotations[ispec.AnnotationRefName]
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
image := fmt.Sprintf("%s:%s", repo, tag)
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
isValidImage, _ := cveinfo.Scanner.IsImageFormatScannable(image)
|
|
|
|
if !isValidImage {
|
|
|
|
continue
|
|
|
|
}
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
cveMap, err := cveinfo.Scanner.ScanImage(image)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
for id := range cveMap {
|
|
|
|
if id == cveID {
|
|
|
|
digest := manifest.Digest
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
imageBlobManifest, err := cveinfo.LayoutUtils.GetImageBlobManifest(repo, digest)
|
|
|
|
if err != nil {
|
|
|
|
cveinfo.Log.Error().Err(err).Msg("unable to read image blob manifest")
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
return []ImageInfoByCVE{}, err
|
|
|
|
}
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
imgList = append(imgList, ImageInfoByCVE{
|
|
|
|
Tag: tag,
|
|
|
|
Digest: digest,
|
|
|
|
Manifest: imageBlobManifest,
|
|
|
|
})
|
2021-10-04 16:27:26 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-06-26 14:09:10 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
return imgList, nil
|
2020-06-26 14:09:10 -05:00
|
|
|
}
|
2020-08-19 01:03:16 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
func (cveinfo BaseCveInfo) GetImageListWithCVEFixed(repo, cveID string) ([]common.TagInfo, error) {
|
|
|
|
tagsInfo, err := cveinfo.LayoutUtils.GetImageTagsWithTimestamp(repo)
|
|
|
|
if err != nil {
|
|
|
|
cveinfo.Log.Error().Err(err).Str("repo", repo).Msg("unable to get list of tags from repo")
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
return []common.TagInfo{}, err
|
|
|
|
}
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
vulnerableTags := make([]common.TagInfo, 0)
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
var hasCVE bool
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
for _, tag := range tagsInfo {
|
|
|
|
image := fmt.Sprintf("%s:%s", repo, tag.Name)
|
|
|
|
tagInfo := common.TagInfo{Name: tag.Name, Timestamp: tag.Timestamp, Digest: tag.Digest}
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
isValidImage, _ := cveinfo.Scanner.IsImageFormatScannable(image)
|
|
|
|
if !isValidImage {
|
|
|
|
cveinfo.Log.Debug().Str("image", image).
|
|
|
|
Msg("image media type not supported for scanning, adding as a vulnerable image")
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
vulnerableTags = append(vulnerableTags, tagInfo)
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
continue
|
2021-04-05 19:40:33 -05:00
|
|
|
}
|
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
cveMap, err := cveinfo.Scanner.ScanImage(image)
|
|
|
|
if err != nil {
|
|
|
|
cveinfo.Log.Debug().Str("image", image).
|
|
|
|
Msg("scanning failed, adding as a vulnerable image")
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
vulnerableTags = append(vulnerableTags, tagInfo)
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
continue
|
|
|
|
}
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
hasCVE = false
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
for id := range cveMap {
|
|
|
|
if id == cveID {
|
|
|
|
hasCVE = true
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
if hasCVE {
|
|
|
|
vulnerableTags = append(vulnerableTags, tagInfo)
|
|
|
|
}
|
|
|
|
}
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
if len(vulnerableTags) != 0 {
|
|
|
|
cveinfo.Log.Info().Str("repo", repo).Msg("comparing fixed tags timestamp")
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
tagsInfo = common.GetFixedTags(tagsInfo, vulnerableTags)
|
|
|
|
} else {
|
|
|
|
cveinfo.Log.Info().Str("repo", repo).Str("cve-id", cveID).
|
|
|
|
Msg("image does not contain any tag that have given cve")
|
2021-04-05 19:40:33 -05:00
|
|
|
}
|
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
return tagsInfo, nil
|
2021-04-05 19:40:33 -05:00
|
|
|
}
|
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
func (cveinfo BaseCveInfo) GetCVEListForImage(image string) (map[string]cvemodel.CVE, error) {
|
|
|
|
cveMap := make(map[string]cvemodel.CVE)
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
isValidImage, err := cveinfo.Scanner.IsImageFormatScannable(image)
|
|
|
|
if !isValidImage {
|
|
|
|
return cveMap, err
|
2021-04-05 19:40:33 -05:00
|
|
|
}
|
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
return cveinfo.Scanner.ScanImage(image)
|
|
|
|
}
|
2022-01-19 10:57:10 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
func (cveinfo BaseCveInfo) GetCVESummaryForImage(image string) (ImageCVESummary, error) {
|
|
|
|
imageCVESummary := ImageCVESummary{
|
|
|
|
Count: 0,
|
|
|
|
MaxSeverity: "UNKNOWN",
|
|
|
|
}
|
2022-01-19 10:57:10 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
isValidImage, err := cveinfo.Scanner.IsImageFormatScannable(image)
|
|
|
|
if !isValidImage {
|
|
|
|
return imageCVESummary, err
|
|
|
|
}
|
2022-01-19 10:57:10 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
cveMap, err := cveinfo.Scanner.ScanImage(image)
|
|
|
|
if err != nil {
|
|
|
|
return imageCVESummary, err
|
|
|
|
}
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
for _, cve := range cveMap {
|
|
|
|
if cveinfo.Scanner.CompareSeverities(imageCVESummary.MaxSeverity, cve.Severity) > 0 {
|
|
|
|
imageCVESummary.MaxSeverity = cve.Severity
|
2021-04-05 19:40:33 -05:00
|
|
|
}
|
|
|
|
}
|
2022-09-28 13:39:54 -05:00
|
|
|
imageCVESummary.Count = len(cveMap)
|
2021-04-05 19:40:33 -05:00
|
|
|
|
2022-09-28 13:39:54 -05:00
|
|
|
return imageCVESummary, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cveinfo BaseCveInfo) UpdateDB() error {
|
|
|
|
return cveinfo.Scanner.UpdateDB()
|
2021-04-05 19:40:33 -05:00
|
|
|
}
|